Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
c1a2dc9
fix(firestore): emit valid backend names from PipelineFunctions array…
Lyokone Oct 2, 2026
1606df2
fix(firestore): encode Pipeline.addFields as a single map argument
Lyokone Oct 2, 2026
424ef4d
fix(firestore): send root ancestor in collection_group pipeline stage
Lyokone Oct 2, 2026
e460211
fix(firestore): encode PipelineValueType.double as float64
Lyokone Oct 2, 2026
71c4719
fix(firestore): require a delimiter in PipelineFunctions.join
Lyokone Oct 2, 2026
b71f1f2
fix(firestore): resolve nested field paths in PipelineResult.get
Lyokone Oct 2, 2026
6f71b5b
fix(firestore): reject duplicate aliases in Pipeline select, aggregat…
Lyokone Oct 2, 2026
c1eb027
fix(firestore): take substring length, not end, in fluent Pipeline API
Lyokone Oct 2, 2026
b39e972
fix(firestore): export top-level pipeline variable() helper
Lyokone Oct 2, 2026
01b77e9
fix(firestore): accept decimal places in PipelineExpression.round
Lyokone Oct 2, 2026
f39062b
fix(firestore): require a delimiter in PipelineFunctions.split
Lyokone Oct 2, 2026
0416ed6
fix(firestore): make mapRemove take a single key like the Node SDK
Lyokone Oct 2, 2026
900a79c
fix(firestore): encode numeric lists as vectors in Pipeline vector fu…
Lyokone Oct 2, 2026
88288d0
fix(firestore): reject duplicate aliases in Pipeline.addFields
Lyokone Oct 2, 2026
c898d39
fix(firestore): build Pipeline collection arguments that hold express…
Lyokone Oct 2, 2026
d209007
docs(firestore): add changelog entries for the Pipeline review fixes
Lyokone Oct 2, 2026
ba1bfb8
test(firestore): use valid field names as mapRemove E2E aliases
Lyokone Oct 2, 2026
df14f50
fix(firestore): traverse any Map in PipelineResult.get
Lyokone Oct 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions packages/google_cloud_firestore/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
- Added `CollectionReference.listDocumentsPages()`, which lists a collection's documents, including missing documents, one `DocumentReferencePage` at a time. It takes an optional `pageSize` and a `pageToken` to resume from a previous page's `nextPageToken`, so large collections can be walked without holding every reference in memory.
- Fixed `CollectionReference.listDocuments()` returning only the first page of results. It now follows `nextPageToken` until the collection is exhausted, matching the Node Admin SDK, so large collections and missing documents past the first page are no longer silently dropped.
- Fixed `DocumentReference.listCollections()` and `Firestore.listCollections()` returning only the first page of collection IDs. They now follow `nextPageToken` until every collection has been returned.
- **Breaking:** `PipelineFunctions.join` and `PipelineFunctions.split` now require their delimiter, matching `PipelineExpression` and the Node Admin SDK. A one-argument call was always rejected by the backend with `INVALID_ARGUMENT`.
- **Breaking:** `PipelineFunctions.mapRemove` and `PipelineExpression.mapRemove` take a single key (a `String` or an expression) and send `map_remove(map, key)`, like the Node Admin SDK, instead of an `Iterable` of keys. Chain `.mapRemove('a').mapRemove('b')` to remove several keys.
- Fixed `PipelineFunctions.arrayMaximum`, `arrayMaximumN`, `arrayMinimum`, `arrayMinimumN` and `arraySum` sending function names (`array_maximum`, ...) that the backend rejects. They now send `maximum`, `maximum_n`, `minimum`, `minimum_n` and `sum`, like their `PipelineExpression` counterparts.
- Fixed `Pipeline.addFields` sending one `alias` function per field instead of a single map keyed by alias, which the backend rejected.
- Fixed `PipelineSource.collectionGroup()`, and `createFrom()` on a collection group query, omitting the leading root ancestor argument of the `collection_group` stage.
- Fixed `PipelineValueType.double` sending `'double'` instead of `'float64'`, which made `isType` fail. Added the `int32`, `decimal128`, `maxKey`, `minKey`, `objectId` and `regex` value types.
- Fixed `cosineDistance`, `dotProduct`, `euclideanDistance` and `Pipeline.findNearest` sending a plain list of numbers as an array instead of a vector.
- Fixed Pipeline functions such as `equalAny`, `notEqualAny`, `arrayContainsAll`, `arrayContainsAny` and `mapMerge` failing when a `List` or `Map` argument holds expressions. Collection arguments are now sent as `array(...)` / `map(...)` functions, like the Node Admin SDK, and the static and fluent forms encode identically.
- Fixed `PipelineResult.get` ignoring nested paths. It now accepts a `String` or a `FieldPath` and resolves dot-separated paths such as `'metadata.lang'`, like `DocumentSnapshot.get`.
- `Pipeline.select`, `addFields`, `aggregate` and `distinct` now throw an `ArgumentError` on a duplicate field name or alias instead of silently keeping the last one, like the Node Admin SDK.
- `PipelineExpression.substring` and `substringLiteral` now take `(position, [length])` like `PipelineFunctions.substring`: the second argument is a length, not an end index, and can be omitted.
- `PipelineExpression.round` now accepts the optional `decimalPlaces` argument.
- Exported the top-level `variable()` Pipeline helper.

## 0.5.5

Expand Down
39 changes: 31 additions & 8 deletions packages/google_cloud_firestore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,10 @@ proportion between 0 and 1. Exactly one of the two must be given.
)
```

`queryVector` takes a `VectorValue`, a plain list of numbers, or an
expression. So does the second argument of `cosineDistance`, `dotProduct` and
`euclideanDistance`; either way it is sent as a vector.

**`rawStage`** — escape hatch for preview stages this SDK does not yet wrap.
`search` is a thin wrapper over the same mechanism.

Expand Down Expand Up @@ -343,8 +347,16 @@ field('title').toUpperCase();
PipelineFunctions.toUpper('title');
```

`Expression.field` / `Expression.constant` are aliases for the top-level
`field` / `constant`, for callers who prefer a namespaced entry point.
`Expression.field` / `Expression.constant` / `Expression.variable` are aliases
for the top-level `field` / `constant` / `variable`, for callers who prefer a
namespaced entry point.

`variable` references a name bound by the enclosing expression, such as the
element alias of `arrayFilter` / `arrayTransform`:

```dart
field('tags').arrayFilter('tag', variable('tag').notEqual('draft'));
```

**Field arguments vs value arguments.** A `String` in a *field* position means a
field reference; in a *value* position it stays a string literal. The field
Expand All @@ -358,6 +370,15 @@ PipelineFunctions.startsWith('title', 'Harry');
PipelineFunctions.startsWith('title', field('prefix'));
```

A `List` or `Map` argument may mix literals and expressions. It is sent as an
`array(...)` / `map(...)` function so the backend evaluates the expressions
inside it; wrap it in `constant` to send a literal value instead:

```dart
PipelineFunctions.equalAny('rating', [field('score'), 5]);
field('metadata').mapMerge([{'reviewer': field('editor')}]);
```

Selected expressions must be aliased with `as` (or `alias`):

```dart
Expand All @@ -375,7 +396,7 @@ available on `PipelineFunctions`; most also exist as a fluent method.
| Logical | `and`, `or`, `xor`, `nor`, `not`, `conditional`, `ifNull`, `coalesce`, `switchOn`, `equalAny`, `notEqualAny` | `and`, `or`, `xor`, `nor`, `not`, `conditional`, `if_null`, `coalesce`, `switch_on`, `equal_any`, `not_equal_any` |
| Aggregate | `count`, `countAll`, `countIf`, `countDistinct`, `sum`, `average`, `minimum`, `maximum`, `first`, `last`, `arrayAgg`, `arrayAggDistinct` | `count`, `count_if`, `count_distinct`, `sum`, `average`, `minimum`, `maximum`, `first`, `last`, `array_agg`, `array_agg_distinct` |
| Arithmetic | `add`, `subtract`, `multiply`, `divide`, `mod`, `abs`, `ceil`, `floor`, `round`, `trunc`, `sqrt`, `pow`, `exp`, `ln`, `log`, `log10`, `rand`, `logicalMinimum`, `logicalMaximum` | `add`, `subtract`, `multiply`, `divide`, `mod`, `abs`, `ceil`, `floor`, `round`, `trunc`, `sqrt`, `pow`, `exp`, `ln`, `log`, `log10`, `rand`, `minimum`, `maximum` |
| Array | `array`, `arrayConcat`, `arrayContains`, `arrayContainsAll`, `arrayContainsAny`, `arrayFilter`, `arrayGet`, `arrayLength`, `arrayReverse`, `arrayFirst`, `arrayFirstN`, `arrayLast`, `arrayLastN`, `arrayIndexOf`, `arrayIndexOfAll`, `arrayLastIndexOf`, `arraySlice`, `arrayTransform`, `arrayMaximum`, `arrayMaximumN`, `arrayMinimum`, `arrayMinimumN`, `arraySum`, `maximumN`, `minimumN`, `join` | `array`, `array_concat`, `array_contains`, `array_contains_all`, `array_contains_any`, `array_filter`, `array_get`, `array_length`, `array_reverse`, `array_first`, `array_first_n`, `array_last`, `array_last_n`, `array_index_of`, `array_index_of_all`, `array_index_of`, `array_slice`, `array_transform`, `array_maximum`, `array_maximum_n`, `array_minimum`, `array_minimum_n`, `array_sum`, `maximum_n`, `minimum_n`, `join` |
| Array | `array`, `arrayConcat`, `arrayContains`, `arrayContainsAll`, `arrayContainsAny`, `arrayFilter`, `arrayGet`, `arrayLength`, `arrayReverse`, `arrayFirst`, `arrayFirstN`, `arrayLast`, `arrayLastN`, `arrayIndexOf`, `arrayIndexOfAll`, `arrayLastIndexOf`, `arraySlice`, `arrayTransform`, `arrayMaximum`, `arrayMaximumN`, `arrayMinimum`, `arrayMinimumN`, `arraySum`, `maximumN`, `minimumN`, `join` | `array`, `array_concat`, `array_contains`, `array_contains_all`, `array_contains_any`, `array_filter`, `array_get`, `array_length`, `array_reverse`, `array_first`, `array_first_n`, `array_last`, `array_last_n`, `array_index_of`, `array_index_of_all`, `array_index_of`, `array_slice`, `array_transform`, `maximum`, `maximum_n`, `minimum`, `minimum_n`, `sum`, `maximum_n`, `minimum_n`, `join` |
| String | `byteLength`, `charLength`, `startsWith`, `endsWith`, `like`, `regexContains`, `regexMatch`, `regexFind`, `regexFindAll`, `stringConcat`, `stringContains`, `stringIndexOf`, `toUpper`, `toLower`, `substring`, `stringReverse`, `stringRepeat`, `stringReplaceAll`, `stringReplaceOne`, `trim`, `ltrim`, `rtrim`, `split` | `byte_length`, `char_length`, `starts_with`, `ends_with`, `like`, `regex_contains`, `regex_match`, `regex_find`, `regex_find_all`, `string_concat`, `string_contains`, `string_index_of`, `to_upper`, `to_lower`, `substring`, `string_reverse`, `string_repeat`, `string_replace_all`, `string_replace_one`, `trim`, `ltrim`, `rtrim`, `split` |
| Generic | `length`, `reverse`, `concat` | `length`, `reverse`, `concat` |
| Map | `map`, `mapGet`, `getField`, `mapSet`, `mapRemove`, `mapMerge`, `mapKeys`, `mapValues`, `mapEntries` | `map`, `map_get`, `get_field`, `map_set`, `map_remove`, `map_merge`, `map_keys`, `map_values`, `map_entries` |
Expand All @@ -393,7 +414,8 @@ maps; `charLength`/`stringReverse`/`stringConcat` and
`logicalMaximum` to compare several operands element-wise.

Anything not yet wrapped is reachable via `PipelineFunctions.raw` or
`pipelineFunction`:
`pipelineFunction`. Their arguments are sent as-is, so build a collection that
holds expressions with `PipelineFunctions.array` / `PipelineFunctions.map`:

```dart
PipelineFunctions.raw('some_new_function', [field('x'), 42]);
Expand Down Expand Up @@ -457,10 +479,11 @@ metadata, its identity:

```dart
for (final result in snapshot.results) {
print(result.data()); // all decoded fields
print(result.get('title')); // a single field
print(result.ref?.path); // null when a projection dropped metadata
print(result.id); // the document ID, or null
print(result.data()); // all decoded fields
print(result.get('title')); // a single field
print(result.get('metadata.lang')); // a nested field (or pass a FieldPath)
print(result.ref?.path); // null when a projection dropped metadata
print(result.id); // the document ID, or null
print(result.createTime);
print(result.updateTime);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ export 'src/firestore.dart'
or,
pipelineFunction,
score,
sum;
sum,
variable;
export 'src/firestore_exception.dart'
show FirestoreClientErrorCode, FirestoreException;
export 'src/status_code.dart' show StatusCode;
Expand Down
Loading
Loading