Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: OR Query implementation #698

Merged
merged 10 commits into from Apr 3, 2023
Merged

feat: OR Query implementation #698

merged 10 commits into from Apr 3, 2023

Conversation

Mariatta
Copy link
Contributor

@Mariatta Mariatta commented Mar 20, 2023

Introduce new Filter classes:

FieldFilter
And
Or

Add filter keyword arg to Query.where()
The positional arguments in Query.where() are now optional. UserWarning is now emitted when using where() without keyword args.

Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly:

  • Make sure to open an issue as a bug/issue before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea
  • Ensure the tests and linter pass
  • Code coverage does not decrease (if any source code was changed)
  • Appropriate docs were updated (if necessary)

Fixes #<issue_number_goes_here> 🦕

@Mariatta Mariatta requested review from a team as code owners March 20, 2023 22:39
@product-auto-label product-auto-label bot added size: xl Pull request size is extra large. api: firestore Issues related to the googleapis/python-firestore API. labels Mar 20, 2023
@Mariatta Mariatta force-pushed the feat-or-query branch 2 times, most recently from 2cb52d3 to 1a7f8fd Compare March 21, 2023 00:48
@Mariatta Mariatta added the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Mar 21, 2023
@yoshi-kokoro yoshi-kokoro removed the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Mar 21, 2023
google/cloud/firestore_v1/base_collection.py Show resolved Hide resolved
tests/system/test_system.py Show resolved Hide resolved
Copy link

@danieljbruce danieljbruce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Just a few comments.

op=_enum_from_op_string(op_string),
value=_helpers.encode_value(value),

field_path_module.split_field_path(field_path) # raises

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was there meant to be more text in this comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, this seems to have always been there since this code was added: https://github.com/googleapis/python-firestore/blame/main/google/cloud/firestore_v1/base_query.py#L246

Perhaps a leftover debugging info. I can remove it.

new_filters = self._field_filters + (filter_pb,)
new_filters += (filter_pb,)
elif isinstance(filter, BaseFilter):
new_filters += (filter._to_pb(),)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something we ran into with nodejs-datastore was that if we stored new variable types in this object that contained the old filter types then users who interacted with this array/list directly would see new filter types in this variable. If the user is then going to expect this variable to be an array of the old filter type then it could cause problems. Would the user ever interact with this variable directly out of the base query?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new_filters is a local variable only on the where function. User will not interact with it directly.

google/cloud/firestore_v1/base_query.py Show resolved Hide resolved
return _filter_pb(self._field_filters[0])
filter = self._field_filters[0]
if isinstance(filter, query.StructuredQuery.CompositeFilter):
return query.StructuredQuery.Filter(composite_filter=filter)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function returns a protobuf?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes.
It returns a new instance of the protobuf query.StructuredQuery.Filter()

@Mariatta Mariatta requested a review from kolea2 March 23, 2023 03:44
@@ -542,13 +544,13 @@ def query_docs(client):
@pytest.fixture
def query(query_docs):
collection, stored, allowed_vals = query_docs
query = collection.where("a", "==", 1)
query = collection.where(filter=FieldFilter("a", "==", 1))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To the reviewers, this is an example of how the change in the where function.
It adds the keyword only arg filter, and you can see how it works before vs now.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old behavior without the filter arg is still expected to work, correct? Are there any system tests that still validate the old behavior or is that unit test only now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it still works, and I only have the unit test for it. I can add the system test too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added additional system tests here: eff9328

count_query = query.count()
result = count_query.get()
for r in result[0]:
assert r.value == 2 # there are still only 2 docs


def test_query_with_and_composite_filter(query_docs):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test cases below shows how to build composite filters using And and Or and how to pass them to the filter argument in where.

Introduce new Filter classes:

FieldFilter
And
Or

Add "filter" keyword arg to "Query.where()"
The positional arguments in "Query.where()" are now optional.
UserWarning is now emitted when using "where()" without keyword args.
google/cloud/firestore_v1/base_query.py Show resolved Hide resolved
@@ -542,13 +544,13 @@ def query_docs(client):
@pytest.fixture
def query(query_docs):
collection, stored, allowed_vals = query_docs
query = collection.where("a", "==", 1)
query = collection.where(filter=FieldFilter("a", "==", 1))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old behavior without the filter arg is still expected to work, correct? Are there any system tests that still validate the old behavior or is that unit test only now?

@Mariatta Mariatta merged commit 44dd5d6 into main Apr 3, 2023
16 checks passed
@Mariatta Mariatta deleted the feat-or-query branch April 3, 2023 15:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: firestore Issues related to the googleapis/python-firestore API. size: xl Pull request size is extra large.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants