@signaldb/core 2.0.0-beta.2 → 2.0.0-beta.21
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/dist/.vite/manifest.json +183 -80
- package/dist/AsyncDataAdapter.d.ts +53 -7
- package/dist/AutoFetchDataAdapter.d.ts +4 -6
- package/dist/Collection/Cursor.d.ts +56 -4
- package/dist/Collection/Observer.d.ts +33 -0
- package/dist/Collection/index.d.ts +66 -19
- package/dist/Collection/types.d.ts +9 -2
- package/dist/DataAdapter.d.ts +24 -6
- package/dist/DefaultDataAdapter.d.ts +5 -5
- package/dist/WorkerDataAdapter.d.ts +57 -5
- package/dist/WorkerDataAdapterHost.d.ts +9 -7
- package/dist/createIndex.d.ts +2 -2
- package/dist/createIndexProvider.d.ts +2 -2
- package/dist/createReactivityAdapter.d.ts +2 -2
- package/dist/createStorageAdapter.d.ts +1 -1
- package/dist/getIndexInfo.d.ts +3 -4
- package/dist/index.cjs.js +33 -31
- package/dist/index.d.ts +6 -1
- package/dist/index.mjs +17 -32
- package/dist/index10.cjs.js +11 -0
- package/dist/index10.mjs +10 -18
- package/dist/index11.cjs.js +23 -0
- package/dist/index11.mjs +22 -15
- package/dist/index12.cjs.js +45 -0
- package/dist/index12.mjs +44 -353
- package/dist/index13.cjs.js +22 -0
- package/dist/index13.mjs +21 -419
- package/dist/index14.cjs.js +45 -0
- package/dist/index14.mjs +44 -206
- package/dist/index15.cjs.js +86 -0
- package/dist/index15.mjs +85 -388
- package/dist/index16.cjs.js +15 -0
- package/dist/index16.mjs +14 -579
- package/dist/index17.cjs.js +141 -0
- package/dist/index17.mjs +140 -152
- package/dist/index18.cjs.js +47 -0
- package/dist/index18.mjs +46 -26
- package/dist/index19.cjs.js +15 -0
- package/dist/index19.mjs +14 -41
- package/dist/index2.cjs.js +33 -0
- package/dist/index2.mjs +32 -258
- package/dist/index20.cjs.js +23 -0
- package/dist/index20.mjs +22 -16
- package/dist/index21.cjs.js +37 -0
- package/dist/index21.mjs +36 -104
- package/dist/index22.cjs.js +35 -0
- package/dist/index22.mjs +34 -128
- package/dist/index23.cjs.js +21 -0
- package/dist/index23.mjs +20 -7
- package/dist/index24.cjs.js +19 -0
- package/dist/index24.mjs +18 -27
- package/dist/index25.cjs.js +157 -0
- package/dist/index25.mjs +156 -11
- package/dist/index26.cjs.js +38 -0
- package/dist/index26.mjs +37 -29
- package/dist/index27.cjs.js +42 -0
- package/dist/index27.mjs +41 -46
- package/dist/index28.cjs.js +347 -0
- package/dist/index28.mjs +345 -7
- package/dist/index29.cjs.js +602 -0
- package/dist/index29.mjs +601 -7
- package/dist/index3.cjs.js +19 -0
- package/dist/index3.mjs +18 -556
- package/dist/index30.cjs.js +11 -0
- package/dist/index30.mjs +10 -42
- package/dist/index31.cjs.js +11 -0
- package/dist/index31.mjs +10 -29
- package/dist/index32.cjs.js +90 -0
- package/dist/index32.mjs +89 -10
- package/dist/index33.cjs.js +53 -0
- package/dist/index33.mjs +52 -5
- package/dist/index34.cjs.js +453 -0
- package/dist/index34.mjs +453 -0
- package/dist/index35.cjs.js +72 -0
- package/dist/index35.mjs +72 -0
- package/dist/index36.cjs.js +580 -0
- package/dist/index36.mjs +580 -0
- package/dist/index37.cjs.js +21 -0
- package/dist/index37.mjs +21 -0
- package/dist/index38.cjs.js +363 -0
- package/dist/index38.mjs +363 -0
- package/dist/index39.cjs.js +513 -0
- package/dist/index39.mjs +513 -0
- package/dist/index4.cjs.js +209 -0
- package/dist/index4.mjs +204 -5
- package/dist/index5.cjs.js +187 -0
- package/dist/index5.mjs +186 -5
- package/dist/index6.cjs.js +303 -0
- package/dist/index6.mjs +301 -28
- package/dist/index7.cjs.js +125 -0
- package/dist/index7.mjs +124 -12
- package/dist/index8.cjs.js +33 -0
- package/dist/index8.mjs +32 -5
- package/dist/index9.cjs.js +12 -0
- package/dist/index9.mjs +11 -133
- package/dist/types/IndexProvider.d.ts +2 -2
- package/dist/types/Modifier.d.ts +1 -1
- package/dist/types/ReactivityAdapter.d.ts +1 -1
- package/dist/types/StorageAdapter.d.ts +9 -1
- package/dist/utils/applyQueryOptions.d.ts +15 -0
- package/dist/utils/createSignal.d.ts +2 -2
- package/dist/utils/getMatchingKeys.d.ts +2 -2
- package/dist/utils/idIndexQuery.d.ts +20 -0
- package/dist/utils/incrementalQueryUpdate.d.ts +62 -0
- package/dist/utils/isFieldExpression.d.ts +1 -1
- package/dist/utils/match.d.ts +1 -1
- package/dist/utils/modify.d.ts +1 -1
- package/dist/utils/projectItems.d.ts +12 -0
- package/dist/utils/queryDelta.d.ts +83 -0
- package/dist/utils/queryId.d.ts +2 -2
- package/dist/utils/reactiveOrAsync.d.ts +59 -0
- package/dist/utils/storageIndexQuery.d.ts +20 -0
- package/package.json +1 -1
- package/dist/index.cjs10.js +0 -18
- package/dist/index.cjs11.js +0 -15
- package/dist/index.cjs12.js +0 -353
- package/dist/index.cjs13.js +0 -419
- package/dist/index.cjs14.js +0 -206
- package/dist/index.cjs15.js +0 -388
- package/dist/index.cjs16.js +0 -579
- package/dist/index.cjs17.js +0 -152
- package/dist/index.cjs18.js +0 -26
- package/dist/index.cjs19.js +0 -42
- package/dist/index.cjs2.js +0 -259
- package/dist/index.cjs20.js +0 -16
- package/dist/index.cjs21.js +0 -104
- package/dist/index.cjs22.js +0 -129
- package/dist/index.cjs23.js +0 -7
- package/dist/index.cjs24.js +0 -27
- package/dist/index.cjs25.js +0 -10
- package/dist/index.cjs26.js +0 -29
- package/dist/index.cjs27.js +0 -46
- package/dist/index.cjs28.js +0 -8
- package/dist/index.cjs29.js +0 -7
- package/dist/index.cjs3.js +0 -557
- package/dist/index.cjs30.js +0 -42
- package/dist/index.cjs31.js +0 -29
- package/dist/index.cjs32.js +0 -9
- package/dist/index.cjs33.js +0 -5
- package/dist/index.cjs4.js +0 -5
- package/dist/index.cjs5.js +0 -5
- package/dist/index.cjs6.js +0 -29
- package/dist/index.cjs7.js +0 -12
- package/dist/index.cjs8.js +0 -5
- package/dist/index.cjs9.js +0 -133
package/dist/index9.mjs
CHANGED
|
@@ -1,134 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Subscribe to an event with a listener function.
|
|
13
|
-
* @param eventName The event name (key of E).
|
|
14
|
-
* @param listener A function that receives the emitted arguments.
|
|
15
|
-
* @returns The emitter instance (for chaining).
|
|
16
|
-
*/
|
|
17
|
-
on(eventName, listener) {
|
|
18
|
-
let listenersSet = this._listenerStore.get(eventName);
|
|
19
|
-
if (!listenersSet) {
|
|
20
|
-
listenersSet = /* @__PURE__ */ new Set();
|
|
21
|
-
this._listenerStore.set(eventName, listenersSet);
|
|
22
|
-
}
|
|
23
|
-
listenersSet.add(listener);
|
|
24
|
-
if (listenersSet.size > this._maxListeners) {
|
|
25
|
-
console.warn(`Possible EventEmitter memory leak detected. ${listenersSet.size} ${String(eventName)} listeners added. Use emitter.setMaxListeners() to increase limit.`);
|
|
26
|
-
}
|
|
27
|
-
return this;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Subscribe to an event with a listener function.
|
|
31
|
-
* @param eventName The event name (key of E).
|
|
32
|
-
* @param listener A function that receives the emitted arguments.
|
|
33
|
-
* @returns The emitter instance (for chaining).
|
|
34
|
-
*/
|
|
35
|
-
addListener(eventName, listener) {
|
|
36
|
-
return this.on(eventName, listener);
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Subscribe to an event, handling it only once. Automatically removes
|
|
40
|
-
* the listener after it fires the first time.
|
|
41
|
-
* @param eventName The event name (key of E).
|
|
42
|
-
* @param listener A function that receives the emitted arguments.
|
|
43
|
-
* @returns The emitter instance (for chaining).
|
|
44
|
-
*/
|
|
45
|
-
once(eventName, listener) {
|
|
46
|
-
const onceWrapper = ((...args) => {
|
|
47
|
-
listener(...args);
|
|
48
|
-
this.off(eventName, onceWrapper);
|
|
49
|
-
});
|
|
50
|
-
return this.on(eventName, onceWrapper);
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Unsubscribe a previously subscribed listener.
|
|
54
|
-
* @param eventName The event name (key of E).
|
|
55
|
-
* @param listener The original function passed to `on` or `once`.
|
|
56
|
-
* @returns The emitter instance (for chaining).
|
|
57
|
-
*/
|
|
58
|
-
off(eventName, listener) {
|
|
59
|
-
const listenersSet = this._listenerStore.get(eventName);
|
|
60
|
-
if (!listenersSet)
|
|
61
|
-
return this;
|
|
62
|
-
listenersSet.delete(listener);
|
|
63
|
-
if (listenersSet.size === 0) {
|
|
64
|
-
this._listenerStore.delete(eventName);
|
|
65
|
-
}
|
|
66
|
-
return this;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Unsubscribe a previously subscribed listener.
|
|
70
|
-
* @param eventName The event name (key of E).
|
|
71
|
-
* @param listener The original function passed to `on` or `once`.
|
|
72
|
-
* @returns The emitter instance (for chaining).
|
|
73
|
-
*/
|
|
74
|
-
removeListener(eventName, listener) {
|
|
75
|
-
return this.off(eventName, listener);
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Emit (dispatch) an event with a variable number of arguments.
|
|
79
|
-
* @param eventName The event name (key of E).
|
|
80
|
-
* @param args The arguments to pass to subscribed listeners.
|
|
81
|
-
*/
|
|
82
|
-
emit(eventName, ...args) {
|
|
83
|
-
this.listeners(eventName).forEach((listener) => {
|
|
84
|
-
listener(...args);
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Returns the array of listener functions currently registered for a given event.
|
|
89
|
-
* @param eventName The event name (key of E).
|
|
90
|
-
* @returns An array of listener functions.
|
|
91
|
-
*/
|
|
92
|
-
listeners(eventName) {
|
|
93
|
-
const listenersSet = this._listenerStore.get(eventName);
|
|
94
|
-
if (!listenersSet)
|
|
95
|
-
return [];
|
|
96
|
-
return [...listenersSet.values()];
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Returns the number of listeners for a given event.
|
|
100
|
-
* @param eventName The event name (key of E).
|
|
101
|
-
* @returns The number of listeners.
|
|
102
|
-
*/
|
|
103
|
-
listenerCount(eventName) {
|
|
104
|
-
const listenersSet = this._listenerStore.get(eventName);
|
|
105
|
-
return listenersSet ? listenersSet.size : 0;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Removes all listeners for a given event, or all events if none is specified.
|
|
109
|
-
* @param eventName Optional. If omitted, clears all events’ listeners.
|
|
110
|
-
* @returns The emitter instance (for chaining).
|
|
111
|
-
*/
|
|
112
|
-
removeAllListeners(eventName) {
|
|
113
|
-
if (eventName === void 0) {
|
|
114
|
-
for (const [eventName_, listenersSet] of this._listenerStore.entries()) {
|
|
115
|
-
for (const listener of listenersSet.values()) {
|
|
116
|
-
this.off(eventName_, listener);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
this._listenerStore.clear();
|
|
120
|
-
} else {
|
|
121
|
-
const listenersSet = this._listenerStore.get(eventName);
|
|
122
|
-
if (listenersSet) {
|
|
123
|
-
for (const listener of listenersSet.values()) {
|
|
124
|
-
this.off(eventName, listener);
|
|
125
|
-
}
|
|
126
|
-
this._listenerStore.delete(eventName);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return this;
|
|
130
|
-
}
|
|
1
|
+
//#region src/utils/randomId.ts
|
|
2
|
+
/**
|
|
3
|
+
* creates a random id
|
|
4
|
+
* @returns a random string of 16 characters
|
|
5
|
+
* @example
|
|
6
|
+
* randomId() // '1234567890abcdef'
|
|
7
|
+
*/
|
|
8
|
+
function randomId() {
|
|
9
|
+
return Array.from({ length: 16 }, () => "abcdefghijklmnopqrstuvwxyz0123456789"[Math.floor(Math.random() * 36)]).join("");
|
|
131
10
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
};
|
|
11
|
+
//#endregion
|
|
12
|
+
export { randomId as default };
|
package/dist/types/Modifier.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { DotNotation, GetType } from './Selector';
|
|
2
2
|
type Dictionary<T> = Record<string, T>;
|
|
3
3
|
type PartialMapTo<T, M> = Partial<Record<DotNotation<T>, M>> & Dictionary<M>;
|
|
4
4
|
type OnlyElementsOfArrays<T> = T extends any[] ? Partial<T[0]> : never;
|
|
@@ -12,7 +12,15 @@ export default interface StorageAdapter<T extends {
|
|
|
12
12
|
readIds(positions: I[]): Promise<T[]>;
|
|
13
13
|
createIndex(field: string): Promise<void>;
|
|
14
14
|
dropIndex(field: string): Promise<void>;
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* The index, keyed by `serializeValue(value)` — not by the raw field value.
|
|
17
|
+
*
|
|
18
|
+
* SignalDB looks an index up with the serialized form, because that is what
|
|
19
|
+
* makes `3`, `'3'` and `new Date(...)` comparable as map keys at all. An
|
|
20
|
+
* adapter that stores its backend's own keys instead answers nothing for
|
|
21
|
+
* every non-string field, and everything for a `$ne` on one.
|
|
22
|
+
*/
|
|
23
|
+
readIndex(field: string): Promise<Map<string | null, Set<I>>>;
|
|
16
24
|
insert(items: T[]): Promise<void>;
|
|
17
25
|
replace(items: T[]): Promise<void>;
|
|
18
26
|
remove(items: T[]): Promise<void>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { QueryOptions } from '../DataAdapter';
|
|
2
|
+
import { default as Selector } from '../types/Selector';
|
|
3
|
+
import { BaseItem } from '../Collection/types';
|
|
4
|
+
/**
|
|
5
|
+
* Filters, sorts, paginates and projects a plain in-memory array the same way
|
|
6
|
+
* DefaultDataAdapter and WorkerDataAdapterHost apply a selector/QueryOptions
|
|
7
|
+
* pair to their stored items. Used to re-derive a query's result locally after
|
|
8
|
+
* a write, without asking the backing store again.
|
|
9
|
+
* @template T - The type of the items.
|
|
10
|
+
* @param items - The items to filter, sort, paginate and project.
|
|
11
|
+
* @param selector - The selector to match items against.
|
|
12
|
+
* @param options - Sort, skip, limit and field projection options.
|
|
13
|
+
* @returns The resulting items.
|
|
14
|
+
*/
|
|
15
|
+
export default function applyQueryOptions<T extends BaseItem>(items: T[], selector: Selector<T>, options?: QueryOptions<T>): T[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { default as ReactivityAdapter } from '../types/ReactivityAdapter';
|
|
2
|
+
import { default as Signal } from '../types/Signal';
|
|
3
3
|
/**
|
|
4
4
|
* Creates a reactive signal for managing state and triggering dependencies.
|
|
5
5
|
* The signal holds a value and provides methods to get and set the value,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { BaseItem } from '../Collection/types';
|
|
2
|
+
import { FlatSelector } from '../types/Selector';
|
|
3
3
|
type KeyResult = {
|
|
4
4
|
include: (string | null)[] | null;
|
|
5
5
|
exclude: (string | null)[] | null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { BaseItem } from '../Collection/types';
|
|
2
|
+
import { IndexResult } from '../types/IndexProvider';
|
|
3
|
+
import { FlatSelector } from '../types/Selector';
|
|
4
|
+
/**
|
|
5
|
+
* Resolves a selector on `id` into the ids it names, without consulting an index.
|
|
6
|
+
*
|
|
7
|
+
* `id` is the one field every storage adapter can look up directly — that is what
|
|
8
|
+
* `readIds` is — so a query on it never needs an index to be declared and never
|
|
9
|
+
* needs the whole collection to be read. This behaves like an index provider that
|
|
10
|
+
* happens to need no stored index, because the ids are already in the selector.
|
|
11
|
+
*
|
|
12
|
+
* Only inclusive forms can be answered this way. `$ne`/`$nin` describe everything
|
|
13
|
+
* except* something, which cannot be enumerated without knowing every id, so they
|
|
14
|
+
* report no match and take the ordinary path.
|
|
15
|
+
* @template T - The type of the items in the collection.
|
|
16
|
+
* @template I - The type of the unique identifier for the items.
|
|
17
|
+
* @param selector - The flat selector to resolve.
|
|
18
|
+
* @returns An index result naming the matched ids, or `{ matched: false }`.
|
|
19
|
+
*/
|
|
20
|
+
export default function idIndexQuery<T extends BaseItem<I> = BaseItem, I = any>(selector: FlatSelector<T>): IndexResult<I>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { QueryOptions } from '../DataAdapter';
|
|
2
|
+
import { BaseItem } from '../Collection/types';
|
|
3
|
+
import { default as Selector } from '../types/Selector';
|
|
4
|
+
/**
|
|
5
|
+
* The items a write created, updated or removed, from the point of view of a store.
|
|
6
|
+
*
|
|
7
|
+
* `upserts` are the *current* state of every item that still exists; `deletes` are the ids of items
|
|
8
|
+
* that no longer do. A write that changes an item's id contributes to both. Callers are responsible
|
|
9
|
+
* for that split — an "affected items" list holding an item's state from before and after a write
|
|
10
|
+
* cannot be told apart from two unrelated items here.
|
|
11
|
+
*/
|
|
12
|
+
export interface QueryChangeset<T extends BaseItem> {
|
|
13
|
+
upserts: T[];
|
|
14
|
+
deletes: any[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Recomputes a query's result from its previous result and the change that was just written,
|
|
18
|
+
* without going back to the store.
|
|
19
|
+
*
|
|
20
|
+
* A store re-executing the query instead reads every item it holds (or every item an index points
|
|
21
|
+
* at) and filters, sorts and projects the lot — for a write that touched one row. This does the
|
|
22
|
+
* same job in the size of the write, which is what a query's result costs to keep up to date when
|
|
23
|
+
* the change that affects it is already in hand.
|
|
24
|
+
*
|
|
25
|
+
* Returns `null` when the previous result is not enough to answer, and the caller has to re-execute
|
|
26
|
+
* the query after all:
|
|
27
|
+
* - `limit` or `skip`: the result is a window onto a larger set, and an item leaving the window has
|
|
28
|
+
* to be replaced by one the previous result never contained.
|
|
29
|
+
* - `fields` together with a `sort` the projection does not keep: the previous items are
|
|
30
|
+
* projected, so a sort key the projection dropped is no longer there to sort by. A projection
|
|
31
|
+
* that keeps every sort key is fine, and is the common case — a list sorted by the same date it
|
|
32
|
+
* displays.
|
|
33
|
+
* - a `null` selector, which matches nothing and is not worth a special case.
|
|
34
|
+
* @template T - The type of the items.
|
|
35
|
+
* @param previous - The query's previous result.
|
|
36
|
+
* @param selector - The query's selector.
|
|
37
|
+
* @param options - The query's options.
|
|
38
|
+
* @param changes - The items the write created, updated or removed.
|
|
39
|
+
* @returns The new result, or `null` when the query has to be re-executed.
|
|
40
|
+
*/
|
|
41
|
+
export default function incrementalQueryUpdate<T extends BaseItem>(previous: T[], selector: Selector<T>, options: QueryOptions<T> | undefined, changes: QueryChangeset<T>): T[] | null;
|
|
42
|
+
/**
|
|
43
|
+
* Folds a change into a query's result, whatever the query's options.
|
|
44
|
+
*
|
|
45
|
+
* The unguarded version of `incrementalQueryUpdate`, for the places where the alternative is not a
|
|
46
|
+
* more accurate answer but a wrong one — layering a write that has not been confirmed yet on top of
|
|
47
|
+
* the last confirmed result, say. For a query returning everything it matches, this is exact. For a
|
|
48
|
+
* window onto a larger set it is the closest the window itself can get: an item that no longer
|
|
49
|
+
* belongs is dropped, one that does is placed, and the window is trimmed back to its length — but
|
|
50
|
+
* an item pulled in from beyond the window is not something the window knows about.
|
|
51
|
+
*
|
|
52
|
+
* What it never does is re-examine the items already in the result. They matched when the store
|
|
53
|
+
* produced them, they still match, and asking again is both wasteful and — for a projected result,
|
|
54
|
+
* whose items no longer carry the fields the selector names — wrong.
|
|
55
|
+
* @template T - The type of the items.
|
|
56
|
+
* @param previous - The query's previous result.
|
|
57
|
+
* @param selector - The query's selector.
|
|
58
|
+
* @param options - The query's options.
|
|
59
|
+
* @param changes - The items the write created, updated or removed.
|
|
60
|
+
* @returns The resulting items.
|
|
61
|
+
*/
|
|
62
|
+
export declare function mergeChangesetIntoResult<T extends BaseItem>(previous: T[], selector: Selector<T>, options: QueryOptions<T> | undefined, changes: QueryChangeset<T>): T[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FieldExpression } from '../types/Selector';
|
|
2
2
|
/**
|
|
3
3
|
* Determines whether a given object is a valid field expression.
|
|
4
4
|
* A field expression is an object containing query operators supported by MongoDB-style queries.
|
package/dist/utils/match.d.ts
CHANGED
package/dist/utils/modify.d.ts
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { QueryOptions } from '../DataAdapter';
|
|
2
|
+
import { BaseItem } from '../Collection/types';
|
|
3
|
+
/**
|
|
4
|
+
* Applies a query's field projection to a list of items, keeping the primary key unless the
|
|
5
|
+
* projection excludes it outright. Returns the items untouched when there is no projection, so a
|
|
6
|
+
* caller does not have to check for one first.
|
|
7
|
+
* @template T - The type of the items.
|
|
8
|
+
* @param items - The items to project.
|
|
9
|
+
* @param fields - The projection, or `undefined` for none.
|
|
10
|
+
* @returns The projected items.
|
|
11
|
+
*/
|
|
12
|
+
export default function projectItems<T extends BaseItem>(items: T[], fields: QueryOptions<T>['fields']): T[];
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { BaseItem } from '../Collection/types';
|
|
2
|
+
/**
|
|
3
|
+
* The change between two consecutive results of the same query, expressed so it can be applied to
|
|
4
|
+
* the earlier result to obtain the later one.
|
|
5
|
+
*
|
|
6
|
+
* Indices in `added` and `moved` are positions in the *resulting* array and are always ascending,
|
|
7
|
+
* which is what makes applying them a matter of splicing in order. Removals and moves name items by
|
|
8
|
+
* id only: whoever applies the delta still holds the previous result and can look the item up
|
|
9
|
+
* there, so there is no reason to send it twice — the point of the whole exercise is that a change
|
|
10
|
+
* costs the size of the change, not the size of the result.
|
|
11
|
+
*/
|
|
12
|
+
export interface QueryDelta<T extends BaseItem = BaseItem> {
|
|
13
|
+
/** Items that were not in the previous result, at their position in the new one. */
|
|
14
|
+
added: {
|
|
15
|
+
index: number;
|
|
16
|
+
item: T;
|
|
17
|
+
}[];
|
|
18
|
+
/** Items that were in the previous result and whose contents changed. */
|
|
19
|
+
changed: T[];
|
|
20
|
+
/** Ids of items that are no longer in the result. */
|
|
21
|
+
removed: any[];
|
|
22
|
+
/** Items that stayed, at their new position, because the order around them changed. */
|
|
23
|
+
moved: {
|
|
24
|
+
index: number;
|
|
25
|
+
id: any;
|
|
26
|
+
}[];
|
|
27
|
+
/** Length of the resulting array — lets a recipient verify it applied the delta to the result it was computed against. */
|
|
28
|
+
resultCount: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Checks whether a delta leaves the result it is applied to unchanged.
|
|
32
|
+
* @param delta - The delta to inspect.
|
|
33
|
+
* @returns `true` when applying the delta would be a no-op.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isEmptyQueryDelta(delta: QueryDelta<any>): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Calls a state-change callback, passing the delta only when there is one.
|
|
38
|
+
*
|
|
39
|
+
* A callback invoked as `callback(state, undefined)` has been handed two arguments, which is a
|
|
40
|
+
* different thing from being handed one — visible to anything that inspects arity, and to any test
|
|
41
|
+
* that asserts on the call.
|
|
42
|
+
* @template T - The type of the items.
|
|
43
|
+
* @param callback - The callback to invoke.
|
|
44
|
+
* @param state - The state to report.
|
|
45
|
+
* @param delta - The delta to report, if there is one.
|
|
46
|
+
*/
|
|
47
|
+
export declare function callWithDelta<T extends BaseItem>(callback: (state: 'active' | 'complete' | 'error', delta?: QueryDelta<T>) => void, state: 'active' | 'complete' | 'error', delta?: QueryDelta<T>): void;
|
|
48
|
+
/**
|
|
49
|
+
* Checks whether a delta describes a change to the given result.
|
|
50
|
+
*
|
|
51
|
+
* A delta is only meaningful against the exact result it was computed from — it names positions in
|
|
52
|
+
* an array and items by id alone. Applying one to anything else produces a result that looks
|
|
53
|
+
* plausible and is wrong, and from then on every further delta compounds the error. This is the
|
|
54
|
+
* cheap structural check that catches that: every id the delta expects to find is there, every id
|
|
55
|
+
* it expects to be new is not, and the arithmetic on the length works out. It costs the size of the
|
|
56
|
+
* delta, not the size of the result.
|
|
57
|
+
* @template T - The type of the items.
|
|
58
|
+
* @param previous - The result the delta would be applied to.
|
|
59
|
+
* @param delta - The delta to check.
|
|
60
|
+
* @returns `true` when the delta can be applied.
|
|
61
|
+
*/
|
|
62
|
+
export declare function canApplyQueryDelta<T extends BaseItem>(previous: T[], delta: QueryDelta<T>): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Computes the delta between two results of the same query.
|
|
65
|
+
*
|
|
66
|
+
* A fallback for the cases where the change that produced the new result is not available — a query
|
|
67
|
+
* that had to be re-executed in full, for instance. It costs a pass over both results, but it is
|
|
68
|
+
* paid once, on the side that has both of them, instead of shipping the entire new result to
|
|
69
|
+
* everyone who only needs to know what changed.
|
|
70
|
+
* @template T - The type of the items.
|
|
71
|
+
* @param previous - The result the delta should be relative to.
|
|
72
|
+
* @param next - The result the delta should produce.
|
|
73
|
+
* @returns The delta between the two results.
|
|
74
|
+
*/
|
|
75
|
+
export declare function diffQueryResults<T extends BaseItem>(previous: T[], next: T[]): QueryDelta<T>;
|
|
76
|
+
/**
|
|
77
|
+
* Applies a delta to the result it was computed against.
|
|
78
|
+
* @template T - The type of the items.
|
|
79
|
+
* @param previous - The result the delta is relative to. Not modified.
|
|
80
|
+
* @param delta - The delta to apply.
|
|
81
|
+
* @returns The resulting items.
|
|
82
|
+
*/
|
|
83
|
+
export declare function applyQueryDelta<T extends BaseItem>(previous: T[], delta: QueryDelta<T>): T[];
|
package/dist/utils/queryId.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { QueryOptions } from '../DataAdapter';
|
|
2
|
+
import { default as Selector } from '../types/Selector';
|
|
3
3
|
/**
|
|
4
4
|
* Generates a unique identifier for a query based on its selector and options.
|
|
5
5
|
* @param selector - The selector object.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export type MaybePromise<T> = T | Promise<T>;
|
|
2
|
+
/**
|
|
3
|
+
* Options that control execution mode (and potential future mode-specific behavior).
|
|
4
|
+
* Keep this minimal; you can extend it later (e.g. signal, timeoutMs, debugLabel).
|
|
5
|
+
*/
|
|
6
|
+
export type ModeOptions = {
|
|
7
|
+
async?: boolean;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* A generator helper that makes TypeScript infer the “synchronous value type” for maybe-async expressions.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* const doc = yield* unwrap(Collection.findOne(...))
|
|
14
|
+
* const list = yield* unwrap(Collection.find(...).fetch())
|
|
15
|
+
*
|
|
16
|
+
* Runtime note:
|
|
17
|
+
* This does not “unwrap” Promises by itself. It yields the value/Promise to the runner and returns the
|
|
18
|
+
* value that the runner feeds back via `.next(...)`.
|
|
19
|
+
* @param value The value (or Promise of a value) to yield to the runner.
|
|
20
|
+
* @returns A generator that yields `value` and resolves to the runner-supplied unwrapped `T`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function unwrap<T>(value: MaybePromise<T>): Generator<MaybePromise<T>, T, T>;
|
|
23
|
+
/**
|
|
24
|
+
* Generator shape used by the factory.
|
|
25
|
+
*
|
|
26
|
+
* `TThis` is the type of `this` inside the generator.
|
|
27
|
+
* `Args` are the method parameters (excluding the mode flag).
|
|
28
|
+
* `TReturn` is the final return value of the workflow.
|
|
29
|
+
* `TNext` is the type that is yielded/awaited and fed back via `.next(...)`.
|
|
30
|
+
*
|
|
31
|
+
* Note:
|
|
32
|
+
* - For best inference at yield sites, prefer `yield* unwrap(expr)` for maybe-async expressions.
|
|
33
|
+
*/
|
|
34
|
+
export type ReactiveOrAsyncGen<TThis, Arguments extends any[], TReturn, TNext> = (this: TThis, a: boolean, ...args: Arguments) => Generator<MaybePromise<TNext>, TReturn, TNext>;
|
|
35
|
+
/**
|
|
36
|
+
* The method type produced from the generator signature.
|
|
37
|
+
* Adds overloads so that `{ async: true }` yields a `Promise<...>` return type.
|
|
38
|
+
*/
|
|
39
|
+
export type ReactiveOrAsyncMethod<TThis, P extends any[], R, N> = {
|
|
40
|
+
(this: TThis, ...args: P): R;
|
|
41
|
+
(this: TThis, ...args: [...P, ModeOptions?]): MaybePromise<R>;
|
|
42
|
+
(this: TThis, ...args: [...P, {
|
|
43
|
+
async: true;
|
|
44
|
+
}]): Promise<R>;
|
|
45
|
+
} & {
|
|
46
|
+
/** Exposes the underlying generator for composition via `yield* method.generator.call(this, a, ...)` */
|
|
47
|
+
generator: (this: TThis, a: boolean, ...args: P) => Generator<MaybePromise<N>, R, N>;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Factory that turns a generator workflow into a callable method that can run in sync (reactive) or async mode.
|
|
51
|
+
*
|
|
52
|
+
* Call style:
|
|
53
|
+
* fn(a, b) -> sync/reactive return
|
|
54
|
+
* await fn(a, b, { async: true }) -> async return
|
|
55
|
+
* @param gen Generator workflow. Receives `(a)` which indicates async mode and should `yield`/`yield* unwrap(...)`
|
|
56
|
+
* any values that may be Promises.
|
|
57
|
+
* @returns A callable method with overloads plus a `.generator` property for composition.
|
|
58
|
+
*/
|
|
59
|
+
export default function reactiveOrAsync<TThis, P extends any[], R, N>(gen: (this: TThis, a: boolean, ...args: P) => Generator<MaybePromise<N>, R, N>): ReactiveOrAsyncMethod<TThis, P, R, N>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { BaseItem } from '../Collection/types';
|
|
2
|
+
import { default as StorageAdapter } from '../types/StorageAdapter';
|
|
3
|
+
import { AsynchronousQueryFunction } from '../types/IndexProvider';
|
|
4
|
+
/**
|
|
5
|
+
* Builds the index provider a data adapter uses to narrow a selector down through
|
|
6
|
+
* a storage adapter's index.
|
|
7
|
+
*
|
|
8
|
+
* Every adapter that keeps its data in a `StorageAdapter` needs exactly this, and
|
|
9
|
+
* each of them used to carry its own copy — three transcriptions of one set of
|
|
10
|
+
* rules about null, `$exists`, inclusion and exclusion, which is how they drift
|
|
11
|
+
* apart without anyone noticing. The index is keyed by `serializeValue(value)`,
|
|
12
|
+
* which is what `getMatchingKeys` produces, so the two only agree while they stay
|
|
13
|
+
* in one place.
|
|
14
|
+
* @template T - The type of the items in the collection.
|
|
15
|
+
* @template I - The type of the unique identifier for the items.
|
|
16
|
+
* @param storage - The storage adapter holding the index.
|
|
17
|
+
* @param field - The indexed field this provider answers for.
|
|
18
|
+
* @returns A query function for `getIndexInfo`.
|
|
19
|
+
*/
|
|
20
|
+
export default function storageIndexQuery<T extends BaseItem<I>, I = any>(storage: Pick<StorageAdapter<T, I>, 'readIndex'>, field: string): AsynchronousQueryFunction<T, I>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signaldb/core",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.21",
|
|
4
4
|
"description": "SignalDB is a client-side database that provides a simple MongoDB-like interface to the data with first-class typescript support to achieve an optimistic UI. Data persistence can be achieved by using storage providers that store the data through a JSON interface to places such as localStorage.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "rimraf dist && vite build",
|
package/dist/index.cjs10.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
function get(value, path) {
|
|
3
|
-
const normalized = path.replaceAll(/\[(\w+)\]/g, ".$1");
|
|
4
|
-
if (normalized.includes("..") || normalized.startsWith(".") || normalized.endsWith(".")) {
|
|
5
|
-
return;
|
|
6
|
-
}
|
|
7
|
-
const segments = normalized.split(".");
|
|
8
|
-
let current = value;
|
|
9
|
-
for (const key of segments) {
|
|
10
|
-
if (current == null)
|
|
11
|
-
return;
|
|
12
|
-
current = current[key];
|
|
13
|
-
}
|
|
14
|
-
if (current === void 0)
|
|
15
|
-
return;
|
|
16
|
-
return current;
|
|
17
|
-
}
|
|
18
|
-
module.exports = get;
|
package/dist/index.cjs11.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
function serializeValue(value) {
|
|
3
|
-
if (value == null)
|
|
4
|
-
return null;
|
|
5
|
-
if (typeof value === "string")
|
|
6
|
-
return value;
|
|
7
|
-
if (typeof value === "number")
|
|
8
|
-
return value.toString();
|
|
9
|
-
if (typeof value === "boolean")
|
|
10
|
-
return value.toString();
|
|
11
|
-
if (value instanceof Date)
|
|
12
|
-
return value.toISOString();
|
|
13
|
-
return JSON.stringify(value);
|
|
14
|
-
}
|
|
15
|
-
module.exports = serializeValue;
|