shelving 1.73.2 → 1.75.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 ADDED
@@ -0,0 +1,49 @@
1
+ import type { Data, Datas, Key } from "../util/data.js";
2
+ import type { ImmutableArray } from "../util/array.js";
3
+ import type { Provider, AsyncProvider } from "../provider/Provider.js";
4
+ import { DataUpdate } from "../update/DataUpdate.js";
5
+ import { Nullish } from "../util/null.js";
6
+ import type { ItemConstraints, ItemData } from "./Item.js";
7
+ export interface Change<T extends Datas, K extends Key<T>> {
8
+ readonly action: string;
9
+ readonly collection: K;
10
+ }
11
+ /** Add on an item. */
12
+ export interface AddChange<T extends Datas, K extends Key<T>> extends Change<T, K> {
13
+ readonly action: "ADD";
14
+ readonly collection: K;
15
+ readonly data: T[K];
16
+ }
17
+ /** Set on an item. */
18
+ export interface SetChange<T extends Datas, K extends Key<T>> extends Change<T, K> {
19
+ readonly action: "SET";
20
+ readonly collection: K;
21
+ readonly id: string;
22
+ readonly data: T[K];
23
+ }
24
+ /** Update change on an item. */
25
+ export interface UpdateChange<T extends Datas, K extends Key<T>> extends Change<T, K> {
26
+ readonly action: "UPDATE";
27
+ readonly collection: K;
28
+ readonly id: string;
29
+ readonly update: DataUpdate<T[K]>;
30
+ }
31
+ /** Delete change on an item. */
32
+ export interface DeleteChange<T extends Datas, K extends Key<T>> extends Change<T, K> {
33
+ readonly action: "DELETE";
34
+ readonly collection: K;
35
+ readonly id: string;
36
+ }
37
+ /** Set, update, or delete change on an item. */
38
+ export declare type ItemChange<T extends Datas, K extends Key<T> = Key<T>> = SetChange<T, K> | UpdateChange<T, K> | DeleteChange<T, K>;
39
+ /** Array of item changes. */
40
+ export declare type ItemChanges<T extends Datas, K extends Key<T> = Key<T>> = ImmutableArray<ItemChange<T, K>>;
41
+ /** Write change on an item. */
42
+ export declare type WriteChange<T extends Datas, K extends Key<T> = Key<T>> = ItemChange<T, K> | AddChange<T, K>;
43
+ /** Array of write changes. */
44
+ export declare type WriteChanges<T extends Datas, K extends Key<T> = Key<T>> = ImmutableArray<WriteChange<T, K>>;
45
+ /** Apply a set of changes to a synchronous provider. */
46
+ export declare function changeProvider<T extends Datas, K extends Key<T> = Key<T>>(provider: Provider<T>, changes: ImmutableArray<Nullish<WriteChange<T, K>>>): ItemChanges<T, K>;
47
+ /** Apply a set of changes to an asynchronous provider. */
48
+ export declare function changeAsyncProvider<T extends Datas, K extends Key<T>>(provider: AsyncProvider<T>, changes: ImmutableArray<Nullish<WriteChange<T, K>>>): Promise<ItemChanges<T, K>>;
49
+ export declare function _getItemConstraint<T extends Data>(id: string): ItemConstraints<ItemData<T>>;
package/db/Change.js ADDED
@@ -0,0 +1,38 @@
1
+ import { QueryConstraints } from "../constraint/QueryConstraints.js";
2
+ import { FilterConstraint } from "../constraint/FilterConstraint.js";
3
+ import { notNullish } from "../util/null.js";
4
+ /** Apply a set of changes to a synchronous provider. */
5
+ export function changeProvider(provider, changes) {
6
+ return changes.filter(notNullish).map(_changeItem, provider);
7
+ }
8
+ function _changeItem(change) {
9
+ const { action, collection } = change;
10
+ if (action === "ADD")
11
+ return { action: "SET", collection, id: this.addItem(collection, change.data), data: change.data };
12
+ else if (action === "SET")
13
+ this.setItem(collection, change.id, change.data);
14
+ else if (action === "UPDATE")
15
+ this.updateQuery(collection, _getItemConstraint(change.id), change.update);
16
+ else if (action === "DELETE")
17
+ this.deleteItem(collection, change.id);
18
+ return change;
19
+ }
20
+ /** Apply a set of changes to an asynchronous provider. */
21
+ export function changeAsyncProvider(provider, changes) {
22
+ return Promise.all(changes.filter(notNullish).map(_changeAsyncItem, provider));
23
+ }
24
+ async function _changeAsyncItem(change) {
25
+ const { collection, action } = change;
26
+ if (action === "ADD")
27
+ return { action: "SET", collection, id: await this.addItem(collection, change.data), data: change.data };
28
+ else if (action === "SET")
29
+ await this.setItem(collection, change.id, change.data);
30
+ else if (action === "UPDATE")
31
+ await this.updateQuery(collection, _getItemConstraint(change.id), change.update);
32
+ else if (action === "DELETE")
33
+ await this.deleteItem(collection, change.id);
34
+ return change;
35
+ }
36
+ export function _getItemConstraint(id) {
37
+ return new QueryConstraints(new FilterConstraint("id", id), undefined, 1);
38
+ }
@@ -1,39 +1,43 @@
1
1
  import type { Datas, Key } from "../util/data.js";
2
+ import type { Nullish } from "../util/null.js";
2
3
  import type { FilterList } from "../constraint/FilterConstraint.js";
