shelving 1.86.8 → 1.88.0
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/constraint/FilterConstraint.d.ts +8 -7
- package/constraint/FilterConstraint.js +34 -27
- package/constraint/QueryConstraints.js +6 -6
- package/constraint/SortConstraint.d.ts +4 -3
- package/constraint/SortConstraint.js +8 -3
- package/db/Change.d.ts +1 -3
- package/db/Change.js +3 -6
- package/db/Item.d.ts +3 -0
- package/db/Item.js +8 -3
- package/{react/useItem.d.ts → db/ItemState.d.ts} +3 -9
- package/{react/useItem.js → db/ItemState.js} +2 -11
- package/{react/useQuery.d.ts → db/QueryState.d.ts} +0 -6
- package/{react/useQuery.js → db/QueryState.js} +0 -8
- package/db/index.d.ts +2 -0
- package/db/index.js +2 -0
- package/feedback/Feedback.d.ts +1 -1
- package/feedback/Feedback.js +1 -1
- package/firestore/client/FirestoreClientProvider.d.ts +1 -1
- package/firestore/client/FirestoreClientProvider.js +2 -2
- package/firestore/lite/FirestoreLiteProvider.js +1 -3
- package/firestore/server/FirestoreServerProvider.js +1 -1
- package/package.json +1 -1
- package/react/index.d.ts +1 -2
- package/react/index.js +1 -2
- package/react/useData.d.ts +15 -0
- package/react/useData.js +17 -0
- package/react/useState.d.ts +8 -6
- package/react/useState.js +15 -7
- package/schema/NumberSchema.d.ts +14 -2
- package/schema/NumberSchema.js +15 -3
- package/schema/Schema.d.ts +1 -1
- package/schema/Schema.js +1 -1
- package/state/State.d.ts +1 -1
- package/state/State.js +1 -1
- package/test/basics.d.ts +9 -0
- package/test/basics.js +14 -9
- package/test/index.d.ts +8 -0
- package/util/array.d.ts +5 -6
- package/util/array.js +5 -6
- package/util/assert.d.ts +2 -2
- package/util/assert.js +6 -6
- package/util/async.d.ts +2 -2
- package/util/async.js +2 -2
- package/util/boolean.d.ts +10 -10
- package/util/boolean.js +20 -20
- package/util/class.d.ts +3 -3
- package/util/class.js +5 -5
- package/util/clone.d.ts +1 -1
- package/util/clone.js +1 -1
- package/util/color.d.ts +2 -2
- package/util/color.js +4 -4
- package/util/data.d.ts +16 -3
- package/util/data.js +1 -1
- package/util/date.d.ts +2 -2
- package/util/date.js +4 -4
- package/util/entry.d.ts +4 -0
- package/util/equal.d.ts +53 -16
- package/util/equal.js +81 -44
- package/util/function.d.ts +2 -2
- package/util/function.js +4 -4
- package/util/hydrate.js +1 -1
- package/util/iterate.d.ts +10 -7
- package/util/iterate.js +12 -4
- package/util/jsx.d.ts +2 -2
- package/util/jsx.js +2 -2
- package/util/map.d.ts +2 -2
- package/util/map.js +4 -4
- package/util/match.d.ts +0 -9
- package/util/match.js +0 -12
- package/util/null.d.ts +8 -8
- package/util/null.js +16 -16
- package/util/number.d.ts +6 -6
- package/util/number.js +16 -16
- package/util/object.d.ts +2 -1
- package/util/object.js +4 -2
- package/util/regexp.d.ts +2 -2
- package/util/regexp.js +4 -4
- package/util/set.d.ts +2 -2
- package/util/set.js +4 -4
- package/util/string.d.ts +2 -2
- package/util/string.js +1 -1
- package/util/time.d.ts +1 -1
- package/util/time.js +1 -1
- package/util/transform.d.ts +28 -23
- package/util/transform.js +17 -19
- package/util/undefined.d.ts +3 -3
- package/util/undefined.js +5 -5
- package/util/url.d.ts +2 -2
- package/util/url.js +4 -4
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Data, DataKey, FlatDataKey } from "../util/data.js";
|
|
2
2
|
import type { Nullish } from "../util/null.js";
|
|
3
3
|
import { ImmutableArray } from "../util/array.js";
|
|
4
|
-
import { Matchable } from "../util/match.js";
|
|
4
|
+
import type { Matchable } from "../util/match.js";
|
|
5
5
|
import type { Constraint } from "./Constraint.js";
|
|
6
6
|
/** Possible operator references. */
|
|
7
7
|
export 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` */
|
|
9
|
-
export type FilterKey<T extends Data> = DataKey<
|
|
9
|
+
export type FilterKey<T extends Data> = DataKey<FilterProps<T>>;
|
|
10
10
|
/** Format that allows multiple filters to be specified as a plain object. */
|
|
11
11
|
export type FilterProps<T extends Data> = {
|
|
12
|
-
[K in
|
|
12
|
+
[K in FlatDataKey<T> as `${K}` | `!${K}`]?: T[K] | ImmutableArray<T[K]>;
|
|
13
13
|
} & {
|
|
14
|
-
[K in
|
|
14
|
+
[K in FlatDataKey<T> as `${K}<` | `${K}<=` | `${K}>` | `${K}>=`]?: T[K];
|
|
15
15
|
} & {
|
|
16
|
-
[K in
|
|
16
|
+
[K in FlatDataKey<T> as `${K}[]`]?: Required<T>[K] extends ImmutableArray<infer X> ? X : never;
|
|
17
17
|
};
|
|
18
18
|
/** List of filters in a flexible format. */
|
|
19
19
|
export type FilterList<T extends Data> = FilterProps<T> | FilterConstraint<T> | Iterable<Nullish<FilterProps<T> | FilterConstraint<T>>>;
|
|
@@ -25,9 +25,10 @@ export type FilterList<T extends Data> = FilterProps<T> | FilterConstraint<T> |
|
|
|
25
25
|
* @param value Value the specified property should be matched against.
|
|
26
26
|
*/
|
|
27
27
|
export declare class FilterConstraint<T extends Data = Data> implements Constraint<T>, Matchable<[T]> {
|
|
28
|
-
readonly
|
|
28
|
+
readonly keys: readonly [string, ...string[]];
|
|
29
29
|
readonly operator: FilterOperator;
|
|
30
30
|
readonly value: unknown;
|
|
31
|
+
get key(): string;
|
|
31
32
|
get filterKey(): string;
|
|
32
33
|
constructor(filterKey: FilterKey<T>, value: unknown);
|
|
33
34
|
match(item: T): boolean;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { getDataProps } from "../util/data.js";
|
|
1
2
|
import { isArray } from "../util/array.js";
|
|
2
|
-
import { isArrayWith,
|
|
3
|
+
import { isArrayWith, isEqualGreater, isEqualLess, isGreater, isInArray, isLess, notInArray, isEqual, notEqual } from "../util/equal.js";
|
|
3
4
|
import { filterItems, isIterable } from "../util/iterate.js";
|
|
5
|
+
import { getProp } from "../util/object.js";
|
|
6
|
+
import { splitString } from "../util/string.js";
|
|
4
7
|
/** Map `FilterOperator` to its corresponding `Match` function. */
|
|
5
8
|
const MATCHERS = {
|
|
6
9
|
IS: isEqual,
|
|
@@ -21,56 +24,60 @@ const MATCHERS = {
|
|
|
21
24
|
* @param value Value the specified property should be matched against.
|
|
22
25
|
*/
|
|
23
26
|
export class FilterConstraint {
|
|
27
|
+
get key() {
|
|
28
|
+
return this.keys.join(".");
|
|
29
|
+
}
|
|
24
30
|
get filterKey() {
|
|
25
31
|
const { operator, key } = this;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
return operator === "IS" || operator === "IN"
|
|
33
|
+
? key
|
|
34
|
+
: operator === "NOT" || operator === "OUT"
|
|
35
|
+
? `!${key}`
|
|
36
|
+
: operator === "CONTAINS"
|
|
37
|
+
? `${key}[]`
|
|
38
|
+
: operator === "LT"
|
|
39
|
+
? `${key}<`
|
|
40
|
+
: operator === "LTE"
|
|
41
|
+
? `${key}<=`
|
|
42
|
+
: operator === "GT"
|
|
43
|
+
? `${key}>`
|
|
44
|
+
: operator === "GTE"
|
|
45
|
+
? `${key}>=`
|
|
46
|
+
: operator; // Never.
|
|
40
47
|
}
|
|
41
48
|
constructor(filterKey, value) {
|
|
42
49
|
if (filterKey.startsWith("!")) {
|
|
43
|
-
this.
|
|
50
|
+
this.keys = splitString(filterKey.slice(1), ".");
|
|
44
51
|
this.operator = isArray(value) ? "OUT" : "NOT";
|
|
45
52
|
}
|
|
53
|
+
else if (filterKey.endsWith("[]")) {
|
|
54
|
+
this.keys = splitString(filterKey.slice(0, -2), ".");
|
|
55
|
+
this.operator = "CONTAINS";
|
|
56
|
+
}
|
|
46
57
|
else if (filterKey.endsWith(">")) {
|
|
47
|
-
this.
|
|
58
|
+
this.keys = splitString(filterKey.slice(0, -1), ".");
|
|
48
59
|
this.operator = "GT";
|
|
49
60
|
}
|
|
50
61
|
else if (filterKey.endsWith(">=")) {
|
|
51
|
-
this.
|
|
62
|
+
this.keys = splitString(filterKey.slice(0, -2), ".");
|
|
52
63
|
this.operator = "GTE";
|
|
53
64
|
}
|
|
54
65
|
else if (filterKey.endsWith("<")) {
|
|
55
|
-
this.
|
|
66
|
+
this.keys = splitString(filterKey.slice(0, -1), ".");
|
|
56
67
|
this.operator = "LT";
|
|
57
68
|
}
|
|
58
69
|
else if (filterKey.endsWith("<=")) {
|
|
59
|
-
this.
|
|
70
|
+
this.keys = splitString(filterKey.slice(0, -2), ".");
|
|
60
71
|
this.operator = "LTE";
|
|
61
72
|
}
|
|
62
|
-
else if (filterKey.endsWith("[]")) {
|
|
63
|
-
this.key = filterKey.slice(0, -2);
|
|
64
|
-
this.operator = "CONTAINS";
|
|
65
|
-
}
|
|
66
73
|
else {
|
|
67
|
-
this.
|
|
74
|
+
this.keys = splitString(filterKey, ".");
|
|
68
75
|
this.operator = isArray(value) ? "IN" : "IS";
|
|
69
76
|
}
|
|
70
77
|
this.value = value;
|
|
71
78
|
}
|
|
72
79
|
match(item) {
|
|
73
|
-
return MATCHERS[this.operator](item
|
|
80
|
+
return MATCHERS[this.operator](getProp(item, ...this.keys), this.value);
|
|
74
81
|
}
|
|
75
82
|
transform(items) {
|
|
76
83
|
return filterItems(items, this);
|
|
@@ -90,7 +97,7 @@ export function* getFilters(list) {
|
|
|
90
97
|
yield* getFilters(filter);
|
|
91
98
|
}
|
|
92
99
|
else {
|
|
93
|
-
for (const [key, value] of
|
|
100
|
+
for (const [key, value] of getDataProps(list))
|
|
94
101
|
yield new FilterConstraint(key, value);
|
|
95
102
|
}
|
|
96
103
|
}
|
|
@@ -94,17 +94,17 @@ function* _getAfterFilters(sorts, item) {
|
|
|
94
94
|
const lastSort = sorts.last;
|
|
95
95
|
assert(lastSort);
|
|
96
96
|
for (const sort of sorts) {
|
|
97
|
-
const { key, direction } = sort;
|
|
98
|
-
const filterKey = direction === "ASC" ? (sort === lastSort ? `${key}>` : `${key}>=`) : sort === lastSort ? `${key}<` : `${key}
|
|
99
|
-
yield new FilterConstraint(filterKey, getProp(item,
|
|
97
|
+
const { key, keys, direction } = sort;
|
|
98
|
+
const filterKey = (direction === "ASC" ? (sort === lastSort ? `${key}>` : `${key}>=`) : sort === lastSort ? `${key}<` : `${key}<=`);
|
|
99
|
+
yield new FilterConstraint(filterKey, getProp(item, ...keys));
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
function* _getBeforeFilters(sorts, item) {
|
|
103
103
|
const lastSort = sorts.last;
|
|
104
104
|
assert(lastSort);
|
|
105
105
|
for (const sort of sorts) {
|
|
106
|
-
const { key, direction } = sort;
|
|
107
|
-
const filterKey = direction === "ASC" ? (sort === lastSort ? `${key}<` : `${key}<=`) : sort === lastSort ? `${key}>` : `${key}
|
|
108
|
-
yield new FilterConstraint(filterKey, getProp(item,
|
|
106
|
+
const { key, keys, direction } = sort;
|
|
107
|
+
const filterKey = (direction === "ASC" ? (sort === lastSort ? `${key}<` : `${key}<=`) : sort === lastSort ? `${key}>` : `${key}>=`);
|
|
108
|
+
yield new FilterConstraint(filterKey, getProp(item, ...keys));
|
|
109
109
|
}
|
|
110
110
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { ImmutableArray } from "../util/array.js";
|
|
2
|
-
import type { Data,
|
|
2
|
+
import type { Data, FlatDataKey } from "../util/data.js";
|
|
3
3
|
import type { Nullish } from "../util/null.js";
|
|
4
4
|
import { Rankable } from "../util/sort.js";
|
|
5
5
|
import type { Constraint } from "./Constraint.js";
|
|
6
6
|
/** 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. */
|
|
7
|
-
export type SortKey<T extends Data> =
|
|
7
|
+
export type SortKey<T extends Data> = FlatDataKey<T> | `${FlatDataKey<T>}` | `!${FlatDataKey<T>}`;
|
|
8
8
|
/** One or more sort keys. */
|
|
9
9
|
export type SortKeys<T extends Data> = SortKey<T> | ImmutableArray<SortKey<T>>;
|
|
10
10
|
/** Possible operator references. */
|
|
@@ -13,8 +13,9 @@ export type SortDirection = "ASC" | "DESC";
|
|
|
13
13
|
export type SortList<T extends Data> = SortKey<T> | SortConstraint<T> | Iterable<Nullish<SortKey<T> | SortConstraint<T>>>;
|
|
14
14
|
/** Sort a list of values. */
|
|
15
15
|
export declare class SortConstraint<T extends Data = Data> implements Constraint<T>, Rankable<T> {
|
|
16
|
-
readonly
|
|
16
|
+
readonly keys: readonly [string, ...string[]];
|
|
17
17
|
readonly direction: SortDirection;
|
|
18
|
+
get key(): string;
|
|
18
19
|
get sortKey(): string;
|
|
19
20
|
constructor(sortKey: SortKey<T>);
|
|
20
21
|
rank(left: T, right: T): number;
|
|
@@ -1,21 +1,26 @@
|
|
|
1
|
+
import { getProp } from "../util/object.js";
|
|
1
2
|
import { rank, rankAsc, rankDesc, sortItems } from "../util/sort.js";
|
|
3
|
+
import { splitString } from "../util/string.js";
|
|
2
4
|
/** Sort a list of values. */
|
|
3
5
|
export class SortConstraint {
|
|
6
|
+
get key() {
|
|
7
|
+
return this.keys.join(".");
|
|
8
|
+
}
|
|
4
9
|
get sortKey() {
|
|
5
10
|
return `"${this.direction === "DESC" ? "!" : ""}${this.key}"`;
|
|
6
11
|
}
|
|
7
12
|
constructor(sortKey) {
|
|
8
13
|
if (sortKey.startsWith("!")) {
|
|
9
|
-
this.
|
|
14
|
+
this.keys = splitString(sortKey.slice(1), ".");
|
|
10
15
|
this.direction = "DESC";
|
|
11
16
|
}
|
|
12
17
|
else {
|
|
13
|
-
this.
|
|
18
|
+
this.keys = splitString(sortKey, ".");
|
|
14
19
|
this.direction = "ASC";
|
|
15
20
|
}
|
|
16
21
|
}
|
|
17
22
|
rank(left, right) {
|
|
18
|
-
return rank(left
|
|
23
|
+
return rank(getProp(left, ...this.keys), this.direction === "ASC" ? rankAsc : rankDesc, getProp(right, ...this.keys));
|
|
19
24
|
}
|
|
20
25
|
transform(items) {
|
|
21
26
|
return sortItems(items, this);
|
package/db/Change.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Datas, DataKey } from "../util/data.js";
|
|
2
2
|
import type { ImmutableArray } from "../util/array.js";
|
|
3
3
|
import type { Provider, AsyncProvider } from "../provider/Provider.js";
|
|
4
4
|
import { Updates } from "../update/DataUpdate.js";
|
|
5
5
|
import { Nullish } from "../util/null.js";
|
|
6
6
|
import { DeepIterable } from "../util/iterate.js";
|
|
7
|
-
import type { ItemConstraints, ItemData } from "./Item.js";
|
|
8
7
|
/** Change on a collection. */
|
|
9
8
|
export interface Change<T extends Datas, K extends DataKey<T> = DataKey<T>> {
|
|
10
9
|
readonly action: string;
|
|
@@ -44,4 +43,3 @@ export type WriteChanges<T extends Datas, K extends DataKey<T> = DataKey<T>> = I
|
|
|
44
43
|
export declare function changeProvider<T extends Datas, K extends DataKey<T>>(provider: Provider<T>, ...changes: DeepIterable<Nullish<WriteChange<T, K>>>[]): ItemChanges<T, K>;
|
|
45
44
|
/** Apply a set of changes to an asynchronous provider. */
|
|
46
45
|
export declare function changeAsyncProvider<T extends Datas, K extends DataKey<T>>(provider: AsyncProvider<T>, ...changes: DeepIterable<Nullish<WriteChange<T, K>>>[]): Promise<ItemChanges<T, K>>;
|
|
47
|
-
export declare function _getItemConstraint<T extends Data>(id: string): ItemConstraints<ItemData<T>>;
|
package/db/Change.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { QueryConstraints } from "../constraint/QueryConstraints.js";
|
|
2
|
-
import { FilterConstraint } from "../constraint/FilterConstraint.js";
|
|
3
2
|
import { notNullish } from "../util/null.js";
|
|
4
3
|
import { flattenItems } from "../util/iterate.js";
|
|
4
|
+
import { getItemFilterConstraints } from "./Item.js";
|
|
5
5
|
/** Apply a set of changes to a synchronous provider. */
|
|
6
6
|
export function changeProvider(provider, ...changes) {
|
|
7
7
|
return Array.from(flattenItems(changes)).filter(notNullish).map(_changeItem, provider);
|
|
@@ -13,7 +13,7 @@ function _changeItem(change) {
|
|
|
13
13
|
else if (action === "SET")
|
|
14
14
|
this.setItem(collection, change.id, change.data);
|
|
15
15
|
else if (action === "UPDATE")
|
|
16
|
-
this.updateQuery(collection,
|
|
16
|
+
this.updateQuery(collection, new QueryConstraints(getItemFilterConstraints(change.id), undefined, 1), change.updates);
|
|
17
17
|
else if (action === "DELETE")
|
|
18
18
|
this.deleteItem(collection, change.id);
|
|
19
19
|
return change;
|
|
@@ -29,11 +29,8 @@ async function _changeAsyncItem(change) {
|
|
|
29
29
|
else if (action === "SET")
|
|
30
30
|
await this.setItem(collection, change.id, change.data);
|
|
31
31
|
else if (action === "UPDATE")
|
|
32
|
-
await this.updateQuery(collection,
|
|
32
|
+
await this.updateQuery(collection, new QueryConstraints(getItemFilterConstraints(change.id), undefined, 1), change.updates);
|
|
33
33
|
else if (action === "DELETE")
|
|
34
34
|
await this.deleteItem(collection, change.id);
|
|
35
35
|
return change;
|
|
36
36
|
}
|
|
37
|
-
export function _getItemConstraint(id) {
|
|
38
|
-
return new QueryConstraints(new FilterConstraint("id", id), undefined, 1);
|
|
39
|
-
}
|
package/db/Item.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Stop, Handler, Dispatch } from "../util/function.js";
|
|
|
3
3
|
import type { QueryConstraints } from "../constraint/QueryConstraints.js";
|
|
4
4
|
import { Data, Datas, DataKey } from "../util/data.js";
|
|
5
5
|
import { DataUpdate, Updates } from "../update/DataUpdate.js";
|
|
6
|
+
import { FilterConstraints } from "../constraint/FilterConstraints.js";
|
|
6
7
|
import type { DeleteChange, SetChange, UpdateChange } from "./Change.js";
|
|
7
8
|
import type { AsyncQuery, Query } from "./Query.js";
|
|
8
9
|
import type { AsyncDatabase, Database } from "./Database.js";
|
|
@@ -90,4 +91,6 @@ export declare class AsyncItem<T extends Datas = Datas, K extends DataKey<T> = D
|
|
|
90
91
|
export declare const getID: <T extends Data>({ id }: ItemData<T>) => string;
|
|
91
92
|
/** Get the IDs of an iterable set item data. */
|
|
92
93
|
export declare function getIDs<T extends Data>(entities: Iterable<ItemData<T>>): Iterable<string>;
|
|
94
|
+
/** Get a `FilterConstraints` instance that targets a single item by its ID. */
|
|
95
|
+
export declare function getItemFilterConstraints<T extends Data>(id: string): FilterConstraints<ItemData<T>>;
|
|
93
96
|
export {};
|
package/db/Item.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getData } from "../util/data.js";
|
|
2
|
-
import { FilterConstraint } from "../constraint/FilterConstraint.js";
|
|
3
2
|
import { runSequence } from "../util/sequence.js";
|
|
3
|
+
import { FilterConstraint } from "../constraint/FilterConstraint.js";
|
|
4
|
+
import { FilterConstraints } from "../constraint/FilterConstraints.js";
|
|
4
5
|
/** Reference to an item in a synchronous or asynchronous database. */
|
|
5
6
|
class BaseItem {
|
|
6
7
|
/** Get a set change for this item. */
|
|
@@ -37,7 +38,7 @@ export class Item extends BaseItem {
|
|
|
37
38
|
this.id = id;
|
|
38
39
|
}
|
|
39
40
|
get optional() {
|
|
40
|
-
return this.db.query(this.collection,
|
|
41
|
+
return this.db.query(this.collection, getItemFilterConstraints(this.id), undefined, 1);
|
|
41
42
|
}
|
|
42
43
|
get exists() {
|
|
43
44
|
return !!this.db.get(this.collection, this.id);
|
|
@@ -67,7 +68,7 @@ export class AsyncItem extends BaseItem {
|
|
|
67
68
|
this.id = id;
|
|
68
69
|
}
|
|
69
70
|
get optional() {
|
|
70
|
-
return this.db.query(this.collection,
|
|
71
|
+
return this.db.query(this.collection, { id: this.id }, undefined, 1);
|
|
71
72
|
}
|
|
72
73
|
get exists() {
|
|
73
74
|
return this.db.get(this.collection, this.id).then(Boolean);
|
|
@@ -95,3 +96,7 @@ export function* getIDs(entities) {
|
|
|
95
96
|
for (const { id } of entities)
|
|
96
97
|
yield id;
|
|
97
98
|
}
|
|
99
|
+
/** Get a `FilterConstraints` instance that targets a single item by its ID. */
|
|
100
|
+
export function getItemFilterConstraints(id) {
|
|
101
|
+
return new FilterConstraints(new FilterConstraint("id", id));
|
|
102
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { Datas, DataKey } from "../util/data.js";
|
|
1
|
+
import { DataKey, Datas } from "../util/data.js";
|
|
2
|
+
import { Dispatch } from "../util/function.js";
|
|
4
3
|
import { State } from "../state/State.js";
|
|
5
4
|
import { BooleanState } from "../state/BooleanState.js";
|
|
5
|
+
import { ItemValue, Item, AsyncItem, ItemData } from "./Item.js";
|
|
6
6
|
/** Hold the current state of a item. */
|
|
7
7
|
export declare class ItemState<T extends Datas, K extends DataKey<T> = DataKey<T>> extends State<ItemValue<T[K]>> {
|
|
8
8
|
readonly ref: Item<T, K> | AsyncItem<T, K>;
|
|
@@ -20,9 +20,3 @@ export declare class ItemState<T extends Datas, K extends DataKey<T> = DataKey<T
|
|
|
20
20
|
/** Subscribe this state to the source provider. */
|
|
21
21
|
connectSource(): Dispatch;
|
|
22
22
|
}
|
|
23
|
-
/**
|
|
24
|
-
* Use an item in a React component.
|
|
25
|
-
* - Uses the default cache, so will error if not used inside `<Cache>`
|
|
26
|
-
*/
|
|
27
|
-
export declare function useItem<T extends Datas, K extends DataKey<T>>(ref: Item<T, K> | AsyncItem<T, K>): ItemState<T, K>;
|
|
28
|
-
export declare function useItem<T extends Datas, K extends DataKey<T>>(ref?: Item<T, K> | AsyncItem<T, K>): ItemState<T, K> | undefined;
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { getData } from "../util/data.js";
|
|
2
|
-
import { getOptionalSource } from "../util/source.js";
|
|
3
|
-
import { setMapItem } from "../util/map.js";
|
|
4
|
-
import { CacheProvider } from "../provider/CacheProvider.js";
|
|
5
2
|
import { State } from "../state/State.js";
|
|
6
3
|
import { BooleanState } from "../state/BooleanState.js";
|
|
4
|
+
import { getOptionalSource } from "../util/source.js";
|
|
7
5
|
import { LazyDeferredSequence } from "../sequence/LazyDeferredSequence.js";
|
|
8
|
-
import {
|
|
9
|
-
import { useCache } from "./useCache.js";
|
|
6
|
+
import { CacheProvider } from "../provider/CacheProvider.js";
|
|
10
7
|
/** Hold the current state of a item. */
|
|
11
8
|
export class ItemState extends State {
|
|
12
9
|
/** Get the data of the item (throws `RequiredError` if item doesn't exist). */
|
|
@@ -58,9 +55,3 @@ export class ItemState extends State {
|
|
|
58
55
|
return this.from(this.ref);
|
|
59
56
|
}
|
|
60
57
|
}
|
|
61
|
-
export function useItem(ref) {
|
|
62
|
-
const cache = useCache();
|
|
63
|
-
const key = ref === null || ref === void 0 ? void 0 : ref.toString();
|
|
64
|
-
const state = ref && key ? cache.get(key) || setMapItem(cache, key, new ItemState(ref)) : undefined;
|
|
65
|
-
return useState(state);
|
|
66
|
-
}
|
|
@@ -41,9 +41,3 @@ export declare class QueryState<T extends Datas, K extends DataKey<T> = DataKey<
|
|
|
41
41
|
/** Iterate over the items. */
|
|
42
42
|
[Symbol.iterator](): Iterator<ItemData<T[K]>>;
|
|
43
43
|
}
|
|
44
|
-
/**
|
|
45
|
-
* Use a query in a React component.
|
|
46
|
-
* - Uses the default cache, so will error if not used inside `<Cache>`
|
|
47
|
-
*/
|
|
48
|
-
export declare function useQuery<T extends Datas, K extends DataKey<T>>(ref: Query<T, K> | AsyncQuery<T, K>): QueryState<T, K>;
|
|
49
|
-
export declare function useQuery<T extends Datas, K extends DataKey<T>>(ref?: Query<T, K> | AsyncQuery<T, K>): QueryState<T, K> | undefined;
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import { setMapItem } from "../util/map.js";
|
|
2
1
|
import { getFirstItem, getLastItem, getOptionalFirstItem, getOptionalLastItem } from "../util/array.js";
|
|
3
2
|
import { getOptionalSource } from "../util/source.js";
|
|
4
3
|
import { CacheProvider } from "../provider/CacheProvider.js";
|
|
5
4
|
import { State } from "../state/State.js";
|
|
6
5
|
import { BooleanState } from "../state/BooleanState.js";
|
|
7
6
|
import { LazyDeferredSequence } from "../sequence/LazyDeferredSequence.js";
|
|
8
|
-
import { useState } from "./useState.js";
|
|
9
|
-
import { useCache } from "./useCache.js";
|
|
10
7
|
/** Hold the current state of a query. */
|
|
11
8
|
export class QueryState extends State {
|
|
12
9
|
/** Can more items be loaded after the current result. */
|
|
@@ -110,8 +107,3 @@ export class QueryState extends State {
|
|
|
110
107
|
return this.value.values();
|
|
111
108
|
}
|
|
112
109
|
}
|
|
113
|
-
export function useQuery(ref) {
|
|
114
|
-
const cache = useCache();
|
|
115
|
-
const key = ref === null || ref === void 0 ? void 0 : ref.toString();
|
|
116
|
-
return useState(ref && key ? cache.get(key) || setMapItem(cache, key, new QueryState(ref)) : undefined);
|
|
117
|
-
}
|
package/db/index.d.ts
CHANGED
package/db/index.js
CHANGED
package/feedback/Feedback.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export declare class Feedback<T = unknown> {
|
|
|
19
19
|
constructor(feedback: string, value?: T);
|
|
20
20
|
}
|
|
21
21
|
/** Is an unknown value a `Feedback` object. */
|
|
22
|
-
export declare const isFeedback: <T extends Feedback<unknown>>(
|
|
22
|
+
export declare const isFeedback: <T extends Feedback<unknown>>(value: unknown) => value is Feedback<unknown>;
|
|
23
23
|
/**
|
|
24
24
|
* Yield the sub-messages in `[key: string, message: string]` format from a feedback's value.
|
|
25
25
|
* - Takes the `.value` property from a `Feedback` instance and looks for keyed `Feedback` instances in either `{ key: Feedback }`. `Feedback[]`, or `Map<key, Feedback>` formats.
|
package/feedback/Feedback.js
CHANGED
|
@@ -29,7 +29,7 @@ __decorate([
|
|
|
29
29
|
setPrototype("name", "Feedback")
|
|
30
30
|
], Feedback.prototype, "name", void 0);
|
|
31
31
|
/** Is an unknown value a `Feedback` object. */
|
|
32
|
-
export const isFeedback = (
|
|
32
|
+
export const isFeedback = (value) => isObject(value) && typeof value.name === "string" && value.name.endsWith("Feedback") && typeof value.message === "string";
|
|
33
33
|
/**
|
|
34
34
|
* Yield the sub-messages in `[key: string, message: string]` format from a feedback's value.
|
|
35
35
|
* - Takes the `.value` property from a `Feedback` instance and looks for keyed `Feedback` instances in either `{ key: Feedback }`. `Feedback[]`, or `Map<key, Feedback>` formats.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Firestore } from "firebase/firestore";
|
|
2
2
|
import type { Data } from "../../util/data.js";
|
|
3
3
|
import type { AsyncProvider } from "../../provider/Provider.js";
|
|
4
4
|
import type { ItemArray, ItemValue, ItemConstraints } from "../../db/Item.js";
|
|
@@ -9,11 +9,11 @@ const OPERATORS = {
|
|
|
9
9
|
NOT: "!=",
|
|
10
10
|
IN: "in",
|
|
11
11
|
OUT: "not-in",
|
|
12
|
+
CONTAINS: "array-contains",
|
|
12
13
|
GT: ">",
|
|
13
14
|
GTE: ">=",
|
|
14
15
|
LT: "<",
|
|
15
16
|
LTE: "<=",
|
|
16
|
-
CONTAINS: "array-contains",
|
|
17
17
|
};
|
|
18
18
|
// Map `Filter.types` to `OrderByDirection`
|
|
19
19
|
const DIRECTIONS = {
|
|
@@ -28,7 +28,7 @@ function* _yieldQueryConstraints({ sorts, filters, limit }) {
|
|
|
28
28
|
for (const { key, direction } of sorts)
|
|
29
29
|
yield firestoreOrderBy(key === "id" ? ID : key, DIRECTIONS[direction]);
|
|
30
30
|
for (const { operator, key, value } of filters)
|
|
31
|
-
yield firestoreWhere(key
|
|
31
|
+
yield firestoreWhere(key, OPERATORS[operator], value);
|
|
32
32
|
if (typeof limit === "number")
|
|
33
33
|
yield firestoreLimit(limit);
|
|
34
34
|
}
|
|
@@ -2,8 +2,6 @@ import { documentId as firestoreDocumentId, orderBy as firestoreOrderBy, where a
|
|
|
2
2
|
import { UnsupportedError } from "../../error/UnsupportedError.js";
|
|
3
3
|
import { ArrayUpdate, DataUpdate, Increment, DictionaryUpdate, Delete, Update } from "../../update/index.js";
|
|
4
4
|
// Constants.
|
|
5
|
-
// const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
|
|
6
|
-
// const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
|
|
7
5
|
const ID = firestoreDocumentId();
|
|
8
6
|
// Map `Filter.types` to `WhereFilterOp`
|
|
9
7
|
const OPERATORS = {
|
|
@@ -11,11 +9,11 @@ const OPERATORS = {
|
|
|
11
9
|
NOT: "!=",
|
|
12
10
|
IN: "in",
|
|
13
11
|
OUT: "not-in",
|
|
12
|
+
CONTAINS: "array-contains",
|
|
14
13
|
GT: ">",
|
|
15
14
|
GTE: ">=",
|
|
16
15
|
LT: "<",
|
|
17
16
|
LTE: "<=",
|
|
18
|
-
CONTAINS: "array-contains",
|
|
19
17
|
};
|
|
20
18
|
// Map `Filter.types` to `OrderByDirection`
|
|
21
19
|
const DIRECTIONS = {
|
|
@@ -9,11 +9,11 @@ const OPERATORS = {
|
|
|
9
9
|
NOT: "!=",
|
|
10
10
|
IN: "in",
|
|
11
11
|
OUT: "not-in",
|
|
12
|
+
CONTAINS: "array-contains",
|
|
12
13
|
GT: ">",
|
|
13
14
|
GTE: ">=",
|
|
14
15
|
LT: "<",
|
|
15
16
|
LTE: "<=",
|
|
16
|
-
CONTAINS: "array-contains",
|
|
17
17
|
};
|
|
18
18
|
// Map `Filter.types` to `OrderByDirection`
|
|
19
19
|
const DIRECTIONS = {
|
package/package.json
CHANGED
package/react/index.d.ts
CHANGED
package/react/index.js
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ImmutableArray } from "../util/array.js";
|
|
2
|
+
import { DataKey, Datas } from "../util/data.js";
|
|
3
|
+
import { AsyncItem } from "../db/Item.js";
|
|
4
|
+
import { ItemState } from "../db/ItemState.js";
|
|
5
|
+
import { AsyncQuery } from "../db/Query.js";
|
|
6
|
+
import { QueryState } from "../db/QueryState.js";
|
|
7
|
+
type Reference<T extends Datas, K extends DataKey<T>> = AsyncItem<T, K> | AsyncQuery<T, K>;
|
|
8
|
+
type ReferenceReferenceState<T extends Reference<Datas, string>> = T extends AsyncItem<infer D, infer K> ? ItemState<D, K> : T extends AsyncQuery<infer D, infer K> ? QueryState<D, K> : never;
|
|
9
|
+
/** Use one or more data items or queries. */
|
|
10
|
+
export declare function useData<T extends Reference<Datas, string>>(ref: T): ReferenceReferenceState<T>;
|
|
11
|
+
export declare function useData<T extends Reference<Datas, string>>(ref: T | undefined): ReferenceReferenceState<T> | undefined;
|
|
12
|
+
export declare function useData<T extends ImmutableArray<Reference<Datas, string>>>(...refs: T): {
|
|
13
|
+
[K in keyof T]: ReferenceReferenceState<T[K]>;
|
|
14
|
+
};
|
|
15
|
+
export {};
|
package/react/useData.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { setMapItem } from "../util/map.js";
|
|
2
|
+
import { mapArray } from "../util/transform.js";
|
|
3
|
+
import { AsyncItem } from "../db/Item.js";
|
|
4
|
+
import { ItemState } from "../db/ItemState.js";
|
|
5
|
+
import { QueryState } from "../db/QueryState.js";
|
|
6
|
+
import { useState } from "./useState.js";
|
|
7
|
+
import { useCache } from "./useCache.js";
|
|
8
|
+
export function useData(...refs) {
|
|
9
|
+
const cache = useCache();
|
|
10
|
+
const states = mapArray(refs, _getReferenceState, cache);
|
|
11
|
+
return useState(...states);
|
|
12
|
+
}
|
|
13
|
+
/** Get the corresponding `ItemState` or `QueryState` instance from the cache for a given `Item` or `Query`. */
|
|
14
|
+
function _getReferenceState(ref, cache) {
|
|
15
|
+
const key = ref === null || ref === void 0 ? void 0 : ref.toString();
|
|
16
|
+
return ref && key ? cache.get(key) || setMapItem(cache, key, ref instanceof AsyncItem ? new ItemState(ref) : new QueryState(ref)) : undefined;
|
|
17
|
+
}
|
package/react/useState.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { AnyState } from "../state/State.js";
|
|
1
|
+
import type { AnyState } from "../state/State.js";
|
|
2
|
+
import { ImmutableArray } from "../util/array.js";
|
|
2
3
|
/**
|
|
3
|
-
* Subscribe to
|
|
4
|
+
* Subscribe to one or more `State` instances.
|
|
4
5
|
*
|
|
5
|
-
* @param state
|
|
6
|
-
* - Subscription is recreated every time
|
|
6
|
+
* @param state `State` instance.
|
|
7
|
+
* - Subscription is recreated every time the state instance changes.
|
|
7
8
|
* - Memoise this value to persist the subscription for the lifetime of the component.
|
|
8
9
|
* - If the value is a `State` instance
|
|
9
10
|
*/
|
|
10
|
-
export declare function useState<
|
|
11
|
-
export declare function useState<
|
|
11
|
+
export declare function useState<T extends AnyState>(state: T): T;
|
|
12
|
+
export declare function useState<T extends AnyState>(state?: T | undefined): T | undefined;
|
|
13
|
+
export declare function useState<T extends ImmutableArray<AnyState | undefined>>(...states: T): T;
|
package/react/useState.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { useEffect, useState as useReactState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
export function useState(
|
|
6
|
-
const
|
|
2
|
+
import { dispatch } from "../util/function.js";
|
|
3
|
+
import { mapArray } from "../util/transform.js";
|
|
4
|
+
import { isDefined } from "../util/undefined.js";
|
|
5
|
+
export function useState(...states) {
|
|
6
|
+
const setValue = useReactState(undefined)[1];
|
|
7
7
|
const [error, setError] = useReactState(undefined);
|
|
8
|
-
useEffect(
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const forceRerender = () => setValue({});
|
|
10
|
+
const stops = mapArray(states, _startState, forceRerender, setError);
|
|
11
|
+
return () => stops.filter(isDefined).forEach(dispatch);
|
|
12
|
+
}, states);
|
|
9
13
|
if (error)
|
|
10
14
|
throw error;
|
|
11
|
-
return
|
|
15
|
+
return states.length <= 1 ? states[0] : states;
|
|
16
|
+
}
|
|
17
|
+
/** Start a subscription to a `ReferenceState` instance. */
|
|
18
|
+
function _startState(state, setValue, setError) {
|
|
19
|
+
return state === null || state === void 0 ? void 0 : state.next.to(setValue, setError);
|
|
12
20
|
}
|