Skip to content

Add != and NOT_IN queries (not public) #1872

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

Merged
merged 3 commits into from
Aug 14, 2020
Merged

Add != and NOT_IN queries (not public) #1872

merged 3 commits into from
Aug 14, 2020

Conversation

thebrianchen
Copy link

Porting from web.

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Aug 10, 2020

Binary Size Report

Affected SDKs

  • firebase-firestore

    Type Base (ed8977b) Head (6324327b) Diff
    aar 996 kB 999 kB +2.95 kB (+0.3%)
    apk (release) 3.13 MB 3.13 MB +1.00 kB (+0.0%)

Test Logs

Notes

Head commit (6324327b) is created by Prow via merging commits: ed8977b cc4397b.

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Aug 10, 2020

Coverage Report

Affected SDKs

  • firebase-firestore

    SDK overall coverage changed from 46.74% (ed8977b) to 46.79% (6324327b) by +0.05%.

    Filename Base (ed8977b) Head (6324327b) Diff
    AsyncQueue.java 77.89% 76.88% -1.01%
    FieldFilter.java 88.68% 88.33% -0.35%
    KeyFieldNotInFilter.java ? 0.00% ?
    NotInFilter.java ? 100.00% ?
    Query.java 4.03% 3.96% -0.07%
    RemoteSerializer.java 83.17% 83.68% +0.51%
    StructuredQuery.java 33.08% 33.38% +0.31%

Test Logs

Notes

HTML coverage reports can be produced locally with ./gradlew <product>:checkCoverage.
Report files are located at <product-build-dir>/reports/jacoco/.

Head commit (6324327b) is created by Prow via merging commits: ed8977b cc4397b.

* @param <T> The type of the values of in common between the expected list and actual set.
*/
// PORTING NOTE: JUnit and XCTest use reversed conventions on expected and actual values :-(.
public static <T> void assertArrayEquals(List<T> expected, List<T> actual) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This name doesn't seem right. Neither argument is an array and the ordered-container property of arrays is explicitly ignored in the implementation.

assertSetEquals above are essentially asserting the two containers are equal without regard for ordering. I think you probably could use the same name here, since that's what you're doing.

However, I think you can combine this with the one above. Make it:

public static <T> void assertSetEquals(Iterable<T> expected, Iterable<T> actual) {
  Set<T> expectedSet = Sets.newHashSet(expected);
  Set<T> actualSet = Sets.newHashSet(actual);
  assertEquals(expectedSet, actualSet);
}

This has the added benefit of allowing Collection<T> to be passed as an argument directly, which will eliminate all the Lists.newArrayList in your callers.

Copy link
Author

Choose a reason for hiding this comment

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

Done. Thanks for the explanation!


QuerySnapshot snapshot = waitFor(collection.whereNotEqualTo("zip", 98101L).get());
assertArrayEquals(
Lists.newArrayList(expectedDocsMap.values()), querySnapshotToValues(snapshot));
Copy link
Contributor

Choose a reason for hiding this comment

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

As noted on assertArrayEquals, remove this Lists.newArrayList, here and throughout.

Copy link
Author

Choose a reason for hiding this comment

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

Removed here and throughout.

/**
* Given an operator, returns the set of operators that cannot be used with it.
*
* <p>Operators in a query must adhere to the following set of rules: 1. Only one array operator
Copy link
Contributor

Choose a reason for hiding this comment

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

To make a list use

<ol>
<li>Only one array operator ...
<li>One one disjunctive ...
</ol>

Copy link
Author

Choose a reason for hiding this comment

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

done.

Copy link
Contributor

Choose a reason for hiding this comment

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

The list wrapper element is required (<ol> indicates an ordered list (aka numbered); use <ul> for unordered (aka bulleted)).

Copy link
Author

Choose a reason for hiding this comment

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

Done for reals.

} else {
hardAssert(
operator != Operator.ARRAY_CONTAINS && operator != Operator.ARRAY_CONTAINS_ANY,
operator.toString() + "queries don't make sense on document keys");
return new KeyFieldFilter(path, operator, value);
}
} else if (Values.isNullValue(value)) {
if (operator != Filter.Operator.EQUAL) {
// TODO(ne-queries): Update error message to include != operator.
if (operator != Filter.Operator.EQUAL && operator != Filter.Operator.NOT_EQUAL) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Operator must already be imported here (see references to Operator.ARRAY_CONTAINS) so you can drop the Filter in Filter.Operator.

Copy link
Author

Choose a reason for hiding this comment

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

done.

@@ -0,0 +1,39 @@
// Copyright 2019 Google LLC
Copy link
Contributor

Choose a reason for hiding this comment

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

2020

Copy link
Author

Choose a reason for hiding this comment

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

done.

@@ -234,4 +240,22 @@ public static int compareByteStrings(ByteString left, ByteString right) {
}
return Util.compareIntegers(left.size(), right.size());
}

public static List<DocumentKey> extractDocumentKeysFromArrayValue(
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't likely to be a widely used or general utility. Better to make this a package private static member of e.g. KeyFieldInFilter and just call it from the other one.

(Another clue that this doesn't belong here is that you're referring to KeyFieldInFilter in the error message. This is therefore pretty specific to those classes.)

Copy link
Author

Choose a reason for hiding this comment

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

Done. Thanks for pointing out the code smell, that's a helpful check I'll keep in mind.

@wilhuff wilhuff assigned thebrianchen and unassigned wilhuff Aug 12, 2020
@thebrianchen thebrianchen requested a review from wilhuff August 14, 2020 00:42
@thebrianchen thebrianchen assigned wilhuff and unassigned thebrianchen Aug 14, 2020
"bb", docD);
CollectionReference collection = testCollectionWithDocs(testDocs);
QuerySnapshot docs = waitFor(collection.whereNotEqualTo(FieldPath.documentId(), "aa").get());
assertEquals(asList(docB, docC, docD), querySnapshotToValues(docs));
Copy link
Contributor

Choose a reason for hiding this comment

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

Apologies for what's going to be an irritating question (since I didn't pick up on this earlier), but why do you assertSetEquals(x, expected) in the test above but assertEquals(asList(x), expected) here when we're testing the same underlying operator?

To me it seems like either the ordering matters or it doesn't. If ordering of query results is predictable, assertSetEquals seems wrong because it allows the result to be unordered when our customers really care that it's ordered. The reverse is also true: if ordering doesn't matter, then this test is too strict, and could create a false positive.

To my understanding, query results always have a well defined ordering (breaking ties on key ordering). This seems to point to assertSetEquals being wrong above.

What's your take on this? Why the discrepancy?

(The same concern applies to the whereNotIn, below).

Copy link
Author

Choose a reason for hiding this comment

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

Thanks for catching this actually! I originally ran into an issue where I was converting the snapshots into a HashSet in order to easily remove the unneeded documents, but converting them back into a List resulted in an ordering that didn't match the query snapshots from the query. Instead of trying to create the expectedDocsMap in the correct order, I took the "shortcut" of comparing them as sets to avoid the ordering errors without realizing that order matters in query results.

I took a look at the code, and realized that Using Maps.newHashMap() keeps the documents in the correct order. Switched back to using assertEquals with Lists.newArrayList().

/**
* Given an operator, returns the set of operators that cannot be used with it.
*
* <p>Operators in a query must adhere to the following set of rules: 1. Only one array operator
Copy link
Contributor

Choose a reason for hiding this comment

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

The list wrapper element is required (<ol> indicates an ordered list (aka numbered); use <ul> for unordered (aka bulleted)).

@@ -0,0 +1,36 @@
// Copyright 2019 Google LLC
Copy link
Contributor

Choose a reason for hiding this comment

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

2020 here too

Copy link
Author

Choose a reason for hiding this comment

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

done.

@wilhuff wilhuff assigned thebrianchen and unassigned wilhuff Aug 14, 2020
@thebrianchen thebrianchen requested a review from wilhuff August 14, 2020 16:23
@thebrianchen thebrianchen assigned wilhuff and unassigned thebrianchen Aug 14, 2020
Copy link
Contributor

@wilhuff wilhuff left a comment

Choose a reason for hiding this comment

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

LGTM

@wilhuff wilhuff assigned thebrianchen and unassigned wilhuff Aug 14, 2020
@thebrianchen thebrianchen merged commit 1ee3caa into master Aug 14, 2020
@thebrianchen thebrianchen deleted the bc/ne branch August 14, 2020 17:31
@firebase firebase locked and limited conversation to collaborators Sep 14, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants