Skip to content

Commit ed0e192

Browse files
committed
Additional validation and additional validation tests for where(..), and(...), and or(...).
1 parent 09046e7 commit ed0e192

File tree

2 files changed

+90
-2
lines changed

2 files changed

+90
-2
lines changed

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

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,12 @@ export function query<T>(
168168

169169
if (nonFilters !== undefined) {
170170
queryConstraints = queryConstraints.concat(
171-
nonFilters as QueryNonFilterConstraint[]
171+
nonFilters as AppliableConstraint[]
172172
);
173173
}
174174

175+
validateQueryConstraintArray(queryConstraints);
176+
175177
for (const constraint of queryConstraints) {
176178
query = constraint._apply(query);
177179
}
@@ -1214,7 +1216,32 @@ export function validateQueryFilterConstraint(
12141216
) {
12151217
throw new FirestoreError(
12161218
Code.INVALID_ARGUMENT,
1217-
`Function ${functionName}() requires AppliableContraints created with a call to 'where(...)', 'or(...)', or 'and(...)'.`
1219+
`Function ${functionName}() requires AppliableConstraints created with a call to 'where(...)', 'or(...)', or 'and(...)'.`
1220+
);
1221+
}
1222+
}
1223+
1224+
function validateQueryConstraintArray(
1225+
queryConstraint: AppliableConstraint[]
1226+
): void {
1227+
const compositeFilterCount = queryConstraint.filter(
1228+
filter => filter instanceof QueryCompositeFilterConstraint
1229+
).length;
1230+
const fieldFilterCount = queryConstraint.filter(
1231+
filter => filter instanceof QueryFieldFilterConstraint
1232+
).length;
1233+
1234+
if (
1235+
compositeFilterCount > 1 ||
1236+
(compositeFilterCount > 0 && fieldFilterCount > 0)
1237+
) {
1238+
throw new FirestoreError(
1239+
Code.INVALID_ARGUMENT,
1240+
'InvalidQuery. When using composite filters, you cannot use ' +
1241+
'more than one filter at the top level. Consider nesting the multiple ' +
1242+
'filters within an `and(...)` statement. For example: ' +
1243+
'change `where(query, where(...), or(...))` to ' +
1244+
'`where(query, and(where(...), or(...)))`.'
12181245
);
12191246
}
12201247
}

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

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,7 +1399,68 @@ apiDescribe('Validation:', (persistence: boolean) => {
13991399
).to.throw(
14001400
"Invalid query. You cannot use 'not-in' filters with 'in' filters."
14011401
);
1402+
1403+
// Multiple top level composite filters
1404+
expect(() =>
1405+
// @ts-ignore
1406+
query(coll, and(where('a', '==', 'b')), or(where('b', '==', 'a')))
1407+
).to.throw(
1408+
'InvalidQuery. When using composite filters, you cannot use ' +
1409+
'more than one filter at the top level. Consider nesting the multiple ' +
1410+
'filters within an `and(...)` statement. For example: ' +
1411+
'change `where(query, where(...), or(...))` to ' +
1412+
'`where(query, and(where(...), or(...)))`.'
1413+
);
1414+
1415+
// Once top level composite filter and one top level field filter
1416+
expect(() =>
1417+
// @ts-ignore
1418+
query(coll, or(where('a', '==', 'b')), where('b', '==', 'a'))
1419+
).to.throw(
1420+
'InvalidQuery. When using composite filters, you cannot use ' +
1421+
'more than one filter at the top level. Consider nesting the multiple ' +
1422+
'filters within an `and(...)` statement. For example: ' +
1423+
'change `where(query, where(...), or(...))` to ' +
1424+
'`where(query, and(where(...), or(...)))`.'
1425+
);
14021426
});
1427+
1428+
validationIt(
1429+
persistence,
1430+
'passing non-filters to composite operators fails',
1431+
db => {
1432+
const compositeOperators = [
1433+
{ name: 'or', func: or },
1434+
{ name: 'and', func: and }
1435+
];
1436+
const nonFilterOps = [
1437+
limit(1),
1438+
limitToLast(2),
1439+
startAt(1),
1440+
startAfter(1),
1441+
endAt(1),
1442+
endBefore(1),
1443+
orderBy('a')
1444+
];
1445+
1446+
for (const compositeOp of compositeOperators) {
1447+
for (const nonFilterOp of nonFilterOps) {
1448+
const coll = collection(db, 'test');
1449+
expect(() =>
1450+
query(
1451+
coll,
1452+
compositeOp.func(
1453+
// @ts-ignore
1454+
nonFilterOp
1455+
)
1456+
)
1457+
).to.throw(
1458+
`Function ${compositeOp.name}() requires AppliableConstraints created with a call to 'where(...)', 'or(...)', or 'and(...)'.`
1459+
);
1460+
}
1461+
}
1462+
}
1463+
);
14031464
});
14041465
});
14051466

0 commit comments

Comments
 (0)