Skip to content

Markduckworth/or queries pr 9 #6755

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 48 commits into from
Nov 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
effced9
Add composite filters. Port of https://github.com/firebase/firebase-a…
MarkDuckworth Jun 24, 2022
eba3b84
Cleanup: lint
MarkDuckworth Jun 24, 2022
33a0896
Support encoding and decoding Composite Filters
MarkDuckworth Jun 29, 2022
9f6e216
Formatting
MarkDuckworth Jun 30, 2022
6556240
Merge remote-tracking branch 'origin/markduckworth/or-queries' into m…
MarkDuckworth Jul 26, 2022
78a8900
Fix issue with readonly array.
MarkDuckworth Jul 26, 2022
80fc05d
WIP: serving results from index.
MarkDuckworth Aug 5, 2022
8b6f05f
Perform DNF transform
MarkDuckworth Aug 10, 2022
152fc18
Cleanup and tests from https://github.com/firebase/firebase-android-s…
MarkDuckworth Aug 10, 2022
8b0bfbd
Merge branch 'markduckworth/or-queries' of github.com:firebase/fireba…
MarkDuckworth Aug 12, 2022
1c948cb
use index if we have composite filters
MarkDuckworth Aug 12, 2022
2cad46c
Merge branch 'markduckworth/or-queries' into markduckworth/or-queries…
MarkDuckworth Aug 12, 2022
266f7f6
Fix bad import
MarkDuckworth Aug 12, 2022
c2d7cd2
Update the orderBy filtering mechanism for OR queries and steps to se…
MarkDuckworth Aug 15, 2022
41d0e29
Adding tests
MarkDuckworth Aug 15, 2022
90f7c50
Test for DNF computation.
MarkDuckworth Aug 16, 2022
ff52ecc
Fix implementation of isFlatConjunction
MarkDuckworth Aug 16, 2022
dfda9f8
Adding integration tests for validation of composite queries.
MarkDuckworth Aug 17, 2022
9bc3336
IndexDb manager tests for partial and full index.
MarkDuckworth Aug 17, 2022
d66abd4
Test query does not include documents with missing fields
MarkDuckworth Aug 17, 2022
e33263d
Run prettier
MarkDuckworth Aug 17, 2022
01c3487
Add missing awaits
MarkDuckworth Aug 17, 2022
7d56b57
Fixing argument validation for and . Updating tests for asserted err…
MarkDuckworth Aug 17, 2022
d01ff74
Prettier
MarkDuckworth Aug 18, 2022
186fd92
Removing duplicate test cases.
MarkDuckworth Aug 18, 2022
409b19c
Update proto with OR operator.
MarkDuckworth Aug 22, 2022
131f4be
Update protos with OR operator.
MarkDuckworth Aug 23, 2022
a514358
Testing query with indexes
MarkDuckworth Aug 23, 2022
0ab215b
Add compile.sh to compile proto updates.
MarkDuckworth Aug 23, 2022
638b0ad
Adding new script to run browser tests against the emulator.
MarkDuckworth Aug 23, 2022
86c9057
Update stringifyFilter to support CompositeFilters
MarkDuckworth Aug 23, 2022
3501135
Lint and formatting
MarkDuckworth Aug 23, 2022
4adf98d
Refactor core/target.ts, extracting classes Bound, OrderBy, and Filte…
MarkDuckworth Aug 24, 2022
60f4276
Formatting
MarkDuckworth Aug 24, 2022
476be61
Making public API changes to ensure that only QueryFilterConstraints …
MarkDuckworth Aug 24, 2022
a0e5d30
Remove QueryNonFilterConstraint from exports.
MarkDuckworth Aug 25, 2022
77afd20
Add overloads for query and deprecate existing query overload that su…
MarkDuckworth Aug 26, 2022
3862740
Merge branch 'markduckworth/or-queries' of github.com:firebase/fireba…
MarkDuckworth Oct 26, 2022
efd98c7
Implementing public API for OR queries that does not need the depreca…
MarkDuckworth Oct 27, 2022
94250da
Implementing 3rd iteration of the public API for OR queries.
MarkDuckworth Oct 28, 2022
ff0eede
Compute IN expansion.
MarkDuckworth Oct 28, 2022
66bf749
Fix edge case a == 1 && a == 6
MarkDuckworth Nov 3, 2022
968d133
Logic utils tests for in expansion.
MarkDuckworth Nov 3, 2022
5f37954
Fixed rogue comment.
MarkDuckworth Nov 8, 2022
ab5cad2
Comment cleanup.
MarkDuckworth Nov 8, 2022
5fa9c76
Comment cleanup.
MarkDuckworth Nov 8, 2022
9c6395b
Test refactoring.
MarkDuckworth Nov 8, 2022
09046e7
Collapsing duplicate tests that covered with and without client side …
MarkDuckworth Nov 9, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions common/api-review/firestore-lite.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,14 @@ export class Query<T = DocumentData> {
withConverter<U>(converter: FirestoreDataConverter<U>): Query<U>;
}

