diff --git a/src/library/formats.js b/src/library/formats.js index e603a1276..c3d887997 100644 --- a/src/library/formats.js +++ b/src/library/formats.js @@ -429,8 +429,15 @@ export async function loadLibraryDataset( const parsed = parseLibraryBody('arcgis', await readPage(url, budget)); candidates.push(...parsed.candidates); if (!parsed.exceededTransferLimit || !parsed.candidates.length) break; - if (candidates.length >= source.maxFeatures) break; - if (page === source.maxPages - 1) truncated = true; + // The upstream holds more than was read: stopping here, at the + // feature cap or the last page, leaves the dataset partial. + if ( + candidates.length >= source.maxFeatures || + page === source.maxPages - 1 + ) { + truncated = true; + break; + } } } else { const parsed = parseLibraryBody( diff --git a/src/library/formats.test.mjs b/src/library/formats.test.mjs index 4337ba818..fe164e4c7 100644 --- a/src/library/formats.test.mjs +++ b/src/library/formats.test.mjs @@ -182,6 +182,27 @@ test('ArcGIS paging follows exceededTransferLimit up to maxPages', async () => { assert.equal(collection.truncated, true); }); +test('ArcGIS stopping at maxFeatures with more upstream reads as truncated', async () => { + const value = entry({ + format: 'arcgis', + url: 'https://s.example.org/FeatureServer/0', + maxFeatures: 3, + maxPages: 5, + }); + let pages = 0; + const collection = await loadLibraryDataset(value, async () => { + pages += 1; + return JSON.stringify({ + type: 'FeatureCollection', + properties: { exceededTransferLimit: true }, + features: [point(1, 0), point(2, 0), point(3, 0)], + }); + }); + assert.equal(pages, 1); + assert.equal(collection.features.length, 3); + assert.equal(collection.truncated, true); +}); + test('a plain dataset request carries the manifest query once', async () => { const value = entry({ format: 'geojson',