3
4
  import type { SortList } from "../constraint/SortConstraint.js";
4
5
  import type { ItemData, AsyncItem, Item } from "./Item.js";
5
6
  import type { AsyncDatabase, Database } from "./Database.js";
6
7
  import type { AsyncQuery, Query } from "./Query.js";
8
+ import type { ItemChanges, WriteChange } from "./Change.js";
7
9
  /** Reference to a collection in a synchronous or asynchronous provider. */
8
- interface CollectionInterface<T extends Datas = Datas, K extends Key<T> = Key<T>> {
9
- readonly db: Database<T> | AsyncDatabase<T>;
10
- readonly collection: K;
10
+ declare abstract class BaseCollection<T extends Datas = Datas, K extends Key<T> = Key<T>> {
11
+ abstract readonly db: Database<T> | AsyncDatabase<T>;
12
+ abstract readonly collection: K;
11
13
  /** Create a query on this item's collection. */
12
- query(filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): Query<T, K> | AsyncQuery<T, K>;
14
+ abstract query(filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): Query<T, K> | AsyncQuery<T, K>;
13
15
  /** Create a query on this item's collection. */
14
- item(id: string): Item<T, K> | AsyncItem<T, K>;
16
+ abstract item(id: string): Item<T, K> | AsyncItem<T, K>;
15
17
  /** Add an item to this collection. */
16
- add(data: T[K]): string | Promise<string>;
18
+ abstract add(data: T[K]): string | Promise<string>;
19
+ /** Run a set of changes on this database. */
20
+ abstract change(...changes: Nullish<WriteChange<T, K>>[]): ItemChanges<T, K> | Promise<ItemChanges<T, K>>;
17
21
  toString(): K;
18
22
  }
19
23
  /** Reference to a collection in a synchronous provider. */
20
- export declare class Collection<T extends Datas = Datas, K extends Key<T> = Key<T>> implements CollectionInterface<T, K> {
24
+ export declare class Collection<T extends Datas = Datas, K extends Key<T> = Key<T>> extends BaseCollection<T, K> {
21
25
  readonly db: Database<T>;
22
26
  readonly collection: K;
23
27
  constructor(db: Database<T>, collection: K);
24
28
  query(filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): Query<T, K>;
25
29
  item(id: string): Item<T, K>;
26
30
  add(data: T[K]): string;
27
- toString(): K;
31
+ change(...changes: Nullish<WriteChange<T, K>>[]): ItemChanges<T, K>;
28
32
  }
29
33
  /** Reference to a collection in an asynchronous provider. */
30
- export declare class AsyncCollection<T extends Datas = Datas, K extends Key<T> = Key<T>> implements CollectionInterface<T, K> {
34
+ export declare class AsyncCollection<T extends Datas = Datas, K extends Key<T> = Key<T>> extends BaseCollection<T, K> {
31
35
  readonly db: AsyncDatabase<T>;
32
36
  readonly collection: K;
33
37
  constructor(db: AsyncDatabase<T>, collection: K);
34
38
  query(filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): AsyncQuery<T, K>;
35
39
  item(id: string): AsyncItem<T, K>;
36
40
  add(data: T[K]): Promise<string>;
37
- toString(): K;
41
+ change(...changes: Nullish<WriteChange<T, K>>[]): Promise<ItemChanges<T, K>>;
38
42
  }
39
43
  export {};
package/db/Collection.js CHANGED
@@ -1,6 +1,14 @@
1
+ /** Reference to a collection in a synchronous or asynchronous provider. */
2
+ class BaseCollection {
3
+ // Implement toString()
4
+ toString() {
5
+ return this.collection;
6
+ }
7
+ }
1
8
  /** Reference to a collection in a synchronous provider. */
2
- export class Collection {
9
+ export class Collection extends BaseCollection {
3
10
  constructor(db, collection) {
11
+ super();
4
12
  this.db = db;
5
13
  this.collection = collection;
6
14
  }
@@ -13,13 +21,14 @@ export class Collection {
13
21
  add(data) {
14
22
  return this.db.provider.addItem(this.collection, data);
15
23
  }
16
- toString() {
17
- return this.collection;
24
+ change(...changes) {
25
+ return this.db.change(...changes);
18
26
  }
19
27
  }
20
28
  /** Reference to a collection in an asynchronous provider. */
21
- export class AsyncCollection {
29
+ export class AsyncCollection extends BaseCollection {
22
30
  constructor(db, collection) {
31
+ super();
23
32
  this.db = db;
24
33
  this.collection = collection;
25
34
  }
@@ -32,7 +41,7 @@ export class AsyncCollection {
32
41
  add(data) {
33
42
  return this.db.provider.addItem(this.collection, data);
34
43
  }
35
- toString() {
36
- return this.collection;
44
+ change(...changes) {
45
+ return this.db.change(...changes);
37
46
  }
38
47
  }
package/db/Database.d.ts CHANGED
@@ -3,33 +3,39 @@ import type { AsyncProvider, Provider } from "../provider/Provider.js";
3
3
  import type { FilterList } from "../constraint/FilterConstraint.js";
4
4
  import type { SortList } from "../constraint/SortConstraint.js";
5
5
  import type { ItemData } from "../db/Item.js";
6
+ import type { Nullish } from "../util/null.js";
6
7
  import { Item, AsyncItem } from "./Item.js";
7
8
  import { Query, AsyncQuery } from "./Query.js";
8
9
  import { Collection, AsyncCollection } from "./Collection.js";
10
+ import { ItemChanges, WriteChange } from "./Change.js";
9
11
  /** Database with a synchronous or asynchronous provider. */
10
- interface AbstractDatabase<T extends Datas> {
11
- readonly provider: Provider<T> | AsyncProvider<T>;
12
+ declare abstract class BaseDatabase<T extends Datas> {
13
+ abstract readonly provider: Provider<T> | AsyncProvider<T>;
12
14
  /** Create a query on a collection in this database. */
13
- collection<K extends Key<T>>(collection: K): Collection<T, K> | AsyncCollection<T, K>;
15
+ abstract collection<K extends Key<T>>(collection: K): Collection<T, K> | AsyncCollection<T, K>;
14
16
  /** Create a query on a collection in this database. */
15
- query<K extends Key<T>>(collection: K, filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): Query<T, K> | AsyncQuery<T, K>;
17
+ abstract query<K extends Key<T>>(collection: K, filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): Query<T, K> | AsyncQuery<T, K>;
16
18
  /** Reference an item in a collection in this database. */
17
- item<K extends Key<T>>(collection: K, id: string): Item<T, K> | AsyncItem<T, K>;
19
+ abstract item<K extends Key<T>>(collection: K, id: string): Item<T, K> | AsyncItem<T, K>;
20
+ /** Run a set of changes on this database. */
21
+ abstract change<K extends Key<T>>(...changes: Nullish<WriteChange<T, K>>[]): ItemChanges<T, K> | Promise<ItemChanges<T, K>>;
18
22
  }
19
23
  /** Database with a synchronous provider. */
20
- export declare class Database<T extends Datas = Datas> implements AbstractDatabase<T> {
24
+ export declare class Database<T extends Datas = Datas> implements BaseDatabase<T> {
21
25
  readonly provider: Provider<T>;
22
26
  constructor(provider: Provider<T>);
23
27
  collection<K extends Key<T>>(collection: K): Collection<T, K>;
24
28
  query<K extends Key<T>>(collection: K, filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): Query<T, K>;
25
29
  item<K extends Key<T>>(collection: K, id: string): Item<T, K>;
30
+ change<K extends Key<T>>(...changes: Nullish<WriteChange<T, K>>[]): ItemChanges<T, K>;
26
31
  }
27
32
  /** Database with a synchronous provider. */
28
- export declare class AsyncDatabase<T extends Datas = Datas> implements AbstractDatabase<T> {
33
+ export declare class AsyncDatabase<T extends Datas = Datas> implements BaseDatabase<T> {
29
34
  readonly provider: AsyncProvider<T>;
30
35
  constructor(provider: AsyncProvider<T>);
31
36
  collection<K extends Key<T>>(collection: K): AsyncCollection<T, K>;
32
37
  query<K extends Key<T>>(collection: K, filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): AsyncQuery<T, K>;
33
38
  item<K extends Key<T>>(collection: K, id: string): AsyncItem<T, K>;
39
+ change<K extends Key<T>>(...changes: Nullish<WriteChange<T, K>>[]): Promise<ItemChanges<T, K>>;
34
40
  }
35
41
  export {};
package/db/Database.js CHANGED
@@ -1,6 +1,10 @@
1
1
  import { Item, AsyncItem } from "./Item.js";
2
2
  import { Query, AsyncQuery } from "./Query.js";
3
3
  import { Collection, AsyncCollection } from "./Collection.js";
4
+ import { changeAsyncProvider, changeProvider } from "./Change.js";
5
+ /** Database with a synchronous or asynchronous provider. */
6
+ class BaseDatabase {
7
+ }
4
8
  /** Database with a synchronous provider. */
5
9
  export class Database {
6
10
  constructor(provider) {
@@ -15,6 +19,9 @@ export class Database {
15
19
  item(collection, id) {
16
20
  return new Item(this, collection, id);
17
21
  }
22
+ change(...changes) {
23
+ return changeProvider(this.provider, changes);
24
+ }
18
25
  }
19
26
  /** Database with a synchronous provider. */
20
27
  export class AsyncDatabase {
@@ -30,4 +37,7 @@ export class AsyncDatabase {
30
37
  item(collection, id) {
31
38
  return new AsyncItem(this, collection, id);
32
39
  }
40
+ change(...changes) {
41
+ return changeAsyncProvider(this.provider, changes);
42
+ }
33
43
  }
package/db/Item.d.ts CHANGED
@@ -7,6 +7,7 @@ import { DataUpdate, PropUpdates } from "../update/DataUpdate.js";
7
7
  import type { QueryConstraints } from "../constraint/QueryConstraints.js";
8
8
  import type { AsyncDatabase, Database } from "./Database.js";
9
9
  import type { AsyncQuery, Query } from "./Query.js";
10
+ import type { DeleteChange, SetChange, UpdateChange } from "./Change.js";
10
11
  /** Item data with a string ID that uniquely identifies it. */
11
12
  export declare type ItemData<T extends Data = Data> = T & {
12
13
  id: string;
@@ -18,21 +19,22 @@ export declare type ItemArray<T extends Data = Data> = ImmutableArray<ItemData<T
18
19
  /** A set of query constraints for item data. */
19
20
  export declare type ItemConstraints<T extends Data = Data> = QueryConstraints<ItemData<T>>;
20
21
  /** Reference to an item in a synchronous or asynchronous provider. */
21
- interface ItemInterface<T extends Datas = Datas, K extends Key<T> = Key<T>> extends Observable<ItemValue<T[K]>> {
22
- readonly collection: K;
23
- readonly id: string;
22
+ declare abstract class BaseItem<T extends Datas = Datas, K extends Key<T> = Key<T>> implements Observable<ItemValue<T[K]>> {
23
+ abstract readonly db: Database<T> | AsyncDatabase<T>;
24
+ abstract readonly collection: K;
25
+ abstract readonly id: string;
24
26
  /** Get an 'optional' reference to this item (uses a `ModelQuery` with an `id` filter). */
25
- optional: Query<T, K> | AsyncQuery<T, K>;
27
+ abstract optional: Query<T, K> | AsyncQuery<T, K>;
26
28
  /**
27
29
  * Does this item exist?
28
30
  * @return `true` if an item exists or `false` otherwise (possibly promised).
29
31
  */
30
- exists: boolean | PromiseLike<boolean>;
32
+ abstract exists: boolean | PromiseLike<boolean>;
31
33
  /**
32
34
  * Get the optional data of this item.
33
35
  * @return Document's data, or `null` if the item doesn't exist (possibly promised).
34
36
  */
35
- value: ItemValue<T[K]> | PromiseLike<ItemValue<T[K]>>;
37
+ abstract value: ItemValue<T[K]> | PromiseLike<ItemValue<T[K]>>;
36
38
  /**
37
39
  * Get the data of this item.
38
40
  * - Useful for destructuring, e.g. `{ name, title } = await itemThatMustExist.asyncData`
@@ -40,7 +42,7 @@ interface ItemInterface<T extends Datas = Datas, K extends Key<T> = Key<T>> exte
40
42
  * @return Document's data (possibly promised).
41
43
  * @throws RequiredError if the item does not exist.
42
44
  */
43
- data: ItemData<T[K]> | PromiseLike<ItemData<T[K]>>;
45
+ abstract data: ItemData<T[K]> | PromiseLike<ItemData<T[K]>>;
44
46
  /**
45
47
  * Subscribe to the result of this item (indefinitely).
46
48
  * - `next()` is called once with the initial result, and again any time the result changes.
@@ -50,15 +52,21 @@ interface ItemInterface<T extends Datas = Datas, K extends Key<T> = Key<T>> exte
50
52
  */
51
53
  subscribe(next: PartialObserver<ItemValue<T[K]>> | Dispatch<[ItemValue<T[K]>]>): Unsubscribe;
52
54
  /** Set the complete data of this item. */
53
- set(data: T[K]): void | PromiseLike<void>;
55
+ abstract set(data: T[K]): void | PromiseLike<void>;
54
56
  /** Update this item. */
55
- update(updates: DataUpdate<T[K]> | PropUpdates<T[K]>): void | PromiseLike<void>;
57
+ abstract update(updates: DataUpdate<T[K]> | PropUpdates<T[K]>): void | PromiseLike<void>;
56
58
  /** Delete this item. */
57
- delete(): void | PromiseLike<void>;
59
+ abstract delete(): void | PromiseLike<void>;
60
+ /** Get a set change for this item. */
61
+ getSet(data: T[K]): SetChange<T, K>;
62
+ /** Get an update change for this item. */
63
+ getUpdate(updates: DataUpdate<T[K]> | PropUpdates<T[K]>): UpdateChange<T, K>;
64
+ /** Get a delete change for this item. */
65
+ getDelete(): DeleteChange<T, K>;
58
66
  toString(): `${K}/${string}`;
59
67
  }
60
68
  /** Reference to an item in a synchronous provider. */
61
- export declare class Item<T extends Datas = Datas, K extends Key<T> = Key<T>> implements ItemInterface<T, K> {
69
+ export declare class Item<T extends Datas = Datas, K extends Key<T> = Key<T>> extends BaseItem<T, K> {
62
70
  readonly db: Database<T>;
63
71
  readonly collection: K;
64
72
  readonly id: string;
@@ -67,14 +75,12 @@ export declare class Item<T extends Datas = Datas, K extends Key<T> = Key<T>> im
67
75
  get exists(): boolean;
68
76
  get value(): ItemValue<T[K]>;
69
77
  get data(): ItemData<T[K]>;
70
- subscribe(next: PartialObserver<ItemValue<T[K]>> | Dispatch<[ItemValue<T[K]>]>): Unsubscribe;
71
78
  set(data: T[K]): void;
72
79
  update(updates: DataUpdate<T[K]> | PropUpdates<T[K]>): void;
73
80
  delete(): void;
74
- toString(): `${K}/${string}`;
75
81
  }
76
82
  /** Reference to an item in an asynchronous provider. */
77
- export declare class AsyncItem<T extends Datas = Datas, K extends Key<T> = Key<T>> implements ItemInterface<T, K> {
83
+ export declare class AsyncItem<T extends Datas = Datas, K extends Key<T> = Key<T>> extends BaseItem<T, K> {
78
84
  readonly db: AsyncDatabase<T>;
79
85
  readonly collection: K;
80
86
  readonly id: string;
@@ -83,11 +89,9 @@ export declare class AsyncItem<T extends Datas = Datas, K extends Key<T> = Key<T
83
89
  get exists(): Promise<boolean>;
84
90
  get value(): Promise<ItemValue<T[K]>>;
85
91
  get data(): Promise<ItemData<T[K]>>;
86
- subscribe(next: PartialObserver<ItemValue<T[K]>> | Dispatch<[ItemValue<T[K]>]>): Unsubscribe;
87
92
  set(data: T[K]): Promise<void>;
88
93
  update(updates: DataUpdate<T[K]> | PropUpdates<T[K]>): Promise<void>;
89
94
  delete(): Promise<void>;
90
- toString(): `${K}/${string}`;
91
95
  }
92
96
  /** Get the ID from item data. */
93
97
  export declare const getID: <T extends Data>({ id }: ItemData<T>) => string;
package/db/Item.js CHANGED
@@ -1,9 +1,40 @@
1
1
  import { getData } from "../util/data.js";
2
2
  import { FilterConstraint } from "../constraint/FilterConstraint.js";
3
3
  import { DataUpdate } from "../update/DataUpdate.js";
4
+ import { isTransformable } from "../util/transform.js";
5
+ /** Reference to an item in a synchronous or asynchronous provider. */
6
+ class BaseItem {
7
+ /**
8
+ * Subscribe to the result of this item (indefinitely).
9
+ * - `next()` is called once with the initial result, and again any time the result changes.
10
+ *
11
+ * @param next Observer with `next`, `error`, or `complete` methods or a `next()` dispatcher.
12
+ * @return Function that ends the subscription.
13
+ */
14
+ subscribe(next) {
15
+ return this.db.provider.subscribeItem(this.collection, this.id, typeof next === "function" ? { next } : next);
16
+ }
17
+ /** Get a set change for this item. */
18
+ getSet(data) {
19
+ return { action: "SET", collection: this.collection, id: this.id, data };
20
+ }
21
+ /** Get an update change for this item. */
22
+ getUpdate(updates) {
23
+ return { action: "UPDATE", collection: this.collection, id: this.id, update: updates instanceof DataUpdate ? updates : new DataUpdate(updates) };
24
+ }
25
+ /** Get a delete change for this item. */
26
+ getDelete() {
27
+ return { action: "DELETE", collection: this.collection, id: this.id };
28
+ }
29
+ // Implement toString()
30
+ toString() {
31
+ return `${this.collection}/${this.id}`;
32
+ }
33
+ }
4
34
  /** Reference to an item in a synchronous provider. */
5
- export class Item {
35
+ export class Item extends BaseItem {
6
36
  constructor(db, collection, id) {
37
+ super();
7
38
  this.db = db;
8
39
  this.collection = collection;
9
40
  this.id = id;
@@ -20,25 +51,20 @@ export class Item {
20
51
  get data() {
21
52
  return getData(this.value);
22
53
  }
23
- subscribe(next) {
24
- return this.db.provider.subscribeItem(this.collection, this.id, typeof next === "function" ? { next } : next);
25
- }
26
54
  set(data) {
27
55
  return this.db.provider.setItem(this.collection, this.id, data);
28
56
  }
29
57
  update(updates) {
30
- return this.db.provider.updateItem(this.collection, this.id, updates instanceof DataUpdate ? updates : new DataUpdate(updates));
58
+ return this.db.provider.updateItem(this.collection, this.id, isTransformable(updates) ? updates : new DataUpdate(updates));
31
59
  }
32
60
  delete() {
33
61
  return this.db.provider.deleteItem(this.collection, this.id);
34
62
  }
35
- toString() {
36
- return `${this.collection}/${this.id}`;
37
- }
38
63
  }
39
64
  /** Reference to an item in an asynchronous provider. */
40
- export class AsyncItem {
65
+ export class AsyncItem extends BaseItem {
41
66
  constructor(provider, collection, id) {
67
+ super();
42
68
  this.db = provider;
43
69
  this.collection = collection;
44
70
  this.id = id;
@@ -55,21 +81,15 @@ export class AsyncItem {
55
81
  get data() {
56
82
  return this.value.then(getData);
57
83
  }
58
- subscribe(next) {
59
- return this.db.provider.subscribeItem(this.collection, this.id, typeof next === "function" ? { next } : next);
60
- }
61
84
  set(data) {
62
85
  return this.db.provider.setItem(this.collection, this.id, data);
63
86
  }
64
87
  update(updates) {
65
- return this.db.provider.updateItem(this.collection, this.id, updates instanceof DataUpdate ? updates : new DataUpdate(updates));
88
+ return this.db.provider.updateItem(this.collection, this.id, isTransformable(updates) ? updates : new DataUpdate(updates));
66
89
  }
67
90
  delete() {
68
91
  return this.db.provider.deleteItem(this.collection, this.id);
69
92
  }
70
- toString() {
71
- return `${this.collection}/${this.id}`;
72
- }
73
93
  }
74
94
  /** Get the ID from item data. */
75
95
  export const getID = ({ id }) => id;
package/db/Query.d.ts CHANGED
@@ -9,43 +9,44 @@ import { DataUpdate, PropUpdates } from "../update/DataUpdate.js";
9
9
  import type { ItemArray, ItemValue, ItemData } from "./Item.js";
10
10
  import type { AsyncDatabase, Database } from "./Database.js";
11
11
  /** Reference to a set of items in a sync or async provider. */
12
- interface QueryInterface<T extends Datas = Datas, K extends Key<T> = Key<T>> extends QueryConstraints<ItemData<T[K]>>, Observable<ItemArray<T[K]>> {
13
- readonly collection: K;
12
+ declare abstract class BaseQuery<T extends Datas = Datas, K extends Key<T> = Key<T>> extends QueryConstraints<ItemData<T[K]>> implements Observable<ItemArray<T[K]>> {
13
+ abstract readonly db: Database<T> | AsyncDatabase<T>;
14
+ abstract readonly collection: K;
14
15
  /**
15
16
  * Get array of entities for this query.
16
17
  * @return Array of entities.
17
18
  */
18
- value: ItemArray<T[K]> | PromiseLike<ItemArray<T[K]>>;
19
+ abstract value: ItemArray<T[K]> | PromiseLike<ItemArray<T[K]>>;
19
20
  /**
20
21
  * Count the number of results of this set of items.
21
22
  * @return Number of items matching the query (possibly promised).
22
23
  */
23
- count: number | PromiseLike<number>;
24
+ abstract count: number | PromiseLike<number>;
24
25
  /**
25
26
  * Does at least one item exist for this query?
26
27
  * @return `true` if a item exists or `false` otherwise (possibly promised).
27
28
  */
28
- exists: boolean | PromiseLike<boolean>;
29
+ abstract exists: boolean | PromiseLike<boolean>;
29
30
  /**
30
31
  * Get the first item matched by this query or `null` if this query has no results.
31
32
  * @throws RequiredError if there were no results for this query.
32
33
  */
33
- firstValue: ItemValue<T[K]> | PromiseLike<ItemValue<T[K]>>;
34
+ abstract firstValue: ItemValue<T[K]> | PromiseLike<ItemValue<T[K]>>;
34
35
  /**
35
36
  * Get the first item matched by this query.
36
37
  * @throws RequiredError if there were no results for this query.
37
38
  */
38
- firstData: ItemData<T[K]> | PromiseLike<ItemData<T[K]>>;
39
+ abstract firstData: ItemData<T[K]> | PromiseLike<ItemData<T[K]>>;
39
40
  /**
40
41
  * Get the last item matched by this query or `null` if this query has no results.
41
42
  * @throws RequiredError if there were no results for this query.
42
43
  */
43
- lastValue: ItemValue<T[K]> | PromiseLike<ItemValue<T[K]>>;
44
+ abstract lastValue: ItemValue<T[K]> | PromiseLike<ItemValue<T[K]>>;
44
45
  /**
45
46
  * Get the last item matched by this query.
46
47
  * @throws RequiredError if there were no results for this query.
47
48
  */
48
- lastData: ItemData<T[K]> | PromiseLike<ItemData<T[K]>>;
49
+ abstract lastData: ItemData<T[K]> | PromiseLike<ItemData<T[K]>>;
49
50
  /**
50
51
  * Subscribe to all matching items.
51
52
  * - `next()` is called once with the initial results, and again any time the results change.
@@ -60,22 +61,23 @@ interface QueryInterface<T extends Datas = Datas, K extends Key<T> = Key<T>> ext
60
61
  * @param data Complete data to set the item to.
61
62
  * @return Nothing (possibly promised).
62
63
  */
63
- set(data: T[K]): number | PromiseLike<number>;
64
+ abstract set(data: T[K]): number | PromiseLike<number>;
64
65
  /**
65
66
  * Update all matching items with the same partial value.
66
67
  *
67
68
  * @param updates `Update` instance or set of updates to apply to every matching item.
68
69
  * @return Nothing (possibly promised).
69
70
  */
70
- update(updates: DataUpdate<T[K]> | PropUpdates<T[K]>): number | PromiseLike<number>;
71
+ abstract update(updates: DataUpdate<T[K]> | PropUpdates<T[K]>): number | PromiseLike<number>;
71
72
  /**
72
73
  * Delete all matching items.
73
74
  * @return Nothing (possibly promised).
74
75
  */
75
- delete(): number | PromiseLike<number>;
76
+ abstract delete(): number | PromiseLike<number>;
77
+ toString(): string;
76
78
  }
77
79
  /** Reference to a set of items in a provider. */
78
- export declare class Query<T extends Datas = Datas, K extends Key<T> = Key<T>> extends QueryConstraints<ItemData<T[K]>> implements QueryInterface<T, K> {
80
+ export declare class Query<T extends Datas = Datas, K extends Key<T> = Key<T>> extends BaseQuery<T, K> implements BaseQuery<T, K> {
79
81
  readonly db: Database<T>;
80
82
  readonly collection: K;
81
83
  constructor(db: Database<T>, collection: K, filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null);
@@ -86,18 +88,15 @@ export declare class Query<T extends Datas = Datas, K extends Key<T> = Key<T>> e
86
88
  get firstData(): ItemData<T[K]>;
87
89
  get lastValue(): ItemValue<T[K]>;
88
90
  get lastData(): ItemData<T[K]>;
89
- subscribe(next: PartialObserver<ItemArray<T[K]>> | Dispatch<[ItemArray<T[K]>]>): Unsubscribe;
90
91
  set(data: T[K]): number;
91
92
  update(updates: DataUpdate<T[K]> | PropUpdates<T[K]>): number;
92
93
  delete(): number;
93
- toString(): string;
94
94
  }
95
95
  /** Reference to a set of items in a provider. */
96
- export declare class AsyncQuery<T extends Datas = Datas, K extends Key<T> = Key<T>> extends QueryConstraints<ItemData<T[K]>> implements QueryInterface<T, K> {
96
+ export declare class AsyncQuery<T extends Datas = Datas, K extends Key<T> = Key<T>> extends BaseQuery<T, K> implements BaseQuery<T, K> {
97
97
  readonly db: AsyncDatabase<T>;
98
98
  readonly collection: K;
99
99
  constructor(db: AsyncDatabase<T>, collection: K, filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null);
100
- closed?: boolean;
101
100
  get value(): Promise<ItemArray<T[K]>>;
102
101
  get count(): Promise<number>;
103
102
  get exists(): Promise<boolean>;
@@ -105,10 +104,8 @@ export declare class AsyncQuery<T extends Datas = Datas, K extends Key<T> = Key<
105
104
  get firstData(): Promise<ItemData<T[K]>>;
106
105
  get lastValue(): Promise<ItemValue<T[K]>>;
107
106
  get lastData(): Promise<ItemData<T[K]>>;
108
- subscribe(next: PartialObserver<ItemArray<T[K]>> | Dispatch<[ItemArray<T[K]>]>): Unsubscribe;
109
107
  set(data: T[K]): Promise<number>;
110
108
  update(updates: DataUpdate<T[K]> | PropUpdates<T[K]>): PromiseLike<number>;
111
109
  delete(): PromiseLike<number>;
112
- toString(): string;
113
110
  }
114
111
  export {};
package/db/Query.js CHANGED
@@ -2,8 +2,25 @@ import { getFirstItem, getLastItem, getOptionalFirstItem, getOptionalLastItem }
2
2
  import { QueryConstraints } from "../constraint/QueryConstraints.js";
3
3
  import { countItems, hasItems } from "../util/iterate.js";
4
4
  import { DataUpdate } from "../update/DataUpdate.js";
5
+ /** Reference to a set of items in a sync or async provider. */
6
+ class BaseQuery extends QueryConstraints {
7
+ /**
8
+ * Subscribe to all matching items.
9
+ * - `next()` is called once with the initial results, and again any time the results change.
10
+ *
11
+ * @param next Observer with `next`, `error`, or `complete` methods or a `next()` dispatcher.
12
+ * @return Function that ends the subscription.
13
+ */
14
+ subscribe(next) {
15
+ return this.db.provider.subscribeQuery(this.collection, this, typeof next === "function" ? { next } : next);
16
+ }
17
+ // Override to include the collection name.
18
+ toString() {
19
+ return `${this.collection}?${super.toString()}`;
20
+ }
21
+ }
5
22
  /** Reference to a set of items in a provider. */
6
- export class Query extends QueryConstraints {
23
+ export class Query extends BaseQuery {
7
24
  constructor(db, collection, filters, sorts, limit) {
8
25
  super(filters, sorts, limit);
9
26
  this.db = db;
@@ -30,9 +47,6 @@ export class Query extends QueryConstraints {
30
47
  get lastData() {
31
48
  return getLastItem(this.value);
32
49
  }
33
- subscribe(next) {
34
- return this.db.provider.subscribeQuery(this.collection, this, typeof next === "function" ? { next } : next);
35
- }
36
50
  set(data) {
37
51
  return this.db.provider.setQuery(this.collection, this, data);
38
52
  }
@@ -42,12 +56,9 @@ export class Query extends QueryConstraints {
42
56
  delete() {
43
57
  return this.db.provider.deleteQuery(this.collection, this);
44
58
  }
45
- toString() {
46
- return `${this.collection}?${super.toString()}`;
47
- }
48
59
  }
49
60
  /** Reference to a set of items in a provider. */
50
- export class AsyncQuery extends QueryConstraints {
61
+ export class AsyncQuery extends BaseQuery {
51
62
  constructor(db, collection, filters, sorts, limit) {
52
63
  super(filters, sorts, limit);
53
64
  this.db = db;
@@ -74,9 +85,6 @@ export class AsyncQuery extends QueryConstraints {
74
85
  get lastData() {
75
86
  return this.value.then(getLastItem);
76
87
  }
77
- subscribe(next) {
78
- return this.db.provider.subscribeQuery(this.collection, this, typeof next === "function" ? { next } : next);
79
- }
80
88
  set(data) {
81
89
  return this.db.provider.setQuery(this.collection, this, data);
82
90
  }
@@ -86,7 +94,4 @@ export class AsyncQuery extends QueryConstraints {
86
94
  delete() {
87
95
  return this.db.provider.deleteQuery(this.collection, this);
88
96
  }
89
- toString() {
90
- return `${this.collection}?${super.toString()}`;
91
- }
92
97
  }
package/db/index.d.ts CHANGED
@@ -2,4 +2,4 @@ export * from "./Database.js";
2
2
  export * from "./Collection.js";
3
3
  export * from "./Item.js";
4
4
  export * from "./Query.js";
5
- export * from "./Changes.js";
5
+ export * from "./Change.js";
package/db/index.js CHANGED
@@ -2,4 +2,4 @@ export * from "./Database.js";
2
2
  export * from "./Collection.js";
3
3
  export * from "./Item.js";
4
4
  export * from "./Query.js";
5
- export * from "./Changes.js";
5
+ export * from "./Change.js";
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "state-management",
12
12
  "query-builder"
13
13
  ],
14
- "version": "1.73.2",
14
+ "version": "1.75.0",
15
15
  "repository": "https://github.com/dhoulb/shelving",
16
16
  "author": "Dave Houlbrooke <dave@shax.com>",
17
17
  "license": "0BSD",
package/util/index.d.ts CHANGED
@@ -28,6 +28,7 @@ export * from "./random.js";
28
28
  export * from "./regexp.js";
29
29
  export * from "./serialise.js";
30
30
  export * from "./sort.js";
31
+ export * from "./source.js";
31
32
  export * from "./string.js";
32
33
  export * from "./template.js";
33
34
  export * from "./timeout.js";
package/util/index.js CHANGED
@@ -28,6 +28,7 @@ export * from "./random.js";
28
28
  export * from "./regexp.js";
29
29
  export * from "./serialise.js";
30
30
  export * from "./sort.js";
31
+ export * from "./source.js";
31
32
  export * from "./string.js";
32
33
  export * from "./template.js";
33
34
  export * from "./timeout.js";
@@ -6,7 +6,7 @@ import type { ArrayType, ImmutableArray } from "./array.js";
6
6
  export interface Transformable<I, O> {
7
7
  transform(input: I): O;
8
8
  }
9
- /** Is an unknown value a derivable. */
9
+ /** Is an unknown value a transformable. */
10
10
  export declare const isTransformable: <T extends Transformable<unknown, unknown>>(v: unknown) => v is T;
11
11
  /** Function that can transform an input value into an output value. */
12
12
  export declare type Transform<I, O> = (input: I) => O;
package/util/transform.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { isFunction } from "./function.js";
2
2
  import { getProps, isData } from "./data.js";
3
3
  import { getEntries } from "./entry.js";
4
- /** Is an unknown value a derivable. */
4
+ /** Is an unknown value a transformable. */
5
5
  export const isTransformable = (v) => isData(v) && typeof v.transform === "function";
6
6
  export function transform(input, transformer) {
7
7
  return isFunction(transformer) ? transformer(input) : isTransformable(transformer) ? transformer.transform(input) : transformer;
package/db/Changes.d.ts DELETED
@@ -1,22 +0,0 @@
1
- import type { Datas, Key } from "../util/data.js";
2
- import { DataUpdate } from "../update/DataUpdate.js";
3
- import type { Provider, AsyncProvider } from "../provider/Provider.js";
4
- import type { Database, AsyncDatabase } from "./Database.js";
5
- /**
6
- * Change set of operations to run against a database in `{ "collection/id": data | DataUpdate | null }` format.
7
- * - If data is an object, sets the item.
8
- * - If data is a `DataUpdate` instance, updates the item.
9
- * - If data is null, deletes the item.
10
- * - If data is undefined, skip the item.
11
- */
12
- export declare type Changes<DB extends Datas> = {
13
- [K in Key<DB> as `${K}/${string}`]: DB[K] | DataUpdate<DB[K]> | null | undefined;
14
- };
15
- /** Apply a set of changes to a synchronous database. */
16
- export declare function changeDatabase<T extends Datas>({ provider }: Database<T>, changes: Changes<T>): Changes<T>;
17
- /** Apply a set of changes to an asynchronous database. */
18
- export declare function changeAsyncDatabase<T extends Datas>({ provider }: AsyncDatabase<T>, changes: Changes<T>): Promise<Changes<T>>;
19
- /** Apply a set of changes to a synchronous provider. */
20
- export declare function changeProvider<T extends Datas>(provider: Provider<T>, changes: Changes<T>): Changes<T>;
21
- /** Apply a set of changes to an asynchronous provider. */
22
- export declare function changeAsyncProvider<T extends Datas>(provider: AsyncProvider<T>, changes: Changes<T>): Promise<Changes<T>>;
package/db/Changes.js DELETED
@@ -1,40 +0,0 @@
1
- import { splitString } from "../util/string.js";
2
- import { DataUpdate } from "../update/DataUpdate.js";
3
- /** Apply a set of changes to a synchronous database. */
4
- export function changeDatabase({ provider }, changes) {
5
- return changeProvider(provider, changes);
6
- }
7
- /** Apply a set of changes to an asynchronous database. */
8
- export function changeAsyncDatabase({ provider }, changes) {
9
- return changeAsyncProvider(provider, changes);
10
- }
11
- /** Apply a set of changes to a synchronous provider. */
12
- export function changeProvider(provider, changes) {
13
- for (const [key, change] of Object.entries(changes)) {
14
- const [collection, id] = splitString(key, "/", 2);
15
- if (change === undefined)
16
- continue;
17
- else if (change === null)
18
- provider.deleteItem(collection, id);
19
- else if (change instanceof DataUpdate)
20
- provider.updateItem(collection, id, change);
21
- else
22
- provider.setItem(collection, id, change);
23
- }
24
- return changes;
25
- }
26
- /** Apply a set of changes to an asynchronous provider. */
27
- export async function changeAsyncProvider(provider, changes) {
28
- for (const [key, change] of Object.entries(changes)) {
29
- const [collection, id] = splitString(key, "/", 2);
30
- if (change === undefined)
31
- continue;
32
- else if (change === null)
33
- await provider.deleteItem(collection, id);
34
- else if (change instanceof DataUpdate)
35
- await provider.updateItem(collection, id, change);
36
- else
37
- await provider.setItem(collection, id, change);
38
- }
39
- return changes;
40
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,11 +0,0 @@
1
- import { DataUpdate } from "../index.js";
2
- test("Typescript", () => {
3
- const operations = {
4
- "collection1/a1": { a: 1, one: false },
5
- "collection1/b2": null,
6
- "collection1/b3": new DataUpdate({ one: true }),
7
- "collection2/a1": { b: 1, one: false },
8
- "collection2/b2": null,
9
- "collection2/c3": new DataUpdate({ one: true }),
10
- };
11
- });