-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Add != and notIn support #6418
Add != and notIn support #6418
Conversation
d470581
to
9fecaa6
Compare
f4e74ba
to
609bda9
Compare
Firestore/CHANGELOG.md
Outdated
- [feature] Added `whereField(_:notIn:)` and `whereField(_:isNotEqualTo:)` query | ||
operators. `whereField(_:notIn:)` finds documents where a specified field’s | ||
value is not in a specified array. `whereField(_:isNotEqualTo:)` finds documents | ||
where a specified field's value does not equal the specified value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a major caveat to this feature, so it's probably worth calling this out explicitly, maybe with a trailing sentence like:
Neither query operator will match documents where the specified field is not present.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
FSTAssertThrows([[coll queryWhereField:@"x" isNotEqualTo:@1] queryWhereField:@"y" | ||
isNotEqualTo:@2], | ||
@"Invalid Query. All where filters with an inequality (lessThan, " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should notEqual
be in this list of inequalities?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching. Updated.
Firestore/core/src/api/query_core.cc
Outdated
@@ -423,6 +418,34 @@ FieldValue Query::ParseExpectedReferenceValue( | |||
} | |||
} | |||
|
|||
std::vector<core::Filter::Operator> Query::ConflictingOps( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The core::Filter::Operator
seems like it could be Filter::Operator
(given the argument type).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
Firestore/core/src/api/query_core.cc
Outdated
Filter::Operator op) const { | ||
switch (op) { | ||
case Filter::Operator::NotEqual: | ||
return std::vector<core::Filter::Operator>{Filter::Operator::NotEqual, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect you can drop the type name in the initializer here (i.e. that you can return {Filter::Operator::NotEqual, Filter::Operator::NotIn};
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
* the specified field and the value does not equal any of the values from the provided array. | ||
* | ||
* A query can have only one `notIn` filter, and it cannot be combined with an `arrayContains`, | ||
* `arrayContainsAny`, `in`, or `notEqual` filter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth calling out the behavior of not-in [null] here? It's counter-intuitive because not-equal null automagically makes that work, but not-in has no equivalent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I originally considered it, but thought it was too specific of an edge case. Added a comment to about the behavior -- should I go more into detail?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is tough. Here's my take, which avoids "results in no document matches" which is a fairly indirect way of saying that the filter can't match the field.
One special case is that
notIn
filters cannot matchnil
values. To query for documents where a field exists and isnil
, use anotEqual
filter, which can handle this special case.
Separately, note that Objective-C and Swift spell "null" as nil
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion! Updated here and in Android with the appropriate names.
namespace firebase { | ||
namespace firestore { | ||
|
||
namespace model { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can get these forward declarations by including Firestore/core/src/model/model_fwd.h
.
Also, this is inconsistent with key_field_not_in_filter.h
which neither makes the forward declarations nor includes the model_fwd.h
header.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using model_fwd.h
in key_field_not_in_filter.h
, key_field_in_filter.h
, and not_in_filter.h
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll submit a separate PR that cleans up the unnecessary inlined forward declarations for the other filters.
Firestore/core/src/core/query.h
Outdated
*/ | ||
absl::optional<Filter::Operator> FirstDisjunctiveOperator() const; | ||
absl::optional<Filter::Operator> FindOperator( | ||
std::vector<Filter::Operator> ops) const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since FindOperator
isn't storing the ops
value in a field (or otherwise retaining it beyond the lifetime of the call), you should pass ops
via const reference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
@@ -369,9 +369,10 @@ class SerializerTest : public ::testing::Test { | |||
create_time_proto->set_nanos(4321); | |||
} | |||
|
|||
void ExpectUnaryOperator(const FieldValue& value, | |||
void ExpectUnaryOperator(std::string opStr, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In C++ variables should be snake_case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very close to LGTM.
* the specified field and the value does not equal any of the values from the provided array. | ||
* | ||
* A query can have only one `notIn` filter, and it cannot be combined with an `arrayContains`, | ||
* `arrayContainsAny`, `in`, or `notEqual` filter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is tough. Here's my take, which avoids "results in no document matches" which is a fairly indirect way of saying that the filter can't match the field.
One special case is that
notIn
filters cannot matchnil
values. To query for documents where a field exists and isnil
, use anotEqual
filter, which can handle this special case.
Separately, note that Objective-C and Swift spell "null" as nil
.
@@ -333,7 +360,8 @@ void Query::ValidateOrderByField(const FieldPath& order_by_field, | |||
if (order_by_field != inequality_field) { | |||
ThrowInvalidArgument( | |||
"Invalid query. You have a where filter with an inequality " | |||
"(lessThan, lessThanOrEqual, greaterThan, or greaterThanOrEqual) on " | |||
"(notEqual, lessThan, lessThanOrEqual, greaterThan, or " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: reflow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
Firestore/core/src/api/query_core.h
Outdated
@@ -20,6 +20,7 @@ | |||
#include <memory> | |||
#include <string> | |||
#include <utility> | |||
#include <vector> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Porting from web and Android.