shelving 1.91.2 → 1.92.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/db/Change.d.ts +19 -20
- package/db/Change.js +22 -21
- package/db/CollectionReference.d.ts +103 -0
- package/db/CollectionReference.js +127 -0
- package/db/Database.d.ts +21 -23
- package/db/Database.js +18 -18
- package/db/{Item.d.ts → ItemReference.d.ts} +13 -14
- package/db/{Item.js → ItemReference.js} +14 -17
- package/db/ItemState.d.ts +3 -3
- package/db/{Query.d.ts → QueryReference.d.ts} +25 -33
- package/db/QueryReference.js +101 -0
- package/db/QueryState.d.ts +10 -10
- package/db/QueryState.js +20 -18
- package/db/index.d.ts +3 -3
- package/db/index.js +3 -3
- package/firestore/client/FirestoreClientProvider.d.ts +13 -13
- package/firestore/client/FirestoreClientProvider.js +55 -84
- package/firestore/lite/FirestoreLiteProvider.d.ts +11 -11
- package/firestore/lite/FirestoreLiteProvider.js +52 -83
- package/firestore/server/FirestoreServerProvider.d.ts +13 -13
- package/firestore/server/FirestoreServerProvider.js +51 -84
- package/index.d.ts +0 -2
- package/index.js +0 -2
- package/package.json +1 -3
- package/provider/CacheProvider.d.ts +7 -7
- package/provider/CacheProvider.js +14 -14
- package/provider/DebugProvider.d.ts +11 -11
- package/provider/DebugProvider.js +28 -29
- package/provider/MemoryProvider.d.ts +17 -17
- package/provider/MemoryProvider.js +41 -43
- package/provider/Provider.d.ts +15 -15
- package/provider/ThroughProvider.d.ts +12 -12
- package/provider/ThroughProvider.js +20 -20
- package/provider/ValidationProvider.d.ts +11 -11
- package/provider/ValidationProvider.js +16 -12
- package/react/useData.d.ts +5 -5
- package/react/useData.js +2 -2
- package/state/DataState.d.ts +4 -8
- package/state/DataState.js +6 -16
- package/state/DictionaryState.d.ts +4 -6
- package/state/DictionaryState.js +4 -9
- package/test/basics.d.ts +1 -1
- package/test/people.d.ts +1 -1
- package/test/util.d.ts +1 -1
- package/test/util.js +1 -1
- package/util/data.d.ts +2 -2
- package/util/equal.js +5 -5
- package/util/hydrate.d.ts +13 -26
- package/util/hydrate.js +44 -60
- package/util/index.d.ts +2 -0
- package/util/index.js +2 -0
- package/util/iterate.d.ts +2 -0
- package/util/match.d.ts +2 -10
- package/util/match.js +4 -8
- package/util/query.d.ts +83 -0
- package/util/query.js +129 -0
- package/util/sort.d.ts +8 -15
- package/util/sort.js +15 -19
- package/util/transform.d.ts +26 -45
- package/util/transform.js +24 -29
- package/util/update.d.ts +22 -0
- package/util/update.js +42 -0
- package/util/validate.js +2 -2
- package/constraint/Constraint.d.ts +0 -7
- package/constraint/Constraint.js +0 -3
- package/constraint/Constraints.d.ts +0 -20
- package/constraint/Constraints.js +0 -34
- package/constraint/Filter.d.ts +0 -34
- package/constraint/Filter.js +0 -89
- package/constraint/Filters.d.ts +0 -27
- package/constraint/Filters.js +0 -41
- package/constraint/Sort.d.ts +0 -18
- package/constraint/Sort.js +0 -33
- package/constraint/Sorts.d.ts +0 -26
- package/constraint/Sorts.js +0 -47
- package/constraint/Statement.d.ts +0 -45
- package/constraint/Statement.js +0 -79
- package/constraint/index.d.ts +0 -7
- package/constraint/index.js +0 -7
- package/db/Collection.d.ts +0 -64
- package/db/Collection.js +0 -83
- package/db/Query.js +0 -94
- package/update/ArrayUpdate.d.ts +0 -17
- package/update/ArrayUpdate.js +0 -31
- package/update/DataUpdate.d.ts +0 -37
- package/update/DataUpdate.js +0 -44
- package/update/Delete.d.ts +0 -10
- package/update/Delete.js +0 -12
- package/update/DictionaryUpdate.d.ts +0 -31
- package/update/DictionaryUpdate.js +0 -62
- package/update/Increment.d.ts +0 -18
- package/update/Increment.js +0 -22
- package/update/Update.d.ts +0 -8
- package/update/Update.js +0 -6
- package/update/hydrations.d.ts +0 -3
- package/update/hydrations.js +0 -13
- package/update/index.d.ts +0 -7
- package/update/index.js +0 -7
package/util/query.d.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { ImmutableArray } from "./array.js";
|
|
2
|
+
import type { Data, FlatData, FlatDataKey } from "./data.js";
|
|
3
|
+
/** Query that can be applied to a list of data objects. */
|
|
4
|
+
export type Query<T extends Data> = {
|
|
5
|
+
readonly [K in FlatDataKey<T> as K | `${K}` | `!${K}`]?: FlatData<T>[K] | ImmutableArray<FlatData<T>[K]> | undefined;
|
|
6
|
+
} & {
|
|
7
|
+
readonly [K in FlatDataKey<T> as `${K}<` | `${K}<=` | `${K}>` | `${K}>=`]?: FlatData<T>[K] | undefined;
|
|
8
|
+
} & {
|
|
9
|
+
readonly [K in FlatDataKey<T> as `${K}[]`]?: FlatData<T>[K] extends ImmutableArray<infer X> ? X | undefined : never;
|
|
10
|
+
} & {
|
|
11
|
+
readonly $order?: FlatDataKey<T> | `${FlatDataKey<T>}` | `!${FlatDataKey<T>}` | ImmutableArray<`${FlatDataKey<T>}` | `!${FlatDataKey<T>}`>;
|
|
12
|
+
readonly $limit?: number | undefined;
|
|
13
|
+
};
|
|
14
|
+
/** A single filter that can be applied to a list of data objects. */
|
|
15
|
+
export type Filter = {
|
|
16
|
+
keys: readonly [string, ...string[]];
|
|
17
|
+
operator: "is";
|
|
18
|
+
value: unknown;
|
|
19
|
+
} | {
|
|
20
|
+
keys: readonly [string, ...string[]];
|
|
21
|
+
operator: "not";
|
|
22
|
+
value: unknown;
|
|
23
|
+
} | {
|
|
24
|
+
keys: readonly [string, ...string[]];
|
|
25
|
+
operator: "in";
|
|
26
|
+
value: ImmutableArray;
|
|
27
|
+
} | {
|
|
28
|
+
keys: readonly [string, ...string[]];
|
|
29
|
+
operator: "out";
|
|
30
|
+
value: ImmutableArray;
|
|
31
|
+
} | {
|
|
32
|
+
keys: readonly [string, ...string[]];
|
|
33
|
+
operator: "contains";
|
|
34
|
+
value: unknown;
|
|
35
|
+
} | {
|
|
36
|
+
keys: readonly [string, ...string[]];
|
|
37
|
+
operator: "lt";
|
|
38
|
+
value: unknown;
|
|
39
|
+
} | {
|
|
40
|
+
keys: readonly [string, ...string[]];
|
|
41
|
+
operator: "lte";
|
|
42
|
+
value: unknown;
|
|
43
|
+
} | {
|
|
44
|
+
keys: readonly [string, ...string[]];
|
|
45
|
+
operator: "gt";
|
|
46
|
+
value: unknown;
|
|
47
|
+
} | {
|
|
48
|
+
keys: readonly [string, ...string[]];
|
|
49
|
+
operator: "gte";
|
|
50
|
+
value: unknown;
|
|
51
|
+
};
|
|
52
|
+
/** A single sort that can be applied to a list of data objects. */
|
|
53
|
+
export type Sort = {
|
|
54
|
+
keys: readonly [string, ...string[]];
|
|
55
|
+
direction: "asc" | "desc";
|
|
56
|
+
};
|
|
57
|
+
/** Get the `Filter` objects for a query. */
|
|
58
|
+
export declare function getFilters<T extends Data>(query: Query<T>): ImmutableArray<Filter>;
|
|
59
|
+
/** Get the `Sort` objects for a query. */
|
|
60
|
+
export declare function getSorts<T extends Data>({ $order }: Query<T>): ImmutableArray<Sort>;
|
|
61
|
+
/** Get the limit for a query. */
|
|
62
|
+
export declare const getLimit: <T extends Data>({ $limit }: Query<T>) => number | undefined;
|
|
63
|
+
/** Query a set of data items using a query. */
|
|
64
|
+
export declare function queryItems<T extends Data>(items: Iterable<T>, query: Query<T>): Iterable<T>;
|
|
65
|
+
/**
|
|
66
|
+
* Query a set of data items for writing using a query.
|
|
67
|
+
* - If no limit is set on the data sorting can be avoided too for performance reasons.
|
|
68
|
+
*/
|
|
69
|
+
export declare function queryWritableItems<T extends Data>(items: Iterable<T>, query: Query<T>): Iterable<T>;
|
|
70
|
+
/** Match a single data item againt a set of filters. */
|
|
71
|
+
export declare function matchQueryItem<T extends Data>(item: T, filters: ImmutableArray<Filter>): boolean;
|
|
72
|
+
/** Filter a set of data items using a set of filters. */
|
|
73
|
+
export declare function filterQueryItems<T extends Data>(items: Iterable<T>, filters: ImmutableArray<Filter>): Iterable<T>;
|
|
74
|
+
/** Compare two data items using a set of sorts. */
|
|
75
|
+
export declare function compareQueryItems<T extends Data>(left: T, right: T, sorts: ImmutableArray<Sort>): number;
|
|
76
|
+
/** Sort a set of data items using a set of sorts. */
|
|
77
|
+
export declare function sortQueryItems<T extends Data>(items: Iterable<T>, sorts: ImmutableArray<Sort>): Iterable<T>;
|
|
78
|
+
/** LImit a set of data items using a set of limit. */
|
|
79
|
+
export declare function limitQueryItems<T extends Data>(items: ImmutableArray<T> | Iterable<T>, limit: number | undefined): Iterable<T>;
|
|
80
|
+
/** Get a query for items that appear before a specified item. */
|
|
81
|
+
export declare function getBeforeQuery<T extends Data>(query: Query<T>, item: T): Query<T>;
|
|
82
|
+
/** Get a query for items that appear after a specified item. */
|
|
83
|
+
export declare function getAfterQuery<T extends Data>(query: Query<T>, item: T): Query<T>;
|
package/util/query.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { getLastItem, isArray, limitArray } from "./array.js";
|
|
2
|
+
import { isArrayWith, isEqual, isEqualGreater, isEqualLess, isGreater, isInArray, isLess, notEqual, notInArray } from "./equal.js";
|
|
3
|
+
import { limitItems } from "./iterate.js";
|
|
4
|
+
import { getProp, getProps } from "./object.js";
|
|
5
|
+
import { compareAscending, compareDescending, sortArray } from "./sort.js";
|
|
6
|
+
import { splitString } from "./string.js";
|
|
7
|
+
import { isDefined } from "./undefined.js";
|
|
8
|
+
/** Map `Filter` operators to corresponding `Match` function. */
|
|
9
|
+
const MATCHERS = {
|
|
10
|
+
is: isEqual,
|
|
11
|
+
not: notEqual,
|
|
12
|
+
in: isInArray,
|
|
13
|
+
out: notInArray,
|
|
14
|
+
contains: isArrayWith,
|
|
15
|
+
lt: isLess,
|
|
16
|
+
lte: isEqualLess,
|
|
17
|
+
gt: isGreater,
|
|
18
|
+
gte: isEqualGreater,
|
|
19
|
+
};
|
|
20
|
+
/** Get the `Filter` objects for a query. */
|
|
21
|
+
export function getFilters(query) {
|
|
22
|
+
return getProps(query).map(_getFilters).filter(isDefined);
|
|
23
|
+
}
|
|
24
|
+
function _getFilters([key, value]) {
|
|
25
|
+
if (key === "$order" || key === "$limit")
|
|
26
|
+
return;
|
|
27
|
+
else if (key.startsWith("!"))
|
|
28
|
+
return isArray(value) ? { keys: splitString(key.slice(1), "."), operator: "out", value } : { keys: splitString(key.slice(1), "."), operator: "not", value };
|
|
29
|
+
else if (key.endsWith("[]"))
|
|
30
|
+
return { keys: splitString(key.slice(0, -2), "."), operator: "contains", value };
|
|
31
|
+
else if (key.endsWith(">"))
|
|
32
|
+
return { keys: splitString(key.slice(0, -1), "."), operator: "gt", value };
|
|
33
|
+
else if (key.endsWith(">="))
|
|
34
|
+
return { keys: splitString(key.slice(0, -2), "."), operator: "gte", value };
|
|
35
|
+
else if (key.endsWith("<"))
|
|
36
|
+
return { keys: splitString(key.slice(0, -1), "."), operator: "lt", value };
|
|
37
|
+
else if (key.endsWith("<="))
|
|
38
|
+
return { keys: splitString(key.slice(0, -2), "."), operator: "lte", value };
|
|
39
|
+
else
|
|
40
|
+
return isArray(value) ? { keys: splitString(key, "."), operator: "in", value } : { keys: splitString(key, "."), operator: "is", value };
|
|
41
|
+
}
|
|
42
|
+
/** Get the `Sort` objects for a query. */
|
|
43
|
+
export function getSorts({ $order }) {
|
|
44
|
+
return !$order ? [] : isArray($order) ? $order.map(_getSort) : [_getSort($order)];
|
|
45
|
+
}
|
|
46
|
+
function _getSort(key) {
|
|
47
|
+
if (key.startsWith("!"))
|
|
48
|
+
return { keys: splitString(key.slice(1), "."), direction: "desc" };
|
|
49
|
+
else
|
|
50
|
+
return { keys: splitString(key, "."), direction: "asc" };
|
|
51
|
+
}
|
|
52
|
+
/** Get the limit for a query. */
|
|
53
|
+
export const getLimit = ({ $limit }) => $limit;
|
|
54
|
+
/** Query a set of data items using a query. */
|
|
55
|
+
export function queryItems(items, query) {
|
|
56
|
+
return limitQueryItems(sortQueryItems(filterQueryItems(items, getFilters(query)), getSorts(query)), getLimit(query));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Query a set of data items for writing using a query.
|
|
60
|
+
* - If no limit is set on the data sorting can be avoided too for performance reasons.
|
|
61
|
+
*/
|
|
62
|
+
export function queryWritableItems(items, query) {
|
|
63
|
+
return getLimit(query) === undefined ? filterQueryItems(items, getFilters(query)) : queryItems(items, query);
|
|
64
|
+
}
|
|
65
|
+
/** Match a single data item againt a set of filters. */
|
|
66
|
+
export function matchQueryItem(item, filters) {
|
|
67
|
+
for (const { keys, operator, value } of filters) {
|
|
68
|
+
const matcher = MATCHERS[operator];
|
|
69
|
+
if (!matcher(getProp(item, ...keys), value))
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
/** Filter a set of data items using a set of filters. */
|
|
75
|
+
export function* filterQueryItems(items, filters) {
|
|
76
|
+
if (filters.length) {
|
|
77
|
+
for (const item of items)
|
|
78
|
+
if (matchQueryItem(item, filters))
|
|
79
|
+
yield item;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
yield* items;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** Compare two data items using a set of sorts. */
|
|
86
|
+
export function compareQueryItems(left, right, sorts) {
|
|
87
|
+
for (const { keys, direction } of sorts) {
|
|
88
|
+
const l = getProp(left, ...keys);
|
|
89
|
+
const r = getProp(right, ...keys);
|
|
90
|
+
const c = direction === "asc" ? compareAscending(l, r) : compareDescending(l, r);
|
|
91
|
+
if (c !== 0)
|
|
92
|
+
return c;
|
|
93
|
+
}
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
96
|
+
/** Sort a set of data items using a set of sorts. */
|
|
97
|
+
export function sortQueryItems(items, sorts) {
|
|
98
|
+
return sorts.length ? sortArray(items, compareQueryItems, sorts) : items;
|
|
99
|
+
}
|
|
100
|
+
/** LImit a set of data items using a set of limit. */
|
|
101
|
+
export function limitQueryItems(items, limit) {
|
|
102
|
+
return typeof limit !== "number" ? items : isArray(items) ? limitArray(items, limit) : limitItems(items, limit);
|
|
103
|
+
}
|
|
104
|
+
/** Get a query for items that appear before a specified item. */
|
|
105
|
+
export function getBeforeQuery(query, item) {
|
|
106
|
+
const sorts = getSorts(query);
|
|
107
|
+
const lastSort = getLastItem(sorts);
|
|
108
|
+
const newQuery = { ...query };
|
|
109
|
+
for (const sort of sorts) {
|
|
110
|
+
const { keys, direction } = sort;
|
|
111
|
+
const key = keys.join(".");
|
|
112
|
+
const value = getProp(item, ...keys);
|
|
113
|
+
newQuery[direction === "asc" ? (sort === lastSort ? `${key}>` : `${key}>=`) : sort === lastSort ? `${key}<` : `${key}<=`] = value;
|
|
114
|
+
}
|
|
115
|
+
return newQuery;
|
|
116
|
+
}
|
|
117
|
+
/** Get a query for items that appear after a specified item. */
|
|
118
|
+
export function getAfterQuery(query, item) {
|
|
119
|
+
const sorts = getSorts(query);
|
|
120
|
+
const lastSort = getLastItem(sorts);
|
|
121
|
+
const newQuery = { ...query };
|
|
122
|
+
for (const sort of sorts) {
|
|
123
|
+
const { keys, direction } = sort;
|
|
124
|
+
const key = keys.join(".");
|
|
125
|
+
const value = getProp(item, ...keys);
|
|
126
|
+
newQuery[direction === "asc" ? (sort === lastSort ? `${key}<` : `${key}<=`) : sort === lastSort ? `${key}>` : `${key}>=`] = value;
|
|
127
|
+
}
|
|
128
|
+
return newQuery;
|
|
129
|
+
}
|
package/util/sort.d.ts
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
import type { ImmutableArray } from "./array.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
/** Function that can rank two values. */
|
|
7
|
-
export type Rank<T> = (left: T, right: T) => number;
|
|
8
|
-
/** Something that can rank two values. */
|
|
9
|
-
export type Ranker<T> = Rankable<T> | Rank<T>;
|
|
10
|
-
/** Rank two values with a `Ranker`. */
|
|
11
|
-
export declare function rank<T>(left: T, ranker: Ranker<T>, right: T): number;
|
|
2
|
+
import type { Arguments } from "./function.js";
|
|
3
|
+
/** Function that can compare two values for sorting. */
|
|
4
|
+
export type Compare<T, A extends Arguments = []> = (left: T, right: T, ...args: A) => number;
|
|
12
5
|
/**
|
|
13
|
-
*
|
|
6
|
+
* Compare two unknown values in ascending order.
|
|
14
7
|
* - Allows values of different types to be ranked for sorting.
|
|
15
8
|
*
|
|
16
9
|
* 1. Numbers and dates (ascending order: -Infinity, negative, zero, positive, Infinity, NaN)
|
|
@@ -26,8 +19,8 @@ export declare function rank<T>(left: T, ranker: Ranker<T>, right: T): number;
|
|
|
26
19
|
*
|
|
27
20
|
* @returns Number below zero if `a` is higher, number above zero if `b` is higher, or `0` if they're equally sorted.
|
|
28
21
|
*/
|
|
29
|
-
export declare function
|
|
30
|
-
/**
|
|
31
|
-
export declare const
|
|
22
|
+
export declare function compareAscending(left: unknown, right: unknown): number;
|
|
23
|
+
/** Compare two unknown values in descending order. */
|
|
24
|
+
export declare const compareDescending: (left: unknown, right: unknown) => number;
|
|
32
25
|
/** Sort an iterable set of items using a ranker (defaults to sorting in ascending order). */
|
|
33
|
-
export declare function
|
|
26
|
+
export declare function sortArray<T, A extends Arguments = []>(input: ImmutableArray<T> | Iterable<T>, compare?: Compare<T, A>, ...args: A): ImmutableArray<T>;
|
package/util/sort.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { isArray } from "./array.js";
|
|
2
|
-
/** Rank two values with a `Ranker`. */
|
|
3
|
-
export function rank(left, ranker, right) {
|
|
4
|
-
return typeof ranker === "function" ? ranker(left, right) : ranker.rank(left, right);
|
|
5
|
-
}
|
|
6
2
|
/**
|
|
7
|
-
*
|
|
3
|
+
* Compare two unknown values in ascending order.
|
|
8
4
|
* - Allows values of different types to be ranked for sorting.
|
|
9
5
|
*
|
|
10
6
|
* 1. Numbers and dates (ascending order: -Infinity, negative, zero, positive, Infinity, NaN)
|
|
@@ -20,7 +16,7 @@ export function rank(left, ranker, right) {
|
|
|
20
16
|
*
|
|
21
17
|
* @returns Number below zero if `a` is higher, number above zero if `b` is higher, or `0` if they're equally sorted.
|
|
22
18
|
*/
|
|
23
|
-
export function
|
|
19
|
+
export function compareAscending(left, right) {
|
|
24
20
|
// Exactly equal is easy.
|
|
25
21
|
if (left === right)
|
|
26
22
|
return 0;
|
|
@@ -72,8 +68,8 @@ export function rankAsc(left, right) {
|
|
|
72
68
|
// Otherwise a is higher.
|
|
73
69
|
return -1;
|
|
74
70
|
}
|
|
75
|
-
/**
|
|
76
|
-
export const
|
|
71
|
+
/** Compare two unknown values in descending order. */
|
|
72
|
+
export const compareDescending = (left, right) => 0 - compareAscending(left, right);
|
|
77
73
|
/**
|
|
78
74
|
* Quick sort algorithm.
|
|
79
75
|
* DH: We implement our own sorting algorithm so that:
|
|
@@ -81,13 +77,13 @@ export const rankDesc = (left, right) => 0 - rankAsc(left, right);
|
|
|
81
77
|
* 2. We can use our own comparison function by default.
|
|
82
78
|
*
|
|
83
79
|
* @param items The actual list of items that's sorted in place.
|
|
84
|
-
* @param
|
|
80
|
+
* @param compare A rank function that takes a left/right value and returns 1/0/-1 (like `Array.prototype.sort()`).
|
|
85
81
|
* @param leftPointer Index in the set of items to start sorting on.
|
|
86
82
|
* @param rightPointer Index in the set of items to stop sorting on.
|
|
87
83
|
*
|
|
88
84
|
* @return `true` if the array order changed, and `false` otherwise.
|
|
89
85
|
*/
|
|
90
|
-
function _quicksort(items,
|
|
86
|
+
function _quicksort(items, compare, args, leftPointer = 0, rightPointer = items.length - 1) {
|
|
91
87
|
// Have any swaps been made?
|
|
92
88
|
let changed = false;
|
|
93
89
|
// Calculate the middle value.
|
|
@@ -97,9 +93,9 @@ function _quicksort(items, ranker, leftPointer = 0, rightPointer = items.length
|
|
|
97
93
|
let l = leftPointer;
|
|
98
94
|
let r = rightPointer;
|
|
99
95
|
while (l <= r) {
|
|
100
|
-
while (
|
|
96
|
+
while (compare(items[l], middle, ...args) < 0)
|
|
101
97
|
l++; // eslint-disable-line @typescript-eslint/no-non-null-assertion
|
|
102
|
-
while (
|
|
98
|
+
while (compare(items[r], middle, ...args) > 0)
|
|
103
99
|
r--; // eslint-disable-line @typescript-eslint/no-non-null-assertion
|
|
104
100
|
if (l <= r) {
|
|
105
101
|
if (l < r) {
|
|
@@ -111,22 +107,22 @@ function _quicksort(items, ranker, leftPointer = 0, rightPointer = items.length
|
|
|
111
107
|
}
|
|
112
108
|
}
|
|
113
109
|
// Sort the lower and upper segments.
|
|
114
|
-
if (leftPointer < l - 1 && _quicksort(items,
|
|
110
|
+
if (leftPointer < l - 1 && _quicksort(items, compare, args, leftPointer, l - 1))
|
|
115
111
|
changed = true;
|
|
116
|
-
if (l < rightPointer && _quicksort(items,
|
|
112
|
+
if (l < rightPointer && _quicksort(items, compare, args, l, rightPointer))
|
|
117
113
|
changed = true;
|
|
118
114
|
// Changes were made.
|
|
119
115
|
return changed;
|
|
120
116
|
}
|
|
121
117
|
/** Sort an iterable set of items using a ranker (defaults to sorting in ascending order). */
|
|
122
|
-
export function
|
|
118
|
+
export function sortArray(input, compare = compareAscending, ...args) {
|
|
123
119
|
if (isArray(input)) {
|
|
124
120
|
if (input.length < 2)
|
|
125
121
|
return input;
|
|
126
122
|
const output = Array.from(input);
|
|
127
|
-
return _quicksort(output,
|
|
123
|
+
return _quicksort(output, compare, args) ? output : input;
|
|
128
124
|
}
|
|
129
|
-
const
|
|
130
|
-
_quicksort(
|
|
131
|
-
return
|
|
125
|
+
const output = Array.from(input);
|
|
126
|
+
_quicksort(output, compare, args);
|
|
127
|
+
return output;
|
|
132
128
|
}
|
package/util/transform.d.ts
CHANGED
|
@@ -3,57 +3,38 @@ import type { ImmutableDictionary, PossibleDictionary } from "./dictionary.js";
|
|
|
3
3
|
import type { Entry } from "./entry.js";
|
|
4
4
|
import type { Arguments } from "./function.js";
|
|
5
5
|
import type { ImmutableObject, ObjectValue } from "./object.js";
|
|
6
|
-
/** Object that transforms an input value into an output value with its `transform()` method. */
|
|
7
|
-
export interface Transformable<I, O, A extends Arguments = []> {
|
|
8
|
-
transform(input: I, ...args: A): O;
|
|
9
|
-
}
|
|
10
|
-
/** Object that transforms an input value into an output value with its `transform()` method. */
|
|
11
|
-
export interface AsyncTransformable<I, O, A extends Arguments = []> {
|
|
12
|
-
transform(input: I, ...args: A): O | PromiseLike<O>;
|
|
13
|
-
}
|
|
14
|
-
/** Is an unknown value a transformable. */
|
|
15
|
-
export declare const isTransformable: <T extends Transformable<unknown, unknown, Arguments>>(value: unknown) => value is T;
|
|
16
6
|
/** Function that can transform an input value into an output value. */
|
|
17
7
|
export type Transform<I, O, A extends Arguments = []> = (input: I, ...args: A) => O;
|
|
18
8
|
/** Function that can transform an input value into an output value. */
|
|
19
9
|
export type AsyncTransform<I, O, A extends Arguments = []> = (input: I, ...args: A) => O | PromiseLike<O>;
|
|
20
|
-
/**
|
|
21
|
-
export type
|
|
22
|
-
|
|
23
|
-
export type AsyncTransformer<I, O, A extends Arguments = []> = AsyncTransformable<I, O, A> | AsyncTransform<I, O, A> | O;
|
|
24
|
-
/** Set of named transformers for a data object (or `undefined` to skip the transform). */
|
|
25
|
-
export type Transformers<I extends ImmutableObject, O extends ImmutableObject, A extends Arguments = []> = {
|
|
26
|
-
readonly [K in keyof I]?: Transformer<I[K], O[K], A>;
|
|
10
|
+
/** Set of named transforms for a data object (or `undefined` to skip the transform). */
|
|
11
|
+
export type Transforms<I extends ImmutableObject, O extends ImmutableObject, A extends Arguments = []> = {
|
|
12
|
+
readonly [K in keyof I]?: Transform<I[K], O[K], A>;
|
|
27
13
|
};
|
|
28
|
-
/**
|
|
29
|
-
export declare function
|
|
30
|
-
export declare function
|
|
31
|
-
|
|
32
|
-
export declare function
|
|
33
|
-
|
|
34
|
-
export declare function
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
export declare function
|
|
38
|
-
export declare function
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
export declare function
|
|
43
|
-
export declare function mapObject<I extends ImmutableObject, O extends ImmutableObject, A extends Arguments = []>(obj: I, transformer: Transformer<ObjectValue<I>, ObjectValue<O>>, ...args: A): O;
|
|
44
|
-
/** Modify the values of a dictionary using a transformer. */
|
|
45
|
-
export declare const mapDictionary: <I, O, A extends Arguments = []>(dictionary: PossibleDictionary<I>, transformer: Transformer<I, O, A>, ...args: A) => ImmutableDictionary<O>;
|
|
46
|
-
/** Modify the values of a set of entries using a transformer. */
|
|
47
|
-
export declare function mapEntries<K, I, O, A extends Arguments = []>(entries: Iterable<Entry<K, I>>, transformer: Transformer<I, O, A>, ...args: A): Iterable<Entry<K, O>>;
|
|
14
|
+
/** Modify a set of items using a transform. */
|
|
15
|
+
export declare function mapItems<I, O, A extends Arguments = []>(items: Iterable<I>, transform: (v: I, ...args: A) => O, ...args: A): Iterable<O>;
|
|
16
|
+
export declare function mapItems<I, O, A extends Arguments = []>(items: Iterable<I>, transform: Transform<I, O, A>, ...args: A): Iterable<O>;
|
|
17
|
+
/** Modify the items of an array using a transform. */
|
|
18
|
+
export declare function mapArray<T extends ImmutableArray>(arr: T, transform: Transform<ArrayItem<T>, ArrayItem<T>>): T;
|
|
19
|
+
export declare function mapArray<I, O, A extends Arguments = []>(arr: Iterable<I>, transform: (v: I, ...args: A) => O, ...args: A): ImmutableArray<O>;
|
|
20
|
+
export declare function mapArray<I, O, A extends Arguments = []>(arr: Iterable<I>, transform: Transform<I, O, A>, ...args: A): ImmutableArray<O>;
|
|
21
|
+
/** Modify the values of the props of an object using a transform. */
|
|
22
|
+
export declare function mapObject<T extends ImmutableObject>(obj: T, transform: Transform<ObjectValue<T>, ObjectValue<T>>): T;
|
|
23
|
+
export declare function mapObject<I extends ImmutableObject, O extends ImmutableObject, A extends Arguments = []>(obj: I, transform: (v: ObjectValue<I>, ...args: A) => ObjectValue<O>, ...args: A): O;
|
|
24
|
+
export declare function mapObject<I extends ImmutableObject, O extends ImmutableObject, A extends Arguments = []>(obj: I, transform: Transform<ObjectValue<I>, ObjectValue<O>, A>, ...args: A): O;
|
|
25
|
+
/** Modify the values of a dictionary using a transform. */
|
|
26
|
+
export declare const mapDictionary: <I, O, A extends Arguments = []>(dictionary: PossibleDictionary<I>, transform: Transform<I, O, A>, ...args: A) => ImmutableDictionary<O>;
|
|
27
|
+
/** Modify the values of a set of entries using a transform. */
|
|
28
|
+
export declare function mapEntries<K, I, O, A extends Arguments = []>(entries: Iterable<Entry<K, I>>, transform: Transform<I, O, A>, ...args: A): Iterable<Entry<K, O>>;
|
|
48
29
|
/**
|
|
49
|
-
* Transform an object using a set of named
|
|
30
|
+
* Transform an object using a set of named transforms.
|
|
50
31
|
*
|
|
51
32
|
* @returns Transformed object (or same object if no changes were made).
|
|
52
33
|
*/
|
|
53
|
-
export declare function transformObject<T extends ImmutableObject, A extends Arguments = []>(obj: T, transforms:
|
|
54
|
-
export declare function transformObject<T extends ImmutableObject, A extends Arguments = []>(obj: T | Partial<T>, transforms:
|
|
55
|
-
export declare function transformObject<I extends ImmutableObject, O extends ImmutableObject, A extends Arguments = []>(obj: I, transforms:
|
|
56
|
-
export declare function transformObject<I extends ImmutableObject, O extends ImmutableObject, A extends Arguments = []>(obj: I | Partial<I>, transforms:
|
|
57
|
-
/** Transform items in a sequence as they are yielded using a (potentially async)
|
|
58
|
-
export declare function mapSequence<I, O, A extends Arguments = []>(sequence: AsyncIterable<I>,
|
|
59
|
-
export declare function mapSequence<I, O, A extends Arguments = []>(sequence: AsyncIterable<I>,
|
|
34
|
+
export declare function transformObject<T extends ImmutableObject, A extends Arguments = []>(obj: T, transforms: Transforms<T, T | Partial<T>, A>, ...args: A): T;
|
|
35
|
+
export declare function transformObject<T extends ImmutableObject, A extends Arguments = []>(obj: T | Partial<T>, transforms: Transforms<T, T | Partial<T>, A>, ...args: A): Partial<T>;
|
|
36
|
+
export declare function transformObject<I extends ImmutableObject, O extends ImmutableObject, A extends Arguments = []>(obj: I, transforms: Transforms<I, O | Partial<O>, A>, ...args: A): O;
|
|
37
|
+
export declare function transformObject<I extends ImmutableObject, O extends ImmutableObject, A extends Arguments = []>(obj: I | Partial<I>, transforms: Transforms<I, O | Partial<O>, A>, ...args: A): Partial<O>;
|
|
38
|
+
/** Transform items in a sequence as they are yielded using a (potentially async) transform. */
|
|
39
|
+
export declare function mapSequence<I, O, A extends Arguments = []>(sequence: AsyncIterable<I>, transform: (input: I, ...args: A) => O | PromiseLike<O>, ...args: A): AsyncIterable<O>;
|
|
40
|
+
export declare function mapSequence<I, O, A extends Arguments = []>(sequence: AsyncIterable<I>, transform: AsyncTransform<I, O, A>, ...args: A): AsyncIterable<O>;
|
package/util/transform.js
CHANGED
|
@@ -1,46 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
/** Is an unknown value a transformable. */
|
|
4
|
-
export const isTransformable = (value) => isObject(value) && typeof value.transform === "function";
|
|
5
|
-
export function transform(input, transformer, ...args) {
|
|
6
|
-
return isFunction(transformer) ? transformer(input, ...args) : isTransformable(transformer) ? transformer.transform(input, ...args) : transformer;
|
|
7
|
-
}
|
|
8
|
-
export function* mapItems(items, transformer, ...args) {
|
|
1
|
+
import { getProps } from "./object.js";
|
|
2
|
+
export function* mapItems(items, transform, ...args) {
|
|
9
3
|
for (const item of items)
|
|
10
|
-
yield transform(item,
|
|
4
|
+
yield transform(item, ...args);
|
|
11
5
|
}
|
|
12
|
-
export function mapArray(arr,
|
|
13
|
-
return Array.from(mapItems(arr,
|
|
6
|
+
export function mapArray(arr, transform, ...args) {
|
|
7
|
+
return Array.from(mapItems(arr, transform, ...args));
|
|
14
8
|
}
|
|
15
|
-
export function mapObject(obj,
|
|
16
|
-
return Object.fromEntries(mapEntries(getProps(obj),
|
|
9
|
+
export function mapObject(obj, transform, ...args) {
|
|
10
|
+
return Object.fromEntries(mapEntries(getProps(obj), transform, ...args));
|
|
17
11
|
}
|
|
18
|
-
/** Modify the values of a dictionary using a
|
|
12
|
+
/** Modify the values of a dictionary using a transform. */
|
|
19
13
|
export const mapDictionary = mapObject;
|
|
20
|
-
/** Modify the values of a set of entries using a
|
|
21
|
-
export function* mapEntries(entries,
|
|
14
|
+
/** Modify the values of a set of entries using a transform. */
|
|
15
|
+
export function* mapEntries(entries, transform, ...args) {
|
|
22
16
|
for (const [k, v] of entries)
|
|
23
|
-
yield [k, transform(v,
|
|
17
|
+
yield [k, transform(v, ...args)];
|
|
24
18
|
}
|
|
25
19
|
export function transformObject(input, transforms, ...args) {
|
|
26
20
|
let changed = false;
|
|
27
21
|
const output = { ...input };
|
|
28
22
|
for (const [k, t] of getProps(transforms)) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
23
|
+
if (t) {
|
|
24
|
+
const i = input[k];
|
|
25
|
+
const o = t(i, ...args);
|
|
26
|
+
if (t === undefined) {
|
|
27
|
+
delete output[k];
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
output[k] = o;
|
|
31
|
+
if (!changed && i !== o)
|
|
32
|
+
changed = true;
|
|
33
|
+
}
|
|
39
34
|
}
|
|
40
35
|
}
|
|
41
36
|
return changed ? output : input;
|
|
42
37
|
}
|
|
43
|
-
export async function* mapSequence(sequence,
|
|
38
|
+
export async function* mapSequence(sequence, transform, ...args) {
|
|
44
39
|
for await (const item of sequence)
|
|
45
|
-
yield transform(item,
|
|
40
|
+
yield transform(item, ...args);
|
|
46
41
|
}
|
package/util/update.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ImmutableArray } from "./array.js";
|
|
2
|
+
import type { Data, FlatData, FlatDataKey } from "./data.js";
|
|
3
|
+
/** Set of named updates for a data object. */
|
|
4
|
+
export type Updates<T extends Data = Data> = {
|
|
5
|
+
readonly [K in FlatDataKey<T> as K | `${K}`]?: FlatData<T>[K];
|
|
6
|
+
} & {
|
|
7
|
+
readonly [K in FlatDataKey<T> as `${K}+=` | `${K}-=`]?: FlatData<T>[K] extends number ? FlatData<T>[K] : never;
|
|
8
|
+
};
|
|
9
|
+
/** A single update to a keyed property in an object. */
|
|
10
|
+
export type Update = {
|
|
11
|
+
action: "set";
|
|
12
|
+
keys: ImmutableArray<string>;
|
|
13
|
+
value: unknown;
|
|
14
|
+
} | {
|
|
15
|
+
action: "sum";
|
|
16
|
+
keys: ImmutableArray<string>;
|
|
17
|
+
value: number;
|
|
18
|
+
};
|
|
19
|
+
/** Yield the prop updates in an `Updates` object as a set of `Update` objects. */
|
|
20
|
+
export declare function getUpdates<T extends Data>(data: Updates<T>): ImmutableArray<Update>;
|
|
21
|
+
/** Update a data object with a set of updates. */
|
|
22
|
+
export declare function updateData<T extends Data>(data: T, updates: Updates<T>): T;
|
package/util/update.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { AssertionError } from "../error/AssertionError.js";
|
|
2
|
+
import { reduceItems } from "./iterate.js";
|
|
3
|
+
import { getNumber } from "./number.js";
|
|
4
|
+
import { getProps, isObject } from "./object.js";
|
|
5
|
+
/** Yield the prop updates in an `Updates` object as a set of `Update` objects. */
|
|
6
|
+
export function getUpdates(data) {
|
|
7
|
+
return getProps(data).map(_getUpdate);
|
|
8
|
+
}
|
|
9
|
+
function _getUpdate([keys, value]) {
|
|
10
|
+
if (keys.endsWith("+="))
|
|
11
|
+
return { action: "sum", keys: keys.slice(0, -2).split("."), value: getNumber(value) };
|
|
12
|
+
else if (keys.endsWith("-="))
|
|
13
|
+
return { action: "sum", keys: keys.slice(0, -2).split("."), value: 0 - getNumber(value) };
|
|
14
|
+
else
|
|
15
|
+
return { action: "set", keys: keys.split("."), value };
|
|
16
|
+
}
|
|
17
|
+
/** Update a data object with a set of updates. */
|
|
18
|
+
export function updateData(data, updates) {
|
|
19
|
+
return reduceItems(getUpdates(updates), _updateProp, data);
|
|
20
|
+
}
|
|
21
|
+
function _updateProp(obj, update, i = 0) {
|
|
22
|
+
const { action, keys, value } = update;
|
|
23
|
+
const key = keys[i];
|
|
24
|
+
if (!key)
|
|
25
|
+
return obj; // Shouldn't happen.
|
|
26
|
+
const oldValue = obj[key];
|
|
27
|
+
let newValue = oldValue;
|
|
28
|
+
if (i === keys.length - 1) {
|
|
29
|
+
if (action === "sum")
|
|
30
|
+
newValue = typeof oldValue === "number" ? oldValue + value : value;
|
|
31
|
+
else if (action === "set")
|
|
32
|
+
newValue = value;
|
|
33
|
+
else
|
|
34
|
+
return action; // Never happens.
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
if (!isObject(oldValue))
|
|
38
|
+
throw new AssertionError(`Prop "${keys.slice(0, i + 1).join(".")}" is not an object`);
|
|
39
|
+
newValue = _updateProp(oldValue, update, i + 1);
|
|
40
|
+
}
|
|
41
|
+
return oldValue === newValue ? obj : { ...obj, [key]: newValue };
|
|
42
|
+
}
|
package/util/validate.js
CHANGED
|
@@ -105,10 +105,10 @@ export function validateDictionary(unsafeDictionary, validator) {
|
|
|
105
105
|
* - `feedback.details` will contain an entry for each invalid item (keyed by their count in the input iterable).
|
|
106
106
|
*/
|
|
107
107
|
export function validateData(unsafeData, validators) {
|
|
108
|
-
const { partial = false } = getValidationContext();
|
|
108
|
+
const { partial = false, id = false } = getValidationContext();
|
|
109
109
|
let valid = true;
|
|
110
110
|
let changed = true;
|
|
111
|
-
const safeData = {};
|
|
111
|
+
const safeData = id && typeof unsafeData.id === "string" ? { id: unsafeData.id } : {};
|
|
112
112
|
const feedbacks = {};
|
|
113
113
|
for (const [key, validator] of getDataProps(validators)) {
|
|
114
114
|
const unsafeValue = unsafeData[key];
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Data } from "../util/data.js";
|
|
2
|
-
import type { Transformable } from "../util/transform.js";
|
|
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
|
-
abstract transform(items: Iterable<T>): Iterable<T>;
|
|
6
|
-
abstract toString(): string;
|
|
7
|
-
}
|
package/constraint/Constraint.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { ImmutableArray } from "../util/array.js";
|
|
2
|
-
import type { Data } from "../util/data.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<Partial<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
|
-
omit(...constraints: C[]): this;
|
|
18
|
-
/** Iterate over the constraints. */
|
|
19
|
-
[Symbol.iterator](): Iterator<C, void>;
|
|
20
|
-
}
|