@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.
@@ -1,61 +1,58 @@
1
1
  /**
2
2
  * Batching store client.
3
3
  *
4
- * Builds a {@link StoreClient} that coalesces concurrent requests of the same kind into a single
5
- * batch, so a connector can serve many requests with one backend round-trip. A connector author
6
- * supplies one {@link Handler} per request type to {@link createBatchingStore}; the returned client
7
- * routes every call through a {@link Broker} that queues like-typed requests and hands each handler
8
- * the whole batch it accumulated.
4
+ * Lets a connector serve many concurrent store requests with few backend round-trips. Requests of the same kind are
5
+ * coalesced into a single batch, and the connector supplies one batch {@link Handler} per kind. The resulting
6
+ * {@link StoreClient} adds conditional CRUD semantics on top, so handlers apply each request unconditionally.
9
7
  *
10
- * Four request types partition the work, each with its own handler:
8
+ * Four request kinds partition the work, each with its own handler:
11
9
  *
12
10
  * - **`detect`** — probes whether each {@link Detect} entry exists in the store
13
- * - **`lookup`** — materialises each {@link Lookup} against its `model`; multi-valued slots reached
14
- * by the model may be delegated to the `select` handler via {@link Broker.select}
15
- * - **`select`** — materialises each {@link Select} collection (see {@link Query} for the admitted
16
- * forms); element resources reached by the query may be delegated to the `lookup` handler via
17
- * {@link Broker.lookup}
18
- * - **`modify`** — creates, updates, or deletes each {@link Modify} target
19
- *
20
- * Retrieval is driven by the requested `model` and `query`, not by the stored graph: `lookup` and
21
- * `select` hand work back and forth, `lookup` spawning a `select` for each multi-valued slot its
22
- * model reaches and `select` spawning a `lookup` for each element resource its query reaches. The
23
- * handover recurses through this alternation and bottoms out where the `model` or `query` stops
24
- * nesting, so each request descends exactly as deep as it asks for, however deep the underlying
25
- * graph runs.
26
- *
27
- * Handlers run concurrently and forward nested requests to one another through the {@link Broker}, so
28
- * a handler must not assume any ordering between handlers, and must await every nested promise it
29
- * issues before settling the request that depends on it. Correctness rests on this data dependency
30
- * alone, not on handler scheduling.
11
+ * - **`detail`** — materialises each {@link Detail} resource against its `model`; multi-valued members reached
12
+ * by the model may be handed to the `select` handler through {@link Broker.select}
13
+ * - **`select`** — materialises each {@link Select} collection against its `query`; element resources reached
14
+ * by the query may be handed to the `detail` handler through {@link Broker.detail}
15
+ * - **`modify`** — creates, updates, or deletes each {@link Modify} target, or links it to a collection
16
+ *
17
+ * Retrieval is driven by the requested `model` and `query`, not by the stored graph. A `detail` handler issues a
18
+ * `select` for each multi-valued member its model reaches, and a `select` handler issues a `detail` for each element
19
+ * resource its query reaches. Each request thus descends exactly as deep as its `model` or `query` nests, however
20
+ * deep the underlying graph runs.
21
+ *
22
+ * > [!IMPORTANT]
23
+ * > Handlers run concurrently and exchange nested requests through the {@link Broker}. A handler must not assume any
24
+ * > ordering between handlers, and must await every nested request it issues before settling the request that
25
+ * > depends on it.
31
26
  *
32
27
  * @module
33
28
  */
34
29
  import type { Property, ResourceShape } from "@metreeca/blue/resource";
35
- import type { Lazy } from "@metreeca/core";
30
+ import { type Match } from "@metreeca/blue/value";
31
+ import { type Lazy } from "@metreeca/core";
36
32
  import type { Tag } from "@metreeca/core/language";
37
- import type { Reference, Resource } from "@metreeca/qest/resource";
38
- import type { Instance, Query, Template } from "@metreeca/qest/template";
33
+ import type { Query, Slot, Template } from "@metreeca/qest/model";
34
+ import type { Reference, Resource, Value } from "@metreeca/qest/state";
39
35
  import type { StoreClient } from "../index.js";
40
36
  /**
41
37
  * Requests accepted by {@link Broker}.
42
38
  */
43
- export type Request = Detect | Lookup | Select | Modify;
39
+ export type Request = Detect | Detail | Select | Modify;
44
40
  /**
45
41
  * Result of running a {@link Request}, narrowed by request variant:
46
42
  *
47
43
  * - a {@link Detect} resolves to a `boolean` existence flag
48
- * - a {@link Lookup} resolves to its materialised resource {@link Instance}
49
- * - a {@link Select} resolves to its materialised collection {@link Instance}
44
+ * - a {@link Detail} resolves to the materialised resource, typed by its shape and model
45
+ * - a {@link Select} resolves to the {@link Value | values} its collection holds, untyped since its shape is
46
+ * carried as a value rather than as a type parameter
50
47
  * - a {@link Modify} resolves to its mutated entry's {@link Reference}
51
48
  *
52
49
  * @typeParam R The request whose result type is selected
53
50
  */
54
- export type Response<R extends Request> = R extends Select<infer T> ? Instance<T> : R extends Lookup<infer T> ? Instance<T> : R extends Modify ? Reference : R extends Detect ? boolean : never;
51
+ export type Response<R extends Request> = R extends Select ? readonly Value[] : R extends Detail<infer T, infer S> ? Match<S, T> : R extends Modify ? Reference : R extends Detect ? boolean : never;
55
52
  /**
56
53
  * Resource existence request.
57
54
  *
58
- * Carries the `entry` to probe; resolves to whether that entry exists in the store.
55
+ * Carries the `entry` to probe, and resolves to whether that entry exists in the store.
59
56
  */
