Skip to content

Commit f900417

Browse files
author
Brian Chen
authored
Make != and NOT_IN publicly available (#3772)
1 parent a865ae9 commit f900417

File tree

12 files changed

+142
-152
lines changed

12 files changed

+142
-152
lines changed

.changeset/shiny-forks-pull.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'firebase': minor
3+
'@firebase/firestore': minor
4+
'@firebase/firestore-types': minor
5+
---
6+
7+
[feature] Added `not-in` and `!=` query operators for use with `.where()`. `not-in` finds documents where a specified field’s value is not in a specified array. `!=` finds documents where a specified field's value does not equal the specified value. Neither query operator will match documents where the specified field is not present.

packages/firebase/index.d.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -9073,17 +9073,20 @@ declare namespace firebase.firestore {
90739073

90749074
/**
90759075
* Filter conditions in a `Query.where()` clause are specified using the
9076-
* strings '<', '<=', '==', '>=', '>', 'array-contains', 'in', and 'array-contains-any'.
9076+
* strings '<', '<=', '==', '!=', '>=', '>', 'array-contains', 'in',
9077+
* 'array-contains-any', and 'not-in'.
90779078
*/
90789079
export type WhereFilterOp =
90799080
| '<'
90809081
| '<='
90819082
| '=='
9083+
| '!='
90829084
| '>='
90839085
| '>'
90849086
| 'array-contains'
90859087
| 'in'
9086-
| 'array-contains-any';
9088+
| 'array-contains-any'
9089+
| 'not-in';
90879090

90889091
/**
90899092
* A `Query` refers to a Query which you can read or listen to. You can also

packages/firestore-types/index.d.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -294,11 +294,13 @@ export type WhereFilterOp =
294294
| '<'
295295
| '<='
296296
| '=='
297+
| '!='
297298
| '>='
298299
| '>'
299300
| 'array-contains'
300301
| 'in'
301-
| 'array-contains-any';
302+
| 'array-contains-any'
303+
| 'not-in';
302304

303305
export class Query<T = DocumentData> {
304306
protected constructor();

packages/firestore/exp-types/index.d.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -277,11 +277,13 @@ export type WhereFilterOp =
277277
| '<'
278278
| '<='
279279
| '=='
280+
| '!='
280281
| '>='
281282
| '>'
282283
| 'array-contains'
283284
| 'in'
284-
| 'array-contains-any';
285+
| 'array-contains-any'
286+
| 'not-in';
285287

286288
export class Query<T = DocumentData> {
287289
protected constructor();

packages/firestore/lite-types/index.d.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -227,11 +227,13 @@ export type WhereFilterOp =
227227
| '<'
228228
| '<='
229229
| '=='
230+
| '!='
230231
| '>='
231232
| '>'
232233
| 'array-contains'
233234
| 'in'
234-
| 'array-contains-any';
235+
| 'array-contains-any'
236+
| 'not-in';
235237

236238
export class Query<T = DocumentData> {
237239
protected constructor();

packages/firestore/src/api/database.ts

+14-18
Original file line numberDiff line numberDiff line change
@@ -1882,24 +1882,20 @@ export class Query<T = DocumentData> implements PublicQuery<T> {
18821882
validateExactNumberOfArgs('Query.where', arguments, 3);
18831883
validateDefined('Query.where', 3, value);
18841884

1885-
// TODO(ne-queries): Add 'not-in' and '!=' to validation.
1886-
let op: Operator;
1887-
if ((opStr as unknown) === 'not-in' || (opStr as unknown) === '!=') {
1888-
op = opStr as Operator;
1889-
} else {
1890-
// Enumerated from the WhereFilterOp type in index.d.ts.
1891-
const whereFilterOpEnums = [
1892-
Operator.LESS_THAN,
1893-
Operator.LESS_THAN_OR_EQUAL,
1894-
Operator.EQUAL,
1895-
Operator.GREATER_THAN_OR_EQUAL,
1896-
Operator.GREATER_THAN,
1897-
Operator.ARRAY_CONTAINS,
1898-
Operator.IN,
1899-
Operator.ARRAY_CONTAINS_ANY
1900-
];
1901-
op = validateStringEnum('Query.where', whereFilterOpEnums, 2, opStr);
1902-
}
1885+
// Enumerated from the WhereFilterOp type in index.d.ts.
1886+
const whereFilterOpEnums = [
1887+
Operator.LESS_THAN,
1888+
Operator.LESS_THAN_OR_EQUAL,
1889+
Operator.EQUAL,
1890+
Operator.NOT_EQUAL,
1891+
Operator.GREATER_THAN_OR_EQUAL,
1892+
Operator.GREATER_THAN,
1893+
Operator.ARRAY_CONTAINS,
1894+
Operator.IN,
1895+
Operator.ARRAY_CONTAINS_ANY,
1896+
Operator.NOT_IN
1897+
];
1898+
const op = validateStringEnum('Query.where', whereFilterOpEnums, 2, opStr);
19031899

19041900
const fieldPath = fieldPathFromArgument('Query.where', field);
19051901
const filter = newQueryFilter(

packages/firestore/src/core/query.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -605,19 +605,17 @@ export class FieldFilter extends Filter {
605605
}
606606
} else if (isNullValue(value)) {
607607
if (op !== Operator.EQUAL && op !== Operator.NOT_EQUAL) {
608-
// TODO(ne-queries): Update error message to include != comparison.
609608
throw new FirestoreError(
610609
Code.INVALID_ARGUMENT,
611-
'Invalid query. Null supports only equality comparisons.'
610+
"Invalid query. Null only supports '==' and '!=' comparisons."
612611
);
613612
}
614613
return new FieldFilter(field, op, value);
615614
} else if (isNanValue(value)) {
616615
if (op !== Operator.EQUAL && op !== Operator.NOT_EQUAL) {
617-
// TODO(ne-queries): Update error message to include != comparison.
618616
throw new FirestoreError(
619617
Code.INVALID_ARGUMENT,
620-
'Invalid query. NaN supports only equality comparisons.'
618+
"Invalid query. NaN only supports '==' and '!=' comparisons."
621619
);
622620
}
623621
return new FieldFilter(field, op, value);
@@ -711,7 +709,8 @@ export class FieldFilter extends Filter {
711709
Operator.LESS_THAN_OR_EQUAL,
712710
Operator.GREATER_THAN,
713711
Operator.GREATER_THAN_OR_EQUAL,
714-
Operator.NOT_EQUAL
712+
Operator.NOT_EQUAL,
713+
Operator.NOT_IN
715714
].indexOf(this.op) >= 0
716715
);
717716
}

packages/firestore/test/integration/api/database.test.ts

+4-26
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ import { EventsAccumulator } from '../util/events_accumulator';
2525
import * as firebaseExport from '../util/firebase_export';
2626
import {
2727
apiDescribe,
28-
notEqualOp,
29-
notInOp,
3028
withTestCollection,
3129
withTestDb,
3230
withTestDbs,
@@ -644,14 +642,6 @@ apiDescribe('Database', (persistence: boolean) => {
644642
});
645643
});
646644

647-
it('inequality and NOT_IN on different fields works', () => {
648-
return withTestCollection(persistence, {}, async coll => {
649-
expect(() =>
650-
coll.where('x', '>=', 32).where('y', notInOp, [1, 2])
651-
).not.to.throw();
652-
});
653-
});
654-
655645
it('inequality and array-contains-any on different fields works', () => {
656646
return withTestCollection(persistence, {}, async coll => {
657647
expect(() =>
@@ -669,12 +659,8 @@ apiDescribe('Database', (persistence: boolean) => {
669659

670660
it('!= same as orderBy works.', () => {
671661
return withTestCollection(persistence, {}, async coll => {
672-
expect(() =>
673-
coll.where('x', notEqualOp, 32).orderBy('x')
674-
).not.to.throw();
675-
expect(() =>
676-
coll.orderBy('x').where('x', notEqualOp, 32)
677-
).not.to.throw();
662+
expect(() => coll.where('x', '!=', 32).orderBy('x')).not.to.throw();
663+
expect(() => coll.orderBy('x').where('x', '!=', 32)).not.to.throw();
678664
});
679665
});
680666

@@ -692,10 +678,10 @@ apiDescribe('Database', (persistence: boolean) => {
692678
it('!= same as first orderBy works.', () => {
693679
return withTestCollection(persistence, {}, async coll => {
694680
expect(() =>
695-
coll.where('x', notEqualOp, 32).orderBy('x').orderBy('y')
681+
coll.where('x', '!=', 32).orderBy('x').orderBy('y')
696682
).not.to.throw();
697683
expect(() =>
698-
coll.orderBy('x').where('x', notEqualOp, 32).orderBy('y')
684+
coll.orderBy('x').where('x', '!=', 32).orderBy('y')
699685
).not.to.throw();
700686
});
701687
});
@@ -720,14 +706,6 @@ apiDescribe('Database', (persistence: boolean) => {
720706
});
721707
});
722708

723-
it('NOT_IN different than orderBy works', () => {
724-
return withTestCollection(persistence, {}, async coll => {
725-
expect(() =>
726-
coll.orderBy('x').where('y', notInOp, [1, 2])
727-
).not.to.throw();
728-
});
729-
});
730-
731709
it('array-contains-any different than orderBy works', () => {
732710
return withTestCollection(persistence, {}, async coll => {
733711
expect(() =>

0 commit comments

Comments
 (0)