Skip to content

Commit 1ee3caa

Browse files
author
Brian Chen
authored
Add != and NOT_IN queries (not public) (#1872)
1 parent ed8977b commit 1ee3caa

File tree

12 files changed

+673
-67
lines changed

12 files changed

+673
-67
lines changed

firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
import androidx.test.ext.junit.runners.AndroidJUnit4;
3333
import com.google.android.gms.tasks.Task;
34+
import com.google.common.collect.Lists;
35+
import com.google.common.collect.Maps;
3436
import com.google.firebase.firestore.Query.Direction;
3537
import com.google.firebase.firestore.testutil.EventAccumulator;
3638
import com.google.firebase.firestore.testutil.IntegrationTestUtil;
@@ -39,6 +41,7 @@
3941
import java.util.Map;
4042
import java.util.concurrent.Semaphore;
4143
import org.junit.After;
44+
import org.junit.Ignore;
4245
import org.junit.Test;
4346
import org.junit.runner.RunWith;
4447

@@ -483,6 +486,79 @@ public void testQueriesFireFromCacheWhenOffline() {
483486
listener.remove();
484487
}
485488

489+
// TODO(ne-queries): Re-enable once emulator support is added to CI.
490+
@Ignore
491+
@Test
492+
public void testQueriesCanUseNotEqualFilters() {
493+
Map<String, Object> docA = map("zip", 98101L);
494+
Map<String, Object> docB = map("zip", 91102L);
495+
Map<String, Object> docC = map("zip", "98101");
496+
Map<String, Object> docD = map("zip", asList(98101L));
497+
Map<String, Object> docE = map("zip", asList("98101", map("zip", 98101L)));
498+
Map<String, Object> docF = map("zip", map("code", 500L));
499+
Map<String, Object> docG = map("zip", asList(98101L, 98102L));
500+
Map<String, Object> docH = map("code", 500L);
501+
Map<String, Object> docI = map("zip", null);
502+
Map<String, Object> docJ = map("zip", Double.NaN);
503+
504+
Map<String, Map<String, Object>> allDocs =
505+
map(
506+
"a", docA, "b", docB, "c", docC, "d", docD, "e", docE, "f", docF, "g", docG, "h", docH,
507+
"i", docI, "j", docJ);
508+
CollectionReference collection = testCollectionWithDocs(allDocs);
509+
510+
// Search for zips not matching 98101.
511+
Map<String, Map<String, Object>> expectedDocsMap = Maps.newHashMap(allDocs);
512+
expectedDocsMap.remove("a");
513+
expectedDocsMap.remove("h");
514+
expectedDocsMap.remove("i");
515+
516+
QuerySnapshot snapshot = waitFor(collection.whereNotEqualTo("zip", 98101L).get());
517+
assertEquals(Lists.newArrayList(expectedDocsMap.values()), querySnapshotToValues(snapshot));
518+
519+
// With objects.
520+
expectedDocsMap = Maps.newHashMap(allDocs);
521+
expectedDocsMap.remove("f");
522+
expectedDocsMap.remove("h");
523+
expectedDocsMap.remove("i");
524+
snapshot = waitFor(collection.whereNotEqualTo("zip", map("code", 500)).get());
525+
assertEquals(Lists.newArrayList(expectedDocsMap.values()), querySnapshotToValues(snapshot));
526+
527+
// With Null.
528+
expectedDocsMap = Maps.newHashMap(allDocs);
529+
expectedDocsMap.remove("h");
530+
expectedDocsMap.remove("i");
531+
snapshot = waitFor(collection.whereNotEqualTo("zip", null).get());
532+
assertEquals(Lists.newArrayList(expectedDocsMap.values()), querySnapshotToValues(snapshot));
533+
534+
// With NaN.
535+
expectedDocsMap = Maps.newHashMap(allDocs);
536+
expectedDocsMap.remove("h");
537+
expectedDocsMap.remove("i");
538+
expectedDocsMap.remove("j");
539+
snapshot = waitFor(collection.whereNotEqualTo("zip", Double.NaN).get());
540+
assertEquals(Lists.newArrayList(expectedDocsMap.values()), querySnapshotToValues(snapshot));
541+
}
542+
543+
// TODO(ne-queries): Re-enable once emulator support is added to CI.
544+
@Ignore
545+
@Test
546+
public void testQueriesCanUseNotEqualFiltersWithDocIds() {
547+
Map<String, String> docA = map("key", "aa");
548+
Map<String, String> docB = map("key", "ab");
549+
Map<String, String> docC = map("key", "ba");
550+
Map<String, String> docD = map("key", "bb");
551+
Map<String, Map<String, Object>> testDocs =
552+
map(
553+
"aa", docA,
554+
"ab", docB,
555+
"ba", docC,
556+
"bb", docD);
557+
CollectionReference collection = testCollectionWithDocs(testDocs);
558+
QuerySnapshot docs = waitFor(collection.whereNotEqualTo(FieldPath.documentId(), "aa").get());
559+
assertEquals(asList(docB, docC, docD), querySnapshotToValues(docs));
560+
}
561+
486562
@Test
487563
public void testQueriesCanUseArrayContainsFilters() {
488564
Map<String, Object> docA = map("array", asList(42L));
@@ -541,6 +617,87 @@ public void testQueriesCanUseInFiltersWithDocIds() {
541617
assertEquals(asList(docA, docB), querySnapshotToValues(docs));
542618
}
543619

620+
// TODO(ne-queries): Re-enable once emulator support is added to CI.
621+
@Ignore
622+
@Test
623+
public void testQueriesCanUseNotInFilters() {
624+
Map<String, Object> docA = map("zip", 98101L);
625+
Map<String, Object> docB = map("zip", 91102L);
626+
Map<String, Object> docC = map("zip", 98103L);
627+
Map<String, Object> docD = map("zip", asList(98101L));
628+
Map<String, Object> docE = map("zip", asList("98101", map("zip", 98101L)));
629+
Map<String, Object> docF = map("zip", map("code", 500L));
630+
Map<String, Object> docG = map("zip", asList(98101L, 98102L));
631+
Map<String, Object> docH = map("code", 500L);
632+
Map<String, Object> docI = map("zip", null);
633+
Map<String, Object> docJ = map("zip", Double.NaN);
634+
635+
Map<String, Map<String, Object>> allDocs =
636+
map(
637+
"a", docA, "b", docB, "c", docC, "d", docD, "e", docE, "f", docF, "g", docG, "h", docH,
638+
"i", docI, "j", docJ);
639+
CollectionReference collection = testCollectionWithDocs(allDocs);
640+
641+
// Search for zips not matching 98101, 98103, or [98101, 98102].
642+
Map<String, Map<String, Object>> expectedDocsMap = Maps.newHashMap(allDocs);
643+
expectedDocsMap.remove("a");
644+
expectedDocsMap.remove("c");
645+
expectedDocsMap.remove("g");
646+
expectedDocsMap.remove("h");
647+
648+
QuerySnapshot snapshot =
649+
waitFor(collection.whereNotIn("zip", asList(98101L, 98103L, asList(98101L, 98102L))).get());
650+
assertEquals(Lists.newArrayList(expectedDocsMap.values()), querySnapshotToValues(snapshot));
651+
652+
// With objects.
653+
expectedDocsMap = Maps.newHashMap(allDocs);
654+
expectedDocsMap.remove("f");
655+
expectedDocsMap.remove("h");
656+
snapshot = waitFor(collection.whereNotIn("zip", asList(map("code", 500L))).get());
657+
assertEquals(Lists.newArrayList(expectedDocsMap.values()), querySnapshotToValues(snapshot));
658+
659+
// With Null.
660+
List<Object> nullArray = new ArrayList<>();
661+
nullArray.add(null);
662+
snapshot = waitFor(collection.whereNotIn("key", nullArray).get());
663+
assertEquals(new ArrayList<>(), querySnapshotToValues(snapshot));
664+
665+
// With NaN.
666+
expectedDocsMap = Maps.newHashMap(allDocs);
667+
expectedDocsMap.remove("h");
668+
expectedDocsMap.remove("j");
669+
snapshot = waitFor(collection.whereNotIn("zip", asList(Double.NaN)).get());
670+
assertEquals(Lists.newArrayList(expectedDocsMap.values()), querySnapshotToValues(snapshot));
671+
672+
// With NaN and a number.
673+
expectedDocsMap = Maps.newHashMap(allDocs);
674+
expectedDocsMap.remove("a");
675+
expectedDocsMap.remove("h");
676+
expectedDocsMap.remove("j");
677+
snapshot = waitFor(collection.whereNotIn("zip", asList(Float.NaN, 98101L)).get());
678+
assertEquals(Lists.newArrayList(expectedDocsMap.values()), querySnapshotToValues(snapshot));
679+
}
680+
681+
// TODO(ne-queries): Re-enable once emulator support is added to CI.
682+
@Ignore
683+
@Test
684+
public void testQueriesCanUseNotInFiltersWithDocIds() {
685+
Map<String, String> docA = map("key", "aa");
686+
Map<String, String> docB = map("key", "ab");
687+
Map<String, String> docC = map("key", "ba");
688+
Map<String, String> docD = map("key", "bb");
689+
Map<String, Map<String, Object>> testDocs =
690+
map(
691+
"aa", docA,
692+
"ab", docB,
693+
"ba", docC,
694+
"bb", docD);
695+
CollectionReference collection = testCollectionWithDocs(testDocs);
696+
QuerySnapshot docs =
697+
waitFor(collection.whereNotIn(FieldPath.documentId(), asList("aa", "ab")).get());
698+
assertEquals(asList(docC, docD), querySnapshotToValues(docs));
699+
}
700+
544701
@Test
545702
public void testQueriesCanUseArrayContainsAnyFilters() {
546703
Map<String, Object> docA = map("array", asList(42L));

firebase-firestore/src/androidTest/java/com/google/firebase/firestore/ValidationTest.java

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,9 @@ public void queriesWithNullOrNaNFiltersOtherThanEqualityFail() {
424424
expectError(
425425
() -> collection.whereIn("a", null),
426426
"Invalid Query. A non-empty array is required for 'in' filters.");
427+
expectError(
428+
() -> collection.whereNotIn("a", null),
429+
"Invalid Query. A non-empty array is required for 'not_in' filters.");
427430

428431
expectError(
429432
() -> collection.whereGreaterThan("a", Double.NaN),
@@ -557,6 +560,19 @@ public void queriesWithInequalityDifferentThanFirstOrderByFail() {
557560
expectError(() -> collection.orderBy("y").whereGreaterThan("x", 32), reason);
558561
expectError(() -> collection.whereGreaterThan("x", 32).orderBy("y").orderBy("x"), reason);
559562
expectError(() -> collection.orderBy("y").orderBy("x").whereGreaterThan("x", 32), reason);
563+
expectError(() -> collection.orderBy("y").orderBy("x").whereNotEqualTo("x", 32), reason);
564+
}
565+
566+
@Test
567+
public void queriesWithMultipleNotEqualAndInequalitiesFail() {
568+
expectError(
569+
() -> testCollection().whereNotEqualTo("x", 32).whereNotEqualTo("x", 33),
570+
"Invalid Query. You cannot use more than one '!=' filter.");
571+
572+
expectError(
573+
() -> testCollection().whereNotEqualTo("x", 32).whereGreaterThan("y", 33),
574+
"All where filters other than whereEqualTo() must be on the same field. But you "
575+
+ "have filters on 'x' and 'y'");
560576
}
561577

562578
@Test
@@ -578,6 +594,21 @@ public void queriesWithMultipleArrayFiltersFail() {
578594
.whereArrayContainsAny("foo", asList(1, 2))
579595
.whereArrayContains("foo", 1),
580596
"Invalid Query. You cannot use 'array_contains' filters with 'array_contains_any' filters.");
597+
598+
expectError(
599+
() -> testCollection().whereNotIn("foo", asList(1, 2)).whereArrayContains("foo", 1),
600+
"Invalid Query. You cannot use 'array_contains' filters with 'not_in' filters.");
601+
}
602+
603+
@Test
604+
public void queriesWithNotEqualAndNotInFiltersFail() {
605+
expectError(
606+
() -> testCollection().whereNotIn("foo", asList(1, 2)).whereNotEqualTo("foo", 1),
607+
"Invalid Query. You cannot use '!=' filters with 'not_in' filters.");
608+
609+
expectError(
610+
() -> testCollection().whereNotEqualTo("foo", 1).whereNotIn("foo", asList(1, 2)),
611+
"Invalid Query. You cannot use 'not_in' filters with '!=' filters.");
581612
}
582613

583614
@Test
@@ -586,6 +617,10 @@ public void queriesWithMultipleDisjunctiveFiltersFail() {
586617
() -> testCollection().whereIn("foo", asList(1, 2)).whereIn("bar", asList(1, 2)),
587618
"Invalid Query. You cannot use more than one 'in' filter.");
588619

620+
expectError(
621+
() -> testCollection().whereNotIn("foo", asList(1, 2)).whereNotIn("bar", asList(1, 2)),
622+
"Invalid Query. You cannot use more than one 'not_in' filter.");
623+
589624
expectError(
590625
() ->
591626
testCollection()
@@ -607,6 +642,28 @@ public void queriesWithMultipleDisjunctiveFiltersFail() {
607642
.whereArrayContainsAny("foo", asList(1, 2)),
608643
"Invalid Query. You cannot use 'array_contains_any' filters with 'in' filters.");
609644

645+
expectError(
646+
() ->
647+
testCollection()
648+
.whereArrayContainsAny("foo", asList(1, 2))
649+
.whereNotIn("bar", asList(1, 2)),
650+
"Invalid Query. You cannot use 'not_in' filters with 'array_contains_any' filters.");
651+
652+
expectError(
653+
() ->
654+
testCollection()
655+
.whereNotIn("bar", asList(1, 2))
656+
.whereArrayContainsAny("foo", asList(1, 2)),
657+
"Invalid Query. You cannot use 'array_contains_any' filters with 'not_in' filters.");
658+
659+
expectError(
660+
() -> testCollection().whereNotIn("bar", asList(1, 2)).whereIn("foo", asList(1, 2)),
661+
"Invalid Query. You cannot use 'in' filters with 'not_in' filters.");
662+
663+
expectError(
664+
() -> testCollection().whereIn("bar", asList(1, 2)).whereNotIn("foo", asList(1, 2)),
665+
"Invalid Query. You cannot use 'not_in' filters with 'in' filters.");
666+
610667
// This is redundant with the above tests, but makes sure our validation doesn't get confused.
611668
expectError(
612669
() ->
@@ -622,7 +679,23 @@ public void queriesWithMultipleDisjunctiveFiltersFail() {
622679
.whereArrayContains("foo", 1)
623680
.whereIn("bar", asList(1, 2))
624681
.whereArrayContainsAny("foo", asList(1, 2)),
625-
"Invalid Query. You cannot use 'array_contains_any' filters with 'in' filters.");
682+
"Invalid Query. You cannot use 'array_contains_any' filters with 'array_contains' filters.");
683+
684+
expectError(
685+
() ->
686+
testCollection()
687+
.whereNotIn("bar", asList(1, 2))
688+
.whereArrayContains("foo", 1)
689+
.whereArrayContainsAny("foo", asList(1, 2)),
690+
"Invalid Query. You cannot use 'array_contains' filters with 'not_in' filters.");
691+
692+
expectError(
693+
() ->
694+
testCollection()
695+
.whereArrayContains("foo", 1)
696+
.whereIn("foo", asList(1, 2))
697+
.whereNotIn("bar", asList(1, 2)),
698+
"Invalid Query. You cannot use 'not_in' filters with 'array_contains' filters.");
626699
}
627700

628701
@Test
@@ -653,6 +726,10 @@ public void queriesInAndArrayContainsAnyArrayRules() {
653726
() -> testCollection().whereIn("bar", asList()),
654727
"Invalid Query. A non-empty array is required for 'in' filters.");
655728

729+
expectError(
730+
() -> testCollection().whereNotIn("bar", asList()),
731+
"Invalid Query. A non-empty array is required for 'not_in' filters.");
732+
656733
expectError(
657734
() -> testCollection().whereArrayContainsAny("bar", asList()),
658735
"Invalid Query. A non-empty array is required for 'array_contains_any' filters.");
@@ -662,6 +739,11 @@ public void queriesInAndArrayContainsAnyArrayRules() {
662739
() -> testCollection().whereIn("bar", asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9)),
663740
"Invalid Query. 'in' filters support a maximum of 10 elements in the value array.");
664741

742+
expectError(
743+
// The 10 element max includes duplicates.
744+
() -> testCollection().whereNotIn("bar", asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9)),
745+
"Invalid Query. 'not_in' filters support a maximum of 10 elements in the value array.");
746+
665747
expectError(
666748
// The 10 element max includes duplicates.
667749
() ->

0 commit comments

Comments
 (0)