shelving 1.92.0 → 1.92.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/db/Database.d.ts +3 -3
- package/db/ItemReference.js +3 -3
- package/db/ItemState.js +2 -2
- package/db/QueryReference.js +3 -3
- package/db/QueryState.js +2 -2
- package/firestore/client/FirestoreClientProvider.js +7 -10
- package/firestore/lite/FirestoreLiteProvider.js +7 -10
- package/firestore/server/FirestoreServerProvider.js +7 -10
- package/package.json +1 -1
- package/state/DataState.js +2 -2
- package/util/data.d.ts +31 -9
- package/util/data.js +14 -8
- package/util/null.d.ts +2 -0
- package/util/null.js +7 -0
- package/util/object.d.ts +24 -37
- package/util/object.js +3 -4
- package/util/query.d.ts +21 -21
- package/util/query.js +36 -38
- package/util/transform.d.ts +5 -5
- package/util/transform.js +5 -2
- package/util/update.d.ts +7 -5
- package/util/update.js +23 -15
package/db/Database.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ declare abstract class AbstractDatabase<T extends Datas> {
|
|
|
13
13
|
/** Create a query on a collection in this database. */
|
|
14
14
|
abstract collection<K extends DataKey<T>>(collection: K): CollectionReference<T[K]> | AsyncCollectionReference<T[K]>;
|
|
15
15
|
/** Create a query on a collection in this database. */
|
|
16
|
-
abstract query<K extends DataKey<T>>(collection: K, query?: ItemQuery<T>): QueryReference<T[K]> | AsyncQueryReference<T[K]>;
|
|
16
|
+
abstract query<K extends DataKey<T>>(collection: K, query?: ItemQuery<T[K]>): QueryReference<T[K]> | AsyncQueryReference<T[K]>;
|
|
17
17
|
/** Reference an item in a collection in this database. */
|
|
18
18
|
abstract item<K extends DataKey<T>>(collection: K, id: string): ItemReference<T[K]> | AsyncItemReference<T[K]>;
|
|
19
19
|
/** Run a set of changes in this database. */
|
|
@@ -42,7 +42,7 @@ export declare class Database<T extends Datas = Datas> extends AbstractDatabase<
|
|
|
42
42
|
readonly provider: Provider;
|
|
43
43
|
constructor(provider: Provider);
|
|
44
44
|
collection<K extends DataKey<T>>(collection: K): CollectionReference<T[K]>;
|
|
45
|
-
query<K extends DataKey<T>>(collection: K, query?: ItemQuery<T>): QueryReference<T[K]>;
|
|
45
|
+
query<K extends DataKey<T>>(collection: K, query?: ItemQuery<T[K]>): QueryReference<T[K]>;
|
|
46
46
|
item<K extends DataKey<T>>(collection: K, id: string): ItemReference<T[K]>;
|
|
47
47
|
change(...changes: Nullish<WriteChange<Data>>[]): ItemChanges;
|
|
48
48
|
get<K extends DataKey<T>>(collection: K, id: string): ItemValue<T[K]>;
|
|
@@ -56,7 +56,7 @@ export declare class AsyncDatabase<T extends Datas = Datas> extends AbstractData
|
|
|
56
56
|
readonly provider: AsyncProvider;
|
|
57
57
|
constructor(provider: AsyncProvider);
|
|
58
58
|
collection<K extends DataKey<T>>(collection: K): AsyncCollectionReference<T[K]>;
|
|
59
|
-
query<K extends DataKey<T>>(collection: K, query?: ItemQuery<T>): AsyncQueryReference<T[K]>;
|
|
59
|
+
query<K extends DataKey<T>>(collection: K, query?: ItemQuery<T[K]>): AsyncQueryReference<T[K]>;
|
|
60
60
|
item<K extends DataKey<T>>(collection: K, id: string): AsyncItemReference<T[K]>;
|
|
61
61
|
change(...changes: Nullish<WriteChange<Data>>[]): Promise<ItemChanges>;
|
|
62
62
|
get<K extends DataKey<T>>(collection: K, id: string): Promise<ItemValue<T[K]>>;
|
package/db/ItemReference.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getRequired } from "../util/null.js";
|
|
2
2
|
import { runSequence } from "../util/sequence.js";
|
|
3
3
|
/** Get the ID from item data. */
|
|
4
4
|
export const getID = ({ id }) => id;
|
|
@@ -53,7 +53,7 @@ export class ItemReference extends AbstractItemReference {
|
|
|
53
53
|
return this.provider.getItem(this.collection, this.id);
|
|
54
54
|
}
|
|
55
55
|
get data() {
|
|
56
|
-
return
|
|
56
|
+
return getRequired(this.value);
|
|
57
57
|
}
|
|
58
58
|
set(data) {
|
|
59
59
|
return this.provider.setItem(this.collection, this.id, data);
|
|
@@ -78,7 +78,7 @@ export class AsyncItemReference extends AbstractItemReference {
|
|
|
78
78
|
return this.provider.getItem(this.collection, this.id);
|
|
79
79
|
}
|
|
80
80
|
get data() {
|
|
81
|
-
return this.value.then(
|
|
81
|
+
return this.value.then(getRequired);
|
|
82
82
|
}
|
|
83
83
|
set(data) {
|
|
84
84
|
return this.provider.setItem(this.collection, this.id, data);
|
package/db/ItemState.js
CHANGED
|
@@ -2,13 +2,13 @@ import { CacheProvider } from "../provider/CacheProvider.js";
|
|
|
2
2
|
import { LazyDeferredSequence } from "../sequence/LazyDeferredSequence.js";
|
|
3
3
|
import { BooleanState } from "../state/BooleanState.js";
|
|
4
4
|
import { State } from "../state/State.js";
|
|
5
|
-
import {
|
|
5
|
+
import { getRequired } from "../util/null.js";
|
|
6
6
|
import { getOptionalSource } from "../util/source.js";
|
|
7
7
|
/** Hold the current state of a item. */
|
|
8
8
|
export class ItemState extends State {
|
|
9
9
|
/** Get the data of the item (throws `RequiredError` if item doesn't exist). */
|
|
10
10
|
get data() {
|
|
11
|
-
return
|
|
11
|
+
return getRequired(this.value);
|
|
12
12
|
}
|
|
13
13
|
/** Does the item exist (i.e. its value isn't `null`)? */
|
|
14
14
|
get exists() {
|
package/db/QueryReference.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { countArray, getOptionalFirstItem, getOptionalLastItem, isArrayLength } from "../util/array.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getRequired } from "../util/null.js";
|
|
3
3
|
import { cloneObjectWith } from "../util/object.js";
|
|
4
4
|
import { runSequence } from "../util/sequence.js";
|
|
5
5
|
/** Reference to a set of items in a sync or async provider. */
|
|
@@ -47,7 +47,7 @@ export class QueryReference extends AbstractQueryReference {
|
|
|
47
47
|
return getOptionalLastItem(this.items);
|
|
48
48
|
}
|
|
49
49
|
get data() {
|
|
50
|
-
return
|
|
50
|
+
return getRequired(this.first);
|
|
51
51
|
}
|
|
52
52
|
set(data) {
|
|
53
53
|
return this.provider.setQuery(this.collection, this.query, data);
|
|
@@ -81,7 +81,7 @@ export class AsyncQueryReference extends AbstractQueryReference {
|
|
|
81
81
|
return this.items.then(getOptionalLastItem);
|
|
82
82
|
}
|
|
83
83
|
get data() {
|
|
84
|
-
return this.first.then(
|
|
84
|
+
return this.first.then(getRequired);
|
|
85
85
|
}
|
|
86
86
|
set(data) {
|
|
87
87
|
return this.provider.setQuery(this.collection, this.query, data);
|
package/db/QueryState.js
CHANGED
|
@@ -3,7 +3,7 @@ import { LazyDeferredSequence } from "../sequence/LazyDeferredSequence.js";
|
|
|
3
3
|
import { BooleanState } from "../state/BooleanState.js";
|
|
4
4
|
import { State } from "../state/State.js";
|
|
5
5
|
import { getOptionalFirstItem, getOptionalLastItem } from "../util/array.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getRequired } from "../util/null.js";
|
|
7
7
|
import { getAfterQuery, getLimit } from "../util/query.js";
|
|
8
8
|
import { getOptionalSource } from "../util/source.js";
|
|
9
9
|
/** Hold the current state of a query. */
|
|
@@ -26,7 +26,7 @@ export class QueryState extends State {
|
|
|
26
26
|
}
|
|
27
27
|
/** Get the first document matched by this query. */
|
|
28
28
|
get data() {
|
|
29
|
-
return
|
|
29
|
+
return getRequired(this.first);
|
|
30
30
|
}
|
|
31
31
|
/** Does the document have at least one result. */
|
|
32
32
|
get exists() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { addDoc, collection, deleteDoc, doc, documentId, getDoc, getDocs, increment, limit, onSnapshot, orderBy, query, setDoc, updateDoc, where } from "firebase/firestore";
|
|
2
2
|
import { LazyDeferredSequence } from "../../sequence/LazyDeferredSequence.js";
|
|
3
3
|
import { getObject } from "../../util/object.js";
|
|
4
|
-
import { getFilters,
|
|
4
|
+
import { getFilters, getLimit, getOrders } from "../../util/query.js";
|
|
5
5
|
import { mapItems } from "../../util/transform.js";
|
|
6
6
|
import { getUpdates } from "../../util/update.js";
|
|
7
7
|
// Constants.
|
|
@@ -23,16 +23,13 @@ function _getQuery(firestore, c, q) {
|
|
|
23
23
|
return query(collection(firestore, c), ..._getConstraints(q));
|
|
24
24
|
}
|
|
25
25
|
function* _getConstraints(q) {
|
|
26
|
-
for (const {
|
|
27
|
-
const key = keys.join(".");
|
|
26
|
+
for (const { key, direction } of getOrders(q))
|
|
28
27
|
yield orderBy(key === "id" ? ID : key, direction);
|
|
29
|
-
}
|
|
30
|
-
for (const { keys, operator, value } of getFilters(q)) {
|
|
31
|
-
const key = keys.join(".");
|
|
28
|
+
for (const { key, operator, value } of getFilters(q))
|
|
32
29
|
yield where(key === "id" ? ID : key, OPERATORS[operator], value);
|
|
33
|
-
|
|
34
|
-
if (typeof
|
|
35
|
-
yield limit(
|
|
30
|
+
const l = getLimit(q);
|
|
31
|
+
if (typeof l === "number")
|
|
32
|
+
yield limit(l);
|
|
36
33
|
}
|
|
37
34
|
function _getItems(snapshot) {
|
|
38
35
|
return snapshot.docs.map(_getItemData);
|
|
@@ -47,7 +44,7 @@ function _getItemValue(snapshot) {
|
|
|
47
44
|
}
|
|
48
45
|
/** Convert `Updates` object into corresponding Firestore `FieldValue` instances. */
|
|
49
46
|
const _getFieldValues = (updates) => getObject(mapItems(getUpdates(updates), _getFieldValue));
|
|
50
|
-
const _getFieldValue = ({
|
|
47
|
+
const _getFieldValue = ({ key, action, value }) => [key, action === "sum" ? increment(value) : action === "set" ? value : action];
|
|
51
48
|
/**
|
|
52
49
|
* Firestore client database provider.
|
|
53
50
|
* - Works with the Firebase JS SDK.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { addDoc, collection, deleteDoc, doc, documentId, getDoc, getDocs, increment, limit, orderBy, query, setDoc, updateDoc, where } from "firebase/firestore/lite";
|
|
2
2
|
import { UnsupportedError } from "../../error/UnsupportedError.js";
|
|
3
3
|
import { getObject } from "../../util/object.js";
|
|
4
|
-
import { getFilters,
|
|
4
|
+
import { getFilters, getLimit, getOrders } from "../../util/query.js";
|
|
5
5
|
import { mapItems } from "../../util/transform.js";
|
|
6
6
|
import { getUpdates } from "../../util/update.js";
|
|
7
7
|
// Constants.
|
|
@@ -23,16 +23,13 @@ function _getQuery(firestore, c, q) {
|
|
|
23
23
|
return query(collection(firestore, c), ..._getConstraints(q));
|
|
24
24
|
}
|
|
25
25
|
function* _getConstraints(q) {
|
|
26
|
-
for (const {
|
|
27
|
-
const key = keys.join(".");
|
|
26
|
+
for (const { key, direction } of getOrders(q))
|
|
28
27
|
yield orderBy(key === "id" ? ID : key, direction);
|
|
29
|
-
}
|
|
30
|
-
for (const { keys, operator, value } of getFilters(q)) {
|
|
31
|
-
const key = keys.join(".");
|
|
28
|
+
for (const { key, operator, value } of getFilters(q))
|
|
32
29
|
yield where(key === "id" ? ID : key, OPERATORS[operator], value);
|
|
33
|
-
|
|
34
|
-
if (typeof
|
|
35
|
-
yield limit(
|
|
30
|
+
const l = getLimit(q);
|
|
31
|
+
if (typeof l === "number")
|
|
32
|
+
yield limit(l);
|
|
36
33
|
}
|
|
37
34
|
function _getItemData(snapshot) {
|
|
38
35
|
const data = snapshot.data();
|
|
@@ -44,7 +41,7 @@ function _getItemValue(snapshot) {
|
|
|
44
41
|
}
|
|
45
42
|
/** Convert `Updates` object into corresponding Firestore `FieldValue` instances. */
|
|
46
43
|
const _getFieldValues = (updates) => getObject(mapItems(getUpdates(updates), _getFieldValue));
|
|
47
|
-
const _getFieldValue = ({
|
|
44
|
+
const _getFieldValue = ({ key, action, value }) => [key, action === "sum" ? increment(value) : action === "set" ? value : action];
|
|
48
45
|
/**
|
|
49
46
|
* Firestore Lite client database provider.
|
|
50
47
|
* - Works with the Firebase JS SDK.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FieldPath, FieldValue, Firestore } from "@google-cloud/firestore";
|
|
2
2
|
import { LazyDeferredSequence } from "../../sequence/LazyDeferredSequence.js";
|
|
3
3
|
import { getObject } from "../../util/object.js";
|
|
4
|
-
import { getFilters,
|
|
4
|
+
import { getFilters, getLimit, getOrders } from "../../util/query.js";
|
|
5
5
|
import { mapItems } from "../../util/transform.js";
|
|
6
6
|
import { getUpdates } from "../../util/update.js";
|
|
7
7
|
// Constants.
|
|
@@ -21,16 +21,13 @@ const OPERATORS = {
|
|
|
21
21
|
/** Create a corresponding `QueryReference` from a Query. */
|
|
22
22
|
function _getQuery(firestore, c, q) {
|
|
23
23
|
let query = firestore.collection(c);
|
|
24
|
-
for (const {
|
|
25
|
-
const key = keys.join(".");
|
|
24
|
+
for (const { key, direction } of getOrders(q))
|
|
26
25
|
query = query.orderBy(key === "id" ? ID : key, direction);
|
|
27
|
-
}
|
|
28
|
-
for (const { keys, operator, value } of getFilters(q)) {
|
|
29
|
-
const key = keys.join(".");
|
|
26
|
+
for (const { key, operator, value } of getFilters(q))
|
|
30
27
|
query = query.where(key === "id" ? ID : key, OPERATORS[operator], value);
|
|
31
|
-
|
|
32
|
-
if (typeof
|
|
33
|
-
query = query.limit(
|
|
28
|
+
const l = getLimit(q);
|
|
29
|
+
if (typeof l === "number")
|
|
30
|
+
query = query.limit(l);
|
|
34
31
|
return query;
|
|
35
32
|
}
|
|
36
33
|
function _getItemArray(snapshot) {
|
|
@@ -46,7 +43,7 @@ function _getItemValue(snapshot) {
|
|
|
46
43
|
}
|
|
47
44
|
/** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
|
|
48
45
|
const _getFieldValues = (updates) => getObject(mapItems(getUpdates(updates), _getFieldValue));
|
|
49
|
-
const _getFieldValue = ({
|
|
46
|
+
const _getFieldValue = ({ key, action, value }) => [key, action === "sum" ? FieldValue.increment(value) : action === "set" ? value : action];
|
|
50
47
|
/**
|
|
51
48
|
* Firestore server database provider.
|
|
52
49
|
* - Works with the Firebase Admin SDK for Node.JS
|
package/package.json
CHANGED
package/state/DataState.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getRequired } from "../util/null.js";
|
|
2
2
|
import { withProp } from "../util/object.js";
|
|
3
3
|
import { updateData } from "../util/update.js";
|
|
4
4
|
import { State } from "./State.js";
|
|
@@ -25,7 +25,7 @@ export class DataState extends State {
|
|
|
25
25
|
export class OptionalDataState extends State {
|
|
26
26
|
/** Get current data value of this state (or throw `Promise` that resolves to the next required value). */
|
|
27
27
|
get data() {
|
|
28
|
-
return
|
|
28
|
+
return getRequired(this.value);
|
|
29
29
|
}
|
|
30
30
|
/** Does the data exist or not? */
|
|
31
31
|
get exists() {
|
package/util/data.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ImmutableArray } from "./array.js";
|
|
2
2
|
import type { EntryObject } from "./entry.js";
|
|
3
|
+
import type { DeepPartial } from "./object.js";
|
|
3
4
|
/** Data object. */
|
|
4
5
|
export type Data = {
|
|
5
6
|
readonly [K in string]: unknown;
|
|
@@ -18,30 +19,51 @@ export type OptionalData<T extends Data> = T | null;
|
|
|
18
19
|
export type Datas = {
|
|
19
20
|
readonly [K in string]: Data;
|
|
20
21
|
};
|
|
21
|
-
/**
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Flattened data object with every branch node of the data, flattened into `a.c.b` format.
|
|
24
|
+
* - Includes all branches, i.e. `{ a: { a2: number } }` will be `{ "a": object, "a.a2": number }`
|
|
25
|
+
*/
|
|
26
|
+
export type BranchData<T extends Data> = EntryObject<BranchProp<T>>;
|
|
23
27
|
/** Key for a flattened data object with deep keys flattened into `a.c.b` format. */
|
|
24
|
-
export type
|
|
28
|
+
export type BranchKey<T extends Data> = BranchProp<T>[0];
|
|
25
29
|
/** Value for a flattened data object with deep keys flattened into `a.c.b` format. */
|
|
26
|
-
export type
|
|
30
|
+
export type BranchValue<T extends Data> = BranchProp<T>[1];
|
|
27
31
|
/** Prop for a flattened data object with deep keys flattened into `a.c.b` format. */
|
|
28
|
-
export type
|
|
29
|
-
readonly [K in DataKey<T>]: (T[K] extends Data ?
|
|
32
|
+
export type BranchProp<T extends Data> = {
|
|
33
|
+
readonly [K in DataKey<T>]: (T[K] extends Data ? readonly [null, T[K]] | BranchProp<T[K]> : readonly [null, T[K]]) extends infer E ? E extends readonly [infer KK, infer VV] ? readonly [KK extends string ? `${K}.${KK}` : K, VV] : never : never;
|
|
34
|
+
}[DataKey<T>];
|
|
35
|
+
/**
|
|
36
|
+
* Flattened data object with only leaf nodes of the data, flattened into `a.c.b` format.
|
|
37
|
+
* - Only include leaf nodes, i.e. `{ a: { a2: number } }` will be `{ "a.a2": number }`
|
|
38
|
+
*/
|
|
39
|
+
export type LeafData<T extends Data> = EntryObject<LeafProp<T>>;
|
|
40
|
+
/** Key for a flattened data object with deep keys flattened into `a.c.b` format. */
|
|
41
|
+
export type LeafKey<T extends Data> = LeafProp<T>[0];
|
|
42
|
+
/** Value for a flattened data object with deep keys flattened into `a.c.b` format. */
|
|
43
|
+
export type LeafValue<T extends Data> = LeafProp<T>[1];
|
|
44
|
+
/** Prop for a flattened data object with deep keys flattened into `a.c.b` format. */
|
|
45
|
+
export type LeafProp<T extends Data> = {
|
|
46
|
+
readonly [K in DataKey<T>]: (T[K] extends Data ? LeafProp<T[K]> : readonly [null, T[K]]) extends infer E ? E extends readonly [infer KK, infer VV] ? readonly [KK extends string ? `${K}.${KK}` : K, VV] : never : never;
|
|
30
47
|
}[DataKey<T>];
|
|
31
48
|
/** Is an unknown value a data object? */
|
|
32
49
|
export declare const isData: <T extends Data>(value: unknown) => value is T;
|
|
33
50
|
/** Assert that an unknown value is a data object. */
|
|
34
51
|
export declare function assertData<T extends Data>(value: T | unknown): asserts value is T;
|
|
35
52
|
/** Is an unknown value the key for an own prop of a data object. */
|
|
36
|
-
export declare const isDataProp: <T extends Data>(
|
|
37
|
-
/**
|
|
38
|
-
export declare function getData<T extends Data>(
|
|
53
|
+
export declare const isDataProp: <T extends Data>(data: T, key: unknown) => key is DataKey<T>;
|
|
54
|
+
/** Convert a data object or set of `DataProp` props for that object back into the full object. */
|
|
55
|
+
export declare function getData<T extends Data>(input: T): T;
|
|
56
|
+
export declare function getData<T extends Data>(input: T | Iterable<DataProp<T>>): Partial<T>;
|
|
39
57
|
/** Get the props of a data object as a set of entries. */
|
|
40
58
|
export declare function getDataProps<T extends Data>(data: T): ImmutableArray<DataProp<T>>;
|
|
41
59
|
export declare function getDataProps<T extends Data>(data: T | Partial<T>): ImmutableArray<DataProp<T>>;
|
|
42
60
|
/** Get the props of a data object as a set of entries. */
|
|
43
61
|
export declare function getDataKeys<T extends Data>(data: T): ImmutableArray<DataKey<T>>;
|
|
44
62
|
export declare function getDataKeys<T extends Data>(data: T | Partial<T>): ImmutableArray<DataKey<T>>;
|
|
63
|
+
/** Get a (possibly deep) prop from a data object. */
|
|
64
|
+
export declare function getDataProp<T extends Data, K extends BranchKey<T>>(data: T, key: K): BranchData<T>[K];
|
|
65
|
+
export declare function getDataProp<T extends Data, K extends BranchKey<T>>(data: DeepPartial<T>, key: K): BranchData<T>[K] | undefined;
|
|
66
|
+
export declare function getDataProp(data: Data, key: string): unknown;
|
|
45
67
|
/** Type that represents an empty data object. */
|
|
46
68
|
export type EmptyData = {
|
|
47
69
|
readonly [K in never]: never;
|
package/util/data.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AssertionError } from "../error/AssertionError.js";
|
|
2
|
-
import {
|
|
3
|
-
import { isPlainObject } from "./object.js";
|
|
2
|
+
import { isIterable } from "./iterate.js";
|
|
3
|
+
import { isObject, isPlainObject } from "./object.js";
|
|
4
4
|
/** Is an unknown value a data object? */
|
|
5
5
|
export const isData = (value) => isPlainObject(value);
|
|
6
6
|
/** Assert that an unknown value is a data object. */
|
|
@@ -9,12 +9,9 @@ export function assertData(value) {
|
|
|
9
9
|
throw new AssertionError("Must be data", value);
|
|
10
10
|
}
|
|
11
11
|
/** Is an unknown value the key for an own prop of a data object. */
|
|
12
|
-
export const isDataProp = (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (!result)
|
|
16
|
-
throw new RequiredError("Data is required");
|
|
17
|
-
return result;
|
|
12
|
+
export const isDataProp = (data, key) => typeof key === "string" && Object.prototype.hasOwnProperty.call(data, key);
|
|
13
|
+
export function getData(input) {
|
|
14
|
+
return isIterable(input) ? Object.fromEntries(input) : input;
|
|
18
15
|
}
|
|
19
16
|
export function getDataProps(data) {
|
|
20
17
|
return Object.entries(data);
|
|
@@ -22,6 +19,15 @@ export function getDataProps(data) {
|
|
|
22
19
|
export function getDataKeys(data) {
|
|
23
20
|
return Object.keys(data);
|
|
24
21
|
}
|
|
22
|
+
export function getDataProp(data, key) {
|
|
23
|
+
let current = data;
|
|
24
|
+
for (const k of key.split(".")) {
|
|
25
|
+
if (!isObject(current))
|
|
26
|
+
return undefined;
|
|
27
|
+
current = current[k];
|
|
28
|
+
}
|
|
29
|
+
return current;
|
|
30
|
+
}
|
|
25
31
|
/** An empty object. */
|
|
26
32
|
export const EMPTY_DATA = { __proto__: null };
|
|
27
33
|
/** Function that returns an an empty object. */
|
package/util/null.d.ts
CHANGED
|
@@ -18,3 +18,5 @@ export declare const notNullish: <T>(value: Nullish<T>) => value is T;
|
|
|
18
18
|
export declare function assertNotNullish<T>(value: Nullish<T>): asserts value is T;
|
|
19
19
|
/** Get the not-nullish version of value. */
|
|
20
20
|
export declare function getNotNullish<T>(value: Nullish<T>): T;
|
|
21
|
+
/** Get a required value. */
|
|
22
|
+
export declare function getRequired<T>(value: Nullish<T>): T;
|
package/util/null.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AssertionError } from "../error/AssertionError.js";
|
|
2
|
+
import { RequiredError } from "../error/RequiredError.js";
|
|
2
3
|
/** Function that always returns null. */
|
|
3
4
|
export const getNull = () => null;
|
|
4
5
|
/** Is a value null? */
|
|
@@ -29,3 +30,9 @@ export function getNotNullish(value) {
|
|
|
29
30
|
assertNotNullish(value);
|
|
30
31
|
return value;
|
|
31
32
|
}
|
|
33
|
+
/** Get a required value. */
|
|
34
|
+
export function getRequired(value) {
|
|
35
|
+
if (isNullish(value))
|
|
36
|
+
throw new RequiredError("Value is required");
|
|
37
|
+
return value;
|
|
38
|
+
}
|
package/util/object.d.ts
CHANGED
|
@@ -8,23 +8,23 @@ export type MutableObject<K extends PropertyKey = PropertyKey, T = unknown> = {
|
|
|
8
8
|
[KK in K]: T;
|
|
9
9
|
};
|
|
10
10
|
/** Prop for an object. */
|
|
11
|
-
export type
|
|
11
|
+
export type Prop<T> = readonly [keyof T, T[keyof T]];
|
|
12
12
|
/** Key for an object prop. */
|
|
13
|
-
export type
|
|
13
|
+
export type Key<T> = keyof T;
|
|
14
14
|
/** Value for an object prop. */
|
|
15
|
-
export type
|
|
15
|
+
export type Value<T> = T[keyof T];
|
|
16
16
|
/** Something that can be converted to an object. */
|
|
17
|
-
export type PossibleObject<T
|
|
17
|
+
export type PossibleObject<T> = T | Iterable<Prop<T>>;
|
|
18
18
|
/** Is an unknown value an unknown object? */
|
|
19
19
|
export declare const isObject: <T extends ImmutableObject<PropertyKey, unknown>>(value: unknown) => value is T;
|
|
20
20
|
/** Assert that a value is an object */
|
|
21
21
|
export declare function assertObject<T extends ImmutableObject>(value: T | unknown): asserts value is T;
|
|
22
22
|
/** is an unknown value an unknown plain object? */
|
|
23
|
-
export declare function isPlainObject(value:
|
|
23
|
+
export declare function isPlainObject<T extends ImmutableObject>(value: T | unknown): value is T;
|
|
24
24
|
/** Assert that a value is an object */
|
|
25
|
-
export declare function assertPlainObject(value:
|
|
25
|
+
export declare function assertPlainObject<T extends ImmutableObject>(value: T | unknown): asserts value is T;
|
|
26
26
|
/** Is an unknown value the key for an own prop of an object. */
|
|
27
|
-
export declare const isProp: <T
|
|
27
|
+
export declare const isProp: <T>(obj: T, key: PropertyKey) => key is keyof T;
|
|
28
28
|
/** turn a possible object into an object. */
|
|
29
29
|
export declare function getObject<T extends ImmutableObject>(obj: PossibleObject<T>): T;
|
|
30
30
|
/**
|
|
@@ -68,43 +68,30 @@ export type OmitProps<T, TT> = Omit<T, {
|
|
|
68
68
|
[K in keyof T]: T[K] extends TT ? K : never;
|
|
69
69
|
}[keyof T]>;
|
|
70
70
|
/** Get the props of an object as a set of entries. */
|
|
71
|
-
export declare function getProps<T
|
|
72
|
-
export declare function getProps<T
|
|
73
|
-
export declare function getProps<T
|
|
71
|
+
export declare function getProps<T>(obj: T): ImmutableArray<Prop<T>>;
|
|
72
|
+
export declare function getProps<T>(obj: T | Partial<T>): ImmutableArray<Prop<T>>;
|
|
73
|
+
export declare function getProps<T>(obj: T | Partial<T> | Iterable<Prop<T>>): Iterable<Prop<T>>;
|
|
74
74
|
/** Get the keys of an object as an array. */
|
|
75
|
-
export declare function getKeys<T
|
|
76
|
-
export declare function getKeys<T
|
|
77
|
-
export declare function getKeys<T
|
|
78
|
-
/**
|
|
79
|
-
|
|
80
|
-
* - Extraction is possibly deep if deeper keys are specified.
|
|
81
|
-
*
|
|
82
|
-
* @param obj The target object to get from.
|
|
83
|
-
* @param k1 The key of the prop in the object to get.
|
|
84
|
-
* @param k2 The sub-key of the prop in the object to get.
|
|
85
|
-
* @param k3 The sub-sub-key of the prop in the object to get.
|
|
86
|
-
* @param k4 The sub-sub-sub-key of the prop in the object to get.
|
|
87
|
-
*/
|
|
88
|
-
export declare function getProp<T extends ImmutableObject, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2], K4 extends keyof T[K1][K2][K3]>(obj: T, k1: K1, k2: K2, k3: K3, k4: K4): T[K1][K2][K3][K4];
|
|
89
|
-
export declare function getProp<T extends ImmutableObject, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, k1: K1, k2: K2, k3: K3): T[K1][K2][K3];
|
|
90
|
-
export declare function getProp<T extends ImmutableObject, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, k1: K1, k2: K2): T[K1][K2];
|
|
91
|
-
export declare function getProp<T extends ImmutableObject, K1 extends keyof T>(obj: T, k1: K1): T[K1];
|
|
92
|
-
export declare function getProp(obj: ImmutableObject, key: string, ...keys: readonly string[]): unknown;
|
|
75
|
+
export declare function getKeys<T>(obj: T): ImmutableArray<Key<T>>;
|
|
76
|
+
export declare function getKeys<T>(obj: T | Partial<T>): ImmutableArray<Key<T>>;
|
|
77
|
+
export declare function getKeys<T>(obj: T | Partial<T> | Iterable<Key<T>>): Iterable<Key<T>>;
|
|
78
|
+
/** Extract the value of a named prop from an object. */
|
|
79
|
+
export declare function getProp<T, K extends Key<T>>(obj: T, key: K): T[K];
|
|
93
80
|
/** Set a prop on an object (immutably) and return a new object including that prop. */
|
|
94
|
-
export declare function withProp<T extends ImmutableObject, K extends
|
|
81
|
+
export declare function withProp<T extends ImmutableObject, K extends Key<T>>(input: T, key: K, value: T[K]): T;
|
|
95
82
|
/** Set several props on an object (immutably) and return a new object including those props. */
|
|
96
|
-
export declare function withProps<T
|
|
97
|
-
export declare function withProps<T
|
|
83
|
+
export declare function withProps<T>(input: T, props: Partial<T>): T;
|
|
84
|
+
export declare function withProps<T>(input: T, props: T | Partial<T> | Iterable<Prop<T>>): T;
|
|
98
85
|
/** Remove several props from an object (immutably) and return a new object without those props. */
|
|
99
|
-
export declare function omitProps<T
|
|
86
|
+
export declare function omitProps<T, K extends Key<T>>(input: T, ...keys: K[]): Omit<T, K>;
|
|
100
87
|
/** Pick several props from an object and return a new object with only thos props. */
|
|
101
|
-
export declare function pickProps<T
|
|
88
|
+
export declare function pickProps<T, K extends Key<T>>(obj: T, ...keys: K[]): Pick<T, K>;
|
|
102
89
|
/** Set a single named prop on an object (by reference) and return its value. */
|
|
103
|
-
export declare function setProp<T extends MutableObject, K extends
|
|
90
|
+
export declare function setProp<T extends MutableObject, K extends Key<T>>(obj: T, key: K, value: T[K]): T[K];
|
|
104
91
|
/** Set several named props on an object (by reference). */
|
|
105
|
-
export declare function setProps<T extends MutableObject>(obj: T, entries: T | Partial<T> | Iterable<
|
|
92
|
+
export declare function setProps<T extends MutableObject>(obj: T, entries: T | Partial<T> | Iterable<Prop<T>>): void;
|
|
106
93
|
/** Remove several key/value entries from an object (by reference). */
|
|
107
|
-
export declare function deleteProps<T extends MutableObject>(obj: T, ...keys:
|
|
94
|
+
export declare function deleteProps<T extends MutableObject>(obj: T, ...keys: Key<T>[]): void;
|
|
108
95
|
/**
|
|
109
96
|
* Format an unknown object as a string.
|
|
110
97
|
* - Use the custom `.toString()` function if it exists (don't use built in `Object.prototype.toString` because it's useless.
|
|
@@ -120,7 +107,7 @@ export declare function getPrototype<T>(obj: T): Partial<T> | null;
|
|
|
120
107
|
/** Shallow clone an object with the same prototype. */
|
|
121
108
|
export declare function cloneObject<T>(input: T): T;
|
|
122
109
|
/** Shallow clone an object with a single changed value. */
|
|
123
|
-
export declare function cloneObjectWith<T, K extends
|
|
110
|
+
export declare function cloneObjectWith<T, K extends Key<T>>(input: T, key: K, value: T[K]): T;
|
|
124
111
|
export declare function cloneObjectWith<T, K extends string, V>(input: T, key: K, value: V): T & {
|
|
125
112
|
[KK in K]: V;
|
|
126
113
|
};
|
package/util/object.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AssertionError } from "../error/AssertionError.js";
|
|
2
|
-
import { isArrayLength } from "./array.js";
|
|
3
2
|
import { isIterable } from "./iterate.js";
|
|
4
3
|
/** Is an unknown value an unknown object? */
|
|
5
4
|
export const isObject = (value) => typeof value === "object" && value !== null;
|
|
@@ -33,9 +32,9 @@ export function getProps(obj) {
|
|
|
33
32
|
export function getKeys(obj) {
|
|
34
33
|
return isIterable(obj) ? obj : Object.keys(obj);
|
|
35
34
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return
|
|
35
|
+
/** Extract the value of a named prop from an object. */
|
|
36
|
+
export function getProp(obj, key) {
|
|
37
|
+
return obj[key];
|
|
39
38
|
}
|
|
40
39
|
/** Set a prop on an object (immutably) and return a new object including that prop. */
|
|
41
40
|
export function withProp(input, key, value) {
|
package/util/query.d.ts
CHANGED
|
@@ -1,63 +1,63 @@
|
|
|
1
1
|
import type { ImmutableArray } from "./array.js";
|
|
2
|
-
import type { Data,
|
|
2
|
+
import type { Data, LeafData, LeafKey } from "./data.js";
|
|
3
3
|
/** Query that can be applied to a list of data objects. */
|
|
4
4
|
export type Query<T extends Data> = {
|
|
5
|
-
readonly [K in
|
|
5
|
+
readonly [K in LeafKey<T> as `${K}` | `!${K}`]?: LeafData<T>[K] | ImmutableArray<LeafData<T>[K]> | undefined;
|
|
6
6
|
} & {
|
|
7
|
-
readonly [K in
|
|
7
|
+
readonly [K in LeafKey<T> as `${K}<` | `${K}<=` | `${K}>` | `${K}>=`]?: LeafData<T>[K] | undefined;
|
|
8
8
|
} & {
|
|
9
|
-
readonly [K in
|
|
9
|
+
readonly [K in LeafKey<T> as `${K}[]`]?: LeafData<T>[K] extends ImmutableArray<infer X> ? X | undefined : never;
|
|
10
10
|
} & {
|
|
11
|
-
readonly $order?:
|
|
11
|
+
readonly $order?: `${LeafKey<T>}` | `!${LeafKey<T>}` | undefined | ImmutableArray<`${LeafKey<T>}` | `!${LeafKey<T>}` | undefined>;
|
|
12
12
|
readonly $limit?: number | undefined;
|
|
13
13
|
};
|
|
14
14
|
/** A single filter that can be applied to a list of data objects. */
|
|
15
15
|
export type Filter = {
|
|
16
|
-
|
|
16
|
+
key: string;
|
|
17
17
|
operator: "is";
|
|
18
18
|
value: unknown;
|
|
19
19
|
} | {
|
|
20
|
-
|
|
20
|
+
key: string;
|
|
21
21
|
operator: "not";
|
|
22
22
|
value: unknown;
|
|
23
23
|
} | {
|
|
24
|
-
|
|
24
|
+
key: string;
|
|
25
25
|
operator: "in";
|
|
26
26
|
value: ImmutableArray;
|
|
27
27
|
} | {
|
|
28
|
-
|
|
28
|
+
key: string;
|
|
29
29
|
operator: "out";
|
|
30
30
|
value: ImmutableArray;
|
|
31
31
|
} | {
|
|
32
|
-
|
|
32
|
+
key: string;
|
|
33
33
|
operator: "contains";
|
|
34
34
|
value: unknown;
|
|
35
35
|
} | {
|
|
36
|
-
|
|
36
|
+
key: string;
|
|
37
37
|
operator: "lt";
|
|
38
38
|
value: unknown;
|
|
39
39
|
} | {
|
|
40
|
-
|
|
40
|
+
key: string;
|
|
41
41
|
operator: "lte";
|
|
42
42
|
value: unknown;
|
|
43
43
|
} | {
|
|
44
|
-
|
|
44
|
+
key: string;
|
|
45
45
|
operator: "gt";
|
|
46
46
|
value: unknown;
|
|
47
47
|
} | {
|
|
48
|
-
|
|
48
|
+
key: string;
|
|
49
49
|
operator: "gte";
|
|
50
50
|
value: unknown;
|
|
51
51
|
};
|
|
52
|
-
/** A single sort that can be applied to a list of data objects. */
|
|
53
|
-
export type
|
|
54
|
-
|
|
52
|
+
/** A single sort order that can be applied to a list of data objects. */
|
|
53
|
+
export type Order = {
|
|
54
|
+
key: string;
|
|
55
55
|
direction: "asc" | "desc";
|
|
56
56
|
};
|
|
57
57
|
/** Get the `Filter` objects for a query. */
|
|
58
58
|
export declare function getFilters<T extends Data>(query: Query<T>): ImmutableArray<Filter>;
|
|
59
|
-
/** Get the `
|
|
60
|
-
export declare function
|
|
59
|
+
/** Get the `Order` objects for a query. */
|
|
60
|
+
export declare function getOrders<T extends Data>({ $order }: Query<T>): ImmutableArray<Order>;
|
|
61
61
|
/** Get the limit for a query. */
|
|
62
62
|
export declare const getLimit: <T extends Data>({ $limit }: Query<T>) => number | undefined;
|
|
63
63
|
/** Query a set of data items using a query. */
|
|
@@ -72,9 +72,9 @@ export declare function matchQueryItem<T extends Data>(item: T, filters: Immutab
|
|
|
72
72
|
/** Filter a set of data items using a set of filters. */
|
|
73
73
|
export declare function filterQueryItems<T extends Data>(items: Iterable<T>, filters: ImmutableArray<Filter>): Iterable<T>;
|
|
74
74
|
/** Compare two data items using a set of sorts. */
|
|
75
|
-
export declare function compareQueryItems<T extends Data>(left: T, right: T, sorts: ImmutableArray<
|
|
75
|
+
export declare function compareQueryItems<T extends Data>(left: T, right: T, sorts: ImmutableArray<Order>): number;
|
|
76
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<
|
|
77
|
+
export declare function sortQueryItems<T extends Data>(items: Iterable<T>, sorts: ImmutableArray<Order>): Iterable<T>;
|
|
78
78
|
/** LImit a set of data items using a set of limit. */
|
|
79
79
|
export declare function limitQueryItems<T extends Data>(items: ImmutableArray<T> | Iterable<T>, limit: number | undefined): Iterable<T>;
|
|
80
80
|
/** Get a query for items that appear before a specified item. */
|
package/util/query.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { getLastItem, isArray, limitArray } from "./array.js";
|
|
2
|
+
import { getDataProp } from "./data.js";
|
|
2
3
|
import { isArrayWith, isEqual, isEqualGreater, isEqualLess, isGreater, isInArray, isLess, notEqual, notInArray } from "./equal.js";
|
|
3
4
|
import { limitItems } from "./iterate.js";
|
|
4
|
-
import {
|
|
5
|
+
import { getProps } from "./object.js";
|
|
5
6
|
import { compareAscending, compareDescending, sortArray } from "./sort.js";
|
|
6
|
-
import { splitString } from "./string.js";
|
|
7
7
|
import { isDefined } from "./undefined.js";
|
|
8
8
|
/** Map `Filter` operators to corresponding `Match` function. */
|
|
9
9
|
const MATCHERS = {
|
|
@@ -22,38 +22,38 @@ export function getFilters(query) {
|
|
|
22
22
|
return getProps(query).map(_getFilters).filter(isDefined);
|
|
23
23
|
}
|
|
24
24
|
function _getFilters([key, value]) {
|
|
25
|
-
if (key
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
25
|
+
if (key !== "$order" && key !== "$limit" && value !== undefined) {
|
|
26
|
+
if (key.startsWith("!"))
|
|
27
|
+
return isArray(value) ? { key: key.slice(1), operator: "out", value } : { key: key.slice(1), operator: "not", value };
|
|
28
|
+
else if (key.endsWith("[]"))
|
|
29
|
+
return { key: key.slice(0, -2), operator: "contains", value };
|
|
30
|
+
else if (key.endsWith(">"))
|
|
31
|
+
return { key: key.slice(0, -1), operator: "gt", value };
|
|
32
|
+
else if (key.endsWith(">="))
|
|
33
|
+
return { key: key.slice(0, -2), operator: "gte", value };
|
|
34
|
+
else if (key.endsWith("<"))
|
|
35
|
+
return { key: key.slice(0, -1), operator: "lt", value };
|
|
36
|
+
else if (key.endsWith("<="))
|
|
37
|
+
return { key: key.slice(0, -2), operator: "lte", value };
|
|
38
|
+
else
|
|
39
|
+
return isArray(value) ? { key, operator: "in", value } : { key: key, operator: "is", value };
|
|
40
|
+
}
|
|
41
41
|
}
|
|
42
|
-
/** Get the `
|
|
43
|
-
export function
|
|
44
|
-
return
|
|
42
|
+
/** Get the `Order` objects for a query. */
|
|
43
|
+
export function getOrders({ $order }) {
|
|
44
|
+
return (isArray($order) ? $order : [$order]).filter(isDefined).map(_getOrder);
|
|
45
45
|
}
|
|
46
|
-
function
|
|
46
|
+
function _getOrder(key) {
|
|
47
47
|
if (key.startsWith("!"))
|
|
48
|
-
return {
|
|
48
|
+
return { key: key.slice(1), direction: "desc" };
|
|
49
49
|
else
|
|
50
|
-
return {
|
|
50
|
+
return { key, direction: "asc" };
|
|
51
51
|
}
|
|
52
52
|
/** Get the limit for a query. */
|
|
53
53
|
export const getLimit = ({ $limit }) => $limit;
|
|
54
54
|
/** Query a set of data items using a query. */
|
|
55
55
|
export function queryItems(items, query) {
|
|
56
|
-
return limitQueryItems(sortQueryItems(filterQueryItems(items, getFilters(query)),
|
|
56
|
+
return limitQueryItems(sortQueryItems(filterQueryItems(items, getFilters(query)), getOrders(query)), getLimit(query));
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
59
|
* Query a set of data items for writing using a query.
|
|
@@ -64,9 +64,9 @@ export function queryWritableItems(items, query) {
|
|
|
64
64
|
}
|
|
65
65
|
/** Match a single data item againt a set of filters. */
|
|
66
66
|
export function matchQueryItem(item, filters) {
|
|
67
|
-
for (const {
|
|
67
|
+
for (const { key, operator, value } of filters) {
|
|
68
68
|
const matcher = MATCHERS[operator];
|
|
69
|
-
if (!matcher(
|
|
69
|
+
if (!matcher(getDataProp(item, key), value))
|
|
70
70
|
return false;
|
|
71
71
|
}
|
|
72
72
|
return true;
|
|
@@ -84,9 +84,9 @@ export function* filterQueryItems(items, filters) {
|
|
|
84
84
|
}
|
|
85
85
|
/** Compare two data items using a set of sorts. */
|
|
86
86
|
export function compareQueryItems(left, right, sorts) {
|
|
87
|
-
for (const {
|
|
88
|
-
const l =
|
|
89
|
-
const r =
|
|
87
|
+
for (const { key, direction } of sorts) {
|
|
88
|
+
const l = getDataProp(left, key);
|
|
89
|
+
const r = getDataProp(right, key);
|
|
90
90
|
const c = direction === "asc" ? compareAscending(l, r) : compareDescending(l, r);
|
|
91
91
|
if (c !== 0)
|
|
92
92
|
return c;
|
|
@@ -103,26 +103,24 @@ export function limitQueryItems(items, limit) {
|
|
|
103
103
|
}
|
|
104
104
|
/** Get a query for items that appear before a specified item. */
|
|
105
105
|
export function getBeforeQuery(query, item) {
|
|
106
|
-
const sorts =
|
|
106
|
+
const sorts = getOrders(query);
|
|
107
107
|
const lastSort = getLastItem(sorts);
|
|
108
108
|
const newQuery = { ...query };
|
|
109
109
|
for (const sort of sorts) {
|
|
110
|
-
const {
|
|
111
|
-
const
|
|
112
|
-
const value = getProp(item, ...keys);
|
|
110
|
+
const { key, direction } = sort;
|
|
111
|
+
const value = getDataProp(item, key);
|
|
113
112
|
newQuery[direction === "asc" ? (sort === lastSort ? `${key}>` : `${key}>=`) : sort === lastSort ? `${key}<` : `${key}<=`] = value;
|
|
114
113
|
}
|
|
115
114
|
return newQuery;
|
|
116
115
|
}
|
|
117
116
|
/** Get a query for items that appear after a specified item. */
|
|
118
117
|
export function getAfterQuery(query, item) {
|
|
119
|
-
const sorts =
|
|
118
|
+
const sorts = getOrders(query);
|
|
120
119
|
const lastSort = getLastItem(sorts);
|
|
121
120
|
const newQuery = { ...query };
|
|
122
121
|
for (const sort of sorts) {
|
|
123
|
-
const {
|
|
124
|
-
const
|
|
125
|
-
const value = getProp(item, ...keys);
|
|
122
|
+
const { key, direction } = sort;
|
|
123
|
+
const value = getDataProp(item, key);
|
|
126
124
|
newQuery[direction === "asc" ? (sort === lastSort ? `${key}<` : `${key}<=`) : sort === lastSort ? `${key}>` : `${key}>=`] = value;
|
|
127
125
|
}
|
|
128
126
|
return newQuery;
|
package/util/transform.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { ArrayItem, ImmutableArray } from "./array.js";
|
|
|
2
2
|
import type { ImmutableDictionary, PossibleDictionary } from "./dictionary.js";
|
|
3
3
|
import type { Entry } from "./entry.js";
|
|
4
4
|
import type { Arguments } from "./function.js";
|
|
5
|
-
import type { ImmutableObject,
|
|
5
|
+
import type { ImmutableObject, Value } from "./object.js";
|
|
6
6
|
/** Function that can transform an input value into an output value. */
|
|
7
7
|
export type Transform<I, O, A extends Arguments = []> = (input: I, ...args: A) => O;
|
|
8
8
|
/** Function that can transform an input value into an output value. */
|
|
@@ -19,11 +19,11 @@ export declare function mapArray<T extends ImmutableArray>(arr: T, transform: Tr
|
|
|
19
19
|
export declare function mapArray<I, O, A extends Arguments = []>(arr: Iterable<I>, transform: (v: I, ...args: A) => O, ...args: A): ImmutableArray<O>;
|
|
20
20
|
export declare function mapArray<I, O, A extends Arguments = []>(arr: Iterable<I>, transform: Transform<I, O, A>, ...args: A): ImmutableArray<O>;
|
|
21
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<
|
|
23
|
-
export declare function mapObject<I extends ImmutableObject, O extends ImmutableObject, A extends Arguments = []>(obj: I, transform: (v:
|
|
24
|
-
export declare function mapObject<I extends ImmutableObject, O extends ImmutableObject, A extends Arguments = []>(obj: I, transform: Transform<
|
|
22
|
+
export declare function mapObject<T extends ImmutableObject>(obj: T, transform: Transform<Value<T>, Value<T>>): T;
|
|
23
|
+
export declare function mapObject<I extends ImmutableObject, O extends ImmutableObject, A extends Arguments = []>(obj: I, transform: (v: Value<I>, ...args: A) => Value<O>, ...args: A): O;
|
|
24
|
+
export declare function mapObject<I extends ImmutableObject, O extends ImmutableObject, A extends Arguments = []>(obj: I, transform: Transform<Value<I>, Value<O>, A>, ...args: A): O;
|
|
25
25
|
/** Modify the values of a dictionary using a transform. */
|
|
26
|
-
export declare
|
|
26
|
+
export declare function mapDictionary<I, O, A extends Arguments = []>(dictionary: PossibleDictionary<I>, transform: (v: I, ...args: A) => O, ...args: A): ImmutableDictionary<O>;
|
|
27
27
|
/** Modify the values of a set of entries using a transform. */
|
|
28
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>>;
|
|
29
29
|
/**
|
package/util/transform.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getDictionaryItems } from "./dictionary.js";
|
|
1
2
|
import { getProps } from "./object.js";
|
|
2
3
|
export function* mapItems(items, transform, ...args) {
|
|
3
4
|
for (const item of items)
|
|
@@ -9,8 +10,10 @@ export function mapArray(arr, transform, ...args) {
|
|
|
9
10
|
export function mapObject(obj, transform, ...args) {
|
|
10
11
|
return Object.fromEntries(mapEntries(getProps(obj), transform, ...args));
|
|
11
12
|
}
|
|
12
|
-
|
|
13
|
-
export
|
|
13
|
+
// export function mapDictionary<I, O, A extends Arguments = []>(dictionary: PossibleDictionary<I>, transform: Transform<I, O, A>, ...args: A): ImmutableDictionary<O>;
|
|
14
|
+
export function mapDictionary(dictionary, transform, ...args) {
|
|
15
|
+
return Object.fromEntries(mapEntries(getDictionaryItems(dictionary), transform, ...args));
|
|
16
|
+
}
|
|
14
17
|
/** Modify the values of a set of entries using a transform. */
|
|
15
18
|
export function* mapEntries(entries, transform, ...args) {
|
|
16
19
|
for (const [k, v] of entries)
|
package/util/update.d.ts
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import type { ImmutableArray } from "./array.js";
|
|
2
|
-
import type { Data,
|
|
2
|
+
import type { BranchData, BranchKey, Data, LeafData, LeafKey } from "./data.js";
|
|
3
3
|
/** Set of named updates for a data object. */
|
|
4
4
|
export type Updates<T extends Data = Data> = {
|
|
5
|
-
readonly [K in
|
|
5
|
+
readonly [K in BranchKey<T> as `${K}`]?: BranchData<T>[K] | undefined;
|
|
6
6
|
} & {
|
|
7
|
-
readonly [K in
|
|
7
|
+
readonly [K in LeafKey<T> as `=${K}`]?: LeafData<T>[K] | undefined;
|
|
8
|
+
} & {
|
|
9
|
+
readonly [K in LeafKey<T> as `+=${K}` | `-=${K}`]?: LeafData<T>[K] extends number ? LeafData<T>[K] | undefined : never;
|
|
8
10
|
};
|
|
9
11
|
/** A single update to a keyed property in an object. */
|
|
10
12
|
export type Update = {
|
|
11
13
|
action: "set";
|
|
12
|
-
|
|
14
|
+
key: string;
|
|
13
15
|
value: unknown;
|
|
14
16
|
} | {
|
|
15
17
|
action: "sum";
|
|
16
|
-
|
|
18
|
+
key: string;
|
|
17
19
|
value: number;
|
|
18
20
|
};
|
|
19
21
|
/** Yield the prop updates in an `Updates` object as a set of `Update` objects. */
|
package/util/update.js
CHANGED
|
@@ -2,28 +2,36 @@ import { AssertionError } from "../error/AssertionError.js";
|
|
|
2
2
|
import { reduceItems } from "./iterate.js";
|
|
3
3
|
import { getNumber } from "./number.js";
|
|
4
4
|
import { getProps, isObject } from "./object.js";
|
|
5
|
+
import { isDefined } from "./undefined.js";
|
|
5
6
|
/** Yield the prop updates in an `Updates` object as a set of `Update` objects. */
|
|
6
7
|
export function getUpdates(data) {
|
|
7
|
-
return getProps(data).map(_getUpdate);
|
|
8
|
+
return getProps(data).map(_getUpdate).filter(isDefined);
|
|
8
9
|
}
|
|
9
|
-
function _getUpdate([
|
|
10
|
-
if (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
function _getUpdate([key, value]) {
|
|
11
|
+
if (value !== undefined) {
|
|
12
|
+
if (key.startsWith("+="))
|
|
13
|
+
return { action: "sum", key: key.slice(2), value: getNumber(value) };
|
|
14
|
+
else if (key.startsWith("-="))
|
|
15
|
+
return { action: "sum", key: key.slice(2), value: 0 - getNumber(value) };
|
|
16
|
+
else if (key.startsWith("="))
|
|
17
|
+
return { action: "set", key: key.slice(1), value };
|
|
18
|
+
else
|
|
19
|
+
return { action: "set", key, value };
|
|
20
|
+
}
|
|
16
21
|
}
|
|
17
22
|
/** Update a data object with a set of updates. */
|
|
18
23
|
export function updateData(data, updates) {
|
|
19
24
|
return reduceItems(getUpdates(updates), _updateProp, data);
|
|
20
25
|
}
|
|
21
|
-
function _updateProp(obj, update
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
function _updateProp(obj, update) {
|
|
27
|
+
return _updatePropDeep(obj, update, update.key.split("."), 0);
|
|
28
|
+
}
|
|
29
|
+
function _updatePropDeep(obj, update, keys, i) {
|
|
30
|
+
const { action, value } = update;
|
|
31
|
+
const k = keys[i];
|
|
32
|
+
if (!k)
|
|
25
33
|
return obj; // Shouldn't happen.
|
|
26
|
-
const oldValue = obj[
|
|
34
|
+
const oldValue = obj[k];
|
|
27
35
|
let newValue = oldValue;
|
|
28
36
|
if (i === keys.length - 1) {
|
|
29
37
|
if (action === "sum")
|
|
@@ -36,7 +44,7 @@ function _updateProp(obj, update, i = 0) {
|
|
|
36
44
|
else {
|
|
37
45
|
if (!isObject(oldValue))
|
|
38
46
|
throw new AssertionError(`Prop "${keys.slice(0, i + 1).join(".")}" is not an object`);
|
|
39
|
-
newValue =
|
|
47
|
+
newValue = _updatePropDeep(oldValue, update, keys, i + 1);
|
|
40
48
|
}
|
|
41
|
-
return oldValue === newValue ? obj : { ...obj, [
|
|
49
|
+
return oldValue === newValue ? obj : { ...obj, [k]: newValue };
|
|
42
50
|
}
|