@procedures/signaldb 0.0.0-stage → 0.24.1

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.
@@ -0,0 +1,224 @@
1
+ /**
2
+ * A collection storage over the SignalDB collection of an app (roadmap CLI-23, server stack D9).
3
+ *
4
+ * The app owns the SignalDB `Collection`: its persistence, its indexes, its cursors and its
5
+ * reactivity. `SignalDbStorage` reads and writes the items of that collection through the
6
+ * `CollectionStorage` contract. Thus the collection is the local copy of a `HybridStorage`, and
7
+ * the `HybridStorage` owns the sync: the queue, the sync state and the remote.
8
+ *
9
+ * The rules:
10
+ * - Each operation waits for the load of the persistence of the collection (`isReady()`). A failed
11
+ * load does not stop the storage: the collection then keeps its items in memory, as SignalDB does.
12
+ * - A write of SignalDB is synchronous. Each write of the storage reads, tests and writes in one
13
+ * synchronous step. Thus two writes do not mix, and a patch and a precondition are atomic.
14
+ * - A write of several items is one `batch()` of the collection: the indexes and the cursors update
15
+ * one time. The validators of the collection examine each item before the first write. Thus an
16
+ * item that a validator refuses changes nothing.
17
+ * - Each write takes a copy of its value, and each read gives a new copy. A cursor of SignalDB gives
18
+ * copies (`structuredClone`) of the items, and the storage reads only through cursors.
19
+ * - `observe()` gives the batches of the writes of the storage, with their origins. It also gives
20
+ * each change that the app makes directly on the collection: one batch for each change, with no
21
+ * origin. Thus a `HybridStorage` with `capture: "observe"` sends the writes of the app.
22
+ * - `query()` applies `queryEntries()` to the values. It does not give the selector to SignalDB.
23
+ * SignalDB applies Mongo selectors to the items with `mingo`. The contract needs the query
24
+ * language of the client on the values.
25
+ * - `close()` stops the storage. The collection stays open, with its items: the app disposes it.
26
+ *
27
+ * The limits:
28
+ * - A load of the persistence (`persistence.received`) changes the items without the events of a
29
+ * change. `observe()` thus does not tell it. The order of the entries after a load is the order of
30
+ * the persistence adapter.
31
+ * - The collection must not have a `transform`: the storage reads the items through cursors.
32
+ * - Each id is a string. An item of the collection whose `id` is not a string is an error.
33
+ * - The storage keeps no change log, so it has no `getChangesSince()`. A cursor copies each item,
34
+ * so the storage has no cheap `getIds()` either.
35
+ * - A listener of the app that throws in a write of the storage stops the write, and the write
36
+ * rejects. SignalDB keeps the changes before the error. The observers get the changes that the
37
+ * storage knows.
38
+ */
39
+ import type { Collection } from "@signaldb/core";
40
+ import type { CollectionStorage, StorageBatchWriteOptions, StorageItemWriteOptions, StorageMetadata, StorageObserver, StorageWriteOptions } from "@procedures/collections";
41
+ import { type ListenerErrorHandler } from "@procedures/collections";
42
+ import { type StoragePatch, type StorageQueryOptions, type StorageQueryPolicy, type StorageSelector } from "@procedures/client/query";
43
+ import { type SignalDbItemCodec } from "./codec.js";
44
+ /**
45
+ * A SignalDB collection of any item type. The storage reads the items as they are in memory, so the
46
+ * collection must not have a `transform`.
47
+ */
48
+ export type SignalDbCollection = Collection<any, any, any, any>;
49
+ /** The options of a `SignalDbStorage`. */
50
+ export interface SignalDbStorageOptions<T = unknown> {
51
+ /**
52
+ * The change of a value to an item of the collection and back.
53
+ * @default documentCodec(): a document whose `id` is its key is the item, and each other value goes into an envelope
54
+ */
55
+ codec?: SignalDbItemCodec<T> | undefined;
56
+ /**
57
+ * The query policy of `query()` for a call without a policy: the operators and the limits. The
58
+ * procedure `find` gives the policy of its host.
59
+ * @default DEFAULT_QUERY_POLICY: no `$regex`
60
+ */
61
+ queryPolicy?: StorageQueryPolicy | undefined;
62
+ /**
63
+ * The version of a value, for example `(item) => item.rev` (roadmap CLI-16). With it, `set`,
64
+ * `delete` and `setBatch` take an expected version: a write whose current value has another
65
+ * version changes nothing and rejects with `VersionConflictError`. Without it, a write with an
66
+ * expected version rejects with a `TypeError`. Give the `versionOf` of the `HybridStorage` to its
67
+ * local copy.
68
+ */
69
+ versionOf?: ((item: T) => string | undefined) | undefined;
70
+ /**
71
+ * The function that gets the error of an observer of `observe()`, and the error of a change of
72
+ * the app that the storage cannot read. The default throws the error again in a microtask
73
+ * (`reportListenerError`). The write and the other observers do not fail.
74
+ */
75
+ onObserverError?: ListenerErrorHandler | undefined;
76
+ }
77
+ /**
78
+ * A collection storage over the SignalDB collection of an app (roadmap CLI-23).
79
+ *
80
+ * - The collection keeps the items. The storage keeps nothing of its own, and a new storage of the
81
+ * same collection reads the same items.
82
+ * - `observe()` tells the writes of the storage and the changes that the app makes on the collection.
83
+ * - `query()` applies a selector, and `patch()` changes an item in one step.
84
+ * - After `close()`, each operation rejects, and a second `close()` does nothing.
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * import { Collection } from "@signaldb/core";
89
+ * import { ApiStorage, HybridStorage } from "@procedures/store/browser";
90
+ * import { SignalDbStorage } from "@procedures/signaldb";
91
+ *
92
+ * const todos = new Collection<Todo>({ persistence: createIndexedDBAdapter("todos") });
93
+ * const storage = new HybridStorage<Todo>(new ApiStorage(client, { collection: "todos" }), {
94
+ * mode: "write-back",
95
+ * local: new SignalDbStorage<Todo>(todos),
96
+ * capture: "observe",
97
+ * });
98
+ * todos.insert({ id: "t1", title: "Write the docs" }); // the storage sends it to the server
99
+ * ```
100
+ */
101
+ export declare class SignalDbStorage<T> implements CollectionStorage<T> {
102
+ private readonly collection;
103
+ private readonly codec;
104
+ /** The query policy of a call without a policy */
105
+ private readonly queryPolicy;
106
+ /** The version of a value, for the preconditions of the writes (roadmap CLI-16) */
107
+ private readonly versionOf;
108
+ private readonly onObserverError;
109
+ /** The observers of `observe()` */
110
+ private readonly observers;
111
+ /** The load of the persistence of the collection. A failed load also resolves. */
112
+ private readonly ready;
113
+ /** True while a write of this storage runs: its events are not changes of the app */
114
+ private writing;
115
+ /** True while the storage listens to the events of the collection */
116
+ private listening;
117
+ private closed;
118
+ /**
119
+ * @param collection - The SignalDB collection of the app. The app owns it, and `close()` does not dispose it.
120
+ * @param options - The codec, the query policy, `versionOf` and the handler of the errors of the observers.
121
+ */
122
+ constructor(collection: SignalDbCollection, options?: SignalDbStorageOptions<T>);
123
+ /** The name of the collection. */
124
+ get name(): string;
125
+ get(id: string): Promise<T | undefined>;
126
+ getAll(): Promise<T[]>;
127
+ /** Every item with its id, in the order of the collection: the order of the first set of each id. */
128
+ getEntries(): Promise<Array<[string, T]>>;
129
+ /** The items for which the predicate gives true, in the order of the entries. The predicate gets a copy of each item. */
130
+ find(predicate: (item: T) => boolean): Promise<T[]>;
131
+ /**
132
+ * The entries whose values match the selector, with the order, the skip and the limit of
133
+ * `queryEntries()`. The policy is the policy of the call, or else of the options. A query that is
134
+ * not correct rejects with a `TypeError` before the storage reads the collection.
135
+ */
136
+ query(selector: StorageSelector, options?: StorageQueryOptions, policy?: StorageQueryPolicy): Promise<Array<[string, T]>>;
137
+ /**
138
+ * This method starts to send the changes of the collection to the observer.
139
+ *
140
+ * - A write of this storage gives one batch, with the origin of its options, before the write resolves.
141
+ * - A change that the app makes directly on the collection gives one batch with one change and no
142
+ * origin, at once. Examples are `insert`, `updateOne`, `replaceOne` and `removeOne`.
143
+ * - The observers share each batch. A load of the persistence gives no batch.
144
+ *
145
+ * @returns The function that stops the batches. A second use of it does nothing.
146
+ * @throws Error after `close()`
147
+ */
148
+ observe(observer: StorageObserver<T>): () => void;
149
+ has(id: string): Promise<boolean>;
150
+ size(): Promise<number>;
151
+ set(id: string, value: T, options?: StorageItemWriteOptions): Promise<void>;
152
+ delete(id: string, options?: StorageItemWriteOptions): Promise<boolean>;
153
+ /** This method deletes each item of the collection in one batch. A collection with items gives one `clear` change. */
154
+ clear(options?: StorageWriteOptions): Promise<void>;
155
+ /**
156
+ * This method changes the item of the id in one step (a JSON Merge Patch, or the operations
157
+ * `$set`, `$unset`, `$remove` and `$insert`), and gives a copy of the new item. A missing id stays
158
+ * missing, and the result is undefined.
159
+ */
160
+ patch(id: string, fields: StoragePatch, options?: StorageWriteOptions): Promise<T | undefined>;
161
+ /**
162
+ * This method sets several items in one batch of the collection. When one expected version has a
163
+ * conflict, or a validator of the collection refuses one item, nothing changes.
164
+ */
165
+ setBatch(items: Array<[string, T]>, options?: StorageBatchWriteOptions): Promise<void>;
166
+ /** This method deletes several items in one batch of the collection. */
167
+ deleteBatch(ids: string[], options?: StorageWriteOptions): Promise<number>;
168
+ getBatch(ids: string[]): Promise<Map<string, T>>;
169
+ /**
170
+ * This method stops the storage. The collection stays open, with its items: a new storage of the
171
+ * collection reads them. After `close()`, each operation rejects, and a second `close()` does nothing.
172
+ */
173
+ close(): Promise<void>;
174
+ getMetadata(): Promise<StorageMetadata>;
175
+ /** This method throws after `close()`. In an async method, the throw rejects the promise. */
176
+ private checkOpen;
177
+ /** This method waits for the load of the persistence. A close during the wait rejects. */
178
+ private whenReady;
179
+ private problem;
180
+ /** The id and the value of an item that a cursor gave. An item without a string id throws. */
181
+ private entryOf;
182
+ /** The current value of an id: a copy. */
183
+ private current;
184
+ /** The item of a value. The codec must give a plain object with the id. */
185
+ private itemOf;
186
+ /** A write of a value: a copy of the value, and its item. */
187
+ private prepare;
188
+ /** This method writes an item. An existing id keeps its place in the order of the entries. */
189
+ private put;
190
+ /** This method deletes the item of an id. True when the item existed. */
191
+ private remove;
192
+ /**
193
+ * One write of the storage: `body` reads, tests and writes in one synchronous step. The events of
194
+ * the collection during the step are not changes of the app. The observers get the changes of the
195
+ * step after it, also when it fails after a change, with copies of the values.
196
+ */
197
+ private write;
198
+ /**
199
+ * One batch of the collection. `Collection.batch()` of SignalDB does not end its batch when the
200
+ * callback throws, so the error leaves the batch first, and the batch ends.
201
+ */
202
+ private batch;
203
+ /**
204
+ * The preconditions of a write. A storage without `versionOf` throws a `TypeError` before the
205
+ * write starts (roadmap CLI-16).
206
+ */
207
+ private preconditions;
208
+ /** This method tests the expected versions in the step of the write. A conflict throws `VersionConflictError`. */
209
+ private checkVersions;
210
+ private readonly onAdded;
211
+ private readonly onChanged;
212
+ private readonly onRemoved;
213
+ /** This method starts to listen to the changes of the collection. */
214
+ private listen;
215
+ /** This method stops to listen to the changes of the collection. */
216
+ private unlisten;
217
+ /**
218
+ * This method gives a change that the app made on the collection to the observers. It does not
219
+ * throw, because it operates in the write of the app. An item that the storage cannot read goes to
220
+ * `onObserverError`.
221
+ */
222
+ private appChange;
223
+ }
224
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}