Skip to content

Commit c5ffda3

Browse files
author
Brian Chen
committed
add != and NOT_IN support
oops
1 parent f833a38 commit c5ffda3

File tree

13 files changed

+694
-69
lines changed

13 files changed

+694
-69
lines changed

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

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static com.google.firebase.firestore.testutil.IntegrationTestUtil.testCollectionWithDocs;
2121
import static com.google.firebase.firestore.testutil.IntegrationTestUtil.testFirestore;
2222
import static com.google.firebase.firestore.testutil.IntegrationTestUtil.waitFor;
23+
import static com.google.firebase.firestore.testutil.TestUtil.assertArrayEquals;
2324
import static com.google.firebase.firestore.testutil.TestUtil.expectError;
2425
import static com.google.firebase.firestore.testutil.TestUtil.map;
2526
import static java.util.Arrays.asList;
@@ -31,6 +32,8 @@
3132

3233
import androidx.test.ext.junit.runners.AndroidJUnit4;
3334
import com.google.android.gms.tasks.Task;
35+
import com.google.common.collect.Lists;
36+
import com.google.common.collect.Maps;
3437
import com.google.firebase.firestore.Query.Direction;
3538
import com.google.firebase.firestore.testutil.EventAccumulator;
3639
import com.google.firebase.firestore.testutil.IntegrationTestUtil;
@@ -39,6 +42,7 @@
3942
import java.util.Map;
4043
import java.util.concurrent.Semaphore;
4144
import org.junit.After;
45+
import org.junit.Ignore;
4246
import org.junit.Test;
4347
import org.junit.runner.RunWith;
4448

@@ -483,6 +487,83 @@ public void testQueriesFireFromCacheWhenOffline() {
483487
listener.remove();
484488
}
485489

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

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