shelving 1.86.7 → 1.87.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/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 +3 -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 +3 -2
- 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 +4 -3
- 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/duration.d.ts +2 -2
- package/util/duration.js +16 -17
- 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 +1 -1
- package/util/transform.js +1 -1
- package/util/undefined.d.ts +3 -3
- package/util/undefined.js +5 -5
- package/util/units.d.ts +7 -0
- package/util/units.js +17 -6
- 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
|
+
}
|
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
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"state-management",
|
|
12
12
|
"query-builder"
|
|
13
13
|
],
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.87.0",
|
|
15
15
|
"repository": "https://github.com/dhoulb/shelving",
|
|
16
16
|
"author": "Dave Houlbrooke <dave@shax.com>",
|
|
17
17
|
"license": "0BSD",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"@typescript-eslint/eslint-plugin": "^5.49.0",
|
|
72
72
|
"@typescript-eslint/parser": "^5.49.0",
|
|
73
73
|
"dpdm": "^3.11.0",
|
|
74
|
-
"esbuild": "^0.
|
|
74
|
+
"esbuild": "^0.17.12",
|
|
75
75
|
"esbuild-jest": "^0.5.0",
|
|
76
76
|
"eslint": "^8.33.0",
|
|
77
77
|
"eslint-config-prettier": "^8.6.0",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"prettier": "^2.8.3",
|
|
84
84
|
"react": "^18.1.0",
|
|
85
85
|
"react-dom": "^18.1.0",
|
|
86
|
-
"typescript": "^
|
|
86
|
+
"typescript": "^5.0.2"
|
|
87
87
|
},
|
|
88
88
|
"peerDependencies": {
|
|
89
89
|
"@google-cloud/firestore": ">=4.0.0",
|
package/schema/Schema.d.ts
CHANGED
|
@@ -29,4 +29,4 @@ export declare abstract class Schema<T extends unknown = unknown> implements Val
|
|
|
29
29
|
abstract validate(unsafeValue: unknown): T;
|
|
30
30
|
}
|
|
31
31
|
/** Is an unknown value a `Schema` instance? */
|
|
32
|
-
export declare const isSchema: <T extends Schema<unknown>>(
|
|
32
|
+
export declare const isSchema: <T extends Schema<unknown>>(value: unknown) => value is T;
|
package/schema/Schema.js
CHANGED
package/state/State.d.ts
CHANGED
|
@@ -43,4 +43,4 @@ export declare class State<T> implements AsyncIterable<T>, Validatable<T> {
|
|
|
43
43
|
validate(value: T): T;
|
|
44
44
|
}
|
|
45
45
|
/** Is an unknown value a `State` instance. */
|
|
46
|
-
export declare const isState: <T extends AnyState>(
|
|
46
|
+
export declare const isState: <T extends AnyState>(value: unknown) => value is T;
|
package/state/State.js
CHANGED
|
@@ -10,7 +10,7 @@ import { DeferredSequence } from "../sequence/DeferredSequence.js";
|
|
|
10
10
|
* - To set the state to be loading, use the `State.NOVALUE` constant or a `Promise` value.
|
|
11
11
|
* - To set the state to an explicit value, use that value or another `State` instance with a value.
|
|
12
12
|
* */
|
|
13
|
-
|
|
13
|
+
class State {
|
|
14
14
|
/** Most recently dispatched value (or throw `Promise` that resolves to the next value). */
|
|
15
15
|
get value() {
|
|
16
16
|
if (this._value === State.NOVALUE)
|
|
@@ -79,5 +79,6 @@ export class State {
|
|
|
79
79
|
}
|
|
80
80
|
/** The `NOVALUE` symbol indicates no value has been received by a `State` instance. */
|
|
81
81
|
State.NOVALUE = Symbol("shelving/State.NOVALUE");
|
|
82
|
+
export { State };
|
|
82
83
|
/** Is an unknown value a `State` instance. */
|
|
83
|
-
export const isState = (
|
|
84
|
+
export const isState = (value) => value instanceof State;
|
package/test/basics.d.ts
CHANGED
|
@@ -5,6 +5,14 @@ export declare const BASIC_SCHEMA: import("../schema/DataSchema.js").DataSchema<
|
|
|
5
5
|
num: number;
|
|
6
6
|
group: "a" | "b" | "c";
|
|
7
7
|
tags: import("../index.js").ImmutableArray<string>;
|
|
8
|
+
odd: boolean;
|
|
9
|
+
even: boolean;
|
|
10
|
+
sub: {
|
|
11
|
+
str: any;
|
|
12
|
+
num: any;
|
|
13
|
+
odd: any;
|
|
14
|
+
even: any;
|
|
15
|
+
};
|
|
8
16
|
}>;
|
|
9
17
|
export type BasicData = ValidatorType<typeof BASIC_SCHEMA>;
|
|
10
18
|
export type BasicItemData = ItemData<BasicData>;
|
|
@@ -18,3 +26,4 @@ export declare const basic7: BasicItemData;
|
|
|
18
26
|
export declare const basic8: BasicItemData;
|
|
19
27
|
export declare const basic9: BasicItemData;
|
|
20
28
|
export declare const basics: ReadonlyArray<BasicItemData>;
|
|
29
|
+
export declare const basic999: BasicData;
|
package/test/basics.js
CHANGED
|
@@ -3,19 +3,24 @@ import { ARRAY } from "../schema/ArraySchema.js";
|
|
|
3
3
|
import { DATA } from "../schema/DataSchema.js";
|
|
4
4
|
import { NUMBER } from "../schema/NumberSchema.js";
|
|
5
5
|
import { STRING } from "../schema/StringSchema.js";
|
|
6
|
+
import { BOOLEAN } from "../schema/BooleanSchema.js";
|
|
6
7
|
export const BASIC_SCHEMA = DATA({
|
|
7
8
|
str: STRING,
|
|
8
9
|
num: NUMBER,
|
|
9
10
|
group: ALLOW_STRING({ a: "A", b: "B", c: "C" }),
|
|
10
11
|
tags: ARRAY(STRING),
|
|
12
|
+
odd: BOOLEAN,
|
|
13
|
+
even: BOOLEAN,
|
|
14
|
+
sub: DATA({ str: STRING, num: NUMBER, odd: BOOLEAN, even: BOOLEAN }),
|
|
11
15
|
});
|
|
12
|
-
export const basic1 = { id: "basic1", str: "aaa", num: 100, group: "a", tags: ["odd", "prime"] };
|
|
13
|
-
export const basic2 = { id: "basic2", str: "bbb", num: 200, group: "a", tags: ["even", "prime"] };
|
|
14
|
-
export const basic3 = { id: "basic3", str: "ccc", num: 300, group: "a", tags: ["odd", "prime"] };
|
|
15
|
-
export const basic4 = { id: "basic4", str: "ddd", num: 400, group: "b", tags: ["even"] };
|
|
16
|
-
export const basic5 = { id: "basic5", str: "eee", num: 500, group: "b", tags: ["odd", "prime"] };
|
|
17
|
-
export const basic6 = { id: "basic6", str: "fff", num: 600, group: "b", tags: ["even"] };
|
|
18
|
-
export const basic7 = { id: "basic7", str: "ggg", num: 700, group: "c", tags: ["odd", "prime"] };
|
|
19
|
-
export const basic8 = { id: "basic8", str: "hhh", num: 800, group: "c", tags: ["even"] };
|
|
20
|
-
export const basic9 = { id: "basic9", str: "iii", num: 900, group: "c", tags: ["odd"] };
|
|
16
|
+
export const basic1 = { id: "basic1", str: "aaa", num: 100, even: false, odd: true, group: "a", tags: ["odd", "prime"], sub: { str: "aaa", num: 100, even: false, odd: true } };
|
|
17
|
+
export const basic2 = { id: "basic2", str: "bbb", num: 200, even: true, odd: false, group: "a", tags: ["even", "prime"], sub: { str: "bbb", num: 200, even: true, odd: false } };
|
|
18
|
+
export const basic3 = { id: "basic3", str: "ccc", num: 300, even: false, odd: true, group: "a", tags: ["odd", "prime"], sub: { str: "ccc", num: 300, even: false, odd: true } };
|
|
19
|
+
export const basic4 = { id: "basic4", str: "ddd", num: 400, even: true, odd: false, group: "b", tags: ["even"], sub: { str: "ddd", num: 400, even: true, odd: false } };
|
|
20
|
+
export const basic5 = { id: "basic5", str: "eee", num: 500, even: false, odd: true, group: "b", tags: ["odd", "prime"], sub: { str: "eee", num: 500, even: false, odd: true } };
|
|
21
|
+
export const basic6 = { id: "basic6", str: "fff", num: 600, even: true, odd: false, group: "b", tags: ["even"], sub: { str: "fff", num: 600, even: true, odd: false } };
|
|
22
|
+
export const basic7 = { id: "basic7", str: "ggg", num: 700, even: false, odd: true, group: "c", tags: ["odd", "prime"], sub: { str: "ggg", num: 700, even: false, odd: true } };
|
|
23
|
+
export const basic8 = { id: "basic8", str: "hhh", num: 800, even: true, odd: false, group: "c", tags: ["even"], sub: { str: "hhh", num: 800, even: true, odd: false } };
|
|
24
|
+
export const basic9 = { id: "basic9", str: "iii", num: 900, even: false, odd: true, group: "c", tags: ["odd"], sub: { str: "iii", num: 900, even: false, odd: true } };
|
|
21
25
|
export const basics = [basic3, basic5, basic7, basic4, basic1, basic2, basic8, basic6, basic9];
|
|
26
|
+
export const basic999 = { str: "zzz", num: 999, even: false, odd: true, group: "a", tags: ["odd", "prime"], sub: { str: "zzz", num: 999, even: false, odd: true } };
|
package/test/index.d.ts
CHANGED
|
@@ -8,6 +8,14 @@ export declare const TEST_COLLECTIONS: {
|
|
|
8
8
|
num: number;
|
|
9
9
|
group: "a" | "b" | "c";
|
|
10
10
|
tags: import("../index.js").ImmutableArray<string>;
|
|
11
|
+
odd: boolean;
|
|
12
|
+
even: boolean;
|
|
13
|
+
sub: {
|
|
14
|
+
str: any;
|
|
15
|
+
num: any;
|
|
16
|
+
odd: any;
|
|
17
|
+
even: any;
|
|
18
|
+
};
|
|
11
19
|
}>;
|
|
12
20
|
people: import("../index.js").DataSchema<{
|
|
13
21
|
name: {
|
package/util/array.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Arguments } from "./function.js";
|
|
2
|
-
import { Matcher } from "./match.js";
|
|
1
|
+
import type { Arguments } from "./function.js";
|
|
2
|
+
import type { Matcher } from "./match.js";
|
|
3
3
|
/**
|
|
4
4
|
* Mutable array: an array that can be changed.
|
|
5
5
|
* - Consistency with `MutableObject<T>` and `ImmutableArray<T>`
|
|
@@ -15,16 +15,15 @@ export type ArrayItem<T extends ImmutableArray> = T[number];
|
|
|
15
15
|
/** Things that can be converted to arrays. */
|
|
16
16
|
export type PossibleArray<T> = ImmutableArray<T> | Iterable<T>;
|
|
17
17
|
/** Is an unknown value an array? */
|
|
18
|
-
export declare const isArray: <T extends ImmutableArray<unknown>>(
|
|
18
|
+
export declare const isArray: <T extends ImmutableArray<unknown>>(value: unknown) => value is T;
|
|
19
19
|
/** Assert that a value is an array. */
|
|
20
20
|
export declare function assertArray<T>(arr: ImmutableArray<T> | unknown): asserts arr is ImmutableArray<T>;
|
|
21
21
|
/** Is an unknown value an item in a specified array? */
|
|
22
|
-
export declare const isArrayItem: <T>(arr: ImmutableArray<T>,
|
|
23
|
-
export declare const isItem: <T>(arr: ImmutableArray<T>, item: unknown) => item is T;
|
|
22
|
+
export declare const isArrayItem: <T>(arr: ImmutableArray<T>, value: unknown) => value is T;
|
|
24
23
|
/** Convert an iterable to an array (if its not already an array). */
|
|
25
24
|
export declare function getArray<T>(items: PossibleArray<T>): ImmutableArray<T>;
|
|
26
25
|
/** Add multiple items to an array (immutably) and return a new array with those items (or the same array if no changes were made). */
|
|
27
|
-
export declare function withArrayItems<T>(
|
|
26
|
+
export declare function withArrayItems<T>(arr: ImmutableArray<T>, ...items: T[]): ImmutableArray<T>;
|
|
28
27
|
/** Pick multiple items from an array (immutably) and return a new array without those items (or the same array if no changes were made). */
|
|
29
28
|
export declare function pickArrayItems<T>(input: ImmutableArray<T> | Iterable<T>, ...pick: T[]): ImmutableArray<T>;
|
|
30
29
|
/** Remove multiple items from an array (immutably) and return a new array without those items (or the same array if no changes were made). */
|
package/util/array.js
CHANGED
|
@@ -3,23 +3,22 @@ import { RequiredError } from "../error/RequiredError.js";
|
|
|
3
3
|
import { filterItems, omitItems, pickItems } from "./iterate.js";
|
|
4
4
|
import { formatRange } from "./number.js";
|
|
5
5
|
/** Is an unknown value an array? */
|
|
6
|
-
export const isArray = (
|
|
6
|
+
export const isArray = (value) => Array.isArray(value);
|
|
7
7
|
/** Assert that a value is an array. */
|
|
8
8
|
export function assertArray(arr) {
|
|
9
9
|
if (!isArray(arr))
|
|
10
10
|
throw new AssertionError(`Must be array`, arr);
|
|
11
11
|
}
|
|
12
12
|
/** Is an unknown value an item in a specified array? */
|
|
13
|
-
export const isArrayItem = (arr,
|
|
14
|
-
export const isItem = isArrayItem;
|
|
13
|
+
export const isArrayItem = (arr, value) => arr.includes(value);
|
|
15
14
|
/** Convert an iterable to an array (if its not already an array). */
|
|
16
15
|
export function getArray(items) {
|
|
17
16
|
return isArray(items) ? items : Array.from(items);
|
|
18
17
|
}
|
|
19
18
|
/** Add multiple items to an array (immutably) and return a new array with those items (or the same array if no changes were made). */
|
|
20
|
-
export function withArrayItems(
|
|
21
|
-
const extras = items.filter(_doesNotInclude,
|
|
22
|
-
return extras.length ? [...
|
|
19
|
+
export function withArrayItems(arr, ...items) {
|
|
20
|
+
const extras = items.filter(_doesNotInclude, arr);
|
|
21
|
+
return extras.length ? [...arr, ...extras] : arr;
|
|
23
22
|
}
|
|
24
23
|
function _doesNotInclude(value) {
|
|
25
24
|
return !this.includes(value);
|
package/util/assert.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Assert a boolean condition is true. */
|
|
2
2
|
export declare function assert(condition: unknown, ...received: unknown[]): asserts condition;
|
|
3
3
|
/** Assert two values are equal. */
|
|
4
|
-
export declare function assertEqual<T>(
|
|
4
|
+
export declare function assertEqual<T>(left: T | unknown, right: T): asserts left is T;
|
|
5
5
|
/** Assert two values are equal. */
|
|
6
|
-
export declare function assertNot<T, N>(
|
|
6
|
+
export declare function assertNot<T, N>(left: T | N, right: N): asserts left is T;
|