shelving 1.72.0 → 1.73.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{query/Rule.d.ts → constraint/Constraint.d.ts} +2 -2
- package/constraint/Constraint.js +3 -0
- package/constraint/Constraints.d.ts +20 -0
- package/constraint/Constraints.js +35 -0
- package/{query/Filter.d.ts → constraint/FilterConstraint.d.ts} +7 -7
- package/{query/Filter.js → constraint/FilterConstraint.js} +6 -9
- package/{query/Filters.d.ts → constraint/FilterConstraints.d.ts} +3 -3
- package/{query/Filters.js → constraint/FilterConstraints.js} +6 -6
- package/{query/Query.d.ts → constraint/QueryConstraints.d.ts} +9 -18
- package/{query/Query.js → constraint/QueryConstraints.js} +19 -23
- package/{query/Sort.d.ts → constraint/SortConstraint.d.ts} +5 -5
- package/{query/Sort.js → constraint/SortConstraint.js} +3 -5
- package/{query/Sorts.d.ts → constraint/SortConstraints.d.ts} +3 -3
- package/{query/Sorts.js → constraint/SortConstraints.js} +6 -6
- package/constraint/index.d.ts +7 -0
- package/constraint/index.js +7 -0
- package/db/Changes.d.ts +10 -9
- package/db/Changes.js +18 -14
- package/db/Changes.test.d.ts +1 -0
- package/db/Changes.test.js +11 -0
- package/db/Collection.d.ts +39 -0
- package/db/Collection.js +38 -0
- package/db/Database.d.ts +23 -29
- package/db/Database.js +17 -19
- package/db/Item.d.ts +96 -0
- package/db/Item.js +80 -0
- package/db/Query.d.ts +114 -0
- package/db/Query.js +92 -0
- package/db/index.d.ts +3 -2
- package/db/index.js +3 -2
- package/feedback/ErrorFeedback.d.ts +1 -0
- package/feedback/ErrorFeedback.js +14 -1
- package/feedback/Feedback.d.ts +1 -4
- package/feedback/Feedback.js +26 -2
- package/feedback/InvalidFeedback.d.ts +1 -0
- package/feedback/InvalidFeedback.js +14 -1
- package/feedback/SuccessFeedback.d.ts +1 -0
- package/feedback/SuccessFeedback.js +14 -1
- package/feedback/WarningFeedback.d.ts +1 -0
- package/feedback/WarningFeedback.js +14 -1
- package/firestore/client/FirestoreClientProvider.d.ts +17 -16
- package/firestore/client/FirestoreClientProvider.js +29 -37
- package/firestore/lite/FirestoreLiteProvider.d.ts +15 -14
- package/firestore/lite/FirestoreLiteProvider.js +26 -34
- package/firestore/server/FirestoreServerProvider.d.ts +16 -15
- package/firestore/server/FirestoreServerProvider.js +38 -40
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/package.json +2 -2
- package/provider/BatchProvider.d.ts +6 -6
- package/provider/BatchProvider.js +19 -22
- package/provider/CacheProvider.d.ts +14 -13
- package/provider/CacheProvider.js +49 -46
- package/provider/DebugProvider.d.ts +26 -24
- package/provider/DebugProvider.js +104 -82
- package/provider/MemoryProvider.d.ts +37 -36
- package/provider/MemoryProvider.js +74 -80
- package/provider/Provider.d.ts +39 -46
- package/provider/Provider.js +1 -1
- package/provider/ThroughProvider.d.ts +28 -36
- package/provider/ThroughProvider.js +44 -67
- package/provider/ValidationProvider.d.ts +37 -35
- package/provider/ValidationProvider.js +59 -61
- package/react/index.d.ts +1 -1
- package/react/index.js +1 -1
- package/react/useItem.d.ts +32 -0
- package/react/{useDocument.js → useItem.js} +14 -14
- package/react/useQuery.d.ts +15 -10
- package/react/useQuery.js +17 -9
- package/schema/ThroughSchema.d.ts +4 -7
- package/schema/ThroughSchema.js +3 -17
- package/test/basics.d.ts +12 -12
- package/test/index.d.ts +2 -2
- package/test/index.js +1 -1
- package/test/people.d.ts +8 -8
- package/test/util.d.ts +5 -4
- package/test/util.js +1 -1
- package/util/array.d.ts +6 -4
- package/util/array.js +21 -16
- package/util/class.d.ts +11 -0
- package/util/class.js +13 -0
- package/util/data.d.ts +1 -13
- package/util/data.js +0 -7
- package/util/source.d.ts +13 -0
- package/util/source.js +23 -0
- package/db/DatabaseDocument.d.ts +0 -87
- package/db/DatabaseDocument.js +0 -91
- package/db/DatabaseQuery.d.ts +0 -120
- package/db/DatabaseQuery.js +0 -120
- package/query/Rule.js +0 -3
- package/query/Rules.d.ts +0 -20
- package/query/Rules.js +0 -35
- package/query/index.d.ts +0 -5
- package/query/index.js +0 -5
- package/react/useDocument.d.ts +0 -32
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Data } from "../util/data.js";
|
|
2
2
|
import type { Transformable } from "../util/transform.js";
|
|
3
|
-
/** Something that can be used to
|
|
4
|
-
export declare abstract class
|
|
3
|
+
/** Something that can be used to constrain a query. */
|
|
4
|
+
export declare abstract class Constraint<T extends Data> implements Transformable<Iterable<T>, Iterable<T>> {
|
|
5
5
|
abstract transform(items: Iterable<T>): Iterable<T>;
|
|
6
6
|
abstract toString(): string;
|
|
7
7
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Data } from "../util/data.js";
|
|
2
|
+
import { ImmutableArray } from "../util/array.js";
|
|
3
|
+
import { Constraint } from "./Constraint.js";
|
|
4
|
+
/** Type of Rule that is powered by several sub-constraints (e.g. `Filters` and `Sorts` and `Query` itself extend this). */
|
|
5
|
+
export declare abstract class Constraints<T extends Data, C extends Constraint<T>> extends Constraint<T> implements Iterable<C> {
|
|
6
|
+
protected readonly _constraints: ImmutableArray<C>;
|
|
7
|
+
/** Get the first constraint. */
|
|
8
|
+
get first(): C | undefined;
|
|
9
|
+
/** Get the last constraint. */
|
|
10
|
+
get last(): C | undefined;
|
|
11
|
+
/** Get the number of constraints. */
|
|
12
|
+
get size(): number;
|
|
13
|
+
constructor(...constraints: C[]);
|
|
14
|
+
/** Clone this set of constraints but add additional constraints. */
|
|
15
|
+
with(...constraints: C[]): this;
|
|
16
|
+
/** Clone this set of constraints but remove specific constraints. */
|
|
17
|
+
without(...constraints: C[]): this;
|
|
18
|
+
/** Iterate over the constraints. */
|
|
19
|
+
[Symbol.iterator](): Iterator<C, void>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { withItems, withoutItems } from "../util/array.js";
|
|
2
|
+
import { Constraint } from "./Constraint.js";
|
|
3
|
+
/** Type of Rule that is powered by several sub-constraints (e.g. `Filters` and `Sorts` and `Query` itself extend this). */
|
|
4
|
+
export class Constraints extends Constraint {
|
|
5
|
+
constructor(...constraints) {
|
|
6
|
+
super();
|
|
7
|
+
this._constraints = constraints;
|
|
8
|
+
}
|
|
9
|
+
/** Get the first constraint. */
|
|
10
|
+
get first() {
|
|
11
|
+
return this._constraints[0];
|
|
12
|
+
}
|
|
13
|
+
/** Get the last constraint. */
|
|
14
|
+
get last() {
|
|
15
|
+
return this._constraints[this._constraints.length - 1];
|
|
16
|
+
}
|
|
17
|
+
/** Get the number of constraints. */
|
|
18
|
+
get size() {
|
|
19
|
+
return this._constraints.length;
|
|
20
|
+
}
|
|
21
|
+
/** Clone this set of constraints but add additional constraints. */
|
|
22
|
+
with(...constraints) {
|
|
23
|
+
const _constraints = withItems(this._constraints, constraints);
|
|
24
|
+
return _constraints !== this._constraints ? { __proto__: Object.getPrototypeOf(this), ...this, _constraints: _constraints } : this;
|
|
25
|
+
}
|
|
26
|
+
/** Clone this set of constraints but remove specific constraints. */
|
|
27
|
+
without(...constraints) {
|
|
28
|
+
const _constraints = withoutItems(this._constraints, constraints);
|
|
29
|
+
return _constraints !== this._constraints ? { __proto__: Object.getPrototypeOf(this), ...this, _constraints: _constraints } : this;
|
|
30
|
+
}
|
|
31
|
+
/** Iterate over the constraints. */
|
|
32
|
+
[Symbol.iterator]() {
|
|
33
|
+
return this._constraints.values();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -2,7 +2,7 @@ import { ArrayType, ImmutableArray } from "../util/array.js";
|
|
|
2
2
|
import { Data, Key } from "../util/data.js";
|
|
3
3
|
import { Matchable } from "../util/match.js";
|
|
4
4
|
import { NotString } from "../util/string.js";
|
|
5
|
-
import {
|
|
5
|
+
import { Constraint } from "./Constraint.js";
|
|
6
6
|
/** Possible operator references. */
|
|
7
7
|
export declare type FilterOperator = "IS" | "NOT" | "IN" | "OUT" | "CONTAINS" | "LT" | "LTE" | "GT" | "GTE";
|
|
8
8
|
/** Format that allows filters to be specified as a string, e.g. `!name` means `name is not` and `age>` means `age is more than` and `tags[]` means `tags array contains` */
|
|
@@ -16,16 +16,16 @@ export declare type FilterProps<T extends Data> = {
|
|
|
16
16
|
[K in Key<T> as `${K}<` | `${K}<=` | `${K}>` | `${K}>=`]?: T[K];
|
|
17
17
|
};
|
|
18
18
|
/** List of filters in a flexible format. */
|
|
19
|
-
export declare type FilterList<T extends Data> = FilterProps<T> |
|
|
19
|
+
export declare type FilterList<T extends Data> = FilterProps<T> | FilterConstraint<T> | Iterable<FilterList<T> & NotString>;
|
|
20
20
|
/**
|
|
21
|
-
* Filter: filters a list of
|
|
21
|
+
* Filter: filters a list of data.
|
|
22
22
|
*
|
|
23
|
-
* @param key The name of a property that might exist on
|
|
23
|
+
* @param key The name of a property that might exist on data in the collection.
|
|
24
24
|
* @param operator FilterOperator, e.g. `IS` or `CONTAINS`
|
|
25
25
|
* @param value Value the specified property should be matched against.
|
|
26
26
|
*/
|
|
27
|
-
export declare class
|
|
28
|
-
readonly key:
|
|
27
|
+
export declare class FilterConstraint<T extends Data = Data> implements Constraint<T>, Matchable<T, void> {
|
|
28
|
+
readonly key: string;
|
|
29
29
|
readonly operator: FilterOperator;
|
|
30
30
|
readonly value: unknown;
|
|
31
31
|
get filterKey(): string;
|
|
@@ -35,4 +35,4 @@ export declare class Filter<T extends Data> extends Rule<T> implements Matchable
|
|
|
35
35
|
toString(): string;
|
|
36
36
|
}
|
|
37
37
|
/** Get the separate filters generated from a list of filters. */
|
|
38
|
-
export declare function getFilters<T extends Data>(filters: FilterList<T>): Iterable<
|
|
38
|
+
export declare function getFilters<T extends Data>(filters: FilterList<T>): Iterable<FilterConstraint<T>>;
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { isArray } from "../util/array.js";
|
|
2
|
-
import { getProp } from "../util/data.js";
|
|
3
2
|
import { isArrayWith, isEqual, isEqualGreater, isEqualLess, isGreater, isInArray, isLess, notEqual, notInArray } from "../util/match.js";
|
|
4
3
|
import { filterItems } from "../util/filter.js";
|
|
5
4
|
import { isIterable } from "../util/iterate.js";
|
|
6
|
-
import { Rule } from "./Rule.js";
|
|
7
5
|
/** Map `FilterOperator` to its corresponding `Match` function. */
|
|
8
6
|
const MATCHERS = {
|
|
9
7
|
IS: isEqual,
|
|
@@ -17,15 +15,14 @@ const MATCHERS = {
|
|
|
17
15
|
GTE: isEqualGreater,
|
|
18
16
|
};
|
|
19
17
|
/**
|
|
20
|
-
* Filter: filters a list of
|
|
18
|
+
* Filter: filters a list of data.
|
|
21
19
|
*
|
|
22
|
-
* @param key The name of a property that might exist on
|
|
20
|
+
* @param key The name of a property that might exist on data in the collection.
|
|
23
21
|
* @param operator FilterOperator, e.g. `IS` or `CONTAINS`
|
|
24
22
|
* @param value Value the specified property should be matched against.
|
|
25
23
|
*/
|
|
26
|
-
export class
|
|
24
|
+
export class FilterConstraint {
|
|
27
25
|
constructor(filterKey, value) {
|
|
28
|
-
super();
|
|
29
26
|
if (filterKey.startsWith("!")) {
|
|
30
27
|
this.key = filterKey.slice(1);
|
|
31
28
|
this.operator = isArray(value) ? "OUT" : "NOT";
|
|
@@ -74,7 +71,7 @@ export class Filter extends Rule {
|
|
|
74
71
|
return key;
|
|
75
72
|
}
|
|
76
73
|
match(item) {
|
|
77
|
-
return MATCHERS[this.operator](
|
|
74
|
+
return MATCHERS[this.operator](item[this.key], this.value);
|
|
78
75
|
}
|
|
79
76
|
transform(items) {
|
|
80
77
|
return filterItems(items, this);
|
|
@@ -85,7 +82,7 @@ export class Filter extends Rule {
|
|
|
85
82
|
}
|
|
86
83
|
/** Get the separate filters generated from a list of filters. */
|
|
87
84
|
export function* getFilters(filters) {
|
|
88
|
-
if (filters instanceof
|
|
85
|
+
if (filters instanceof FilterConstraint) {
|
|
89
86
|
yield filters;
|
|
90
87
|
}
|
|
91
88
|
else if (isIterable(filters)) {
|
|
@@ -94,6 +91,6 @@ export function* getFilters(filters) {
|
|
|
94
91
|
}
|
|
95
92
|
else {
|
|
96
93
|
for (const [key, value] of Object.entries(filters))
|
|
97
|
-
yield new
|
|
94
|
+
yield new FilterConstraint(key, value);
|
|
98
95
|
}
|
|
99
96
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Data } from "../util/data.js";
|
|
2
2
|
import type { Matchable } from "../util/match.js";
|
|
3
|
-
import { FilterList, FilterProps,
|
|
4
|
-
import {
|
|
3
|
+
import { FilterList, FilterProps, FilterConstraint } from "./FilterConstraint.js";
|
|
4
|
+
import { Constraints } from "./Constraints.js";
|
|
5
5
|
/**
|
|
6
6
|
* Interface to make sure an object implements all matchers.
|
|
7
7
|
* - Extends `Matchable` so this object itself can be directly be used in `filterItems()` and `filterEntries()`
|
|
@@ -13,7 +13,7 @@ export interface Filterable<T extends Data> extends Matchable<T, void> {
|
|
|
13
13
|
match(item: T): boolean;
|
|
14
14
|
}
|
|
15
15
|
/** A set of filters. */
|
|
16
|
-
export declare class
|
|
16
|
+
export declare class FilterConstraints<T extends Data = Data> extends Constraints<T, FilterConstraint<T>> implements Filterable<T> {
|
|
17
17
|
constructor(...filters: FilterList<T>[]);
|
|
18
18
|
filter(...filters: FilterList<T>[]): this;
|
|
19
19
|
match(item: T): boolean;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { filterItems } from "../util/filter.js";
|
|
2
|
-
import { getFilters } from "./
|
|
3
|
-
import {
|
|
2
|
+
import { getFilters } from "./FilterConstraint.js";
|
|
3
|
+
import { Constraints } from "./Constraints.js";
|
|
4
4
|
/** A set of filters. */
|
|
5
|
-
export class
|
|
5
|
+
export class FilterConstraints extends Constraints {
|
|
6
6
|
constructor(...filters) {
|
|
7
7
|
super(...getFilters(filters));
|
|
8
8
|
}
|
|
@@ -11,17 +11,17 @@ export class Filters extends Rules {
|
|
|
11
11
|
return this.with(...getFilters(filters));
|
|
12
12
|
}
|
|
13
13
|
match(item) {
|
|
14
|
-
for (const rule of this.
|
|
14
|
+
for (const rule of this._constraints)
|
|
15
15
|
if (!rule.match(item))
|
|
16
16
|
return false;
|
|
17
17
|
return true;
|
|
18
18
|
}
|
|
19
19
|
// Implement `Rule`
|
|
20
20
|
transform(items) {
|
|
21
|
-
return this.
|
|
21
|
+
return this._constraints.length ? filterItems(items, this) : items;
|
|
22
22
|
}
|
|
23
23
|
// Stringify as object syntax.
|
|
24
24
|
toString() {
|
|
25
|
-
return `{${this.
|
|
25
|
+
return `{${this._constraints.map(String).join(",")}`;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
import { Data } from "../util/data.js";
|
|
2
|
-
import { Filterable,
|
|
3
|
-
import { Sortable,
|
|
4
|
-
import {
|
|
5
|
-
import { FilterList } from "./
|
|
6
|
-
import { SortKeys, SortList } from "./
|
|
7
|
-
/** Set of props for a query defined as an object. */
|
|
8
|
-
export declare type QueryProps<T extends Data> = {
|
|
9
|
-
readonly filter?: FilterList<T>;
|
|
10
|
-
readonly sort?: SortList<T>;
|
|
11
|
-
readonly limit?: number | null;
|
|
12
|
-
};
|
|
2
|
+
import { Filterable, FilterConstraints } from "./FilterConstraints.js";
|
|
3
|
+
import { Sortable, SortConstraints } from "./SortConstraints.js";
|
|
4
|
+
import { Constraint } from "./Constraint.js";
|
|
5
|
+
import { FilterList } from "./FilterConstraint.js";
|
|
6
|
+
import { SortKeys, SortList } from "./SortConstraint.js";
|
|
13
7
|
/** Interface that combines Filterable, Sortable, Sliceable. */
|
|
14
8
|
export interface Queryable<T extends Data> extends Filterable<T>, Sortable<T> {
|
|
15
9
|
/**
|
|
@@ -31,15 +25,13 @@ export interface Queryable<T extends Data> extends Filterable<T>, Sortable<T> {
|
|
|
31
25
|
readonly limit: number | null;
|
|
32
26
|
/** Return a new instance of this class with a limit set. */
|
|
33
27
|
max(max: number | null): this;
|
|
34
|
-
/** Return a new instance of this class with new filters, sorts, limits set. */
|
|
35
|
-
query(query: QueryProps<T>): this;
|
|
36
28
|
}
|
|
37
29
|
/** Allows filtering, sorting, and limiting on a set of results. */
|
|
38
|
-
export declare class
|
|
39
|
-
readonly filters:
|
|
40
|
-
readonly sorts:
|
|
30
|
+
export declare class QueryConstraints<T extends Data = Data> extends Constraint<T> implements Queryable<T> {
|
|
31
|
+
readonly filters: FilterConstraints<T>;
|
|
32
|
+
readonly sorts: SortConstraints<T>;
|
|
41
33
|
readonly limit: number | null;
|
|
42
|
-
constructor(
|
|
34
|
+
constructor(filters?: FilterList<T>, sorts?: SortList<T>, limit?: number | null);
|
|
43
35
|
filter(...filters: FilterList<T>[]): this;
|
|
44
36
|
get unfilter(): this;
|
|
45
37
|
match(item: T): boolean;
|
|
@@ -49,7 +41,6 @@ export declare class Query<T extends Data> extends Rule<T> implements Queryable<
|
|
|
49
41
|
after(item: T): this;
|
|
50
42
|
before(item: T): this;
|
|
51
43
|
max(limit: number | null): this;
|
|
52
|
-
query({ sort, limit, filter }: QueryProps<T>): this;
|
|
53
44
|
transform(items: Iterable<T>): Iterable<T>;
|
|
54
45
|
toString(): string;
|
|
55
46
|
}
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import { getProp } from "../util/data.js";
|
|
2
2
|
import { assert } from "../util/assert.js";
|
|
3
3
|
import { limitItems } from "../util/iterate.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
4
|
+
import { FilterConstraints } from "./FilterConstraints.js";
|
|
5
|
+
import { SortConstraints } from "./SortConstraints.js";
|
|
6
|
+
import { Constraint } from "./Constraint.js";
|
|
7
|
+
import { FilterConstraint } from "./FilterConstraint.js";
|
|
8
8
|
// Instances to save resources for the default case (empty query).
|
|
9
|
-
const EMPTY_FILTERS = new
|
|
10
|
-
const EMPTY_SORTS = new
|
|
11
|
-
const EMPTY_PROPS = { filter: EMPTY_FILTERS, sort: EMPTY_SORTS, limit: null }; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
9
|
+
const EMPTY_FILTERS = new FilterConstraints(); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
10
|
+
const EMPTY_SORTS = new SortConstraints(); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
12
11
|
/** Allows filtering, sorting, and limiting on a set of results. */
|
|
13
|
-
export class
|
|
14
|
-
constructor(
|
|
12
|
+
export class QueryConstraints extends Constraint {
|
|
13
|
+
constructor(filters = EMPTY_FILTERS, sorts = EMPTY_SORTS, limit = null) {
|
|
15
14
|
super();
|
|
16
|
-
this.filters =
|
|
17
|
-
this.sorts =
|
|
15
|
+
this.filters = filters instanceof FilterConstraints ? filters : new FilterConstraints(filters);
|
|
16
|
+
this.sorts = sorts instanceof SortConstraints ? sorts : new SortConstraints(sorts);
|
|
18
17
|
this.limit = limit;
|
|
19
18
|
}
|
|
20
19
|
// Implement `Filterable`
|
|
@@ -26,6 +25,8 @@ export class Query extends Rule {
|
|
|
26
25
|
};
|
|
27
26
|
}
|
|
28
27
|
get unfilter() {
|
|
28
|
+
if (!this.filters.size)
|
|
29
|
+
return this;
|
|
29
30
|
return {
|
|
30
31
|
__proto__: Object.getPrototypeOf(this),
|
|
31
32
|
...this,
|
|
@@ -44,6 +45,8 @@ export class Query extends Rule {
|
|
|
44
45
|
};
|
|
45
46
|
}
|
|
46
47
|
get unsort() {
|
|
48
|
+
if (!this.sorts.size)
|
|
49
|
+
return this;
|
|
47
50
|
return {
|
|
48
51
|
__proto__: Object.getPrototypeOf(this),
|
|
49
52
|
...this,
|
|
@@ -69,21 +72,14 @@ export class Query extends Rule {
|
|
|
69
72
|
};
|
|
70
73
|
}
|
|
71
74
|
max(limit) {
|
|
75
|
+
if (this.limit === limit)
|
|
76
|
+
return this;
|
|
72
77
|
return {
|
|
73
78
|
__proto__: Object.getPrototypeOf(this),
|
|
74
79
|
...this,
|
|
75
80
|
limit,
|
|
76
81
|
};
|
|
77
82
|
}
|
|
78
|
-
query({ sort, limit, filter }) {
|
|
79
|
-
return {
|
|
80
|
-
__proto__: Object.getPrototypeOf(this),
|
|
81
|
-
...this,
|
|
82
|
-
filters: filter ? this.filters.filter(filter) : this.filters,
|
|
83
|
-
sorts: sort ? this.sorts.sort(sort) : this.sorts,
|
|
84
|
-
limit: limit !== undefined ? limit : this.limit,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
83
|
// Implement `Rule`
|
|
88
84
|
transform(items) {
|
|
89
85
|
const sorted = this.sorts.transform(this.filters.transform(items));
|
|
@@ -91,7 +87,7 @@ export class Query extends Rule {
|
|
|
91
87
|
}
|
|
92
88
|
// Implement toString()
|
|
93
89
|
toString() {
|
|
94
|
-
return `{"
|
|
90
|
+
return `{"filters":${this.filters.toString()}},"sorts":${this.sorts.toString()},"limit":${this.limit}}`;
|
|
95
91
|
}
|
|
96
92
|
}
|
|
97
93
|
function* _getAfterFilters(sorts, item) {
|
|
@@ -100,7 +96,7 @@ function* _getAfterFilters(sorts, item) {
|
|
|
100
96
|
for (const sort of sorts) {
|
|
101
97
|
const { key, direction } = sort;
|
|
102
98
|
const filterKey = direction === "ASC" ? (sort === lastSort ? `${key}>` : `${key}>=`) : sort === lastSort ? `${key}<` : `${key}<=`;
|
|
103
|
-
yield new
|
|
99
|
+
yield new FilterConstraint(filterKey, getProp(item, key));
|
|
104
100
|
}
|
|
105
101
|
}
|
|
106
102
|
function* _getBeforeFilters(sorts, item) {
|
|
@@ -109,6 +105,6 @@ function* _getBeforeFilters(sorts, item) {
|
|
|
109
105
|
for (const sort of sorts) {
|
|
110
106
|
const { key, direction } = sort;
|
|
111
107
|
const filterKey = direction === "ASC" ? (sort === lastSort ? `${key}<` : `${key}<=`) : sort === lastSort ? `${key}>` : `${key}>=`;
|
|
112
|
-
yield new
|
|
108
|
+
yield new FilterConstraint(filterKey, getProp(item, key));
|
|
113
109
|
}
|
|
114
110
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ImmutableArray } from "../util/array.js";
|
|
2
2
|
import { Data, Key } from "../util/data.js";
|
|
3
3
|
import { Rankable } from "../util/sort.js";
|
|
4
|
-
import {
|
|
4
|
+
import { Constraint } from "./Constraint.js";
|
|
5
5
|
/** Format that allows sorts to be set as a plain string, e.g. `name` sorts by name in ascending order and `!date` sorts by date in descending order. */
|
|
6
6
|
export declare type SortKey<T extends Data> = Key<T> | `${Key<T>}` | `!${Key<T>}`;
|
|
7
7
|
/** One or more sort keys. */
|
|
@@ -9,10 +9,10 @@ export declare type SortKeys<T extends Data> = SortKey<T> | ImmutableArray<SortK
|
|
|
9
9
|
/** Possible operator references. */
|
|
10
10
|
export declare type SortDirection = "ASC" | "DESC";
|
|
11
11
|
/** List of sorts in a flexible format. */
|
|
12
|
-
export declare type SortList<T extends Data> = SortKeys<T> |
|
|
12
|
+
export declare type SortList<T extends Data> = SortKeys<T> | SortConstraint<T> | Iterable<SortList<T>>;
|
|
13
13
|
/** Sort a list of values. */
|
|
14
|
-
export declare class
|
|
15
|
-
readonly key:
|
|
14
|
+
export declare class SortConstraint<T extends Data = Data> implements Constraint<T>, Rankable<T> {
|
|
15
|
+
readonly key: string;
|
|
16
16
|
readonly direction: SortDirection;
|
|
17
17
|
get sortKey(): string;
|
|
18
18
|
constructor(sortKey: SortKey<T>);
|
|
@@ -21,4 +21,4 @@ export declare class Sort<T extends Data> extends Rule<T> implements Rankable<T>
|
|
|
21
21
|
toString(): string;
|
|
22
22
|
}
|
|
23
23
|
/** Get the separate sorts generated from a list of sorts. */
|
|
24
|
-
export declare function getSorts<T extends Data>(sorts: SortList<T>): Iterable<
|
|
24
|
+
export declare function getSorts<T extends Data>(sorts: SortList<T>): Iterable<SortConstraint<T>>;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { getProp } from "../util/data.js";
|
|
2
2
|
import { rank, rankAsc, rankDesc, sortItems } from "../util/sort.js";
|
|
3
|
-
import { Rule } from "./Rule.js";
|
|
4
3
|
/** Sort a list of values. */
|
|
5
|
-
export class
|
|
4
|
+
export class SortConstraint {
|
|
6
5
|
constructor(sortKey) {
|
|
7
|
-
super();
|
|
8
6
|
if (sortKey.startsWith("!")) {
|
|
9
7
|
this.key = sortKey.slice(1);
|
|
10
8
|
this.direction = "DESC";
|
|
@@ -30,9 +28,9 @@ export class Sort extends Rule {
|
|
|
30
28
|
/** Get the separate sorts generated from a list of sorts. */
|
|
31
29
|
export function* getSorts(sorts) {
|
|
32
30
|
if (typeof sorts === "string") {
|
|
33
|
-
yield new
|
|
31
|
+
yield new SortConstraint(sorts);
|
|
34
32
|
}
|
|
35
|
-
else if (sorts instanceof
|
|
33
|
+
else if (sorts instanceof SortConstraint) {
|
|
36
34
|
yield sorts;
|
|
37
35
|
}
|
|
38
36
|
else {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Data } from "../util/data.js";
|
|
2
2
|
import { Rankable } from "../util/sort.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { Constraints } from "./Constraints.js";
|
|
4
|
+
import { SortConstraint, SortKeys, SortList } from "./SortConstraint.js";
|
|
5
5
|
/**
|
|
6
6
|
* Interface to make sure an object implements all directions.
|
|
7
7
|
* - Extends `Rankable` so this object itself can be directly be used with `filterItems()` and `filterEntries()`
|
|
@@ -11,7 +11,7 @@ export interface Sortable<T extends Data> extends Rankable<T> {
|
|
|
11
11
|
sort(...keys: SortKeys<T>[]): this;
|
|
12
12
|
}
|
|
13
13
|
/** A set of sorts. */
|
|
14
|
-
export declare class
|
|
14
|
+
export declare class SortConstraints<T extends Data = Data> extends Constraints<T, SortConstraint<T>> implements Sortable<T> {
|
|
15
15
|
constructor(...sorts: SortList<T>[]);
|
|
16
16
|
sort(...sorts: SortList<T>[]): this;
|
|
17
17
|
rank(left: T, right: T): number;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { sortItems } from "../util/sort.js";
|
|
2
|
-
import {
|
|
3
|
-
import { getSorts } from "./
|
|
2
|
+
import { Constraints } from "./Constraints.js";
|
|
3
|
+
import { getSorts } from "./SortConstraint.js";
|
|
4
4
|
/** A set of sorts. */
|
|
5
|
-
export class
|
|
5
|
+
export class SortConstraints extends Constraints {
|
|
6
6
|
constructor(...sorts) {
|
|
7
7
|
super(...getSorts(sorts));
|
|
8
8
|
}
|
|
@@ -11,7 +11,7 @@ export class Sorts extends Rules {
|
|
|
11
11
|
return this.with(...getSorts(sorts));
|
|
12
12
|
}
|
|
13
13
|
rank(left, right) {
|
|
14
|
-
for (const rule of this.
|
|
14
|
+
for (const rule of this._constraints) {
|
|
15
15
|
const l = rule.rank(left, right);
|
|
16
16
|
if (l !== 0)
|
|
17
17
|
return l;
|
|
@@ -20,10 +20,10 @@ export class Sorts extends Rules {
|
|
|
20
20
|
}
|
|
21
21
|
// Implement `Rule`
|
|
22
22
|
transform(items) {
|
|
23
|
-
return this.
|
|
23
|
+
return this._constraints.length ? sortItems(items, this) : items;
|
|
24
24
|
}
|
|
25
25
|
// Stringify as array syntax.
|
|
26
26
|
toString() {
|
|
27
|
-
return `[${this.
|
|
27
|
+
return `[${this._constraints.map(String).join(",")}]`;
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from "./Constraint.js";
|
|
2
|
+
export * from "./Constraints.js";
|
|
3
|
+
export * from "./FilterConstraint.js";
|
|
4
|
+
export * from "./FilterConstraints.js";
|
|
5
|
+
export * from "./SortConstraint.js";
|
|
6
|
+
export * from "./SortConstraints.js";
|
|
7
|
+
export * from "./QueryConstraints.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from "./Constraint.js";
|
|
2
|
+
export * from "./Constraints.js";
|
|
3
|
+
export * from "./FilterConstraint.js";
|
|
4
|
+
export * from "./FilterConstraints.js";
|
|
5
|
+
export * from "./SortConstraint.js";
|
|
6
|
+
export * from "./SortConstraints.js";
|
|
7
|
+
export * from "./QueryConstraints.js";
|
package/db/Changes.d.ts
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import type { Datas, Key } from "../util/data.js";
|
|
2
2
|
import { DataUpdate } from "../update/DataUpdate.js";
|
|
3
3
|
import type { Provider, AsyncProvider } from "../provider/Provider.js";
|
|
4
|
-
import type {
|
|
4
|
+
import type { Database, AsyncDatabase } from "./Database.js";
|
|
5
5
|
/**
|
|
6
6
|
* Change set of operations to run against a database in `{ "collection/id": data | DataUpdate | null }` format.
|
|
7
|
-
* - If data is an object, sets the
|
|
8
|
-
* - If data is a `DataUpdate` instance, updates the
|
|
9
|
-
* - If data is null, deletes the
|
|
7
|
+
* - If data is an object, sets the item.
|
|
8
|
+
* - If data is a `DataUpdate` instance, updates the item.
|
|
9
|
+
* - If data is null, deletes the item.
|
|
10
|
+
* - If data is undefined, skip the item.
|
|
10
11
|
*/
|
|
11
12
|
export declare type Changes<DB extends Datas> = {
|
|
12
|
-
[K in Key<DB> as `${K}/${string}`]: DB[K] | DataUpdate<DB[K]> | null;
|
|
13
|
+
[K in Key<DB> as `${K}/${string}`]: DB[K] | DataUpdate<DB[K]> | null | undefined;
|
|
13
14
|
};
|
|
14
15
|
/** Apply a set of changes to a synchronous database. */
|
|
15
|
-
export declare function
|
|
16
|
+
export declare function changeDatabase<T extends Datas>({ provider }: Database<T>, changes: Changes<T>): Changes<T>;
|
|
16
17
|
/** Apply a set of changes to an asynchronous database. */
|
|
17
|
-
export declare function
|
|
18
|
+
export declare function changeAsyncDatabase<T extends Datas>({ provider }: AsyncDatabase<T>, changes: Changes<T>): Promise<Changes<T>>;
|
|
18
19
|
/** Apply a set of changes to a synchronous provider. */
|
|
19
|
-
export declare function
|
|
20
|
+
export declare function changeProvider<T extends Datas>(provider: Provider<T>, changes: Changes<T>): Changes<T>;
|
|
20
21
|
/** Apply a set of changes to an asynchronous provider. */
|
|
21
|
-
export declare function
|
|
22
|
+
export declare function changeAsyncProvider<T extends Datas>(provider: AsyncProvider<T>, changes: Changes<T>): Promise<Changes<T>>;
|
package/db/Changes.js
CHANGED
|
@@ -1,36 +1,40 @@
|
|
|
1
1
|
import { splitString } from "../util/string.js";
|
|
2
2
|
import { DataUpdate } from "../update/DataUpdate.js";
|
|
3
3
|
/** Apply a set of changes to a synchronous database. */
|
|
4
|
-
export function
|
|
5
|
-
return
|
|
4
|
+
export function changeDatabase({ provider }, changes) {
|
|
5
|
+
return changeProvider(provider, changes);
|
|
6
6
|
}
|
|
7
7
|
/** Apply a set of changes to an asynchronous database. */
|
|
8
|
-
export function
|
|
9
|
-
return
|
|
8
|
+
export function changeAsyncDatabase({ provider }, changes) {
|
|
9
|
+
return changeAsyncProvider(provider, changes);
|
|
10
10
|
}
|
|
11
11
|
/** Apply a set of changes to a synchronous provider. */
|
|
12
|
-
export function
|
|
12
|
+
export function changeProvider(provider, changes) {
|
|
13
13
|
for (const [key, change] of Object.entries(changes)) {
|
|
14
14
|
const [collection, id] = splitString(key, "/", 2);
|
|
15
|
-
if (
|
|
16
|
-
|
|
15
|
+
if (change === undefined)
|
|
16
|
+
continue;
|
|
17
|
+
else if (change === null)
|
|
18
|
+
provider.deleteItem(collection, id);
|
|
17
19
|
else if (change instanceof DataUpdate)
|
|
18
|
-
provider.
|
|
20
|
+
provider.updateItem(collection, id, change);
|
|
19
21
|
else
|
|
20
|
-
provider.
|
|
22
|
+
provider.setItem(collection, id, change);
|
|
21
23
|
}
|
|
22
24
|
return changes;
|
|
23
25
|
}
|
|
24
26
|
/** Apply a set of changes to an asynchronous provider. */
|
|
25
|
-
export async function
|
|
27
|
+
export async function changeAsyncProvider(provider, changes) {
|
|
26
28
|
for (const [key, change] of Object.entries(changes)) {
|
|
27
29
|
const [collection, id] = splitString(key, "/", 2);
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
+
if (change === undefined)
|
|
31
|
+
continue;
|
|
32
|
+
else if (change === null)
|
|
33
|
+
await provider.deleteItem(collection, id);
|
|
30
34
|
else if (change instanceof DataUpdate)
|
|
31
|
-
await provider.
|
|
35
|
+
await provider.updateItem(collection, id, change);
|
|
32
36
|
else
|
|
33
|
-
await provider.
|
|
37
|
+
await provider.setItem(collection, id, change);
|
|
34
38
|
}
|
|
35
39
|
return changes;
|
|
36
40
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DataUpdate } from "../index.js";
|
|
2
|
+
test("Typescript", () => {
|
|
3
|
+
const operations = {
|
|
4
|
+
"collection1/a1": { a: 1, one: false },
|
|
5
|
+
"collection1/b2": null,
|
|
6
|
+
"collection1/b3": new DataUpdate({ one: true }),
|
|
7
|
+
"collection2/a1": { b: 1, one: false },
|
|
8
|
+
"collection2/b2": null,
|
|
9
|
+
"collection2/c3": new DataUpdate({ one: true }),
|
|
10
|
+
};
|
|
11
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Datas, Key } from "../util/data.js";
|
|
2
|
+
import type { FilterList } from "../constraint/FilterConstraint.js";
|
|
3
|
+
import type { SortList } from "../constraint/SortConstraint.js";
|
|
4
|
+
import type { ItemData, AsyncItem, Item } from "./Item.js";
|
|
5
|
+
import type { AsyncDatabase, Database } from "./Database.js";
|
|
6
|
+
import type { AsyncQuery, Query } from "./Query.js";
|
|
7
|
+
/** Reference to a collection in a synchronous or asynchronous provider. */
|
|
8
|
+
interface CollectionInterface<T extends Datas = Datas, K extends Key<T> = Key<T>> {
|
|
9
|
+
readonly db: Database<T> | AsyncDatabase<T>;
|
|
10
|
+
readonly collection: K;
|
|
11
|
+
/** Create a query on this item's collection. */
|
|
12
|
+
query(filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): Query<T, K> | AsyncQuery<T, K>;
|
|
13
|
+
/** Create a query on this item's collection. */
|
|
14
|
+
item(id: string): Item<T, K> | AsyncItem<T, K>;
|
|
15
|
+
/** Add an item to this collection. */
|
|
16
|
+
add(data: T[K]): string | Promise<string>;
|
|
17
|
+
toString(): K;
|
|
18
|
+
}
|
|
19
|
+
/** Reference to a collection in a synchronous provider. */
|
|
20
|
+
export declare class Collection<T extends Datas = Datas, K extends Key<T> = Key<T>> implements CollectionInterface<T, K> {
|
|
21
|
+
readonly db: Database<T>;
|
|
22
|
+
readonly collection: K;
|
|
23
|
+
constructor(db: Database<T>, collection: K);
|
|
24
|
+
query(filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): Query<T, K>;
|
|
25
|
+
item(id: string): Item<T, K>;
|
|
26
|
+
add(data: T[K]): string;
|
|
27
|
+
toString(): K;
|
|
28
|
+
}
|
|
29
|
+
/** Reference to a collection in an asynchronous provider. */
|
|
30
|
+
export declare class AsyncCollection<T extends Datas = Datas, K extends Key<T> = Key<T>> implements CollectionInterface<T, K> {
|
|
31
|
+
readonly db: AsyncDatabase<T>;
|
|
32
|
+
readonly collection: K;
|
|
33
|
+
constructor(db: AsyncDatabase<T>, collection: K);
|
|
34
|
+
query(filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): AsyncQuery<T, K>;
|
|
35
|
+
item(id: string): AsyncItem<T, K>;
|
|
36
|
+
add(data: T[K]): Promise<string>;
|
|
37
|
+
toString(): K;
|
|
38
|
+
}
|
|
39
|
+
export {};
|