Skip to content

Commit 36558bd

Browse files
OR queries - relaxing in restrictions (#7024)
Relaxing query validations performed by the Firestore SDK package
1 parent b970dc5 commit 36558bd

File tree

6 files changed

+256
-381
lines changed

6 files changed

+256
-381
lines changed

.changeset/heavy-starfishes-count.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@firebase/firestore-compat": feat
3+
"@firebase/firestore": feat
4+
---
5+
6+
Relaxing query validation performed by the SDK

packages/firestore-compat/test/validation.test.ts

-164
Original file line numberDiff line numberDiff line change
@@ -901,47 +901,6 @@ apiDescribe('Validation:', (persistence: boolean) => {
901901
}
902902
);
903903

904-
validationIt(persistence, 'with multiple array filters fail', db => {
905-
expect(() =>
906-
db
907-
.collection('test')
908-
.where('foo', 'array-contains', 1)
909-
.where('foo', 'array-contains', 2)
910-
).to.throw(
911-
"Invalid query. You cannot use more than one 'array-contains' filter."
912-
);
913-
914-
expect(() =>
915-
db
916-
.collection('test')
917-
.where('foo', 'array-contains', 1)
918-
.where('foo', 'array-contains-any', [2, 3])
919-
).to.throw(
920-
"Invalid query. You cannot use 'array-contains-any' filters with " +
921-
"'array-contains' filters."
922-
);
923-
924-
expect(() =>
925-
db
926-
.collection('test')
927-
.where('foo', 'array-contains-any', [2, 3])
928-
.where('foo', 'array-contains', 1)
929-
).to.throw(
930-
"Invalid query. You cannot use 'array-contains' filters with " +
931-
"'array-contains-any' filters."
932-
);
933-
934-
expect(() =>
935-
db
936-
.collection('test')
937-
.where('foo', 'not-in', [2, 3])
938-
.where('foo', 'array-contains', 1)
939-
).to.throw(
940-
"Invalid query. You cannot use 'array-contains' filters with " +
941-
"'not-in' filters."
942-
);
943-
});
944-
945904
validationIt(persistence, 'with != and not-in filters fail', db => {
946905
expect(() =>
947906
db
@@ -963,13 +922,6 @@ apiDescribe('Validation:', (persistence: boolean) => {
963922
});
964923

965924
validationIt(persistence, 'with multiple disjunctive filters fail', db => {
966-
expect(() =>
967-
db
968-
.collection('test')
969-
.where('foo', 'in', [1, 2])
970-
.where('foo', 'in', [2, 3])
971-
).to.throw("Invalid query. You cannot use more than one 'in' filter.");
972-
973925
expect(() =>
974926
db
975927
.collection('test')
@@ -979,36 +931,6 @@ apiDescribe('Validation:', (persistence: boolean) => {
979931
"Invalid query. You cannot use more than one 'not-in' filter."
980932
);
981933

982-
expect(() =>
983-
db
984-
.collection('test')
985-
.where('foo', 'array-contains-any', [1, 2])
986-
.where('foo', 'array-contains-any', [2, 3])
987-
).to.throw(
988-
"Invalid query. You cannot use more than one 'array-contains-any'" +
989-
' filter.'
990-
);
991-
992-
expect(() =>
993-
db
994-
.collection('test')
995-
.where('foo', 'array-contains-any', [2, 3])
996-
.where('foo', 'in', [2, 3])
997-
).to.throw(
998-
"Invalid query. You cannot use 'in' filters with " +
999-
"'array-contains-any' filters."
1000-
);
1001-
1002-
expect(() =>
1003-
db
1004-
.collection('test')
1005-
.where('foo', 'in', [2, 3])
1006-
.where('foo', 'array-contains-any', [2, 3])
1007-
).to.throw(
1008-
"Invalid query. You cannot use 'array-contains-any' filters with " +
1009-
"'in' filters."
1010-
);
1011-
1012934
expect(() =>
1013935
db
1014936
.collection('test')
@@ -1046,51 +968,6 @@ apiDescribe('Validation:', (persistence: boolean) => {
1046968
).to.throw(
1047969
"Invalid query. You cannot use 'not-in' filters with 'in' filters."
1048970
);
1049-
1050-
// This is redundant with the above tests, but makes sure our validation
1051-
// doesn't get confused.
1052-
expect(() =>
1053-
db
1054-
.collection('test')
1055-
.where('foo', 'in', [2, 3])
1056-
.where('foo', 'array-contains', 1)
1057-
.where('foo', 'array-contains-any', [2])
1058-
).to.throw(
1059-
"Invalid query. You cannot use 'array-contains-any' filters with 'in' filters."
1060-
);
1061-
1062-
expect(() =>
1063-
db
1064-
.collection('test')
1065-
.where('foo', 'array-contains', 1)
1066-
.where('foo', 'in', [2, 3])
1067-
.where('foo', 'array-contains-any', [2])
1068-
).to.throw(
1069-
"Invalid query. You cannot use 'array-contains-any' filters with " +
1070-
"'array-contains' filters."
1071-
);
1072-
1073-
expect(() =>
1074-
db
1075-
.collection('test')
1076-
.where('foo', 'not-in', [2, 3])
1077-
.where('foo', 'array-contains', 2)
1078-
.where('foo', 'array-contains-any', [2])
1079-
).to.throw(
1080-
"Invalid query. You cannot use 'array-contains' filters with " +
1081-
"'not-in' filters."
1082-
);
1083-
1084-
expect(() =>
1085-
db
1086-
.collection('test')
1087-
.where('foo', 'array-contains', 2)
1088-
.where('foo', 'in', [2])
1089-
.where('foo', 'not-in', [2, 3])
1090-
).to.throw(
1091-
"Invalid query. You cannot use 'not-in' filters with " +
1092-
"'array-contains' filters."
1093-
);
1094971
});
1095972

1096973
validationIt(
@@ -1110,24 +987,6 @@ apiDescribe('Validation:', (persistence: boolean) => {
1110987
.where('foo', 'in', [2, 3])
1111988
.where('foo', 'array-contains', 1)
1112989
).not.to.throw();
1113-
1114-
expect(() =>
1115-
db
1116-
.collection('test')
1117-
.where('foo', 'in', [2, 3])
1118-
.where('foo', 'array-contains', 1)
1119-
.where('foo', 'array-contains', 2)
1120-
).to.throw(
1121-
"Invalid query. You cannot use more than one 'array-contains' filter."
1122-
);
1123-
1124-
expect(() =>
1125-
db
1126-
.collection('test')
1127-
.where('foo', 'array-contains', 1)
1128-
.where('foo', 'in', [2, 3])
1129-
.where('foo', 'in', [2, 3])
1130-
).to.throw("Invalid query. You cannot use more than one 'in' filter.");
1131990
}
1132991
);
1133992

@@ -1146,29 +1005,6 @@ apiDescribe('Validation:', (persistence: boolean) => {
11461005
"'array-contains-any' filters."
11471006
);
11481007

1149-
expect(() =>
1150-
db
1151-
.collection('test')
1152-
// The 10 element max includes duplicates.
1153-
.where('foo', 'in', [1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9])
1154-
).to.throw(
1155-
"Invalid Query. 'in' filters support a maximum of 10 elements in " +
1156-
'the value array.'
1157-
);
1158-
1159-
expect(() =>
1160-
db
1161-
.collection('test')
1162-
.where(
1163-
'foo',
1164-
'array-contains-any',
1165-
[1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9]
1166-
)
1167-
).to.throw(
1168-
"Invalid Query. 'array-contains-any' filters support a maximum of " +
1169-
'10 elements in the value array.'
1170-
);
1171-
11721008
expect(() => db.collection('test').where('foo', 'in', [])).to.throw(
11731009
"Invalid Query. A non-empty array is required for 'in' filters."
11741010
);

packages/firestore/src/core/query.ts

+1-8
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
boundSortsAfterDocument,
2626
boundSortsBeforeDocument
2727
} from './bound';
28-
import { CompositeFilter, Filter } from './filter';
28+
import { Filter } from './filter';
2929
import { Direction, OrderBy } from './order_by';
3030
import {
3131
canonifyTarget,
@@ -165,13 +165,6 @@ export function queryMatchesAllDocuments(query: Query): boolean {
165165
);
166166
}
167167

168-
export function queryContainsCompositeFilters(query: Query): boolean {
169-
return (
170-
query.filters.find(filter => filter instanceof CompositeFilter) !==
171-
undefined
172-
);
173-
}
174-
175168
export function getFirstOrderByField(query: Query): FieldPath | null {
176169
return query.explicitOrderBy.length > 0
177170
? query.explicitOrderBy[0].field

packages/firestore/src/lite-api/query.ts

+7-29
Original file line numberDiff line numberDiff line change
@@ -1050,49 +1050,27 @@ function validateDisjunctiveFilterElements(
10501050
`'${operator.toString()}' filters.`
10511051
);
10521052
}
1053-
if (value.length > 10) {
1054-
throw new FirestoreError(
1055-
Code.INVALID_ARGUMENT,
1056-
`Invalid Query. '${operator.toString()}' filters support a ` +
1057-
'maximum of 10 elements in the value array.'
1058-
);
1059-
}
10601053
}
10611054

10621055
/**
10631056
* Given an operator, returns the set of operators that cannot be used with it.
10641057
*
1065-
* Operators in a query must adhere to the following set of rules:
1066-
* 1. Only one array operator is allowed.
1067-
* 2. Only one disjunctive operator is allowed.
1068-
* 3. `NOT_EQUAL` cannot be used with another `NOT_EQUAL` operator.
1069-
* 4. `NOT_IN` cannot be used with array, disjunctive, or `NOT_EQUAL` operators.
1058+
* This is not a comprehensive check, and this function should be removed in the
1059+
* long term. Validations should occur in the Firestore backend.
10701060
*
1071-
* Array operators: `ARRAY_CONTAINS`, `ARRAY_CONTAINS_ANY`
1072-
* Disjunctive operators: `IN`, `ARRAY_CONTAINS_ANY`, `NOT_IN`
1061+
* Operators in a query must adhere to the following set of rules:
1062+
* 1. Only one inequality per query.
1063+
* 2. `NOT_IN` cannot be used with array, disjunctive, or `NOT_EQUAL` operators.
10731064
*/
10741065
function conflictingOps(op: Operator): Operator[] {
10751066
switch (op) {
10761067
case Operator.NOT_EQUAL:
10771068
return [Operator.NOT_EQUAL, Operator.NOT_IN];
1078-
case Operator.ARRAY_CONTAINS:
1079-
return [
1080-
Operator.ARRAY_CONTAINS,
1081-
Operator.ARRAY_CONTAINS_ANY,
1082-
Operator.NOT_IN
1083-
];
1084-
case Operator.IN:
1085-
return [Operator.ARRAY_CONTAINS_ANY, Operator.IN, Operator.NOT_IN];
10861069
case Operator.ARRAY_CONTAINS_ANY:
1087-
return [
1088-
Operator.ARRAY_CONTAINS,
1089-
Operator.ARRAY_CONTAINS_ANY,
1090-
Operator.IN,
1091-
Operator.NOT_IN
1092-
];
1070+
case Operator.IN:
1071+
return [Operator.NOT_IN];
10931072
case Operator.NOT_IN:
10941073
return [
1095-
Operator.ARRAY_CONTAINS,
10961074
Operator.ARRAY_CONTAINS_ANY,
10971075
Operator.IN,
10981076
Operator.NOT_IN,

0 commit comments

Comments
 (0)