diff --git a/firebase-firestore/CHANGELOG.md b/firebase-firestore/CHANGELOG.md index 745b4905503..e89f4d95e4d 100644 --- a/firebase-firestore/CHANGELOG.md +++ b/firebase-firestore/CHANGELOG.md @@ -1,5 +1,5 @@ # Unreleased - +* [fixed] Fixed the `null` value handling in `whereNotEqualTo` and `whereNotIn` filters. # 25.1.3 * [fixed] Use lazy encoding in UTF-8 encoded byte comparison for strings to solve performance issues. [#6706](//github.com/firebase/firebase-android-sdk/pull/6706) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java index 4ebba7b6d06..f6209dd49a4 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java @@ -1647,4 +1647,53 @@ public void testOrderByEquality() { Query query2 = collection.where(inArray("a", asList(2, 3))).orderBy("a"); checkOnlineAndOfflineResultsMatch(collection, query2, "doc6", "doc3"); } + + @Test + public void testSDKUsesNotEqualFiltersSameAsServer() { + Map> testDocs = + map( + "a", map("zip", Double.NaN), + "b", map("zip", 91102L), + "c", map("zip", 98101L), + "d", map("zip", "98101"), + "e", map("zip", asList(98101L)), + "f", map("zip", asList(98101L, 98102L)), + "g", map("zip", asList("98101", map("zip", 98101L))), + "h", map("zip", map("code", 500L)), + "i", map("zip", null), + "j", map("code", 500L)); + CollectionReference collection = testCollectionWithDocs(testDocs); + + Query query = collection.whereNotEqualTo("zip", 98101L); + checkOnlineAndOfflineResultsMatch(collection, query, "a", "b", "d", "e", "f", "g", "h"); + + query = collection.whereNotEqualTo("zip", Double.NaN); + checkOnlineAndOfflineResultsMatch(collection, query, "b", "c", "d", "e", "f", "g", "h"); + + query = collection.whereNotEqualTo("zip", null); + checkOnlineAndOfflineResultsMatch(collection, query, "a", "b", "c", "d", "e", "f", "g", "h"); + } + + @Test + public void testSDKUsesNotInFiltersSameAsServer() { + Map> testDocs = + map( + "a", map("zip", Double.NaN), + "b", map("zip", 91102L), + "c", map("zip", 98101L), + "d", map("zip", "98101"), + "e", map("zip", asList(98101L)), + "f", map("zip", asList(98101L, 98102L)), + "g", map("zip", asList("98101", map("zip", 98101L))), + "h", map("zip", map("code", 500L)), + "i", map("zip", null), + "j", map("code", 500L)); + CollectionReference collection = testCollectionWithDocs(testDocs); + + Query query = collection.whereNotIn("zip", asList(98101L, 98103L, asList(98101L, 98102L))); + checkOnlineAndOfflineResultsMatch(collection, query, "a", "b", "d", "e", "g", "h"); + + query = collection.whereNotIn("zip", nullList()); + checkOnlineAndOfflineResultsMatch(collection, query); + } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java index 6ebf26d0718..04a6f252a80 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java @@ -115,7 +115,9 @@ public boolean matches(Document doc) { Value other = doc.getField(field); // Types do not have to match in NOT_EQUAL filters. if (operator == Operator.NOT_EQUAL) { - return other != null && this.matchesComparison(Values.compare(other, value)); + return other != null + && !other.hasNullValue() + && this.matchesComparison(Values.compare(other, value)); } // Only compare types with matching backend order (such as double and int). return other != null diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/NotInFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/NotInFilter.java index 1f827f688e8..2f430d7f71c 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/NotInFilter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/NotInFilter.java @@ -34,6 +34,8 @@ public boolean matches(Document doc) { return false; } Value other = doc.getField(getField()); - return other != null && !Values.contains(getValue().getArrayValue(), other); + return other != null + && !other.hasNullValue() + && !Values.contains(getValue().getArrayValue(), other); } } diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/core/QueryTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/core/QueryTest.java index de3de67463c..cdc932bfa01 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/core/QueryTest.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/core/QueryTest.java @@ -237,7 +237,7 @@ public void testNotInFilters() { // Null match. document = doc("collection/1", 0, map("zip", null)); - assertTrue(query.matches(document)); + assertFalse(query.matches(document)); // NaN match. document = doc("collection/1", 0, map("zip", Double.NaN)); @@ -333,7 +333,7 @@ public void testNaNFilter() { assertTrue(query.matches(doc3)); assertTrue(query.matches(doc4)); assertTrue(query.matches(doc5)); - assertTrue(query.matches(doc6)); + assertFalse(query.matches(doc6)); } @Test