Repository navigation
feat(data): read ArcGIS layers past their record limit, in the app and the browser - #823
Conversation
…d the browser An ArcGIS FeatureServer or MapServer query that stops at the server's maxRecordCount (exceededTransferLimit) is now read again from the start in pages of resultOffset and resultRecordCount, ordered by the layer's object id field, up to 100,000 features. The first page, asked for in no order, can hold other features than the ordered first (Hawaii's zoning MapServer: 964 of 1,000 shared), so offsets continued from it skip and repeat features. The layer's description is read once to check advancedQueryCapabilities.supportsPagination; layers without it, or whose paging fails before an ordered page lands, keep the first page and its note. A server that ignores resultOffset, and a query that sets its own window, are read as before. Paging is now a sans-I/O state machine (ogc::read_pages -> Step::Fetch / Step::Done). service.add drives it blocking, as before; the app's download poll drives it off the frame, so layers added from Add From Service or the Connections tree are paged on the desktop and in the browser. That path previously read one page for OGC API collections too (opengeos#519 paged only service.add), so they are now paged there as well. The shared test server matches a route's path with its query, so a layer's pages are told apart; tests/support/ogc.rs gains ArcGIS page and layer generators. Closes opengeos#764 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Shared paging state and behavior crates/data/src/ogc.rs |
The shared reader now detects eligible ArcGIS truncation, checks layer pagination support, and reads offset pages within the feature limit. It retains linked-page traversal and adds tests for pagination, limits, and failure cases. Service notes describe the updated page limits. |
Command download integration crates/engine/src/cmd/service.rs, crates/engine/src/tests.rs, tests/support/ogc.rs, tests/support/ogc_server.rs |
Command downloads now drive the page state machine and validate each page URL against its referrer. Tests cover supported and unsupported ArcGIS pagination, with fixtures that match requests by query string. |
Background UI downloads crates/ui-egui/src/lib.rs, crates/ui-egui/src/serviceui.rs, crates/ui-egui/tests/smoke.rs |
The UI tracks service page reads, fetches subsequent pages within the remaining byte budget, and adds completed downloads. Smoke tests cover ArcGIS offset pages and OGC API next links. |
Priority:
Estimated code review effort: 4 (Complex) | ~45 minutes
Change: Feature · Severity of issue fixed: Medium
Sequence Diagram(s)
sequenceDiagram
participant UiState
participant PollPages as serviceui::poll_pages
participant Pages
participant GoOn as serviceui::go_on
participant HTTP
participant AddLanded as add_landed
UiState->>PollPages: poll pending page reads
PollPages->>Pages: land downloaded response
Pages-->>GoOn: return Fetch or Done
GoOn->>HTTP: validate and fetch next-page URL
HTTP-->>PollPages: return page response
GoOn->>AddLanded: add completed download
Suggested reviewers: giswqs, dekhtiarjonathan
Merge Risk: 
Minimal · up to e0a9c
-
The change makes ArcGIS and OGC API layers read past their per-request record limit, up to 100,000 features, in both commands and the app. Failures fall back to the first page with a note. Tests cover paging, the fallbacks and the app path, and no concrete merge-blocking risk remains.
Pre-merge checks: 
4 · 
1
-
Failed checks: 1 inconclusive Passed checks: 4 passed-
Full details: Linked Issues check
-
Explanation
Directly linked issue
#764is the only active target. Its coding requirements are met at the reviewed head.- ArcGIS paging past the record limit.
crates/data/src/ogc.rsread_pagesstarts ArcGIS paging only when a/queryanswer setsexceededTransferLimit. It then requestsresultOffsetandresultRecordCountpages.service.add(crates/engine/src/cmd/service.rsdownload_features) drives the same state machine with the existingMAX_PAGED_FEATURES, byte budget (left), andBLOCKING_TIMEOUT. A feature cap or budget overrun keeps the read features and adds the notethe first {max} features are read; the rest aren't. - Fallback without pagination.
arcgis_pagingreturnsNoneunlessadvancedQueryCapabilities.supportsPaginationistrue. Pre-10.3 servers, unreadable descriptions, and non-positive or non-numericmaxRecordCountvalues fall back to the first page with its existing note. AmaxRecordCountoutside 1 toMAX_PAGED_FEATURESfalls back to the first page size. - Recorded-answer tests. The PR reports
ogc::tests::arcgis_pages_joined_from_offsets(joined pages, feature cap, hostilemaxRecordCount, no-pagination and unreadable-description fallbacks), plus engine and app integration tests. I did not re-run them.
The issue's open question on browser paging is answered. The same state machine runs in the app path (
crates/ui-egui/src/serviceui.rsread_pages/poll_pages) throughfetch_into_limited. That path keeps the shared byte budget and per-page address checks.Limits of this assessment. The tail of the
ogc.rsdiff, which holdsfinish,stop, andfinish_at_max, was truncated. I relied on the diff head, the summary, and theservice.rsdiff for those behaviors. The app path has no one-minute limit. The PR states this, and the issue's timeout requirement applies to the blocking commands, which keep it. - ArcGIS paging past the record limit.
Full details: Out of Scope Changes check
-
Explanation
Each changed area connects to
#764or to the paging behavior it requests.crates/data/src/ogc.rs: the ArcGIS paging, theread_pages/Pages/Stepstate machine, andjoin_pagesas a blocking wrapper. These implement#764. Theogc_apinote now reads the same on every target. This follows from the browser paging the issue raises.crates/engine/src/cmd/service.rs:download_featuresdrives the state machine and keeps its budget and timeout. This is the blocking path the issue names.crates/ui-egui/src/lib.rsandserviceui.rs: the app download path pages layers from the Add From Service dialog and the Connections tree. The issue targets ArcGIS layers users add, and the issue's browser question covers this path. The PR states that OGC API collections added from the app are also paged. That is a consequence of the shared state machine and a fix to the#519gap, not an unrelated feature.- Tests (
crates/engine/src/tests.rs,crates/ui-egui/tests/smoke.rs,tests/support/ogc.rs,tests/support/ogc_server.rs): these support the new behavior. The route matching change lets the fixture return a different answer for each page. docs/user-guide/data-formats.md: documents the new limits and the one-minute note.
Service group import and refresh (
service.import,service.refresh) are not changed, as the PR states.No unrelated change was found in the summaries or the inspected diffs.
-
Full details: Docstring Coverage
-
Explanation
Docstring coverage is 76.92% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 39 functions across 7 files. (2 skipped: 1 unsupported, 1 too large.)
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
-
Finishing Touches
-
🧪 Generate unit tests (beta)
-
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
A rabbit checks the pages in rows,
Then hops where each next query goes.
The features gather, ordered right,
Until the cap ends their long flight.
The map gets pages, one by one,
And rests when all the reads are done.
Comment @coderabbitai help to get the list of available commands.
Code reviewI read the whole diff and the surrounding source. I found no confirmed bugs. I couldn't run the build or the tests (no Bash tool), so the new tests are unexecuted. What I checked
Quality (low confidence, optional)
AGENTS.md
BugsNone found. SecurityNone found. Paged and described URLs go through PerformanceNone found. Reading the layer again from offset 0 costs one extra first-page request, and the code comments explain why that's needed. Change sizeCompared: the whole PR against main (merge base e7dad1e to PR head e0a9c4d)
|
📖 Docs preview
GitHub Pages takes a minute or two to publish a new commit. |
Summary
Before, an ArcGIS FeatureServer or MapServer layer stopped at the server's
maxRecordCount, often 1,000 or 2,000 features, and RustGIS said "the rest aren't read". After, RustGIS reads the rest page by page, up to 100,000 features. That works in the desktop app, in the browser, and throughservice.add.Along the way I found that #519's OGC API paging only ran inside the blocking
service.addcommand. When you add a layer from the Add From Service dialog or the Connections tree, the app downloads it withui.addUrlandlayer.addDownload, and that path read only the first page, on the desktop as well as on the web. This PR pages that path too, so OGC API collections added from the app now get every page as well.How it works
ogc::read_pagesis now a small state machine with no network code of its own. It returnsStep::Fetch(Pages)(the next address, plus the page it was found on) orStep::Done(bytes, note). Two drivers run the same logic:service.addanddownload_featureskeep their blocking loop, with the byte budget and the one-minute limit.join_pagesis a blocking wrapper around the same state machine, so fix: OGC API Features layers read every page of a collection #519's tests still cover it.serviceui::read_pagesandpoll_pages) fetches each further page off the frame throughcache::download_limited, which works in both builds. Each address is checked against the page it came from, the pages share the download's byte budget, and the layer is added once the read is done. A read whose project was closed meanwhile is dropped with the same notice as an ordinary download.nextlink, as before.exceededTransferLimit, RustGIS reads the layer's description (…/FeatureServer/0?f=json, with the query's token), then reads the layer again from offset 0, in pages ofresultOffsetandresultRecordCountordered by object id. It restarts because the first page, requested in no particular order, can hold different features from the ordered first page. On Hawaii's zoning MapServer they shared only 964 of 1,000, and continuing from offset 1,000 read 36 features twice and missed 36. The restart costs one request per layer. If paging fails before an ordered page arrives, RustGIS keeps the original first page and its note.advancedQueryCapabilities.supportsPaginationmust betrue. Otherwise, including servers before 10.3 (which don't report the flag) and descriptions that can't be read, RustGIS keeps the first page and its existing "record limit" note.maxRecordCountis the page size if it's between 1 and 100,000. A hostile value (0, negative, fractional, huge, a string) falls back to the size of the first page.objectIdField, or the field typedesriFieldTypeOID, becomesorderByFields. MapServer layers usually give only the latter: none of the three live MapServers I tested setobjectIdField. The name is only used if it's plain, because it goes into the address. AnorderByFieldsalready in the query is kept.resultOffsetand sends the first ordered page again, that page is dropped with a note. A page that adds nothing would ask for itself again, which the existing loop guard catches. A query that already setsresultOffsetorresultRecordCountis read exactly as written.Not in this PR: service group import and refresh (
service.import,service.refresh) still read one answer per layer.No new dependency, and no change to command ids or the project format.
Testing
cargo xtask ci: passed (1,955 tests, layers ok)cargo build --locked --target wasm32-unknown-unknown -p rustgis-web: passedLive servers. I checked each layer against the server's own
returnCountOnlycount, and that every object id appears exactly once:service.add(CLI)service.add(CLI)service.add(CLI)service.add(CLI)ui_shot)I didn't find a live server without pagination to test the fallback against. That case is covered by the recorded answers below. Fairfax took 54 s of the one-minute limit that blocking commands have, so on a slower connection
service.addmay stop at that limit first, with its own note. The app path has no such limit.Tests. The two integration tests use the shared fixture server in
tests/support/. Its routes can now match a path together with its query, so each page gets its own answer, and the tests assert the exact sequence of requests.tests/support/ogc.rsgainsarcgis_pageandarcgis_layer.smoke::service_features_are_read_page_by_page_off_the_framedrives the app'sui.addUrl {"service": true}path. It covers an ArcGIS layer whose first page is unordered, which reads 0–4 in order from offsets 0, 2 and 4, and an OGC API collection in two pages, with no "aren't read" note.tests::arcgis_features_read_past_the_record_limitdoes the same throughservice.add, plus a layer that can't page: it keeps its first page and its note, and its description is the only extra request.[3, 0, 2, 3, 4]. With the app's paging branch removed, the app test reads the first page only.ogc::tests::arcgis_pages_joined_from_offsetsuses recorded answers to cover:maxRecordCountvalues;resultOffset; an empty or failing first ordered page, which falls back to the first page; a later failing page, which keeps what was read and adds a note;ogc::tests::arcgis_page_addressescovers the page and layer-description addresses and how the object-id field is chosen.pages_joined_up_to_a_limitandogc_api_features_follow_next_pagespass unchanged on the state machine.Related issue
Closes #764
🤖 Generated with Claude Code
Summary by CodeRabbit
service.addwait up to one minute for page-by-page downloads.