Skip to content

feat: queryAll, queryMore, and full-result pagination - #49

Merged
WalrusSoup merged 2 commits into
mainfrom
feature/queryMore
Jun 30, 2026
Merged

feat: queryAll, queryMore, and full-result pagination#49
WalrusSoup merged 2 commits into
mainfrom
feature/queryMore

Conversation

@WalrusSoup

Copy link
Copy Markdown
Contributor

Summary

Adds first-class support for the Salesforce queryAll resource and cursor-based pagination (queryMore), plus a convenience wrapper that transparently fetches an entire result set across all pages.

Salesforce returns query results in batches (up to 2,000 records). To retrieve everything you must follow the nextRecordsUrl cursor returned on each response until done is true. This PR wires that up end to end.

What's new

  • executeQueryAll($builder) / executeQueryAllRaw($rawQuery) — run SOQL against the queryAll endpoint, which also returns soft-deleted and archived records.
  • queryMore($nextRecordsUrl) — fetch the next batch of records using the nextRecordsUrl from a prior response. Works for both query and queryAll results.
  • getAllRecords($builder, $includeDeleted = false) / getAllRecordsRaw($rawQuery, $includeDeleted = false) — follow pagination until Salesforce reports done, returning the complete result set as a single array. Pass $includeDeleted = true to page through the queryAll endpoint.

Implementation notes

  • New QueryMore request strips the /services/data/v{XX.X} prefix from nextRecordsUrl before resolving the endpoint, because the Saloon connector base URL already includes it (absolute URLs are not permitted).
  • Per the Salesforce docs, a queryAll request returns a nextRecordsUrl containing /query/ (not /queryAll/) — it still serves the remaining results from the original queryAll. QueryMore handles either path transparently.
  • Extracted a shared stripAttributes() helper so record-attribute stripping is no longer duplicated between unpackResponseIfNeeded() and the pagination path.
  • getAllRecords* reads the raw response so it can see done / nextRecordsUrl; note that enabling recordsOnly() strips this metadata, so manual queryMore pagination requires it to be off.

Salesforce reference

Tests

  • New tests/QueryMoreTest.php covering: nextRecordsUrl prefix stripping (query, queryAll, and fully-qualified forms using the real doc example value), multi-page pagination, single-page short-circuit, queryAll endpoint routing, and queryMore request resolution.
  • Full suite: 95 passed.

Docs

  • README gains a "Running SOQL Queries" section documenting executeQuery/executeQueryAll, manual queryMore pagination (with the recordsOnly() caveat), and getAllRecords full-fetch (with a memory note pointing to the Bulk API for very large exports).

Add a "Running SOQL Queries" section covering executeQuery/executeQueryAll,
manual queryMore pagination, and getAllRecords full-result fetching.
@WalrusSoup
WalrusSoup merged commit cbd8e9d into main Jun 30, 2026
2 checks passed
@WalrusSoup
WalrusSoup deleted the feature/queryMore branch June 30, 2026 21:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant