Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d04a241

Browse filesBrowse files
feat(firestore): support array_agg(), array_agg_distinct(), first(), last() (#16029)
TODO: - [x] verify docstring - referred to firebase/firebase-js-sdk#9576 for docstring text --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 7fc88cf commit d04a241
Copy full SHA for d04a241

3 files changed

+274-1Lines changed: 274 additions & 1 deletion

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py‎

Copy file name to clipboardExpand all lines: packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py
+80Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,6 +1410,86 @@ def timestamp_to_unix_micros(self) -> "Expression":
14101410
"""
14111411
return FunctionExpression("timestamp_to_unix_micros", [self])
14121412

1413+
@expose_as_static
1414+
def array_agg(self) -> "Expression":
1415+
"""Creates an aggregation that collects all values of an expression
1416+
across multiple stage inputs into an array.
1417+
1418+
If the expression resolves to an absent value, it is converted to
1419+
`None`. The order of elements in the output array is not stable and
1420+
shouldn't be relied upon.
1421+
1422+
This API is provided as a preview for developers and may change based
1423+
on feedback that we receive. Do not use this API in a production
1424+
environment.
1425+
1426+
Example:
1427+
>>> # Collect all values of field 'color' into an array
1428+
>>> Field.of("color").array_agg()
1429+
1430+
Returns:
1431+
A new `AggregateFunction` representing the array aggregation.
1432+
"""
1433+
return AggregateFunction("array_agg", [self])
1434+
1435+
@expose_as_static
1436+
def array_agg_distinct(self) -> "Expression":
1437+
"""Creates an aggregation that collects all distinct values of an
1438+
expression across multiple stage inputs into an array.
1439+
1440+
If the expression resolves to an absent value, it is converted to
1441+
`None`. The order of elements in the output array is not stable and
1442+
shouldn't be relied upon.
1443+
1444+
This API is provided as a preview for developers and may change based
1445+
on feedback that we receive. Do not use this API in a production
1446+
environment.
1447+
1448+
Example:
1449+
>>> # Collect distinct values of field 'color' into an array
1450+
>>> Field.of("color").array_agg_distinct()
1451+
1452+
Returns:
1453+
A new `AggregateFunction` representing the distinct array aggregation.
1454+
"""
1455+
return AggregateFunction("array_agg_distinct", [self])
1456+
1457+
@expose_as_static
1458+
def first(self) -> "Expression":
1459+
"""Creates an aggregation that finds the first value of an expression
1460+
across multiple stage inputs.
1461+
1462+
This API is provided as a preview for developers and may change based
1463+
on feedback that we receive. Do not use this API in a production
1464+
environment.
1465+
1466+
Example:
1467+
>>> # Select the first value of field 'color'
1468+
>>> Field.of("color").first()
1469+
1470+
Returns:
1471+
A new `AggregateFunction` representing the first aggregation.
1472+
"""
1473+
return AggregateFunction("first", [self])
1474+
1475+
@expose_as_static
1476+
def last(self) -> "Expression":
1477+
"""Creates an aggregation that finds the last value of an expression
1478+
across multiple stage inputs.
1479+
1480+
This API is provided as a preview for developers and may change based
1481+
on feedback that we receive. Do not use this API in a production
1482+
environment.
1483+
1484+
Example:
1485+
>>> # Select the last value of field 'color'
1486+
>>> Field.of("color").last()
1487+
1488+
Returns:
1489+
A new `AggregateFunction` representing the last aggregation.
1490+
"""
1491+
return AggregateFunction("last", [self])
1492+
14131493
@expose_as_static
14141494
def unix_micros_to_timestamp(self) -> "Expression":
14151495
"""Creates an expression that converts a number of microseconds since the epoch (1970-01-01
Collapse file

‎packages/google-cloud-firestore/tests/system/pipeline_e2e/aggregates.yaml‎

Copy file name to clipboardExpand all lines: packages/google-cloud-firestore/tests/system/pipeline_e2e/aggregates.yaml
+158-1Lines changed: 158 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,4 +281,161 @@ tests:
281281
- "total_rating"
282282
assert_results:
283283
- total_rating: 8.8
284-
284+
- description: testArrayAgg
285+
pipeline:
286+
- Collection: books
287+
- Sort:
288+
- Ordering:
289+
- Field: title
290+
- ASCENDING
291+
- Aggregate:
292+
- AliasedExpression:
293+
- FunctionExpression.array_agg:
294+
- Field: title
295+
- "all_titles"
296+
assert_results:
297+
- all_titles:
298+
- "1984"
299+
- "Crime and Punishment"
300+
- "Dune"
301+
- "One Hundred Years of Solitude"
302+
- "Pride and Prejudice"
303+
- "The Great Gatsby"
304+
- "The Handmaid's Tale"
305+
- "The Hitchhiker's Guide to the Galaxy"
306+
- "The Lord of the Rings"
307+
- "To Kill a Mockingbird"
308+
assert_proto:
309+
pipeline:
310+
stages:
311+
- args:
312+
- referenceValue: /books
313+
name: collection
314+
- args:
315+
- mapValue:
316+
fields:
317+
direction:
318+
stringValue: ascending
319+
expression:
320+
fieldReferenceValue: title
321+
name: sort
322+
- args:
323+
- mapValue:
324+
fields:
325+
all_titles:
326+
functionValue:
327+
name: array_agg
328+
args:
329+
- fieldReferenceValue: title
330+
- mapValue: {}
331+
name: aggregate
332+
- description: testArrayAggDistinct
333+
pipeline:
334+
- Collection: books
335+
- Aggregate:
336+
- AliasedExpression:
337+
- FunctionExpression.array_agg_distinct:
338+
- Field: genre
339+
- "distinct_genres"
340+
assert_results:
341+
- distinct_genres:
342+
- 'Dystopian'
343+
- 'Romance'
344+
- 'Magical Realism'
345+
- 'Fantasy'
346+
- 'Southern Gothic'
347+
- 'Science Fiction'
348+
- 'Psychological Thriller'
349+
- 'Modernist'
350+
assert_proto:
351+
pipeline:
352+
stages:
353+
- args:
354+
- referenceValue: /books
355+
name: collection
356+
- args:
357+
- mapValue:
358+
fields:
359+
distinct_genres:
360+
functionValue:
361+
name: array_agg_distinct
362+
args:
363+
- fieldReferenceValue: genre
364+
- mapValue: {}
365+
name: aggregate
366+
- description: testFirst
367+
pipeline:
368+
- Collection: books
369+
- Sort:
370+
- Ordering:
371+
- Field: title
372+
- ASCENDING
373+
- Aggregate:
374+
- AliasedExpression:
375+
- FunctionExpression.first:
376+
- Field: title
377+
- "first_title"
378+
assert_results:
379+
- first_title: "1984"
380+
assert_proto:
381+
pipeline:
382+
stages:
383+
- args:
384+
- referenceValue: /books
385+
name: collection
386+
- args:
387+
- mapValue:
388+
fields:
389+
direction:
390+
stringValue: ascending
391+
expression:
392+
fieldReferenceValue: title
393+
name: sort
394+
- args:
395+
- mapValue:
396+
fields:
397+
first_title:
398+
functionValue:
399+
name: first
400+
args:
401+
- fieldReferenceValue: title
402+
- mapValue: {}
403+
name: aggregate
404+
- description: testLast
405+
pipeline:
406+
- Collection: books
407+
- Sort:
408+
- Ordering:
409+
- Field: title
410+
- ASCENDING
411+
- Aggregate:
412+
- AliasedExpression:
413+
- FunctionExpression.last:
414+
- Field: title
415+
- "last_title"
416+
assert_results:
417+
- last_title: "To Kill a Mockingbird"
418+
assert_proto:
419+
pipeline:
420+
stages:
421+
- args:
422+
- referenceValue: /books
423+
name: collection
424+
- args:
425+
- mapValue:
426+
fields:
427+
direction:
428+
stringValue: ascending
429+
expression:
430+
fieldReferenceValue: title
431+
name: sort
432+
- args:
433+
- mapValue:
434+
fields:
435+
last_title:
436+
functionValue:
437+
name: last
438+
args:
439+
- fieldReferenceValue: title
440+
- mapValue: {}
441+
name: aggregate
Collapse file

‎packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py‎

Copy file name to clipboardExpand all lines: packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py
+36Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,3 +1583,39 @@ def test_maximum(self):
15831583
assert repr(instance) == "Value.maximum()"
15841584
infix_instance = arg1.maximum()
15851585
assert infix_instance == instance
1586+
1587+
def test_array_agg(self):
1588+
arg1 = self._make_arg("Value")
1589+
instance = Expression.array_agg(arg1)
1590+
assert instance.name == "array_agg"
1591+
assert instance.params == [arg1]
1592+
assert repr(instance) == "Value.array_agg()"
1593+
infix_instance = arg1.array_agg()
1594+
assert infix_instance == instance
1595+
1596+
def test_array_agg_distinct(self):
1597+
arg1 = self._make_arg("Value")
1598+
instance = Expression.array_agg_distinct(arg1)
1599+
assert instance.name == "array_agg_distinct"
1600+
assert instance.params == [arg1]
1601+
assert repr(instance) == "Value.array_agg_distinct()"
1602+
infix_instance = arg1.array_agg_distinct()
1603+
assert infix_instance == instance
1604+
1605+
def test_first(self):
1606+
arg1 = self._make_arg("Value")
1607+
instance = Expression.first(arg1)
1608+
assert instance.name == "first"
1609+
assert instance.params == [arg1]
1610+
assert repr(instance) == "Value.first()"
1611+
infix_instance = arg1.first()
1612+
assert infix_instance == instance
1613+
1614+
def test_last(self):
1615+
arg1 = self._make_arg("Value")
1616+
instance = Expression.last(arg1)
1617+
assert instance.name == "last"
1618+
assert instance.params == [arg1]
1619+
assert repr(instance) == "Value.last()"
1620+
infix_instance = arg1.last()
1621+
assert infix_instance == instance

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.