@metreeca/keep 0.10.0 → 0.11.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/README.md +49 -42
- package/dist/clients/batching.core.d.ts +30 -10
- package/dist/clients/batching.core.d.ts.map +1 -1
- package/dist/clients/batching.core.js +74 -29
- package/dist/clients/batching.core.js.map +1 -1
- package/dist/clients/batching.d.ts +84 -89
- package/dist/clients/batching.d.ts.map +1 -1
- package/dist/clients/batching.js +36 -32
- package/dist/clients/batching.js.map +1 -1
- package/dist/clients/validating.d.ts +25 -22
- package/dist/clients/validating.d.ts.map +1 -1
- package/dist/clients/validating.js +70 -48
- package/dist/clients/validating.js.map +1 -1
- package/dist/index.d.ts +285 -179
- package/dist/index.d.ts.map +1 -1
- package/dist/stores/caching.d.ts +17 -20
- package/dist/stores/caching.d.ts.map +1 -1
- package/dist/stores/caching.js +60 -51
- package/dist/stores/caching.js.map +1 -1
- package/dist/stores/managing.d.ts +44 -42
- package/dist/stores/managing.d.ts.map +1 -1
- package/dist/stores/managing.js +58 -70
- package/dist/stores/managing.js.map +1 -1
- package/package.json +6 -6
package/dist/stores/managing.js
CHANGED
|
@@ -13,91 +13,79 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
|
|
17
|
-
* Managing store wrapper.
|
|
18
|
-
*
|
|
19
|
-
* Manages mutation events, transactional execution, and lifecycle for a plain {@link StoreClient},
|
|
20
|
-
* exposing it as a full {@link Store}.
|
|
21
|
-
*
|
|
22
|
-
* @module
|
|
23
|
-
*/
|
|
24
|
-
import { isString } from "@metreeca/core";
|
|
16
|
+
import { some } from "@metreeca/core/arrays";
|
|
25
17
|
import { isNestedIRI } from "@metreeca/core/resource";
|
|
26
|
-
import { immutable } from "@metreeca/core/
|
|
18
|
+
import { immutable } from "@metreeca/core/values";
|
|
27
19
|
/**
|
|
28
|
-
* Manages mutation events, transactional execution, and lifecycle for a
|
|
20
|
+
* Manages mutation events, transactional execution, and lifecycle for a connector's {@link StoreClient},
|
|
29
21
|
* exposing it as a full {@link Store}.
|
|
30
22
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* batch of mutation signals and delivers a single filtered event to each matching registered
|
|
37
|
-
* {@link StoreObserver observer} when the call resolves; if it rejects, pending signals are discarded
|
|
38
|
-
* and no observers are notified. Both synchronous throws and asynchronous rejections from observers
|
|
39
|
-
* are caught and silently ignored so that one faulty observer cannot break delivery to others.
|
|
23
|
+
* A connector can implement only the {@link StoreClient} data surface and still offer the full {@link Store}
|
|
24
|
+
* contract. The connector supplies its transaction primitive through `management.execute`, which hands the
|
|
25
|
+
* connector's {@link StoreClient} to every data call. The option is required, since only the connector knows what
|
|
26
|
+
* atomicity its backend can provide. Backend primitives supplied through `management` may also back `observe` or
|
|
27
|
+
* `close`, and the wrapper fills in whatever is missing.
|
|
40
28
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
29
|
+
* Each standalone mutation call and each {@link Store.execute execute} call delivers a single filtered event to each
|
|
30
|
+
* matching {@link StoreObserver observer} once the call resolves. If the call rejects, its pending events are
|
|
31
|
+
* discarded and no observer is notified. Synchronous throws and asynchronous rejections from observers are caught and
|
|
32
|
+
* silently ignored, so one faulty observer cannot break delivery to others.
|
|
43
33
|
*
|
|
44
|
-
* All errors
|
|
45
|
-
* {@link @metreeca/http!Problem | Problem}
|
|
46
|
-
*
|
|
34
|
+
* All errors, including {@link !RangeError RangeError}, {@link @metreeca/core!TraceError | TraceError} and
|
|
35
|
+
* {@link @metreeca/http!Problem | Problem}, propagate as promise rejections, in line with the unified {@link Store}
|
|
36
|
+
* error channel.
|
|
47
37
|
*
|
|
48
38
|
* > [!IMPORTANT]
|
|
49
|
-
* > **Transaction Isolation** —
|
|
50
|
-
* >
|
|
51
|
-
* > the level is determined by that wrapper (typically a backend transaction primitive).
|
|
39
|
+
* > **Transaction Isolation** — Determined by the supplied `execute` option, typically through a backend
|
|
40
|
+
* > transaction primitive: the wrapper adds neither isolation nor atomicity of its own.
|
|
52
41
|
*
|
|
53
42
|
* > [!IMPORTANT]
|
|
54
43
|
* > **Mutation Events** — emits in-process observer events: each standalone mutation and each
|
|
55
44
|
* > {@link Store.execute execute} call delivers a single filtered batch to matching {@link StoreObserver observer}s
|
|
56
|
-
* > on resolve, and none on rejection.
|
|
57
|
-
* > `observe`
|
|
45
|
+
* > on resolve, and none on rejection. Mutations made by other clients reach local observers only if a
|
|
46
|
+
* > backend-bridging `observe` option is supplied through `management`.
|
|
58
47
|
*
|
|
59
|
-
* @param
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* @
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
48
|
+
* @param management - {@link Store} management methods backed by the connector: `execute` is required, and the
|
|
49
|
+
* wrapper fills in whatever else is missing
|
|
50
|
+
* @param management.execute - Transaction wrapper applied to every standalone StoreClient call and to the body of
|
|
51
|
+
* each {@link Store.execute execute} call, typically a backend transaction primitive (for example,
|
|
52
|
+
* `graph.execute` for a SPARQL connector) responsible for atomic commit and rollback. A backend with no
|
|
53
|
+
* transaction primitive supplies a wrapper applying the task directly to its StoreClient, and declares on its
|
|
54
|
+
* factory that a failing task neither rolls back nor isolates its mutations. The option MUST call each task it
|
|
55
|
+
* receives with a `scope` StoreClient dedicated to that call, so per-call state, such as a freshly bound graph
|
|
56
|
+
* buffer, never leaks across concurrent invocations; every data call within the transaction is routed through
|
|
57
|
+
* `scope`. Calls made by a user task inside {@link Store.execute execute} do not open further transactions: they
|
|
58
|
+
* share the outer one. The option MUST convert synchronous throws from the task into promise rejections, to
|
|
59
|
+
* preserve the unified Store error channel: lookups are routed through it with no additional guard
|
|
60
|
+
* @param management.observe - Backend registration for storage-level events, such as mutations made by other clients
|
|
61
|
+
* sharing the backend. Each observer is registered both with this option and locally, and a single detach call
|
|
62
|
+
* releases both registrations. The resource filter always arrives as an array of references, or as `undefined`
|
|
63
|
+
* for an unfiltered registration, so the option never has to handle bare references or single-pass iterables.
|
|
64
|
+
* Absent by default
|
|
65
|
+
* @param management.close - Exposed as is on the returned store. Defaults to a resolved no-op
|
|
76
66
|
*
|
|
77
|
-
* @returns An immutable {@link Store}
|
|
67
|
+
* @returns An immutable {@link Store} serving data calls through the supplied `management` opts
|
|
78
68
|
*/
|
|
79
|
-
export function createManagingStore(
|
|
69
|
+
export function createManagingStore({ observe, execute, close = () => Promise.resolve() }) {
|
|
80
70
|
const observers = new Map();
|
|
81
71
|
return immutable({
|
|
82
|
-
lookup: (
|
|
83
|
-
create:
|
|
84
|
-
update:
|
|
85
|
-
delete:
|
|
86
|
-
insert:
|
|
87
|
-
remove:
|
|
72
|
+
lookup: (request, opts) => execute(store => store.lookup(request, opts)),
|
|
73
|
+
create: request => notify(({ mutated }) => execute(store => store.create(request).then(mutated))),
|
|
74
|
+
update: request => notify(({ mutated }) => execute(store => store.update(request).then(mutated))),
|
|
75
|
+
delete: request => notify(({ deleted }) => execute(store => store.delete(request).then(deleted))),
|
|
76
|
+
insert: request => notify(({ mutated }) => execute(store => store.insert(request).then(mutated))),
|
|
77
|
+
remove: request => notify(({ deleted }) => execute(store => store.remove(request).then(deleted))),
|
|
88
78
|
observe(observer, resources) {
|
|
89
|
-
|
|
79
|
+
// normalise upfront: the filter is drawn from once, so a single-pass iterable is safely
|
|
80
|
+
// shared between the local registration and the delegate
|
|
81
|
+
const filter = resources === undefined ? undefined : some(resources);
|
|
82
|
+
if (filter?.length === 0) {
|
|
90
83
|
return observe?.(observer, []) ?? (() => { });
|
|
91
84
|
}
|
|
92
85
|
else {
|
|
93
86
|
const token = Symbol();
|
|
94
|
-
const detach = observe?.(observer,
|
|
95
|
-
observers.set(token, {
|
|
96
|
-
observer,
|
|
97
|
-
resources: resources === undefined ? undefined
|
|
98
|
-
: isString(resources) ? [resources]
|
|
99
|
-
: [...resources]
|
|
100
|
-
});
|
|
87
|
+
const detach = observe?.(observer, filter);
|
|
88
|
+
observers.set(token, { observer, resources: filter });
|
|
101
89
|
return () => {
|
|
102
90
|
try {
|
|
103
91
|
detach?.();
|
|
@@ -110,12 +98,12 @@ export function createManagingStore(store, { observe, execute = (task) => Promis
|
|
|
110
98
|
},
|
|
111
99
|
execute(task) {
|
|
112
100
|
return notify(({ mutated, deleted }) => execute(store => task(immutable({
|
|
113
|
-
lookup: (
|
|
114
|
-
create:
|
|
115
|
-
update:
|
|
116
|
-
delete:
|
|
117
|
-
insert:
|
|
118
|
-
remove:
|
|
101
|
+
lookup: (request, opts) => store.lookup(request, opts),
|
|
102
|
+
create: request => store.create(request).then(mutated),
|
|
103
|
+
update: request => store.update(request).then(mutated),
|
|
104
|
+
delete: request => store.delete(request).then(deleted),
|
|
105
|
+
insert: request => store.insert(request).then(mutated),
|
|
106
|
+
remove: request => store.remove(request).then(deleted)
|
|
119
107
|
}))));
|
|
120
108
|
},
|
|
121
109
|
close
|
|
@@ -141,7 +129,7 @@ export function createManagingStore(store, { observe, execute = (task) => Promis
|
|
|
141
129
|
const event = {};
|
|
142
130
|
mutations.forEach((exists, id) => {
|
|
143
131
|
// `resources` is `undefined` for an unfiltered registration (fires for every mutation)
|
|
144
|
-
// and an array
|
|
132
|
+
// and an array (possibly empty) for a filtered one
|
|
145
133
|
if (resources === undefined || resources.some(r => isNestedIRI(r, id))) {
|
|
146
134
|
event[id] = exists;
|
|
147
135
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managing.js","sourceRoot":"","sources":["../../src/stores/managing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"managing.js","sourceRoot":"","sources":["../../src/stores/managing.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metreeca/keep",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Core model-driven storage API for @metreeca/keep.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"dist"
|
|
55
55
|
],
|
|
56
56
|
"engines": {
|
|
57
|
-
"node": ">=22.
|
|
57
|
+
"node": ">=22.22.0"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"clean": "rm -rf dist docs node_modules",
|
|
@@ -62,10 +62,10 @@
|
|
|
62
62
|
"check": "npx vitest --typecheck run"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@metreeca/blue": "^0.
|
|
66
|
-
"@metreeca/core": "^0.
|
|
67
|
-
"@metreeca/http": "^0.
|
|
68
|
-
"@metreeca/qest": "^0.
|
|
65
|
+
"@metreeca/blue": "^0.12.0",
|
|
66
|
+
"@metreeca/core": "^0.12.0",
|
|
67
|
+
"@metreeca/http": "^0.4.0",
|
|
68
|
+
"@metreeca/qest": "^0.12.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"typescript": "^5.9.3",
|