// @public
export function query<T>(query: Query<T>, compositeFilter: QueryCompositeFilterConstraint, ...queryConstraints: QueryNonFilterConstraint[]): Query<T>;

// @public
export function query<T>(query: Query<T>, ...queryConstraints: QueryConstraint[]): Query<T>;

// @public
export class QueryCompositeFilterConstraint extends QueryFilterConstraint {
export class QueryCompositeFilterConstraint {
readonly type: 'or' | 'and';
}

Expand All @@ -244,7 +247,7 @@ export abstract class QueryConstraint {
}

// @public
export type QueryConstraintType = 'where' | 'orderBy' | 'limit' | 'limitToLast' | 'startAt' | 'startAfter' | 'endAt' | 'endBefore' | 'and' | 'or';
export type QueryConstraintType = 'where' | 'orderBy' | 'limit' | 'limitToLast' | 'startAt' | 'startAfter' | 'endAt' | 'endBefore';

// @public
export class QueryDocumentSnapshot<T = DocumentData> extends DocumentSnapshot<T> {
Expand All @@ -261,19 +264,21 @@ export class QueryEndAtConstraint extends QueryConstraint {
export function queryEqual<T>(left: Query<T>, right: Query<T>): boolean;

// @public
export class QueryFieldFilterConstraint extends QueryFilterConstraint {
export class QueryFieldFilterConstraint extends QueryConstraint {
readonly type = "where";
}

// @public
export abstract class QueryFilterConstraint extends QueryConstraint {
}
export type QueryFilterConstraint = QueryFieldFilterConstraint | QueryCompositeFilterConstraint;

// @public
export class QueryLimitConstraint extends QueryConstraint {
readonly type: 'limit' | 'limitToLast';
}

// @public
export type QueryNonFilterConstraint = QueryOrderByConstraint | QueryLimitConstraint | QueryStartAtConstraint | QueryEndAtConstraint;

// @public
export class QueryOrderByConstraint extends QueryConstraint {
readonly type = "orderBy";
Expand Down
15 changes: 10 additions & 5 deletions common/api-review/firestore.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,11 +359,14 @@ export class Query<T = DocumentData> {
withConverter<U>(converter: FirestoreDataConverter<U>): Query<U>;
}

// @public
export function query<T>(query: Query<T>, compositeFilter: QueryCompositeFilterConstraint, ...queryConstraints: QueryNonFilterConstraint[]): Query<T>;

// @public
export function query<T>(query: Query<T>, ...queryConstraints: QueryConstraint[]): Query<T>;

// @public
export class QueryCompositeFilterConstraint extends QueryFilterConstraint {
export class QueryCompositeFilterConstraint {
readonly type: 'or' | 'and';
}

Expand All @@ -373,7 +376,7 @@ export abstract class QueryConstraint {
}

// @public
export type QueryConstraintType = 'where' | 'orderBy' | 'limit' | 'limitToLast' | 'startAt' | 'startAfter' | 'endAt' | 'endBefore' | 'and' | 'or';
export type QueryConstraintType = 'where' | 'orderBy' | 'limit' | 'limitToLast' | 'startAt' | 'startAfter' | 'endAt' | 'endBefore';

// @public
export class QueryDocumentSnapshot<T = DocumentData> extends DocumentSnapshot<T> {
Expand All @@ -390,19 +393,21 @@ export class QueryEndAtConstraint extends QueryConstraint {
export function queryEqual<T>(left: Query<T>, right: Query<T>): boolean;

// @public
export class QueryFieldFilterConstraint extends QueryFilterConstraint {
export class QueryFieldFilterConstraint extends QueryConstraint {
readonly type = "where";
}

// @public
export abstract class QueryFilterConstraint extends QueryConstraint {
}
export type QueryFilterConstraint = QueryFieldFilterConstraint | QueryCompositeFilterConstraint;

// @public
export class QueryLimitConstraint extends QueryConstraint {
readonly type: 'limit' | 'limitToLast';
}

// @public
export type QueryNonFilterConstraint = QueryOrderByConstraint | QueryLimitConstraint | QueryStartAtConstraint | QueryEndAtConstraint;

// @public
export class QueryOrderByConstraint extends QueryConstraint {
readonly type = "orderBy";
Expand Down
3 changes: 2 additions & 1 deletion packages/firestore/lite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,11 @@ export {
QueryConstraint,
QueryConstraintType,
QueryCompositeFilterConstraint,
QueryFieldFilterConstraint,
QueryFilterConstraint,
QueryFieldFilterConstraint,
QueryOrderByConstraint,
QueryLimitConstraint,
QueryNonFilterConstraint,
QueryStartAtConstraint,
QueryEndAtConstraint,
OrderByDirection,
Expand Down
1 change: 1 addition & 0 deletions packages/firestore/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"test:all:ci": "run-p test:browser test:lite:browser test:travis",
"test:all": "run-p test:browser test:lite:browser test:travis test:minified",
"test:browser": "karma start --single-run",
"test:browser:emulator:debug": "karma start --browsers=Chrome --local",
"test:browser:emulator": "karma start --single-run --local",
"test:browser:unit": "karma start --single-run --unit",
"test:browser:debug": "karma start --browsers=Chrome --auto-watch",
Expand Down
3 changes: 2 additions & 1 deletion packages/firestore/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,11 @@ export {
QueryConstraint,
QueryConstraintType,
QueryCompositeFilterConstraint,
QueryFieldFilterConstraint,
QueryFilterConstraint,
QueryFieldFilterConstraint,
QueryOrderByConstraint,
QueryLimitConstraint,
QueryNonFilterConstraint,
QueryStartAtConstraint,
QueryEndAtConstraint,
OrderByDirection,
Expand Down
3 changes: 2 additions & 1 deletion packages/firestore/src/api/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ export {
QueryOrderByConstraint,
QueryLimitConstraint,
QueryStartAtConstraint,
QueryEndAtConstraint
QueryEndAtConstraint,
QueryNonFilterConstraint
} from '../lite-api/query';
149 changes: 108 additions & 41 deletions packages/firestore/src/lite-api/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,67 +84,108 @@ export type QueryConstraintType =
| 'startAt'
| 'startAfter'
| 'endAt'
| 'endBefore'
| 'and'
| 'or';
| 'endBefore';

/**
* An `AppliableConstraint` is an abstraction of a constraint that can be applied
* to a Firestore query.
*/
export abstract class AppliableConstraint {
/**
* Takes the provided {@link Query} and returns a copy of the {@link Query} with this
* {@link AppliableConstraint} applied.
*/
abstract _apply<T>(query: Query<T>): Query<T>;
}

/**
* A `QueryConstraint` is used to narrow the set of documents returned by a
* Firestore query. `QueryConstraint`s are created by invoking {@link where},
* {@link orderBy}, {@link (startAt:1)}, {@link (startAfter:1)}, {@link
* (endBefore:1)}, {@link (endAt:1)}, {@link limit}, {@link limitToLast}, {@link or} or {@link and} and
* {@link orderBy}, {@link startAt}, {@link startAfter}, {@link
* endBefore}, {@link endAt}, {@link limit}, {@link limitToLast} and
* can then be passed to {@link query} to create a new query instance that
* also contains this `QueryConstraint`.
*/
export abstract class QueryConstraint {
export abstract class QueryConstraint extends AppliableConstraint {
/** The type of this query constraint */
abstract readonly type: QueryConstraintType;

/**
* Takes the provided {@link Query} and returns a copy of the {@link Query} with this
* {@link QueryConstraint} applied.
* {@link AppliableConstraint} applied.
*/
abstract _apply<T>(query: Query<T>): Query<T>;
}

/**
* Creates a new immutable instance of {@link Query} that is extended to also include
* additional query constraints.
* Creates a new immutable instance of {@link Query} that is extended to also
* include additional query constraints.
*
* @param query - The {@link Query} instance to use as a base for the new
* constraints.
* @param compositeFilter - The {@link QueryCompositeFilterConstraint} to
* apply. Create {@link QueryCompositeFilterConstraint} using {@link and} or
* {@link or}.
* @param queryConstraints - Additional {@link QueryNonFilterConstraint}s to
* apply (e.g. {@link orderBy}, {@link limit}).
* @throws if any of the provided query constraints cannot be combined with the
* existing or new constraints.
*/
export function query<T>(
query: Query<T>,
compositeFilter: QueryCompositeFilterConstraint,
...queryConstraints: QueryNonFilterConstraint[]
): Query<T>;

/**
* Creates a new immutable instance of {@link Query} that is extended to also
* include additional query constraints.
*
* @param query - The {@link Query} instance to use as a base for the new constraints.
* @param query - The {@link Query} instance to use as a base for the new
* constraints.
* @param queryConstraints - The list of {@link QueryConstraint}s to apply.
* @throws if any of the provided query constraints cannot be combined with the
* existing or new constraints.
*/
export function query<T>(
query: Query<T>,
...queryConstraints: QueryConstraint[]
): Query<T>;

export function query<T>(
query: Query<T>,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
filterOrQueryConstraints: any,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
...nonFilters: any
): Query<T> {
let queryConstraints: AppliableConstraint[] = [];
if (filterOrQueryConstraints instanceof AppliableConstraint) {
queryConstraints.push(filterOrQueryConstraints);
} else if (Array.isArray(filterOrQueryConstraints)) {
queryConstraints.concat(filterOrQueryConstraints as AppliableConstraint[]);
}

if (nonFilters !== undefined) {
queryConstraints = queryConstraints.concat(
nonFilters as QueryNonFilterConstraint[]
);
}

for (const constraint of queryConstraints) {
query = constraint._apply(query);
}
return query;
}

/**
* A `QueryFilterConstraint` is used to narrow the set of documents returned by
* A `QueryFieldFilterConstraint` is used to narrow the set of documents returned by
* a Firestore query by filtering on one or more document fields.
* `QueryFilterConstraint`s are created by invoking {@link where}, {@link or} or
* {@link and} and can then be passed to {@link query} to create a new query
* instance that also contains this `QueryFilterConstraint`.
*/
export abstract class QueryFilterConstraint extends QueryConstraint {
abstract _parse<T>(query: Query<T>): Filter;
}

/**
* A `QueryFieldFilterConstraint` is used to narrow the set of documents
* returned by a Firestore query by filtering on one document field.
* `QueryFieldFilterConstraint`s are created by invoking {@link where} and
* can then be passed to {@link query} to create a new query instance that
* also contains this `QueryFieldFilterConstraint`.
* `QueryFieldFilterConstraint`s are created by invoking {@link where} and can then
* be passed to {@link query} to create a new query instance that also contains
* this `QueryFieldFilterConstraint`.
*/
export class QueryFieldFilterConstraint extends QueryFilterConstraint {
export class QueryFieldFilterConstraint extends QueryConstraint {
/** The type of this query constraint */
readonly type = 'where';

Expand Down Expand Up @@ -233,12 +274,12 @@ export function where(
/**
* A `QueryCompositeFilterConstraint` is used to narrow the set of documents
* returned by a Firestore query by performing the logical OR or AND of multiple
* {@link QueryFieldFilterConstraint} or {@link QueryCompositeFilterConstraint}.
* {@link QueryFieldFilterConstraint}s or {@link QueryCompositeFilterConstraint}s.
* `QueryCompositeFilterConstraint`s are created by invoking {@link or} or
* {@link and} and can then be passed to {@link query} to create a new query
* instance that also contains this `QueryCompositeFilterConstraint`.
* instance that also contains the `QueryCompositeFilterConstraint`.
*/
export class QueryCompositeFilterConstraint extends QueryFilterConstraint {
export class QueryCompositeFilterConstraint extends AppliableConstraint {
/**
* @internal
*/
Expand Down Expand Up @@ -287,7 +328,7 @@ export class QueryCompositeFilterConstraint extends QueryFilterConstraint {
);
}

_getQueryConstraints(): readonly QueryConstraint[] {
_getQueryConstraints(): readonly AppliableConstraint[] {
return this._queryConstraints;
}

Expand All @@ -296,13 +337,39 @@ export class QueryCompositeFilterConstraint extends QueryFilterConstraint {
}
}

/**
* `QueryNonFilterConstraint` is a helper union type that represents
* QueryConstraints which are used to narrow or order the set of documents,
* but that do not explicitly filter on a document field.
* `QueryNonFilterConstraint`s are created by invoking {@link orderBy},
* {@link startAt}, {@link startAfter}, {@link endBefore}, {@link endAt},
* {@link limit} or {@link limitToLast} and can then be passed to {@link query}
* to create a new query instance that also contains the `QueryConstraint`.
*/
export type QueryNonFilterConstraint =
| QueryOrderByConstraint
| QueryLimitConstraint
| QueryStartAtConstraint
| QueryEndAtConstraint;

/**
* `QueryFilterConstraint` is a helper union type that represents
* {@link QueryFieldFilterConstraint} and {@link QueryCompositeFilterConstraint}.
* `QueryFilterConstraint`s are created by invoking {@link or} or {@link and}
* and can then be passed to {@link query} to create a new query instance that
* also contains the `QueryConstraint`.
*/
export type QueryFilterConstraint =
| QueryFieldFilterConstraint
| QueryCompositeFilterConstraint;

/**
* Creates a {@link QueryCompositeFilterConstraint} that performs a logical OR
* of all the provided {@link QueryFilterConstraint}.
* of all the provided {@link QueryFilterConstraint}s.
*
* @param queryConstraints - Optional. The {@link queryConstraints} for OR
* operation. These must be created with calls to {@link where}, {@link or}, or
* {@link and}.
* @param queryConstraints - Optional. The {@link QueryFilterConstraint}s
* for OR operation. These must be created with calls to {@link where},
* {@link or}, or {@link and}.
* @returns The created {@link QueryCompositeFilterConstraint}.
*/
export function or(
Expand All @@ -321,11 +388,11 @@ export function or(

/**
* Creates a {@link QueryCompositeFilterConstraint} that performs a logical AND
* of all the provided {@link QueryFilterConstraint}.
* of all the provided {@link QueryFilterConstraint}s.
*
* @param queryConstraints - Optional. The {@link queryConstraints} for AND
* operation. These must be created with calls to {@link where}, {@link or}, or
* {@link and}.
* @param queryConstraints - Optional. The {@link QueryFilterConstraint}s
* for AND operation. These must be created with calls to {@link where},
* {@link or}, or {@link and}.
* @returns The created {@link QueryCompositeFilterConstraint}.
*/
export function and(
Expand Down Expand Up @@ -1139,15 +1206,15 @@ function validateOrderByAndInequalityMatch(

export function validateQueryFilterConstraint(
functionName: string,
queryConstraint: QueryConstraint
queryConstraint: AppliableConstraint
): void {
if (
!(queryConstraint instanceof QueryFilterConstraint) &&
!(queryConstraint instanceof QueryFieldFilterConstraint) &&
!(queryConstraint instanceof QueryCompositeFilterConstraint)
) {
throw new FirestoreError(
Code.INVALID_ARGUMENT,
`Function ${functionName}() requires QueryContraints created with a call to 'where(...)'.`
`Function ${functionName}() requires AppliableContraints created with a call to 'where(...)', 'or(...)', or 'and(...)'.`
);
}
}
Loading