Skip to content

Commit d914433

Browse files
author
Brian Chen
committed
resolve comments
1 parent b2346f3 commit d914433

File tree

5 files changed

+63
-51
lines changed

5 files changed

+63
-51
lines changed

packages/firestore/src/api/database.ts

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,7 +1667,7 @@ function parseDocumentIdValue(
16671667
}
16681668

16691669
/**
1670-
* Validates that the value passed into a disjunctrive filter satisfies all
1670+
* Validates that the value passed into a disjunctive filter satisfies all
16711671
* array requirements.
16721672
*/
16731673
function validateDisjunctiveFilterElements(
@@ -1688,45 +1688,58 @@ function validateDisjunctiveFilterElements(
16881688
'maximum of 10 elements in the value array.'
16891689
);
16901690
}
1691-
if (value.indexOf(null) >= 0 && operator !== Operator.NOT_IN) {
1692-
throw new FirestoreError(
1693-
Code.INVALID_ARGUMENT,
1694-
`Invalid Query. '${operator.toString()}' filters cannot contain 'null' ` +
1695-
'in the value array.'
1696-
);
1697-
}
1698-
if (
1699-
value.filter(element => Number.isNaN(element)).length > 0 &&
1700-
operator !== Operator.NOT_IN
1701-
) {
1702-
throw new FirestoreError(
1703-
Code.INVALID_ARGUMENT,
1704-
`Invalid Query. '${operator.toString()}' filters cannot contain 'NaN' ` +
1705-
'in the value array.'
1706-
);
1691+
if (operator === Operator.IN || operator === Operator.ARRAY_CONTAINS_ANY) {
1692+
if (value.indexOf(null) >= 0) {
1693+
throw new FirestoreError(
1694+
Code.INVALID_ARGUMENT,
1695+
`Invalid Query. '${operator.toString()}' filters cannot contain 'null' ` +
1696+
'in the value array.'
1697+
);
1698+
}
1699+
if (value.filter(element => Number.isNaN(element)).length > 0) {
1700+
throw new FirestoreError(
1701+
Code.INVALID_ARGUMENT,
1702+
`Invalid Query. '${operator.toString()}' filters cannot contain 'NaN' ` +
1703+
'in the value array.'
1704+
);
1705+
}
17071706
}
17081707
}
17091708

1709+
/**
1710+
* Given an operator, returns the set of operators that cannot be used with it.
1711+
*
1712+
* Array operators: ARRAY_CONTAINS, ARRAY_CONTAINS_ANY
1713+
* Disjunctive operators: IN, ARRAY_CONTAINS_ANY, NOT_IN
1714+
*/
17101715
function conflictingOps(op: Operator): Operator[] {
17111716
switch (op) {
17121717
case Operator.NOT_EQUAL:
1713-
return [Operator.NOT_IN, Operator.NOT_EQUAL];
1718+
// No other NOT_EQUAL or NOT_IN operator can be used with NOT_EQUAL.
1719+
return [Operator.NOT_EQUAL, Operator.NOT_IN];
17141720
case Operator.ARRAY_CONTAINS:
17151721
return [
1722+
// Only 1 ARRAY operator can be used.
17161723
Operator.ARRAY_CONTAINS,
17171724
Operator.ARRAY_CONTAINS_ANY,
1725+
// NOT_IN cannot be used with any array operators.
17181726
Operator.NOT_IN
17191727
];
17201728
case Operator.IN:
1729+
// Only one disjunctive operator can be used.
17211730
return [Operator.ARRAY_CONTAINS_ANY, Operator.IN, Operator.NOT_IN];
17221731
case Operator.ARRAY_CONTAINS_ANY:
17231732
return [
1733+
// Only one ARRAY operator can be used.
17241734
Operator.ARRAY_CONTAINS,
1735+
// Only one disjunctive operator can be used.
17251736
Operator.ARRAY_CONTAINS_ANY,
17261737
Operator.IN,
17271738
Operator.NOT_IN
17281739
];
17291740
case Operator.NOT_IN:
1741+
// NOT_IN cannot be used with another array, disjunctive, or NOT_EQUAL
1742+
// operator.
17301743
return [
17311744
Operator.ARRAY_CONTAINS,
17321745
Operator.ARRAY_CONTAINS_ANY,
@@ -1762,7 +1775,7 @@ function validateNewFilter(query: InternalQuery, filter: Filter): void {
17621775

17631776
const conflictingOp = query.findFilterOperator(conflictingOps(filter.op));
17641777
if (conflictingOp !== null) {
1765-
// We special case when it's a duplicate op to give a slightly clearer error message.
1778+
// Special case when it's a duplicate op to give a slightly clearer error message.
17661779
if (conflictingOp === filter.op) {
17671780
throw new FirestoreError(
17681781
Code.INVALID_ARGUMENT,

packages/firestore/src/core/query.ts

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -647,13 +647,9 @@ export class FieldFilter extends Filter {
647647

648648
private static createKeyFieldInFilter(
649649
field: FieldPath,
650-
op: Operator,
650+
op: Operator.IN | Operator.NOT_IN,
651651
value: api.Value
652652
): FieldFilter {
653-
debugAssert(
654-
op === Operator.IN || op === Operator.NOT_IN,
655-
'createKeyFieldInFilter requires an IN or NOT_IN operator'
656-
);
657653
debugAssert(
658654
isArray(value),
659655
`Comparing on key with ${op.toString()}` +
@@ -784,14 +780,7 @@ export class KeyFieldInFilter extends FieldFilter {
784780

785781
constructor(field: FieldPath, value: api.Value) {
786782
super(field, Operator.IN, value);
787-
debugAssert(isArray(value), 'KeyFieldInFilter expects an ArrayValue');
788-
this.keys = (value.arrayValue.values || []).map(v => {
789-
debugAssert(
790-
isReferenceValue(v),
791-
'Comparing on key with IN, but an array value was not a ReferenceValue'
792-
);
793-
return DocumentKey.fromName(v.referenceValue);
794-
});
783+
this.keys = extractDocumentKeysFromArrayValue(Operator.IN, value);
795784
}
796785

797786
matches(doc: Document): boolean {
@@ -805,21 +794,32 @@ export class KeyFieldNotInFilter extends FieldFilter {
805794

806795
constructor(field: FieldPath, value: api.Value) {
807796
super(field, Operator.NOT_IN, value);
808-
debugAssert(isArray(value), 'KeyFieldNotInFilter expects an ArrayValue');
809-
this.keys = (value.arrayValue.values || []).map(v => {
810-
debugAssert(
811-
isReferenceValue(v),
812-
'Comparing on key with NOT_IN, but an array value was not a ReferenceValue'
813-
);
814-
return DocumentKey.fromName(v.referenceValue);
815-
});
797+
this.keys = extractDocumentKeysFromArrayValue(Operator.NOT_IN, value);
816798
}
817799

818800
matches(doc: Document): boolean {
819801
return !this.keys.some(key => key.isEqual(doc.key));
820802
}
821803
}
822804

805+
function extractDocumentKeysFromArrayValue(
806+
op: Operator.IN | Operator.NOT_IN,
807+
value: api.Value
808+
): DocumentKey[] {
809+
debugAssert(
810+
isArray(value),
811+
'KeyFieldInFilter/KeyFieldNotInFilter expects an ArrayValue'
812+
);
813+
return (value.arrayValue?.values || []).map(v => {
814+
debugAssert(
815+
isReferenceValue(v),
816+
`Comparing on key with ${op.toString()}, but an array value was not ` +
817+
`a ReferenceValue`
818+
);
819+
return DocumentKey.fromName(v.referenceValue);
820+
});
821+
}
822+
823823
/** A Filter that implements the array-contains operator. */
824824
export class ArrayContainsFilter extends FieldFilter {
825825
constructor(field: FieldPath, value: api.Value) {

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,14 +1216,14 @@ apiDescribe('Validation:', (persistence: boolean) => {
12161216
);
12171217
});
12181218

1219-
validationIt(persistence, 'with != and NOT_IN filters fail', db => {
1219+
validationIt(persistence, 'with != and not-in filters fail', db => {
12201220
expect(() =>
12211221
db
12221222
.collection('test')
12231223
.where('foo', notInOp, [2, 3])
12241224
.where('foo', notEqualOp, 4)
12251225
).to.throw(
1226-
"Invalid query. You cannot use '!=' filters with " + "'not-in' filters."
1226+
"Invalid query. You cannot use '!=' filters with 'not-in' filters."
12271227
);
12281228

12291229
expect(() =>
@@ -1232,7 +1232,7 @@ apiDescribe('Validation:', (persistence: boolean) => {
12321232
.where('foo', notEqualOp, 4)
12331233
.where('foo', notInOp, [2, 3])
12341234
).to.throw(
1235-
"Invalid query. You cannot use 'not-in' filters with " + "'!=' filters."
1235+
"Invalid query. You cannot use 'not-in' filters with '!=' filters."
12361236
);
12371237
});
12381238

@@ -1309,7 +1309,7 @@ apiDescribe('Validation:', (persistence: boolean) => {
13091309
.where('foo', notInOp, [2, 3])
13101310
.where('foo', 'in', [2, 3])
13111311
).to.throw(
1312-
"Invalid query. You cannot use 'in' filters with " + "'not-in' filters."
1312+
"Invalid query. You cannot use 'in' filters with 'not-in' filters."
13131313
);
13141314

13151315
expect(() =>
@@ -1318,7 +1318,7 @@ apiDescribe('Validation:', (persistence: boolean) => {
13181318
.where('foo', 'in', [2, 3])
13191319
.where('foo', notInOp, [2, 3])
13201320
).to.throw(
1321-
"Invalid query. You cannot use 'not-in' filters with " + "'in' filters."
1321+
"Invalid query. You cannot use 'not-in' filters with 'in' filters."
13221322
);
13231323

13241324
// This is redundant with the above tests, but makes sure our validation
@@ -1330,8 +1330,7 @@ apiDescribe('Validation:', (persistence: boolean) => {
13301330
.where('foo', 'array-contains', 1)
13311331
.where('foo', 'array-contains-any', [2])
13321332
).to.throw(
1333-
"Invalid query. You cannot use 'array-contains-any' filters with " +
1334-
"'in' filters."
1333+
"Invalid query. You cannot use 'array-contains-any' filters with 'in' filters."
13351334
);
13361335

13371336
expect(() =>

packages/firestore/test/integration/util/helpers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,8 @@ export function withTestCollectionSettings(
279279
}
280280

281281
// TODO(ne-queries): This exists just so we don't have to do the cast
282-
// repeatedly. Once we expose '!=' publicly we can remove it and
283-
// just use 'array-contains-any' in all the tests.
282+
// repeatedly. Once we expose '!=' publicly we can remove it and just use '!='
283+
// in all the tests.
284284
export const notEqualOp = '!=' as firestore.WhereFilterOp;
285285

286286
// TODO(ne-queries): This exists just so we don't have to do the cast

packages/firestore/test/unit/core/query.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ describe('Query', () => {
218218
expect(queryMatches(query1, document)).to.be.true;
219219
});
220220

221-
it('matches NOT_IN filters', () => {
221+
it('matches not-in filters', () => {
222222
const query1 = query('collection', filter('zip', 'not-in', [12345]));
223223

224224
// No match.
@@ -260,7 +260,7 @@ describe('Query', () => {
260260
expect(queryMatches(query1, document)).to.be.false;
261261
});
262262

263-
it('matches NOT_IN filters with object values', () => {
263+
it('matches not-in filters with object values', () => {
264264
const query1 = query('collection', filter('zip', 'not-in', [{ a: [42] }]));
265265

266266
// Containing object in array.

0 commit comments

Comments
 (0)