-
Notifications
You must be signed in to change notification settings - Fork 938
Add NOT_IN and != queries (not public) #3557
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
Conversation
💥 No ChangesetLatest commit: 8fef964 Merging this PR will not cause any packages to be released. If these changes should not cause updates to packages in this repo, this is fine 🙂 If these changes should be published to npm, you need to add a changeset. This PR includes no changesetsWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types Click here to learn what changesets are, and how to add one. Click here if you're a maintainer who wants to add a changeset to this PR |
Binary Size ReportAffected SDKs
Test Logs |
@@ -1684,14 +1688,17 @@ function validateDisjunctiveFilterElements( | |||
'maximum of 10 elements in the value array.' | |||
); | |||
} | |||
if (value.indexOf(null) >= 0) { | |||
if (value.indexOf(null) >= 0 && operator !== Operator.NOT_IN) { |
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.
Avoid double negatives if you can. In this case, the only valid operators are IN and NOT_IN, so you could make this check === Operator.IN
and be clearer without loss of functionality.
Also, if you put the operator check first then we won't have to search the array for null
in cases where that doesn't apply.
Same feedback below, though also consider factoring out the common if check:
if (operator === Operator.IN) {
if (contains null) {
...
}
if (contains NaN) {
...
}
}
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.
Refactored. However, it's possible for the operator to be ARRAY_CONTAINS_ANY
inside newQueryFilter()
, so I added that as well.
@@ -1700,14 +1707,41 @@ function validateDisjunctiveFilterElements( | |||
} | |||
} | |||
|
|||
function conflictingOps(op: Operator): Operator[] { |
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.
Comments please. In particular please document the context in which these operations could be conflicting.
Within the body of this function it would be useful to spell out the rules by which you arrived at these results.
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.
Attempted.
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.
These comments are mostly just repeating what the code is doing. What I was hoping for was a higher-level comment (outside the switch statement) that gave the collective rules together. For example, as you've implemented this now, you've repeated "Only one ARRAY operator can be used" in multiple places and I'm prompting for it to be in one place.
Basically: when you constructed these lists, you had to evaluate a list of rules. Then for each operator pair you evaluated those rules to determine if they were incompatible. What I want you to document is the list of rules you used to build this structure.
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.
Makes sense. Documented at the top of the function.
|
||
const conflictingOp = query.findFilterOperator(conflictingOps(filter.op)); | ||
if (conflictingOp !== null) { | ||
// We special case when it's a duplicate op to give a slightly clearer error message. |
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.
When commenting in code like this, you can drop the "we" and write as if you're telling the computer what to do (i.e. in the imperative mood with an implicit subject).
Special case when ...
(Though I see you're just moving the comment from below.)
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.
op: Operator, | ||
value: api.Value | ||
): FieldFilter { | ||
debugAssert( |
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 avoid this assertion by making this a part of the type of the parameter. I believe you can declare op
like this:
op: Operator.IN | Operator.NOT_IN
and then the caller will have to be in a context where this is true.
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.
Much cleaner, thanks!
} | ||
|
||
matches(doc: Document): boolean { | ||
return !this.keys.some(key => key.isEqual(doc.key)); |
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 difference between these types is the operator name and this exclamation point. It seems like you could either:
- extract a common class for this that takes the operator as a parameter;
- extract a helper function for creating the keys array;
- make
KeyFiieldInFilter
the base class and have it take the operator as a parameter; - move the construction of the keys array into the caller (passing it as an extra argument) since you now have a dedicated
createKeyFieldInFilter
.
(listed in order of my decreasing preference, but my preference isn't strong.)
Just duplicating the code seems size unfriendly.
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.
Extracted into helper.
collection.where('y', '>', 32).where('x', notEqualOp, 33) | ||
).to.throw( | ||
'Invalid query. All where filters with an ' + | ||
'inequality (<, <=, >, or >=) must be on the same field.' + |
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 !=
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.
I included a TODO in the validation check to update the message once !=
queries are public. That way developers won't see it until the feature is released.
); | ||
}); | ||
|
||
validationIt(persistence, 'with != and NOT_IN filters fail', db => { |
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 the user-visible spelling for NOT_IN is not-in, maybe describe this in terms of "not-in" rather than the proto name for this operator?
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.
.where('foo', notInOp, [2, 3]) | ||
.where('foo', notEqualOp, 4) | ||
).to.throw( | ||
"Invalid query. You cannot use '!=' filters with " + "'not-in' filters." |
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.
What's with the extra plus sign in here? There's a couple in this file. Search for " + "
.
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. I think it may have been due to line wrapping, but it's no longer an issue now.
|
||
// TODO(ne-queries): This exists just so we don't have to do the cast | ||
// repeatedly. Once we expose '!=' publicly we can remove it and | ||
// just use 'array-contains-any' in all the tests. |
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.
Typo? Surely you don't mean "array-contains-any" here (or "in" in the next one).
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.
Fixed. sloppy copy/paste
@@ -218,6 +218,64 @@ describe('Query', () => { | |||
expect(queryMatches(query1, document)).to.be.true; | |||
}); | |||
|
|||
it('matches NOT_IN filters', () => { |
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.
Same comment re NOT_IN vs not-in. NOT_IN is a proto representation detail while not-in
is the public API 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.
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.
LGTM
No description provided.