60
57
  export type Detect = {
61
58
  readonly entry: Reference;
@@ -63,28 +60,28 @@ export type Detect = {
63
60
  /**
64
61
  * Resource retrieval request.
65
62
  *
66
- * Carries a single resource (`entry` of `shape`), the `model` against which to materialise it, and
67
- * the `locale` priority driving language negotiation for its localised content (§6.2). Resolves to
68
- * the materialised resource.
63
+ * Carries a single resource (`entry` of `shape`), the `model` to materialise it against, and the `locale` priority
64
+ * for coalescing its localised content (QEST §6.2). Resolves to the materialised resource.
69
65
  *
70
- * @typeParam T The resource model selecting the result shape
66
+ * @typeParam T The resource model selecting the members of the result
67
+ * @typeParam S The shape describing the resource
71
68
  */
72
- export type Lookup<T extends Template = Template> = {
69
+ export type Detail<T extends Template = Template, S extends Lazy<ResourceShape> = Lazy<ResourceShape>> = {
73
70
  readonly entry: Reference;
74
- readonly shape: Lazy<ResourceShape>;
71
+ readonly shape: S;
75
72
  readonly model: T;
76
73
  readonly locale: readonly Tag[];
77
74
  };
78
75
  /**
79
76
  * Collection retrieval request.
80
77
  *
81
- * Carries a single multi-valued property (`field` on `entry` of `shape`), the `query` describing the
82
- * shape of its values (one of the {@link Query} arms), and the `locale` priority driving language
83
- * negotiation for its localised content (§6.2). Resolves to the materialised collection.
78
+ * Carries a single multi-valued property (`field` on `entry` of `shape`), the `query` describing its values, and the
79
+ * `locale` priority for coalescing its localised content (QEST §6.2). Resolves to the materialised collection: items
80
+ * for a template query, rows for a projection.
84
81
  *
85
- * @typeParam T The collection query selecting the result shape
82
+ * @typeParam T The collection query selecting the form of the result
86
83
  */
87
- export type Select<T extends Query = Query> = {
84
+ export type Select<T extends Query<Slot> = Query<Slot>> = {
88
85
  readonly entry: Reference;
89
86
  readonly shape: Lazy<ResourceShape>;
90
87
  readonly field: Property;
@@ -94,25 +91,29 @@ export type Select<T extends Query = Query> = {
94
91
  /**
95
92
  * Resource mutation request.
96
93
  *
97
- * Carries the `entry` to mutate (of `shape`) and the target `state` to persist: a present `state`
98
- * creates or updates the entry, an omitted `state` deletes it. Resolves to the mutated entry's
99
- * {@link Reference}.
94
+ * Carries the `entry` to mutate (of `shape`) and the target `state` to persist. A present `state` creates or updates
95
+ * the entry, and an omitted `state` deletes it. A request carrying a `link` instead adds `item` to the collection
96
+ * held by `entry` under `property`, leaving the rest of the entry unchanged. Resolves to the {@link Reference} of the
97
+ * mutated entry.
100
98
  */
101
99
  export type Modify = {
102
100
  readonly entry: Reference;
103
101
  readonly shape: Lazy<ResourceShape>;
104
102
  readonly state?: Resource;
103
+ readonly link?: {
104
+ readonly property: Property;
105
+ readonly item: Reference;
106
+ };
105
107
  };
106
108
  /**
107
109
  * Batch handler for a single request type.
108
110
  *
109
- * Supplied by the connector author to {@link createBatchingStore}, one per request type. Receives the
110
- * whole batch the {@link Broker} has accumulated for this type, together with the broker for issuing
111
- * nested requests, and settles each {@link Deferred} in the batch with its result or error. The
112
- * returned promise must resolve only once every request the handler owns has settled, including any
113
- * nested requests issued through the broker.
111
+ * Supplied by the connector to {@link createBatchingStore}, one per request type. A handler receives every request of
112
+ * its type accumulated since the previous batch, together with a {@link Broker} for issuing nested requests. It
113
+ * settles each {@link Deferred} in the batch with its result or error. The returned promise must resolve only once
114
+ * every request in the batch has settled, including any nested requests issued through the broker.
114
115
  *
115
- * The broker never dispatches an empty batch, so the handler need not guard against one.
116
+ * Batches are never empty, so handlers need not guard against an empty one.
116
117
  *
117
118
  * @typeParam R The request variant handled
118
119
  */
@@ -122,12 +123,11 @@ export type Handler<R extends Request> = {
122
123
  /**
123
124
  * A queued request paired with its promise-resolution hooks.
124
125
  *
125
- * Each batch a {@link Handler} receives is an array of `Deferred` entries. The handler reads each
126
- * `request`, then calls `resolve` with its result (typed by {@link Response | Response<R>}) or
127
- * `reject` with an error, once the backend round-trip and any nested requests issued through the
128
- * {@link Broker} have settled.
126
+ * Each batch a {@link Handler} receives is an array of `Deferred` entries. For each entry, the handler reads the
127
+ * `request` and settles it, calling `resolve` with its result (typed by {@link Response | Response<R>}) or `reject`
128
+ * with an error.
129
129
  *
130
- * @typeParam R The queued request variant: a {@link Detect} probe, a {@link Lookup} resource fetch,
130
+ * @typeParam R The queued request variant: a {@link Detect} probe, a {@link Detail} resource fetch,
131
131
  * a {@link Select} collection fetch, or a {@link Modify} mutation
132
132
  */
133
133
  export type Deferred<R extends Request> = {
@@ -138,10 +138,9 @@ export type Deferred<R extends Request> = {
138
138
  /**
139
139
  * Request-submission surface over the batching {@link Handler | handlers}.
140
140
  *
141
- * Brokers each store request (detection, lookup, selection, modification) to its handler: a call
142
- * enqueues the request and returns a promise that settles with the request's result. Held both by
143
- * outside callers, as the entry point, and by handlers, to delegate nested work to a sibling
144
- * handler.
141
+ * Routes each request (detection, detail, selection, modification) to the handler for its type. Each call queues the
142
+ * request for the next batch and returns a promise that settles with its result. Handlers receive a broker to hand
143
+ * nested work to a sibling handler.
145
144
  */
146
145
  export type Broker = {
147
146
  /**
@@ -154,18 +153,17 @@ export type Broker = {
154
153
  */
155
154
  detect(request: Detect): Promise<boolean>;
156
155
  /**
157
- * Enqueue a {@link Lookup} request.
156
+ * Enqueue a {@link Detail} request.
158
157
  *
159
158
  * Carries no existence precondition: an entry with no stored state resolves to an empty instance of
160
159
  * the request's `model` rather than rejecting.
161
160
  *
162
161
  * @param request The resource and model to materialise
163
162
  *
164
- * @returns A promise resolving to the materialised {@link Instance} of the request's `model` (the
165
- * resource value), settled once the owning batch and any nested promises needed to assemble its
166
- * value have resolved
163
+ * @returns A promise resolving to the resource materialised against the request's `model`, settled once the
164
+ * owning batch and any nested requests needed to assemble it have resolved
167
165
  */
168
- lookup<T extends Template>(request: Lookup<T>): Promise<Instance<T>>;
166
+ detail<S extends Lazy<ResourceShape>, T extends Template>(request: Detail<T, S>): Promise<Match<S, T>>;
169
167
  /**
170
168
  * Enqueue a {@link Select} request.
171
169
  *
@@ -174,21 +172,20 @@ export type Broker = {
174
172
  *
175
173
  * @param request The property and query to materialise
176
174
  *
177
- * @returns A promise resolving to the materialised {@link Instance} of the request's `query` (one
178
- * of the tuple-wrapped {@link Query} arms), settled once the owning batch and any nested promises
179
- * needed to assemble its value have resolved
175
+ * @returns A promise resolving to the values the collection holds as the request's `query` narrows them,
176
+ * items for a template and rows for a projection, settled once the owning batch and any nested requests
177
+ * needed to assemble them have resolved
180
178
  */
181
- select<T extends Query>(request: Select<T>): Promise<Instance<T>>;
179
+ select<T extends Query<Slot>>(request: Select<T>): Promise<readonly Value[]>;
182
180
  /**
183
181
  * Enqueue a {@link Modify} request.
184
182
  *
185
- * Mutates unconditionally, with no existence precondition: a present `state` upserts the entry,
186
- * creating it when absent; an omitted `state` deletes it leniently, resolving as a no-op when
187
- * absent.
183
+ * Mutates unconditionally, with no existence precondition. A present `state` upserts the entry, creating it if
184
+ * absent. An omitted `state` deletes the entry, and is a no-op if the entry is absent.
188
185
  *
189
- * @param request The entry and target state to persist
186
+ * @param request The entry and target state to persist, or the collection link to add
190
187
  *
191
- * @returns A promise resolving to the mutated entry's {@link Reference}, settled once the owning
188
+ * @returns A promise resolving to the {@link Reference} of the mutated entry, settled once the owning
192
189
  * batch has completed
193
190
  */
194
191
  modify(request: Modify): Promise<Reference>;
@@ -196,27 +193,25 @@ export type Broker = {
196
193
  /**
197
194
  * Creates a batching store client backed by a set of request handlers.
198
195
  *
199
- * Routes every {@link StoreClient} call through a {@link Broker} that coalesces concurrent requests
200
- * into batches and dispatches each batch through the matching `handlers` entry. Adds conditional CRUD
201
- * semantics on top of the handlers: existence is probed through the `detect` handler before a create,
202
- * update, or delete is delegated to `modify`, sparing each handler that bookkeeping.
196
+ * Coalesces concurrent {@link StoreClient} calls into batches, each served by the matching `handlers` entry. The
197
+ * client adds conditional CRUD semantics on top of the handlers: `create`, `update` and `delete` probe for existence
198
+ * through the `detect` handler before handing the mutation to `modify`. `create` mints the identifier of the new
199
+ * resource, if its state names none, and links it to the collecting resource.
203
200
  *
204
- * The `modify` handler is additionally wrapped so the batching layer, not the storage handler,
205
- * enforces the §4.1 state-`id` constraint: a request whose `state` carries an `id` other than its
206
- * `entry` is rejected on its own before dispatch, and a backend failure is settled as a rejection
207
- * across the surviving batch rather than surfaced as a handler throw. The wrapped handler thus always
208
- * receives a non-empty batch of pre-validated requests to apply unconditionally.
201
+ * The `modify` handler receives only requests whose `state` carries no `id` other than their `entry`. A request
202
+ * failing this check is rejected on its own, and the rest of the batch still applies. If the `modify` handler throws,
203
+ * the error rejects every request in its batch.
209
204
  *
210
- * @param handlers The batch handlers, one per request type, dispatching detect, lookup, select, and
211
- * modify requests
205
+ * @param handlers The batch handlers, one per request type
212
206
  *
213
- * @returns An immutable {@link StoreClient} that batches its requests through the broker
207
+ * @returns An immutable {@link StoreClient} serving its requests in batches through `handlers`
214
208
  *
215
- * @throws {RangeError} If a create or update `state` carries an `id` that differs from its `entry`
209
+ * @throws {@link !RangeError RangeError} If an update or insert `state` carries an `id` that differs from its `entry`,
210
+ * or if a create `state` member filling an identifier slot is not a single path segment
216
211
  */
217
212
  export declare function createBatchingStore(handlers: {
218
213
  detect: Handler<Detect>;
219
- lookup: Handler<Lookup>;
214
+ detail: Handler<Detail>;
220
215
  select: Handler<Select>;
221
216
  modify: Handler<Modify>;
222
217
  }): StoreClient;
@@ -1 +1 @@
1
- {"version":3,"file":"batching.d.ts","sourceRoot":"","sources":["../../src/clients/batching.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"batching.d.ts","sourceRoot":"","sources":["../../src/clients/batching.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAY,KAAK,IAAI,EAAiB,MAAM,gBAAgB,CAAC;AACpE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAEnD,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C;;GAEG;AACH,MAAM,MAAM,OAAO,GAChB,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,CAAC;AAEV;;;;;;;;;;GAUG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,OAAO,IACrC,CAAC,SAAS,MAAM,GAAG,SAAS,KAAK,EAAE,GAChC,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAC/C,CAAC,SAAS,MAAM,GAAG,SAAS,GAC3B,CAAC,SAAS,MAAM,GAAG,OAAO,GACzB,KAAK,CAAC;AAGb;;;;GAIG;AACH,MAAM,MAAM,MAAM,GAAG;IAEpB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;CAE1B,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,MAAM,CACjB,CAAC,SAAS,QAAQ,GAAG,QAAQ,EAC7B,CAAC,SAAS,IAAI,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,IAChD;IAEH,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAElB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,EAAE,CAAC;CAEhC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,SAAS,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI;IAEzD,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAElB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,EAAE,CAAC;CAEhC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,MAAM,GAAG;IAEpB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IACpC,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;IAE1B,QAAQ,CAAC,IAAI,CAAC,EAAE;QAEf,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;QAC5B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;KAEzB,CAAC;CAEF,CAAC;AAGF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,OAAO,IAAI;IAExC,CAAC,KAAK,EAAE,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAE9D,CAAA;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,OAAO,IAAI;IAEzC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IAEpB,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAElC,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CAE7B,CAAC;AAGF;;;;;;GAMG;AACH,MAAM,MAAM,MAAM,GAAG;IAEpB;;;;;;;OAOG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE1C;;;;;;;;;;OAUG;IACH,MAAM,CAAC,CAAC,SAAS,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,SAAS,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAEvG;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,CAAC,SAAS,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;IAE7E;;;;;;;;;;OAUG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CAE5C,CAAC;AAKF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE;IAE7C,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;IACvB,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;IACvB,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;IACvB,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;CAEvB,GAAG,WAAW,CA8Hd"}
@@ -13,37 +13,36 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { eager } from "@metreeca/blue/value";
17
- import { immutable } from "@metreeca/core/structures";
18
- import { createBroker } from "./batching.core.js";
16
+ import { blueprint, collection } from "@metreeca/blue/value";
17
+ import { isString } from "@metreeca/core";
18
+ import { immutable } from "@metreeca/core/values";
19
+ import { createBroker, mint } from "./batching.core.js";
19
20
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
20
21
  /**
21
22
  * Creates a batching store client backed by a set of request handlers.
22
23
  *
23
- * Routes every {@link StoreClient} call through a {@link Broker} that coalesces concurrent requests
24
- * into batches and dispatches each batch through the matching `handlers` entry. Adds conditional CRUD
25
- * semantics on top of the handlers: existence is probed through the `detect` handler before a create,
26
- * update, or delete is delegated to `modify`, sparing each handler that bookkeeping.
24
+ * Coalesces concurrent {@link StoreClient} calls into batches, each served by the matching `handlers` entry. The
25
+ * client adds conditional CRUD semantics on top of the handlers: `create`, `update` and `delete` probe for existence
26
+ * through the `detect` handler before handing the mutation to `modify`. `create` mints the identifier of the new
27
+ * resource, if its state names none, and links it to the collecting resource.
27
28
  *
28
- * The `modify` handler is additionally wrapped so the batching layer, not the storage handler,
29
- * enforces the §4.1 state-`id` constraint: a request whose `state` carries an `id` other than its
30
- * `entry` is rejected on its own before dispatch, and a backend failure is settled as a rejection
31
- * across the surviving batch rather than surfaced as a handler throw. The wrapped handler thus always
32
- * receives a non-empty batch of pre-validated requests to apply unconditionally.
29
+ * The `modify` handler receives only requests whose `state` carries no `id` other than their `entry`. A request
30
+ * failing this check is rejected on its own, and the rest of the batch still applies. If the `modify` handler throws,
31
+ * the error rejects every request in its batch.
33
32
  *
34
- * @param handlers The batch handlers, one per request type, dispatching detect, lookup, select, and
35
- * modify requests
33
+ * @param handlers The batch handlers, one per request type
36
34
  *
37
- * @returns An immutable {@link StoreClient} that batches its requests through the broker
35
+ * @returns An immutable {@link StoreClient} serving its requests in batches through `handlers`
38
36
  *
39
- * @throws {RangeError} If a create or update `state` carries an `id` that differs from its `entry`
37
+ * @throws {@link !RangeError RangeError} If an update or insert `state` carries an `id` that differs from its `entry`,
38
+ * or if a create `state` member filling an identifier slot is not a single path segment
40
39
  */
41
40
  export function createBatchingStore(handlers) {
42
41
  const broker = createBroker({
43
42
  ...handlers,
44
43
  async modify(batch, broker) {
45
44
  const items = batch.filter(({ request: { entry, state }, reject }) => {
46
- // reject each request whose state id contradicts its entry (§4.1) on its own, so the
45
+ // reject each request whose state id contradicts its entry on its own, so the
47
46
  // rest of the batch still applies and the check stays out of storage-specific handlers
48
47
  const matching = state?.id === undefined || state.id === entry;
49
48
  if (!matching) {
@@ -65,25 +64,30 @@ export function createBatchingStore(handlers) {
65
64
  });
66
65
  return immutable({
67
66
  async lookup({ entry, shape, model }, { locale = ["und"] } = {}) {
68
- // virtual resources have no stored state of their own: their members are derived from
69
- // selection constraints rather than from stored content, so the existence probe is skipped.
70
- return eager(shape).virtual || await broker.detect({ entry })
71
- ? broker.lookup({ entry, shape, model, locale })
67
+ return await broker.detect({ entry })
68
+ ? broker.detail({ entry, shape, model, locale })
72
69
  : undefined;
73
70
  },
74
- async create({ entry, shape, state }) {
75
- // the entry identifies the target: a state carrying a different id contradicts it (§4.1)
76
- if (state.id !== undefined && state.id !== entry) {
77
- throw new RangeError(`mismatched state id <${String(state.id)}> for entry <${entry}>`);
78
- }
79
- return await broker.detect({ entry })
80
- ? undefined
81
- : broker.modify({ entry, shape, state });
71
+ async create({ entry, shape, model, state }) {
72
+ // the new resource is stored under the identifier its state names, or under one minted for it off the
73
+ // blueprint of the collection; either way it is the resource probed for existence and written, not the
74
+ // collection
75
+ const target = collection(shape, model);
76
+ const plan = blueprint(shape, model);
77
+ const { id } = state;
78
+ const child = isString(id) ? id : mint(entry, plan, state);
79
+ // a collection a plain property holds is linked to its new member; one exposed through
80
+ // a foreign property is a view over the member's own link and reaches it on its own
81
+ return await broker.detect({ entry: child }) ? undefined
82
+ : broker.modify({ entry: child, shape: plan, state }).then(created => target.foreign
83
+ ? created
84
+ : broker.modify({ entry, shape, link: { property: target, item: created } }).then(() => created));
82
85
  },
83
86
  async update({ entry, shape, state }) {
84
- // the entry identifies the target: a state carrying a different id contradicts it (§4.1)
85
- if (state.id !== undefined && state.id !== entry) {
86
- throw new RangeError(`mismatched state id <${String(state.id)}> for entry <${entry}>`);
87
+ // the entry identifies the target: a state carrying a different id contradicts it
88
+ const { id } = state;
89
+ if (id !== undefined && id !== entry) {
90
+ throw new RangeError(`mismatched state id <${String(id)}> for entry <${entry}>`);
87
91
  }
88
92
  return await broker.detect({ entry })
89
93
  ? broker.modify({ entry, shape, state })
@@ -1 +1 @@
1
- {"version":3,"file":"batching.js","sourceRoot":"","sources":["../../src/clients/batching.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"batching.js","sourceRoot":"","sources":["../../src/clients/batching.ts"],"names":[],"mappings":"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"}
@@ -2,37 +2,40 @@ import type { StoreClient } from "../index.js";
2
2
  /**
3
3
  * Creates a validating store backed by a delegate.
4
4
  *
5
- * Each method validates the relevant inputs against the supplied shape before delegating to `store`:
5
+ * Each method validates its inputs against the supplied shape before forwarding the request to `store`:
6
6
  *
7
- * - `entry` is checked for absolute-IRI form (no query string, no fragment) — failures rejected as `RangeError`
8
- * - `state.id`, when present, is checked for equality with `entry` — mismatches rejected as `RangeError`, since
9
- * the entry identifies the target and a contradicting payload identity is a caller error
10
- * - `model` is validated as a {@link @metreeca/blue!validate | template} for
11
- * {@link StoreClient.lookup lookup}, with the `lookup` `plain`/`depth`/`limit` opts forwarded as
12
- * query-complexity caps
13
- * - `state` is validated as a resource for {@link StoreClient.create create}/
14
- * {@link StoreClient.update update}/{@link StoreClient.insert insert}; `create` and
15
- * `update` always cap captive expansion at depth `0` (inline captive batches rejected), while `insert` honours its
16
- * `depth` opt
17
- * (omitted leaves expansion unbounded)
7
+ * - `entry` must be an absolute IRI with no query string and no fragment; otherwise the request is rejected with a
8
+ * {@link !RangeError RangeError}
9
+ * - `model` is validated as a {@link @metreeca/blue!validate | template} for {@link StoreClient.lookup lookup},
10
+ * within the query-complexity bounds (`plain`, `depth`, `limit`) of the caller's
11
+ * {@link StoreScope | retrieval scope}, and as a collection slice for {@link StoreClient.create create}
12
+ * - `state.id`, if present, must be nested under `entry` for {@link StoreClient.create create}, and equal to `entry`
13
+ * for {@link StoreClient.update update} and {@link StoreClient.insert insert}; otherwise the request is rejected
14
+ * with a {@link !RangeError RangeError}
15
+ * - `state` is validated as a resource with captive expansion capped at depth `0`, so inline captive batches are
16
+ * rejected; {@link StoreClient.create create} validates it against the shape of the collected resources, and
17
+ * {@link StoreClient.update update} and {@link StoreClient.insert insert} against the supplied shape
18
18
  *
19
- * The `trusted` opt controls whether {@link StoreClient.lookup lookup} responses are re-validated
20
- * against the shape narrowed by the caller's `model` template before surfacing. Defaults to `false`
21
- * — connectors whose backing source isn't trusted to deliver shape-conforming data (for example, a
22
- * remote REST endpoint) get the safe default. Local stores that compute results themselves should
23
- * pass `trusted: true` to skip the redundant pass.
19
+ * The `trusted` option controls whether {@link StoreClient.lookup lookup} responses are re-validated against the
20
+ * shape, as narrowed by the caller's `model`. It defaults to `false`, the safe choice for connectors whose source may
21
+ * deliver non-conforming data, such as a remote REST endpoint. Local stores that compute results themselves can pass
22
+ * `trusted: true` to skip the redundant check.
24
23
  *
25
- * Validation failures surface as {@link @metreeca/core!TraceError | TraceError} or `RangeError` rejections per the
26
- * unified {@link Store} error channel.
24
+ * Validation failures surface as {@link @metreeca/core!TraceError | TraceError} or {@link !RangeError RangeError}
25
+ * rejections, in line with the unified {@link Store} error channel.
27
26
  *
28
- * @param store - Inner StoreClient to delegate to after validation
27
+ * @param store - Inner StoreClient receiving the validated requests
29
28
  * @param options - Optional validation options
30
- * @param options.trusted - When `true`, skips re-validation of the {@link StoreClient.lookup lookup}
31
- * response against the shape narrowed by the caller's `model`; defaults to `false`
32
29
  *
33
30
  * @returns An immutable {@link StoreClient} wrapping `store` with input validation
34
31
  */
35
32
  export declare function createValidatingStore(store: StoreClient, { trusted }?: {
33
+ /**
34
+ * Whether to skip re-validation of {@link StoreClient.lookup lookup} responses against the shape, as narrowed by
35
+ * the caller's `model`.
36
+ *
37
+ * @defaultValue `false`, treating the wrapped store as untrusted
38
+ */
36
39
  readonly trusted?: boolean;
37
40
  }): StoreClient;
38
41
  //# sourceMappingURL=validating.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validating.d.ts","sourceRoot":"","sources":["../../src/clients/validating.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAS,WAAW,EAAE,MAAM,aAAa,CAAC;AAGtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,WAAW,EAAE,EAEzD,OAAe,EAEf,GAAE;IAEF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAErB,GAAG,WAAW,CA+GnB"}
1
+ {"version":3,"file":"validating.d.ts","sourceRoot":"","sources":["../../src/clients/validating.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAS,WAAW,EAAc,MAAM,aAAa,CAAC;AAGlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,WAAW,EAAE,EAEzD,OAAe,EAEf,GAAE;IAEF;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAErB,GAAG,WAAW,CAkJnB"}