feat(firestore)!: add collection group queries - #88
Merged
Merged
Conversation
Add `queryGroup` and `streamQueryGroup` to `FirestoreServiceShape`, so a
query can span every collection with a given ID at any depth
(`posts/{p}/comments` and `users/{u}/comments` both belong to the
`comments` group).
- core: every repository gains a `group` view exposing the same four query
methods (`query`, `queryStream`, `getByQuery`, `getByQueryStream`) over
the collection group named by the last segment of `collectionPath`.
New optional `pathField` (constrained to string fields) fills a model
field with each document's full path on every read. The query methods
are built once by a shared helper for both views.
- core: `validateCollectionId` / `collectionIdOf` exported and shared by
the repository factory and every backend.
- admin/client: build the base query from `collectionGroup(id)` with the
constraint handling shared with single-collection queries. The ID is
validated up front so both the effect and the stream fail with a typed
`FirestoreError` (`invalid-argument`) instead of a defect. The client
dies inside a transaction, matching `query`.
- mock: `docsInCollectionGroup` matches documents whose parent collection
segment equals the ID; simulated state resolves by collection ID.
`MockFirestoreService` gains the two throwing defaults.
- noopLayer, docs (core AGENTS/README/MIGRATION, mock README, root
README) and tests for all four packages.
BREAKING CHANGE: `FirestoreServiceShape` has two new required members,
`queryGroup` and `streamQueryGroup`. Hand-written `FirestoreService`
layers must implement them; `noopLayer` and `MockFirestoreService`
already do. See MIGRATION.md step 8.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xo119tdUdoz5hd3eZ6QuzP
fwal
marked this pull request as ready for review
September 18, 2026 11:48
|
`__name__` ordering and the implicit document-name tiebreaker compared `ref.id`, so two group documents with the same ID under different parents compared equal and paged differently from the real backends. Compare the full path instead, and accept a `__name__` cursor as either a bare ID (single-collection query, expanded against the document's parent) or a full path (collection group query), matching Firestore. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xo119tdUdoz5hd3eZ6QuzP
Both SDKs require a full document path for a `__name__` cursor in a collection group query; the mock accepted a bare ID and expanded it per snapshot, so a pagination test could pass against the mock and fail on Firestore. `queryGroup` and `streamQueryGroup` now fail with `invalid-argument` for a cursor that is not a document path (even, non-empty segments), mirroring the SDK error. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xo119tdUdoz5hd3eZ6QuzP
A collection group cursor carrying more values than the query orders by (explicit orderBys plus the implicit document-name tiebreaker) indexed past the end of the orderBy list while validating, throwing a TypeError instead of the typed invalid-argument failure the SDKs return. Validate the cursor length up front, and read the orderBy entry defensively so an out-of-range index can never dereference undefined. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xo119tdUdoz5hd3eZ6QuzP
Firestore only appends the implicit document-name ordering when the query does not already order by __name__, so a query ordering by document ID accepts exactly one cursor value per orderBy. The cursor length check reserved an extra position regardless, letting a group query pass in the mock that both SDKs reject. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xo119tdUdoz5hd3eZ6QuzP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds collection group queries across the stack.
FirestoreService.queryGroup/streamQueryGroup(admin, client, mock,noopLayer,MockFirestoreService).groupview with the same four query methods, run over the collection group named by the last segment ofcollectionPath.makeRepositoryoptionpathField(string fields only) fills a model field with each document's full path on read.validateCollectionId/collectionIdOfexported from core and shared by all backends; malformed IDs fail with a typedFirestoreErroron both effect and stream.Breaking:
FirestoreServiceShapehas two new required members. Hand-written layers must implement them; see MIGRATION.md step 8.Verified:
nx run-many -t build test lintgreen for all 8 projects.effect-firebase:typecheckfails identically onmain(pre-existingtsconfig.spec.jsonissue).🤖 Generated with Claude Code
https://claude.ai/code/session_01Xo119tdUdoz5hd3eZ6QuzP
Generated by Claude Code