Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -1178,4 +1178,167 @@ public void testOrQueriesWithArrayMembership() {
"doc4",
"doc6");
}

@Test
public void testMultipleInOps() {
Map<String, Map<String, Object>> testDocs =
map(
"doc1", map("a", 1, "b", 0),
"doc2", map("b", 1),
"doc3", map("a", 3, "b", 2),
"doc4", map("a", 1, "b", 3),
"doc5", map("a", 1),
"doc6", map("a", 2));
CollectionReference collection = testCollectionWithDocs(testDocs);

// Two IN operations on different fields with disjunction.
Query query1 =
collection
.where(Filter.or(Filter.inArray("a", asList(2, 3)), Filter.inArray("b", asList(0, 2))))
.orderBy("a");
checkOnlineAndOfflineResultsMatch(query1, "doc1", "doc6", "doc3");

// Two IN operations on different fields with conjunction.
Query query2 =
collection
.where(Filter.and(Filter.inArray("a", asList(2, 3)), Filter.inArray("b", asList(0, 2))))
.orderBy("a");
checkOnlineAndOfflineResultsMatch(query2, "doc3");

// Two IN operations on the same field.
// a IN [1,2,3] && a IN [0,1,4] should result in "a==1".
Query query3 =
collection.where(
Filter.and(Filter.inArray("a", asList(1, 2, 3)), Filter.inArray("a", asList(0, 1, 4))));
checkOnlineAndOfflineResultsMatch(query3, "doc1", "doc4", "doc5");

// a IN [2,3] && a IN [0,1,4] is never true and so the result should be an empty set.
Query query4 =
collection.where(
Filter.and(Filter.inArray("a", asList(2, 3)), Filter.inArray("a", asList(0, 1, 4))));
checkOnlineAndOfflineResultsMatch(query4);

// a IN [0,3] || a IN [0,2] should union them (similar to: a IN [0,2,3]).
Query query5 =
collection.where(
Filter.or(Filter.inArray("a", asList(0, 3)), Filter.inArray("a", asList(0, 2))));
checkOnlineAndOfflineResultsMatch(query5, "doc3", "doc6");

// Nested composite filter on the same field.
Query query6 =
collection.where(
Filter.and(
Filter.inArray("a", asList(1, 3)),
Filter.or(
Filter.inArray("a", asList(0, 2)),
Filter.and(
Filter.greaterThanOrEqualTo("b", 1), Filter.inArray("a", asList(1, 3))))));
checkOnlineAndOfflineResultsMatch(query6, "doc3", "doc4");

// Nested composite filter on different fields.
Query query7 =
collection.where(
Filter.and(
Filter.inArray("b", asList(0, 3)),
Filter.or(
Filter.inArray("b", asList(1)),
Filter.and(
Filter.inArray("b", asList(2, 3)), Filter.inArray("a", asList(1, 3))))));
checkOnlineAndOfflineResultsMatch(query7, "doc4");
}

@Test
public void testUsingInWithArrayContainsAny() {
Map<String, Map<String, Object>> testDocs =
map(
"doc1", map("a", 1, "b", asList(0)),
"doc2", map("b", asList(1)),
"doc3", map("a", 3, "b", asList(2, 7), "c", 10),
"doc4", map("a", 1, "b", asList(3, 7)),
"doc5", map("a", 1),
"doc6", map("a", 2, "c", 20));
CollectionReference collection = testCollectionWithDocs(testDocs);

Query query1 =
collection.where(
Filter.or(
Filter.inArray("a", asList(2, 3)), Filter.arrayContainsAny("b", asList(0, 7))));
checkOnlineAndOfflineResultsMatch(query1, "doc1", "doc3", "doc4", "doc6");

Query query2 =
collection.where(
Filter.and(
Filter.inArray("a", asList(2, 3)), Filter.arrayContainsAny("b", asList(0, 7))));
checkOnlineAndOfflineResultsMatch(query2, "doc3");

Query query3 =
collection.where(
Filter.or(
Filter.and(Filter.inArray("a", asList(2, 3)), Filter.equalTo("c", 10)),
Filter.arrayContainsAny("b", asList(0, 7))));
checkOnlineAndOfflineResultsMatch(query3, "doc1", "doc3", "doc4");

Query query4 =
collection.where(
Filter.and(
Filter.inArray("a", asList(2, 3)),
Filter.or(Filter.arrayContainsAny("b", asList(0, 7)), Filter.equalTo("c", 20))));
checkOnlineAndOfflineResultsMatch(query4, "doc3", "doc6");
}

@Test
public void testUsingInWithArrayContains() {
Map<String, Map<String, Object>> testDocs =
map(
"doc1", map("a", 1, "b", asList(0)),
"doc2", map("b", asList(1)),
"doc3", map("a", 3, "b", asList(2, 7)),
"doc4", map("a", 1, "b", asList(3, 7)),
"doc5", map("a", 1),
"doc6", map("a", 2));
CollectionReference collection = testCollectionWithDocs(testDocs);

Query query1 =
collection.where(
Filter.or(Filter.inArray("a", asList(2, 3)), Filter.arrayContains("b", 3)));
checkOnlineAndOfflineResultsMatch(query1, "doc3", "doc4", "doc6");

Query query2 =
collection.where(
Filter.and(Filter.inArray("a", asList(2, 3)), Filter.arrayContains("b", 7)));
checkOnlineAndOfflineResultsMatch(query2, "doc3");

Query query3 =
collection.where(
Filter.or(
Filter.inArray("a", asList(2, 3)),
Filter.and(Filter.arrayContains("b", 3), Filter.equalTo("a", 1))));
checkOnlineAndOfflineResultsMatch(query3, "doc3", "doc4", "doc6");

Query query4 =
collection.where(
Filter.and(
Filter.inArray("a", asList(2, 3)),
Filter.or(Filter.arrayContains("b", 7), Filter.equalTo("a", 1))));
checkOnlineAndOfflineResultsMatch(query4, "doc3");
}

@Test
public void testOrderByEquality() {
Map<String, Map<String, Object>> testDocs =
map(
"doc1", map("a", 1, "b", asList(0)),
"doc2", map("b", asList(1)),
"doc3", map("a", 3, "b", asList(2, 7), "c", 10),
"doc4", map("a", 1, "b", asList(3, 7)),
"doc5", map("a", 1),
"doc6", map("a", 2, "c", 20));
CollectionReference collection = testCollectionWithDocs(testDocs);

Query query1 = collection.where(Filter.equalTo("a", 1)).orderBy("a");
checkOnlineAndOfflineResultsMatch(query1, "doc1", "doc4", "doc5");

Query query2 = collection.where(Filter.inArray("a", asList(2, 3))).orderBy("a");
checkOnlineAndOfflineResultsMatch(query2, "doc6", "doc3");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static com.google.firebase.firestore.Filter.equalTo;
import static com.google.firebase.firestore.Filter.greaterThan;
import static com.google.firebase.firestore.Filter.inArray;
import static com.google.firebase.firestore.Filter.notEqualTo;
import static com.google.firebase.firestore.Filter.notInArray;
import static com.google.firebase.firestore.Filter.or;
import static com.google.firebase.firestore.testutil.Assert.assertThrows;
Expand Down Expand Up @@ -595,10 +596,6 @@ public void queriesWithNotEqualAndNotInFiltersFail() {

@Test
public void queriesWithMultipleDisjunctiveFiltersFail() {
expectError(
() -> testCollection().whereIn("foo", asList(1, 2)).whereIn("bar", asList(1, 2)),
"Invalid Query. You cannot use more than one 'in' filter.");

expectError(
() -> testCollection().whereNotIn("foo", asList(1, 2)).whereNotIn("bar", asList(1, 2)),
"All where filters with an inequality (notEqualTo, notIn, lessThan, "
Expand All @@ -612,20 +609,6 @@ public void queriesWithMultipleDisjunctiveFiltersFail() {
.whereArrayContainsAny("bar", asList(1, 2)),
"Invalid Query. You cannot use more than one 'array_contains_any' filter.");

expectError(
() ->
testCollection()
.whereArrayContainsAny("foo", asList(1, 2))
.whereIn("bar", asList(1, 2)),
"Invalid Query. You cannot use 'in' filters with 'array_contains_any' filters.");

expectError(
() ->
testCollection()
.whereIn("bar", asList(1, 2))
.whereArrayContainsAny("foo", asList(1, 2)),
"Invalid Query. You cannot use 'array_contains_any' filters with 'in' filters.");

expectError(
() ->
testCollection()
Expand Down Expand Up @@ -655,7 +638,7 @@ public void queriesWithMultipleDisjunctiveFiltersFail() {
.whereIn("bar", asList(1, 2))
.whereArrayContains("foo", 1)
.whereArrayContainsAny("foo", asList(1, 2)),
"Invalid Query. You cannot use 'array_contains_any' filters with 'in' filters.");
"Invalid Query. You cannot use 'array_contains_any' filters with 'array_contains' filters.");

expectError(
() ->
Expand Down Expand Up @@ -694,14 +677,6 @@ public void queriesCanUseInWithArrayContains() {
.whereArrayContains("foo", 1)
.whereArrayContains("foo", 1),
"Invalid Query. You cannot use more than one 'array_contains' filter.");

expectError(
() ->
testCollection()
.whereArrayContains("foo", 1)
.whereIn("bar", asList(1, 2))
.whereIn("bar", asList(1, 2)),
"Invalid Query. You cannot use more than one 'in' filter.");
}

@Test
Expand All @@ -719,20 +694,31 @@ public void queriesInAndArrayContainsAnyArrayRules() {
"Invalid Query. A non-empty array is required for 'array_contains_any' filters.");

expectError(
// The 10 element max includes duplicates.
() -> testCollection().whereIn("bar", asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9)),
"Invalid Query. 'in' filters support a maximum of 10 elements in the value array.");
// The 30 element max includes duplicates.
() ->
testCollection()
.whereIn(
"bar",
asList(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31)),
"Invalid Query. 'in' filters support a maximum of 30 elements in the value array.");

expectError(
// The 10 element max includes duplicates.
() -> testCollection().whereNotIn("bar", asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9)),
// The 30 element max includes duplicates.
() -> testCollection().whereNotIn("bar", asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)),
"Invalid Query. 'not_in' filters support a maximum of 10 elements in the value array.");

expectError(
// The 10 element max includes duplicates.
() ->
testCollection().whereArrayContainsAny("bar", asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9)),
"Invalid Query. 'array_contains_any' filters support a maximum of 10 elements in the value array.");
testCollection()
.whereArrayContainsAny(
"bar",
asList(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31)),
"Invalid Query. 'array_contains_any' filters support a maximum of 30 elements in the value array.");
}

@Test
Expand Down Expand Up @@ -890,6 +876,54 @@ public void testInvalidQueryFilters() {
reason);
}

@Test
public void testDisjunctionWithNotInFilter() {
CollectionReference collection = testCollection();
String reason = "The 'notIn' filter should not be used in a query that contains a disjunction.";
expectError(
() -> collection.where(or(equalTo("a", "b"), notInArray("c", asList(1, 2)))), reason);
expectError(
() ->
collection.where(
and(equalTo("x", "y"), or(equalTo("a", "b"), notInArray("c", asList(1, 2))))),
reason);
expectError(
() ->
collection.where(
or(equalTo("x", "y"), and(equalTo("a", "b"), notInArray("c", asList(1, 2))))),
reason);
}

@Test
public void testOrderByEqualityWithDisjunctions() {
CollectionReference collection = testCollection();
String reason =
"Performing an equality ('in' and '==') and an inequality (notEqualTo, notIn, "
+ "lessThan, lessThanOrEqualTo, greaterThan, or greaterThanOrEqualTo) on the same field "
+ "is not yet allowed in disjunctions.";
// Using ==
expectError(() -> collection.where(or(equalTo("a", "b"), notEqualTo("a", "c"))), reason);
expectError(
() -> collection.where(and(greaterThan("a", 5), or(equalTo("a", 6), equalTo("b", "c")))),
reason);
expectError(
() -> collection.where(or(greaterThan("a", 5), and(equalTo("a", 6), equalTo("b", "c")))),
reason);

// Using 'in'
expectError(() -> collection.where(or(inArray("a", asList(1, 2)), notEqualTo("a", 5))), reason);
expectError(
() ->
collection.where(
and(greaterThan("a", 5), or(inArray("a", asList(1, 2)), equalTo("b", "c")))),
reason);
expectError(
() ->
collection.where(
or(greaterThan("a", 5), and(inArray("a", asList(1, 2)), equalTo("b", "c")))),
reason);
}

// Helpers

/** Performs a write using each write API and makes sure it succeeds. */
Expand Down
Loading