Skip to content

Commit ce867b0

Browse files
author
Brian Chen
authored
Make IN queries publicly available (#2217)
1 parent cf2be75 commit ce867b0

File tree

8 files changed

+142
-135
lines changed

8 files changed

+142
-135
lines changed

packages/firebase/index.d.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8062,11 +8062,17 @@ declare namespace firebase.firestore {
80628062

80638063
/**
80648064
* Filter conditions in a `Query.where()` clause are specified using the
8065-
* strings '<', '<=', '==', '>=', '>', and 'array-contains'.
8065+
* strings '<', '<=', '==', '>=', '>', 'array-contains', 'in', and 'array-contains-any'.
80668066
*/
8067-
// TODO(in-queries): Add 'array-contains-any' and 'in' once backend support
8068-
// lands.
8069-
export type WhereFilterOp = '<' | '<=' | '==' | '>=' | '>' | 'array-contains';
8067+
export type WhereFilterOp =
8068+
| '<'
8069+
| '<='
8070+
| '=='
8071+
| '>='
8072+
| '>'
8073+
| 'array-contains'
8074+
| 'in'
8075+
| 'array-contains-any';
80708076

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

packages/firestore-types/index.d.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,11 +1037,17 @@ export type OrderByDirection = 'desc' | 'asc';
10371037

10381038
/**
10391039
* Filter conditions in a `Query.where()` clause are specified using the
1040-
* strings '<', '<=', '==', '>=', '>', and 'array-contains'.
1040+
* strings '<', '<=', '==', '>=', '>', 'array-contains', 'in', and 'array-contains-any'.
10411041
*/
1042-
// TODO(in-queries): Add 'array-contains-any' and 'in' once backend support
1043-
// lands.
1044-
export type WhereFilterOp = '<' | '<=' | '==' | '>=' | '>' | 'array-contains';
1042+
export type WhereFilterOp =
1043+
| '<'
1044+
| '<='
1045+
| '=='
1046+
| '>='
1047+
| '>'
1048+
| 'array-contains'
1049+
| 'in'
1050+
| 'array-contains-any';
10451051

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

packages/firestore/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Unreleased
22
- [changed] The client can now recover if certain periodic IndexedDB operations
33
fail.
4+
- [feature] Added `in` and `array-contains-any` query operators for use with
5+
`.where()`. `in` finds documents where a specified field’s value is IN a
6+
specified array. `array-contains-any` finds documents where a specified field
7+
is an array and contains ANY element of a specified array.
48

59
# 1.6.3
610
- [changed] Improved iOS 13 support by eliminating an additional crash in our

packages/firestore/src/api/database.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,15 +1443,18 @@ export class Query implements firestore.Query {
14431443
validateExactNumberOfArgs('Query.where', arguments, 3);
14441444
validateDefined('Query.where', 3, value);
14451445

1446-
// TODO(in-queries): Add 'in' and 'array-contains-any' to validation.
1447-
if (
1448-
(opStr as unknown) !== 'in' &&
1449-
(opStr as unknown) !== 'array-contains-any'
1450-
) {
1451-
// Enumerated from the WhereFilterOp type in index.d.ts.
1452-
const whereFilterOpEnums = ['<', '<=', '==', '>=', '>', 'array-contains'];
1453-
validateStringEnum('Query.where', whereFilterOpEnums, 2, opStr);
1454-
}
1446+
// Enumerated from the WhereFilterOp type in index.d.ts.
1447+
const whereFilterOpEnums = [
1448+
'<',
1449+
'<=',
1450+
'==',
1451+
'>=',
1452+
'>',
1453+
'array-contains',
1454+
'in',
1455+
'array-contains-any'
1456+
];
1457+
validateStringEnum('Query.where', whereFilterOpEnums, 2, opStr);
14551458

14561459
let fieldValue: FieldValue;
14571460
const fieldPath = fieldPathFromArgument('Query.where', field);

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ import { EventsAccumulator } from '../util/events_accumulator';
2929
import firebase from '../util/firebase_export';
3030
import {
3131
apiDescribe,
32-
arrayContainsAnyOp,
33-
inOp,
3432
withTestCollection,
3533
withTestDb,
3634
withTestDbs,
@@ -612,15 +610,15 @@ apiDescribe('Database', (persistence: boolean) => {
612610
it('inequality and IN on different fields works', () => {
613611
return withTestCollection(persistence, {}, async coll => {
614612
expect(() =>
615-
coll.where('x', '>=', 32).where('y', inOp, [1, 2])
613+
coll.where('x', '>=', 32).where('y', 'in', [1, 2])
616614
).not.to.throw();
617615
});
618616
});
619617

620618
it('inequality and array-contains-any on different fields works', () => {
621619
return withTestCollection(persistence, {}, async coll => {
622620
expect(() =>
623-
coll.where('x', '>=', 32).where('y', arrayContainsAnyOp, [1, 2])
621+
coll.where('x', '>=', 32).where('y', 'array-contains-any', [1, 2])
624622
).not.to.throw();
625623
});
626624
});
@@ -665,14 +663,14 @@ apiDescribe('Database', (persistence: boolean) => {
665663

666664
it('IN different than orderBy works', () => {
667665
return withTestCollection(persistence, {}, async coll => {
668-
expect(() => coll.orderBy('x').where('y', inOp, [1, 2])).not.to.throw();
666+
expect(() => coll.orderBy('x').where('y', 'in', [1, 2])).not.to.throw();
669667
});
670668
});
671669

672670
it('array-contains-any different than orderBy works', () => {
673671
return withTestCollection(persistence, {}, async coll => {
674672
expect(() =>
675-
coll.orderBy('x').where('y', arrayContainsAnyOp, [1, 2])
673+
coll.orderBy('x').where('y', 'array-contains-any', [1, 2])
676674
).not.to.throw();
677675
});
678676
});

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

Lines changed: 48 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ import { EventsAccumulator } from '../util/events_accumulator';
2626
import firebase from '../util/firebase_export';
2727
import {
2828
apiDescribe,
29-
arrayContainsAnyOp,
30-
inOp,
3129
isRunningAgainstEmulator,
3230
toChangesArray,
3331
toDataArray,
@@ -562,33 +560,28 @@ apiDescribe('Queries', (persistence: boolean) => {
562560
});
563561
});
564562

565-
// TODO(in-queries): Enable browser tests once backend support is ready.
566-
// eslint-disable-next-line no-restricted-properties
567-
(isRunningAgainstEmulator() ? it : it.skip)(
568-
'can use IN filters',
569-
async () => {
570-
const testDocs = {
571-
a: { zip: 98101 },
572-
b: { zip: 91102 },
573-
c: { zip: 98103 },
574-
d: { zip: [98101] },
575-
e: { zip: ['98101', { zip: 98101 }] },
576-
f: { zip: { code: 500 } }
577-
};
563+
it('can use IN filters', async () => {
564+
const testDocs = {
565+
a: { zip: 98101 },
566+
b: { zip: 91102 },
567+
c: { zip: 98103 },
568+
d: { zip: [98101] },
569+
e: { zip: ['98101', { zip: 98101 }] },
570+
f: { zip: { code: 500 } }
571+
};
578572

579-
await withTestCollection(persistence, testDocs, async coll => {
580-
const snapshot = await coll.where('zip', inOp, [98101, 98103]).get();
581-
expect(toDataArray(snapshot)).to.deep.equal([
582-
{ zip: 98101 },
583-
{ zip: 98103 }
584-
]);
573+
await withTestCollection(persistence, testDocs, async coll => {
574+
const snapshot = await coll.where('zip', 'in', [98101, 98103]).get();
575+
expect(toDataArray(snapshot)).to.deep.equal([
576+
{ zip: 98101 },
577+
{ zip: 98103 }
578+
]);
585579

586-
// With objects.
587-
const snapshot2 = await coll.where('zip', inOp, [{ code: 500 }]).get();
588-
expect(toDataArray(snapshot2)).to.deep.equal([{ zip: { code: 500 } }]);
589-
});
590-
}
591-
);
580+
// With objects.
581+
const snapshot2 = await coll.where('zip', 'in', [{ code: 500 }]).get();
582+
expect(toDataArray(snapshot2)).to.deep.equal([{ zip: { code: 500 } }]);
583+
});
584+
});
592585

593586
// eslint-disable-next-line no-restricted-properties,
594587
(isRunningAgainstEmulator() ? it : it.skip)(
@@ -602,7 +595,7 @@ apiDescribe('Queries', (persistence: boolean) => {
602595
};
603596
await withTestCollection(persistence, testDocs, async coll => {
604597
const snapshot = await coll
605-
.where(FieldPath.documentId(), inOp, ['aa', 'ab'])
598+
.where(FieldPath.documentId(), 'in', ['aa', 'ab'])
606599
.get();
607600

608601
expect(toDataArray(snapshot)).to.deep.equal([
@@ -613,40 +606,35 @@ apiDescribe('Queries', (persistence: boolean) => {
613606
}
614607
);
615608

616-
// TODO(in-queries): Enable browser tests once backend support is ready.
617-
// eslint-disable-next-line no-restricted-properties
618-
(isRunningAgainstEmulator() ? it : it.skip)(
619-
'can use array-contains-any filters',
620-
async () => {
621-
const testDocs = {
622-
a: { array: [42] },
623-
b: { array: ['a', 42, 'c'] },
624-
c: { array: [41.999, '42', { a: [42] }] },
625-
d: { array: [42], array2: ['bingo'] },
626-
e: { array: [43] },
627-
f: { array: [{ a: 42 }] },
628-
g: { array: 42 }
629-
};
609+
it('can use array-contains-any filters', async () => {
610+
const testDocs = {
611+
a: { array: [42] },
612+
b: { array: ['a', 42, 'c'] },
613+
c: { array: [41.999, '42', { a: [42] }] },
614+
d: { array: [42], array2: ['bingo'] },
615+
e: { array: [43] },
616+
f: { array: [{ a: 42 }] },
617+
g: { array: 42 }
618+
};
630619

631-
await withTestCollection(persistence, testDocs, async coll => {
632-
const snapshot = await coll
633-
.where('array', arrayContainsAnyOp, [42, 43])
634-
.get();
635-
expect(toDataArray(snapshot)).to.deep.equal([
636-
{ array: [42] },
637-
{ array: ['a', 42, 'c'] },
638-
{ array: [42], array2: ['bingo'] },
639-
{ array: [43] }
640-
]);
620+
await withTestCollection(persistence, testDocs, async coll => {
621+
const snapshot = await coll
622+
.where('array', 'array-contains-any', [42, 43])
623+
.get();
624+
expect(toDataArray(snapshot)).to.deep.equal([
625+
{ array: [42] },
626+
{ array: ['a', 42, 'c'] },
627+
{ array: [42], array2: ['bingo'] },
628+
{ array: [43] }
629+
]);
641630

642-
// With objects.
643-
const snapshot2 = await coll
644-
.where('array', arrayContainsAnyOp, [{ a: 42 }])
645-
.get();
646-
expect(toDataArray(snapshot2)).to.deep.equal([{ array: [{ a: 42 }] }]);
647-
});
648-
}
649-
);
631+
// With objects.
632+
const snapshot2 = await coll
633+
.where('array', 'array-contains-any', [{ a: 42 }])
634+
.get();
635+
expect(toDataArray(snapshot2)).to.deep.equal([{ array: [{ a: 42 }] }]);
636+
});
637+
});
650638

651639
it('throws custom error when using docChanges as property', () => {
652640
const querySnap = querySnapshot('foo/bar', {}, {}, keys(), false, false);

0 commit comments

Comments
 (0)