feat(firestore): support array functions#16128
feat(firestore): support array functions#16128Linchin wants to merge 10 commits intogoogleapis:mainfrom
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request enhances the Firestore client library by integrating new array manipulation functions directly into pipeline expressions. This provides developers with more powerful and convenient ways to query and transform data within array fields, improving data processing capabilities without requiring client-side array handling. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request adds support for array_first, array_last, array_first_n, and array_last_n functions in Firestore pipelines. The implementation and system tests look good. However, I found issues in the unit tests for array_first_n and array_last_n where the parameter order is asserted incorrectly, leading to internally inconsistent tests. I've provided suggestions to fix these tests.
packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py
Outdated
Show resolved
Hide resolved
packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py
Outdated
Show resolved
Hide resolved
…nit and system tests.
… array elements with optional index.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request adds support for a number of new array functions in Firestore pipelines. The implementation looks mostly good, but there are a few areas for improvement.
There are some inconsistencies in the naming of the generated functions (e.g., maximum vs array_maximum) which should be standardized. The e2e tests for these functions are also missing assert_proto blocks to verify the generated output.
Additionally, there are some minor issues with docstrings and redundant code that can be cleaned up. The signature for array_transform is also a bit confusing and could be made clearer.
Overall, a solid addition with a few refinements needed.
| def array_maximum(self) -> "Expression": | ||
| """Creates an expression that returns the maximum element of an array. | ||
|
|
||
| Example: | ||
| >>> # Select the maximum element of array 'scores' | ||
| >>> Field.of("scores").array_maximum() | ||
|
|
||
| Returns: | ||
| A new `Expression` representing the maximum element of the array. | ||
| """ | ||
| return FunctionExpression("maximum", [self]) |
There was a problem hiding this comment.
The function name used for array_maximum is "maximum". This is inconsistent with other new array functions like array_first which uses "array_first". For consistency, this should probably be "array_maximum".
This same issue applies to:
array_minimum(uses"minimum")array_maximum_n(uses"maximum_n")array_minimum_n(uses"minimum_n")
Please update them all to use the array_ prefix for consistency and to prevent potential backend errors.
return FunctionExpression("array_maximum", [self])| name: array_last_n | ||
| name: select | ||
|
|
||
| - description: testArrayMaximum |
There was a problem hiding this comment.
This test, along with testArrayMinimum, testArrayMaximumN, testArrayMinimumN, testArraySlice1Arg, and testArraySlice2Args, is missing an assert_proto block. These assertions are crucial for verifying that the client is generating the correct protocol buffer messages for the backend. Please add them to ensure the implementation is correct. For example, this is needed to confirm whether the function name should be maximum or array_maximum.
| def array_slice( | ||
| self, offset: int | "Expression", length: int | "Expression" | None = None | ||
| ) -> "Expression": | ||
| """Ccreates an expression that returns a slice of an array starting from the specified |
| def array_transform( | ||
| self, element_alias: str, body: "Expression", index_alias: str | None = None | ||
| ) -> "Expression": |
There was a problem hiding this comment.
The method signature for array_transform is (self, element_alias: str, body: "Expression", index_alias: str | None = None). However, the implementation and the expected backend protocol place the body argument last in the argument list sent to the backend. This discrepancy can be confusing and lead to incorrect usage.
To improve clarity and prevent misuse, consider making index_alias a keyword-only argument. This enforces that it's passed by name and makes the signature less ambiguous.
def array_transform(
self, element_alias: str, body: "Expression", *, index_alias: str | None = None
) -> "Expression":| if index_alias is not None: | ||
| args.append(self._cast_to_expr_or_convert_to_constant(index_alias)) | ||
|
|
||
| args.append(self._cast_to_expr_or_convert_to_constant(body)) |
There was a problem hiding this comment.
The body parameter is already typed as Expression. Calling _cast_to_expr_or_convert_to_constant on it is redundant, as unit tests suggest this function is a no-op for Expression instances. You can append body directly to the args list for clarity.
This also applies to array_filter on line 1733.
args.append(body)| """ | ||
| Takes an array, evaluates a boolean expression on each element, and returns a new | ||
| array containing only the elements for which the expression evaluates to True. | ||
|
|
||
| Args: | ||
| element_alias: Element variable name. | ||
| body: Boolean expression applied to each element. | ||
|
|
||
| Returns: | ||
| Expression: The created FunctionExpression AST node. | ||
| """ |
There was a problem hiding this comment.
The docstring for array_filter is inconsistent with the other new functions in this PR.
- It's missing an
Example:section. - The
Returns:description is not as user-friendly as the others.
Please update it for consistency. For example:
"""
Takes an array and returns a new array containing only the elements for which
the given boolean expression evaluates to True.
Example:
>>> # Filter for numbers greater than 5
>>> Field.of("numbers").array_filter("num", Field.of("num").greater_than(5))
Args:
element_alias: Element variable name.
body: Boolean expression applied to each element.
Returns:
A new `Expression` representing the filtered array.
"""
Supports the following: