Skip to content

Commit

Permalink
feat(firestore): allow query with range and inequality filters on mul…
Browse files Browse the repository at this point in the history
…tiple fields (#12564)

* feat(firestore): allow query with range and inequality filters on multiple fields

* remove more asserts

* format
  • Loading branch information
Lyokone committed Apr 2, 2024
1 parent 9431b78 commit 00ae837
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 134 deletions.
73 changes: 0 additions & 73 deletions packages/cloud_firestore/cloud_firestore/lib/src/query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -261,15 +261,6 @@ class _JsonQuery implements Query<Map<String, dynamic>> {
return parameters['endAt'] != null || parameters['endBefore'] != null;
}

/// Returns whether the current operator is an inequality operator.
bool _isInequality(String operator) {
return operator == '<' ||
operator == '<=' ||
operator == '>' ||
operator == '>=' ||
operator == '!=';
}

bool isNotIn(String operator) {
return operator == 'not-in';
}
Expand Down Expand Up @@ -512,46 +503,6 @@ class _JsonQuery implements Query<Map<String, dynamic>> {
orders.add([fieldPath, descending]);
}

final List<List<dynamic>> conditions =
List<List<dynamic>>.from(parameters['where']);

if (conditions.isNotEmpty) {
for (final dynamic condition in conditions) {
dynamic conditionField = condition[0];
String operator = condition[1];

// Initial orderBy() parameter has to match every where() fieldPath parameter when
// inequality or 'not-in' operator is invoked
if (_isInequality(operator) || isNotIn(operator)) {
assert(
conditionField == orders[0][0],
'The initial orderBy() field "$orders[0][0]" has to be the same as '
'the where() field parameter "$conditionField" when an inequality operator is invoked.',
);
}

for (final dynamic order in orders) {
dynamic orderField = order[0];

// Any where() fieldPath parameter cannot match any orderBy() parameter when
// '==' operand is invoked
if (operator == '==') {
assert(
conditionField != orderField,
"The '$orderField' cannot be the same as your where() field parameter '$conditionField'.",
);
}

if (conditionField == FieldPath.documentId) {
assert(
orderField == FieldPath.documentId,
"'[FieldPath.documentId]' cannot be used in conjunction with a different orderBy() parameter.",
);
}
}
}
}

return _JsonQuery(firestore, _delegate.orderBy(orders));
}

Expand Down Expand Up @@ -716,7 +667,6 @@ class _JsonQuery implements Query<Map<String, dynamic>> {
}
}

dynamic hasInequality;
bool hasIn = false;
bool hasNotIn = false;
bool hasNotEqualTo = false;
Expand All @@ -732,17 +682,6 @@ class _JsonQuery implements Query<Map<String, dynamic>> {
String operator = condition[1];
dynamic value = condition[2];

// Initial orderBy() parameter has to match every where() fieldPath parameter when
// inequality operator is invoked
List<List<dynamic>> orders = List.from(parameters['orderBy']);
if (_isInequality(operator) && orders.isNotEmpty) {
assert(
field == orders[0][0],
"The initial orderBy() field '$orders[0][0]' has to be the same as "
"the where() field parameter '$field' when an inequality operator is invoked.",
);
}

if (field != FieldPath.documentId && hasDocumentIdField) {
assert(
operator != '!=',
Expand Down Expand Up @@ -842,18 +781,6 @@ class _JsonQuery implements Query<Map<String, dynamic>> {
"You cannot use both 'array-contains-any' or 'array-contains' filters together.",
);
}

if (_isInequality(operator)) {
if (hasInequality == null) {
hasInequality = field;
} else {
assert(
hasInequality == field,
'All where filters with an inequality (<, <=, >, or >=) must be '
"on the same field. But you have inequality filters on '$hasInequality' and '$field'.",
);
}
}
}

return _JsonQuery(firestore, _delegate.where(conditions));
Expand Down
76 changes: 15 additions & 61 deletions packages/cloud_firestore/cloud_firestore/test/query_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,10 @@ void main() {
expect(() => query!.where(123), throwsAssertionError);
});

test('throws if multiple inequalities on different paths is provided',
() {
expect(
() => query!
.where('foo.bar', isGreaterThanOrEqualTo: 123)
.where('bar', isLessThan: 123),
throwsAssertionError,
);
test('allows multiple inequalities on different paths is provided', () {
query!
.where('foo.bar', isGreaterThanOrEqualTo: 123)
.where('bar', isLessThan: 123);
});

test('allows inequality on the same path', () {
Expand Down Expand Up @@ -85,59 +81,17 @@ void main() {
);
});

test('throws if inequality is different to first orderBy', () {
expect(
() => query!.where('foo', isGreaterThan: 123).orderBy('bar'),
throwsAssertionError,
);
expect(
() => query!.orderBy('bar').where('foo', isGreaterThan: 123),
throwsAssertionError,
);
expect(
() => query!
.where('foo', isGreaterThan: 123)
.orderBy('bar')
.orderBy('foo'),
throwsAssertionError,
);
expect(
() => query!
.orderBy('bar')
.orderBy('foo')
.where('foo', isGreaterThan: 123),
throwsAssertionError,
);

expect(
() => query!
.where(FieldPath.documentId, whereNotIn: ['bar']).orderBy('foo'),
throwsAssertionError,
);
expect(
() =>
query!.where(FieldPath.documentId, isLessThan: 3).orderBy('foo'),
throwsAssertionError,
);
expect(
() => query!
.where(FieldPath.documentId, isGreaterThan: 3)
.orderBy('foo'),
throwsAssertionError,
);

expect(
() => query!.where('foo', whereNotIn: ['bar']).orderBy('baz'),
throwsAssertionError,
);
expect(
() => query!.where('foo', isLessThan: 3).orderBy('bar'),
throwsAssertionError,
);
expect(
() => query!.where('foo', isGreaterThan: 3).orderBy('bar'),
throwsAssertionError,
);
test('allows inequality different to first orderBy', () {
query!.where('foo', isGreaterThan: 123).orderBy('bar');
query!.orderBy('bar').where('foo', isGreaterThan: 123);
query!.where('foo', isGreaterThan: 123).orderBy('bar').orderBy('foo');
query!.orderBy('bar').orderBy('foo').where('foo', isGreaterThan: 123);
query!.where(FieldPath.documentId, whereNotIn: ['bar']).orderBy('foo');
query!.where(FieldPath.documentId, isLessThan: 3).orderBy('foo');
query!.where(FieldPath.documentId, isGreaterThan: 3).orderBy('foo');
query!.where('foo', whereNotIn: ['bar']).orderBy('baz');
query!.where('foo', isLessThan: 3).orderBy('bar');
query!.where('foo', isGreaterThan: 3).orderBy('bar');
});

test('throws if whereIn query length is greater than 30', () {
Expand Down

0 comments on commit 00ae837

Please sign in to comment.