Skip to content

Commit

Permalink
fix(firestore): allow null value to isEqualsTo & isNotEqualsTo
Browse files Browse the repository at this point in the history
…in `where()` query (#11896)

* fix(firestore): allow `null` value to `isEqualsTo` `isNotEqualsTo` & `arrayContains` for `where()` queries

* test(firestore): allow `null` value to `isEqualsTo` `isNotEqualsTo` & `arrayContains` for `where()` queries

* chore: analyze and format issues

* refactor: cannot use `null` with `arrayContains` to query. doesn't work

* chore: fix typo

* feat: export the "where" sentinel value for usage in the ODM

* fix(firestore): revert named param types back to original

* feat: Support `whereField(isEqualTo: null)` and similar

* chore: Revert header removal

* chore: fix analyze

* chore: header again....

---------

Co-authored-by: Remi Rousselet <darky12s@gmail.com>
  • Loading branch information
russellwheatley and rrousselGit committed Nov 21, 2023
1 parent abbea17 commit 3ee59a7
Show file tree
Hide file tree
Showing 7 changed files with 1,130 additions and 978 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1813,6 +1813,56 @@ void runQueryTests() {
expect(snapshot.docs.length, equals(1));
expect(snapshot.docs[0].get('foo'), equals(ref));
});

testWidgets('pass `null` to `isEqualTo`', (_) async {
CollectionReference<Map<String, dynamic>> collection =
await initializeTest('where-null-isEqualTo');

await Future.wait([
collection.add({
'foo': 1,
}),
collection.add({'foo': 2}),
collection.add({
'foo': null,
}),
collection.add({
'foo': null,
}),
]);

QuerySnapshot<Map<String, dynamic>> snapshot =
await collection.where('foo', isEqualTo: null).get();

expect(snapshot.docs.length, equals(2));
expect(snapshot.docs[0].get('foo'), equals(null));
expect(snapshot.docs[1].get('foo'), equals(null));
});

testWidgets('pass `null` to `isNotEqualTo`', (_) async {
CollectionReference<Map<String, dynamic>> collection =
await initializeTest('where-null-isNotEqualTo');

await Future.wait([
collection.add({
'foo': 11,
}),
collection.add({'foo': 11}),
collection.add({
'foo': null,
}),
collection.add({
'foo': null,
}),
]);

QuerySnapshot<Map<String, dynamic>> snapshot =
await collection.where('foo', isNotEqualTo: null).get();

expect(snapshot.docs.length, equals(2));
expect(snapshot.docs[0].get('foo'), equals(11));
expect(snapshot.docs[1].get('foo'), equals(11));
});
});

group('Query.where() with Filter class', () {
Expand Down
72 changes: 44 additions & 28 deletions packages/cloud_firestore/cloud_firestore/lib/src/query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

part of cloud_firestore;

/// Sentinel value to check whether user passed values explicitly through .where() method
@internal
const notSetQueryParam = Object();

/// Represents a [Query] over the data at a particular location.
///
/// Can construct refined [Query] objects by adding filters and ordering.
Expand Down Expand Up @@ -595,13 +599,13 @@ class _JsonQuery implements Query<Map<String, dynamic>> {
@override
Query<Map<String, dynamic>> where(
Object fieldOrFilter, {
Object? isEqualTo,
Object? isNotEqualTo,
Object? isLessThan,
Object? isLessThanOrEqualTo,
Object? isGreaterThan,
Object? isGreaterThanOrEqualTo,
Object? arrayContains,
Object? isEqualTo = notSetQueryParam,
Object? isNotEqualTo = notSetQueryParam,
Object? isLessThan = notSetQueryParam,
Object? isLessThanOrEqualTo = notSetQueryParam,
Object? isGreaterThan = notSetQueryParam,
Object? isGreaterThanOrEqualTo = notSetQueryParam,
Object? arrayContains = notSetQueryParam,
Iterable<Object?>? arrayContainsAny,
Iterable<Object?>? whereIn,
Iterable<Object?>? whereNotIn,
Expand All @@ -611,13 +615,13 @@ class _JsonQuery implements Query<Map<String, dynamic>> {

if (fieldOrFilter is Filter) {
assert(
isEqualTo == null &&
isNotEqualTo == null &&
isLessThan == null &&
isLessThanOrEqualTo == null &&
isGreaterThan == null &&
isGreaterThanOrEqualTo == null &&
arrayContains == null &&
identical(isEqualTo, notSetQueryParam) &&
identical(isNotEqualTo, notSetQueryParam) &&
identical(isLessThan, notSetQueryParam) &&
identical(isLessThanOrEqualTo, notSetQueryParam) &&
identical(isGreaterThan, notSetQueryParam) &&
identical(isGreaterThanOrEqualTo, notSetQueryParam) &&
identical(arrayContains, notSetQueryParam) &&
arrayContainsAny == null &&
whereIn == null &&
whereNotIn == null &&
Expand Down Expand Up @@ -655,17 +659,29 @@ class _JsonQuery implements Query<Map<String, dynamic>> {
conditions.add(condition);
}

if (isEqualTo != null) addCondition(field, '==', isEqualTo);
if (isNotEqualTo != null) addCondition(field, '!=', isNotEqualTo);
if (isLessThan != null) addCondition(field, '<', isLessThan);
if (isLessThanOrEqualTo != null) {
if (!identical(isEqualTo, notSetQueryParam)) {
addCondition(field, '==', isEqualTo);
}

if (!identical(isNotEqualTo, notSetQueryParam)) {
addCondition(field, '!=', isNotEqualTo);
}

if (!identical(isLessThan, notSetQueryParam)) {
addCondition(field, '<', isLessThan);
}

if (!identical(isLessThanOrEqualTo, notSetQueryParam)) {
addCondition(field, '<=', isLessThanOrEqualTo);
}
if (isGreaterThan != null) addCondition(field, '>', isGreaterThan);
if (isGreaterThanOrEqualTo != null) {
if (!identical(isGreaterThan, notSetQueryParam)) {
addCondition(field, '>', isGreaterThan);
}

if (!identical(isGreaterThanOrEqualTo, notSetQueryParam)) {
addCondition(field, '>=', isGreaterThanOrEqualTo);
}
if (arrayContains != null) {
if (!identical(arrayContains, notSetQueryParam)) {
addCondition(field, 'array-contains', arrayContains);
}
if (arrayContainsAny != null) {
Expand Down Expand Up @@ -952,13 +968,13 @@ class _WithConverterQuery<T extends Object?> implements Query<T> {
@override
Query<T> where(
Object field, {
Object? isEqualTo,
Object? isNotEqualTo,
Object? isLessThan,
Object? isLessThanOrEqualTo,
Object? isGreaterThan,
Object? isGreaterThanOrEqualTo,
Object? arrayContains,
Object? isEqualTo = notSetQueryParam,
Object? isNotEqualTo = notSetQueryParam,
Object? isLessThan = notSetQueryParam,
Object? isLessThanOrEqualTo = notSetQueryParam,
Object? isGreaterThan = notSetQueryParam,
Object? isGreaterThanOrEqualTo = notSetQueryParam,
Object? arrayContains = notSetQueryParam,
Iterable<Object?>? arrayContainsAny,
Iterable<Object?>? whereIn,
Iterable<Object?>? whereNotIn,
Expand Down

0 comments on commit 3ee59a7

Please sign in to comment.