graphddb 0.7.10 → 0.8.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.
- package/README.md +6 -6
- package/dist/cdc/index.d.ts +389 -5
- package/dist/cdc/index.js +4 -4
- package/dist/{chunk-AD6ZQTTE.js → chunk-GS4C5VGO.js} +2 -6
- package/dist/{chunk-DFUKGU2Q.js → chunk-HNY2EJPV.js} +216 -229
- package/dist/{chunk-3ZU2VW3L.js → chunk-L2NEDS7U.js} +582 -781
- package/dist/chunk-L4QRCHRQ.js +278 -0
- package/dist/chunk-LAT64YCZ.js +1987 -0
- package/dist/chunk-S2NI4PBW.js +187 -0
- package/dist/{chunk-EOJDN3SA.js → chunk-T44OB5GU.js} +3757 -6138
- package/dist/{chunk-PDUVTYC5.js → chunk-XTWXMOHD.js} +0 -1
- package/dist/cli.js +63 -254
- package/dist/index.d.ts +23 -1550
- package/dist/index.js +94 -1850
- package/dist/internal/index.d.ts +84 -0
- package/dist/internal/index.js +701 -0
- package/dist/{maintenance-view-adapter-BAZ9uBGe.d.ts → key-DZtjAQDh.d.ts} +573 -1817
- package/dist/linter/index.d.ts +39 -7
- package/dist/linter/index.js +22 -4
- package/dist/{registry-LWE54Sdc.d.ts → linter-DQY7gUEk.d.ts} +22 -22
- package/dist/prepared-artifact-HFealr1q.d.ts +281 -0
- package/dist/spec/index.d.ts +506 -5
- package/dist/spec/index.js +22 -18
- package/dist/testing/index.d.ts +2 -3
- package/dist/testing/index.js +4 -4
- package/dist/transform/index.d.ts +1 -1
- package/dist/transform/index.js +4 -4
- package/dist/{types-BQLzTEqh.d.ts → types-2PMXEn5x.d.ts} +8 -10
- package/dist/types-DW__-Icc.d.ts +450 -0
- package/docs/cdc-projection.md +5 -5
- package/docs/class-hydration.md +1 -1
- package/docs/cqrs-contract.md +79 -20
- package/docs/design-patterns.md +5 -5
- package/docs/docs-generation.md +6 -6
- package/docs/middleware.md +15 -15
- package/docs/mutation-command-derivation.md +52 -42
- package/docs/prepared-statements.md +14 -14
- package/docs/python-bridge.md +96 -65
- package/docs/spec.md +153 -124
- package/docs/testing.md +9 -8
- package/package.json +14 -4
- package/dist/chunk-3UD3XIF2.js +0 -860
- package/dist/chunk-MMVHOUM4.js +0 -24
- package/dist/from-change-Ty95KA8C.d.ts +0 -327
- package/dist/index-Dc7d8mWI.d.ts +0 -1089
- package/dist/relation-depth-BRS513Tq.d.ts +0 -36
|
@@ -1,11 +1,149 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MetadataRegistry,
|
|
3
3
|
attachHiddenKey
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-L2NEDS7U.js";
|
|
5
5
|
import {
|
|
6
6
|
resolveKey,
|
|
7
7
|
segmentFieldNames
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-XTWXMOHD.js";
|
|
9
|
+
|
|
10
|
+
// src/define/entity-writes.ts
|
|
11
|
+
var MAINTAIN_TRIGGER_RE = /^[^.\s$[\]*]+\.(?:created|updated|removed)$/;
|
|
12
|
+
function isMaintainTrigger(value) {
|
|
13
|
+
return typeof value === "string" && MAINTAIN_TRIGGER_RE.test(value);
|
|
14
|
+
}
|
|
15
|
+
function makeProjectionTransform(path, op, args) {
|
|
16
|
+
if (op === "preview") {
|
|
17
|
+
const [n] = args;
|
|
18
|
+
if (typeof n !== "number" || !Number.isInteger(n) || n <= 0) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
`transform: the \`preview\` op requires a positive integer length bound (e.g. \`preview('$.body', 200)\`), but received ${JSON.stringify(n)}.`
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
return { kind: "transform", path, op, args: [n] };
|
|
24
|
+
}
|
|
25
|
+
if (op === "identity") {
|
|
26
|
+
if (args.length > 0) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`transform: the \`identity\` op takes no arguments, but received ${JSON.stringify(args)}.`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return { kind: "transform", path, op, args: [] };
|
|
32
|
+
}
|
|
33
|
+
throw new Error(
|
|
34
|
+
`transform: unknown projection op ${JSON.stringify(op)} (expected \`identity\` or \`preview\`).`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
function pathOf(value) {
|
|
38
|
+
return typeof value === "string" ? value : value.path;
|
|
39
|
+
}
|
|
40
|
+
function preview(path, n) {
|
|
41
|
+
return makeProjectionTransform(pathOf(path), "preview", [n]);
|
|
42
|
+
}
|
|
43
|
+
function identity(path) {
|
|
44
|
+
return makeProjectionTransform(pathOf(path), "identity", []);
|
|
45
|
+
}
|
|
46
|
+
var LIFECYCLE_CONTRACT_MARKER = /* @__PURE__ */ Symbol(
|
|
47
|
+
"graphddb:lifecycleContract"
|
|
48
|
+
);
|
|
49
|
+
function isLifecycleContract(value) {
|
|
50
|
+
return typeof value === "object" && value !== null && value[LIFECYCLE_CONTRACT_MARKER] === true;
|
|
51
|
+
}
|
|
52
|
+
var ENTITY_WRITES_MARKER = /* @__PURE__ */ Symbol("graphddb:entityWrites");
|
|
53
|
+
function isEntityWritesDefinition(value) {
|
|
54
|
+
return typeof value === "object" && value !== null && value[ENTITY_WRITES_MARKER] === true;
|
|
55
|
+
}
|
|
56
|
+
function freezeEffects(effects) {
|
|
57
|
+
const out = {};
|
|
58
|
+
if (effects.requires !== void 0) out.requires = effects.requires;
|
|
59
|
+
if (effects.unique !== void 0) out.unique = effects.unique;
|
|
60
|
+
if (effects.edges !== void 0) out.edges = effects.edges;
|
|
61
|
+
if (effects.derive !== void 0) out.derive = effects.derive;
|
|
62
|
+
if (effects.emits !== void 0) out.emits = effects.emits;
|
|
63
|
+
if (effects.idempotency !== void 0) out.idempotency = effects.idempotency;
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
var recorder = {
|
|
67
|
+
lifecycle(effects = {}) {
|
|
68
|
+
return {
|
|
69
|
+
[LIFECYCLE_CONTRACT_MARKER]: true,
|
|
70
|
+
effects: freezeEffects(effects)
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
exists(targetFactory, keys) {
|
|
74
|
+
return { kind: "requires", targetFactory, keys };
|
|
75
|
+
},
|
|
76
|
+
unique(spec) {
|
|
77
|
+
return { kind: "unique", name: spec.name, scope: spec.scope, fields: spec.fields };
|
|
78
|
+
},
|
|
79
|
+
putEdge(targetFactory, relationProperty) {
|
|
80
|
+
return { kind: "putEdge", targetFactory, relationProperty };
|
|
81
|
+
},
|
|
82
|
+
deleteEdge(targetFactory, relationProperty) {
|
|
83
|
+
return { kind: "deleteEdge", targetFactory, relationProperty };
|
|
84
|
+
},
|
|
85
|
+
dualEdge(forward, inverse) {
|
|
86
|
+
return {
|
|
87
|
+
kind: "putEdge",
|
|
88
|
+
targetFactory: forward.target,
|
|
89
|
+
relationProperty: forward.relationProperty,
|
|
90
|
+
inverse: {
|
|
91
|
+
adjacencyFactory: inverse.adjacency,
|
|
92
|
+
targetFactory: inverse.target,
|
|
93
|
+
relationProperty: inverse.relationProperty
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
increment(targetFactory, keys, attribute, amount) {
|
|
98
|
+
return { kind: "derive", targetFactory, keys, attribute, amount };
|
|
99
|
+
},
|
|
100
|
+
transform(path, op, ...args) {
|
|
101
|
+
return makeProjectionTransform(path, op, args);
|
|
102
|
+
},
|
|
103
|
+
event(name, payload) {
|
|
104
|
+
return { kind: "event", name, payload };
|
|
105
|
+
},
|
|
106
|
+
idempotentBy(token) {
|
|
107
|
+
return { kind: "idempotency", token };
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
function entityWrites(builder) {
|
|
111
|
+
const shape = builder(recorder);
|
|
112
|
+
for (const phase of ["create", "update", "remove"]) {
|
|
113
|
+
const contract = shape[phase];
|
|
114
|
+
if (contract !== void 0 && !isLifecycleContract(contract)) {
|
|
115
|
+
throw new Error(
|
|
116
|
+
`entityWrites: the '${phase}' lifecycle must be built with \`w.lifecycle({...})\` (it carries the \xA72 effect arrays), but received ${JSON.stringify(contract)}.`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (shape.create === void 0 && shape.update === void 0 && shape.remove === void 0) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
"entityWrites(...) must declare at least one lifecycle (`create` / `update` / `remove`); an empty save contract declares nothing."
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
[ENTITY_WRITES_MARKER]: true,
|
|
127
|
+
...shape.create !== void 0 ? { create: shape.create } : {},
|
|
128
|
+
...shape.update !== void 0 ? { update: shape.update } : {},
|
|
129
|
+
...shape.remove !== void 0 ? { remove: shape.remove } : {}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function getEntityWrites(modelClass) {
|
|
133
|
+
for (const name of Object.getOwnPropertyNames(modelClass)) {
|
|
134
|
+
let value;
|
|
135
|
+
try {
|
|
136
|
+
value = modelClass[name];
|
|
137
|
+
} catch {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (isEntityWritesDefinition(value)) return value;
|
|
141
|
+
}
|
|
142
|
+
return void 0;
|
|
143
|
+
}
|
|
144
|
+
function lifecyclePhaseForIntent(intent) {
|
|
145
|
+
return intent === "upsert" ? "create" : intent;
|
|
146
|
+
}
|
|
9
147
|
|
|
10
148
|
// src/types/select-builder.ts
|
|
11
149
|
var SELECT_BUILDER = /* @__PURE__ */ Symbol.for("graphddb.selectBuilder");
|
|
@@ -226,150 +364,98 @@ function deserializeValue(value, fieldMeta) {
|
|
|
226
364
|
return value;
|
|
227
365
|
}
|
|
228
366
|
|
|
229
|
-
// src/
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
`maintainTrigger: a maintenance trigger must be an \`Entity.event\` string where event is one of \`created\` / \`updated\` / \`removed\` (e.g. \`"Post.created"\`), but received ${JSON.stringify(value)}.`
|
|
235
|
-
);
|
|
367
|
+
// src/cdc/from-change.ts
|
|
368
|
+
function buildFullSelect(metadata) {
|
|
369
|
+
const select = {};
|
|
370
|
+
for (const field of metadata.fields) {
|
|
371
|
+
select[field.propertyName] = true;
|
|
236
372
|
}
|
|
237
|
-
return
|
|
238
|
-
}
|
|
239
|
-
function isMaintainTrigger(value) {
|
|
240
|
-
return typeof value === "string" && MAINTAIN_TRIGGER_RE.test(value);
|
|
373
|
+
return select;
|
|
241
374
|
}
|
|
242
|
-
function
|
|
243
|
-
if (
|
|
244
|
-
|
|
245
|
-
if (typeof n !== "number" || !Number.isInteger(n) || n <= 0) {
|
|
246
|
-
throw new Error(
|
|
247
|
-
`transform: the \`preview\` op requires a positive integer length bound (e.g. \`preview('$.body', 200)\`), but received ${JSON.stringify(n)}.`
|
|
248
|
-
);
|
|
249
|
-
}
|
|
250
|
-
return { kind: "transform", path, op, args: [n] };
|
|
375
|
+
function eventOwnedBy(event, metadata, modelName) {
|
|
376
|
+
if (event.model !== void 0) {
|
|
377
|
+
return event.model === modelName;
|
|
251
378
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
379
|
+
return metadata.prefix.length > 0 && event.keys.pk.startsWith(metadata.prefix);
|
|
380
|
+
}
|
|
381
|
+
function hydrateImage(image, select, metadata, modelClass) {
|
|
382
|
+
if (image === void 0) return null;
|
|
383
|
+
const [hydrated] = hydrate([image], select, metadata);
|
|
384
|
+
const instance = new modelClass();
|
|
385
|
+
Object.assign(instance, hydrated);
|
|
386
|
+
for (const emb of metadata.embeddedFields) {
|
|
387
|
+
const rawEmb = image[emb.propertyName];
|
|
388
|
+
if (rawEmb !== void 0 && rawEmb !== null) {
|
|
389
|
+
instance[emb.propertyName] = rawEmb;
|
|
257
390
|
}
|
|
258
|
-
return { kind: "transform", path, op, args: [] };
|
|
259
391
|
}
|
|
260
|
-
|
|
261
|
-
`transform: unknown projection op ${JSON.stringify(op)} (expected \`identity\` or \`preview\`).`
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
function pathOf(value) {
|
|
265
|
-
return typeof value === "string" ? value : value.path;
|
|
266
|
-
}
|
|
267
|
-
function preview(path, n) {
|
|
268
|
-
return makeProjectionTransform(pathOf(path), "preview", [n]);
|
|
269
|
-
}
|
|
270
|
-
function identity(path) {
|
|
271
|
-
return makeProjectionTransform(pathOf(path), "identity", []);
|
|
272
|
-
}
|
|
273
|
-
var LIFECYCLE_CONTRACT_MARKER = /* @__PURE__ */ Symbol(
|
|
274
|
-
"graphddb:lifecycleContract"
|
|
275
|
-
);
|
|
276
|
-
function isLifecycleContract(value) {
|
|
277
|
-
return typeof value === "object" && value !== null && value[LIFECYCLE_CONTRACT_MARKER] === true;
|
|
278
|
-
}
|
|
279
|
-
var ENTITY_WRITES_MARKER = /* @__PURE__ */ Symbol("graphddb:entityWrites");
|
|
280
|
-
function isEntityWritesDefinition(value) {
|
|
281
|
-
return typeof value === "object" && value !== null && value[ENTITY_WRITES_MARKER] === true;
|
|
392
|
+
return instance;
|
|
282
393
|
}
|
|
283
|
-
function
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
return out;
|
|
394
|
+
function parseChange(event, metadata, modelName, modelClass) {
|
|
395
|
+
if (!eventOwnedBy(event, metadata, modelName)) {
|
|
396
|
+
return [null, null];
|
|
397
|
+
}
|
|
398
|
+
const select = buildFullSelect(metadata);
|
|
399
|
+
const oldRecord = hydrateImage(event.oldImage, select, metadata, modelClass);
|
|
400
|
+
const newRecord = hydrateImage(event.newImage, select, metadata, modelClass);
|
|
401
|
+
return [oldRecord, newRecord];
|
|
292
402
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
};
|
|
299
|
-
},
|
|
300
|
-
exists(targetFactory, keys) {
|
|
301
|
-
return { kind: "requires", targetFactory, keys };
|
|
302
|
-
},
|
|
303
|
-
unique(spec) {
|
|
304
|
-
return { kind: "unique", name: spec.name, scope: spec.scope, fields: spec.fields };
|
|
305
|
-
},
|
|
306
|
-
putEdge(targetFactory, relationProperty) {
|
|
307
|
-
return { kind: "putEdge", targetFactory, relationProperty };
|
|
308
|
-
},
|
|
309
|
-
deleteEdge(targetFactory, relationProperty) {
|
|
310
|
-
return { kind: "deleteEdge", targetFactory, relationProperty };
|
|
311
|
-
},
|
|
312
|
-
dualEdge(forward, inverse) {
|
|
313
|
-
return {
|
|
314
|
-
kind: "putEdge",
|
|
315
|
-
targetFactory: forward.target,
|
|
316
|
-
relationProperty: forward.relationProperty,
|
|
317
|
-
inverse: {
|
|
318
|
-
adjacencyFactory: inverse.adjacency,
|
|
319
|
-
targetFactory: inverse.target,
|
|
320
|
-
relationProperty: inverse.relationProperty
|
|
321
|
-
}
|
|
322
|
-
};
|
|
323
|
-
},
|
|
324
|
-
increment(targetFactory, keys, attribute, amount) {
|
|
325
|
-
return { kind: "derive", targetFactory, keys, attribute, amount };
|
|
326
|
-
},
|
|
327
|
-
transform(path, op, ...args) {
|
|
328
|
-
return makeProjectionTransform(path, op, args);
|
|
329
|
-
},
|
|
330
|
-
event(name, payload) {
|
|
331
|
-
return { kind: "event", name, payload };
|
|
332
|
-
},
|
|
333
|
-
idempotentBy(token) {
|
|
334
|
-
return { kind: "idempotency", token };
|
|
403
|
+
|
|
404
|
+
// src/cdc/subscribe.ts
|
|
405
|
+
function resolveRoutableModels(handlers) {
|
|
406
|
+
const byName = /* @__PURE__ */ new Map();
|
|
407
|
+
for (const [cls, meta] of MetadataRegistry.getAll()) {
|
|
408
|
+
byName.set(cls.name, { cls, meta });
|
|
335
409
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
const contract = shape[phase];
|
|
341
|
-
if (contract !== void 0 && !isLifecycleContract(contract)) {
|
|
410
|
+
const routable = /* @__PURE__ */ new Map();
|
|
411
|
+
for (const modelName of Object.keys(handlers)) {
|
|
412
|
+
const entry = byName.get(modelName);
|
|
413
|
+
if (!entry) {
|
|
342
414
|
throw new Error(
|
|
343
|
-
`
|
|
415
|
+
`DDBModel.subscribe: no model named '${modelName}' is registered. Did you import the model module (so its @model decorator ran) and spell the handler key exactly as the class name?`
|
|
344
416
|
);
|
|
345
417
|
}
|
|
418
|
+
if (!entry.meta.cdcProjected) {
|
|
419
|
+
throw new Error(
|
|
420
|
+
`DDBModel.subscribe: model '${modelName}' is not @cdcProjected, so its change events cannot be parsed. Add @cdcProjected() to the model, or remove its handler.`
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
routable.set(modelName, {
|
|
424
|
+
modelClass: entry.cls,
|
|
425
|
+
metadata: entry.meta,
|
|
426
|
+
modelName
|
|
427
|
+
});
|
|
346
428
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
429
|
+
return routable;
|
|
430
|
+
}
|
|
431
|
+
async function dispatchEvent(event, routable, handlers) {
|
|
432
|
+
for (const { modelClass, metadata, modelName } of routable.values()) {
|
|
433
|
+
const [oldRecord, newRecord] = parseChange(
|
|
434
|
+
event,
|
|
435
|
+
metadata,
|
|
436
|
+
modelName,
|
|
437
|
+
modelClass
|
|
350
438
|
);
|
|
439
|
+
if (oldRecord === null && newRecord === null) continue;
|
|
440
|
+
const handler = handlers[modelName];
|
|
441
|
+
await handler(oldRecord, newRecord);
|
|
442
|
+
return true;
|
|
351
443
|
}
|
|
352
|
-
return
|
|
353
|
-
[ENTITY_WRITES_MARKER]: true,
|
|
354
|
-
...shape.create !== void 0 ? { create: shape.create } : {},
|
|
355
|
-
...shape.update !== void 0 ? { update: shape.update } : {},
|
|
356
|
-
...shape.remove !== void 0 ? { remove: shape.remove } : {}
|
|
357
|
-
};
|
|
444
|
+
return false;
|
|
358
445
|
}
|
|
359
|
-
function
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
446
|
+
function buildSubscribeHandler(handlers) {
|
|
447
|
+
const routable = resolveRoutableModels(handlers);
|
|
448
|
+
return async (batch) => {
|
|
449
|
+
const batchItemFailures = [];
|
|
450
|
+
for (const event of batch.records) {
|
|
451
|
+
try {
|
|
452
|
+
await dispatchEvent(event, routable, handlers);
|
|
453
|
+
} catch {
|
|
454
|
+
batchItemFailures.push(event.sequenceNumber);
|
|
455
|
+
}
|
|
366
456
|
}
|
|
367
|
-
|
|
368
|
-
}
|
|
369
|
-
return void 0;
|
|
370
|
-
}
|
|
371
|
-
function lifecyclePhaseForIntent(intent) {
|
|
372
|
-
return intent;
|
|
457
|
+
return { batchItemFailures };
|
|
458
|
+
};
|
|
373
459
|
}
|
|
374
460
|
|
|
375
461
|
// src/relation/maintenance-view-adapter.ts
|
|
@@ -1073,100 +1159,6 @@ function buildMaintenanceGraphImpl(registry, views) {
|
|
|
1073
1159
|
};
|
|
1074
1160
|
}
|
|
1075
1161
|
|
|
1076
|
-
// src/cdc/from-change.ts
|
|
1077
|
-
function buildFullSelect(metadata) {
|
|
1078
|
-
const select = {};
|
|
1079
|
-
for (const field of metadata.fields) {
|
|
1080
|
-
select[field.propertyName] = true;
|
|
1081
|
-
}
|
|
1082
|
-
return select;
|
|
1083
|
-
}
|
|
1084
|
-
function eventOwnedBy(event, metadata, modelName) {
|
|
1085
|
-
if (event.model !== void 0) {
|
|
1086
|
-
return event.model === modelName;
|
|
1087
|
-
}
|
|
1088
|
-
return metadata.prefix.length > 0 && event.keys.pk.startsWith(metadata.prefix);
|
|
1089
|
-
}
|
|
1090
|
-
function hydrateImage(image, select, metadata, modelClass) {
|
|
1091
|
-
if (image === void 0) return null;
|
|
1092
|
-
const [hydrated] = hydrate([image], select, metadata);
|
|
1093
|
-
const instance = new modelClass();
|
|
1094
|
-
Object.assign(instance, hydrated);
|
|
1095
|
-
for (const emb of metadata.embeddedFields) {
|
|
1096
|
-
const rawEmb = image[emb.propertyName];
|
|
1097
|
-
if (rawEmb !== void 0 && rawEmb !== null) {
|
|
1098
|
-
instance[emb.propertyName] = rawEmb;
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
return instance;
|
|
1102
|
-
}
|
|
1103
|
-
function parseChange(event, metadata, modelName, modelClass) {
|
|
1104
|
-
if (!eventOwnedBy(event, metadata, modelName)) {
|
|
1105
|
-
return [null, null];
|
|
1106
|
-
}
|
|
1107
|
-
const select = buildFullSelect(metadata);
|
|
1108
|
-
const oldRecord = hydrateImage(event.oldImage, select, metadata, modelClass);
|
|
1109
|
-
const newRecord = hydrateImage(event.newImage, select, metadata, modelClass);
|
|
1110
|
-
return [oldRecord, newRecord];
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
// src/cdc/subscribe.ts
|
|
1114
|
-
function resolveRoutableModels(handlers) {
|
|
1115
|
-
const byName = /* @__PURE__ */ new Map();
|
|
1116
|
-
for (const [cls, meta] of MetadataRegistry.getAll()) {
|
|
1117
|
-
byName.set(cls.name, { cls, meta });
|
|
1118
|
-
}
|
|
1119
|
-
const routable = /* @__PURE__ */ new Map();
|
|
1120
|
-
for (const modelName of Object.keys(handlers)) {
|
|
1121
|
-
const entry = byName.get(modelName);
|
|
1122
|
-
if (!entry) {
|
|
1123
|
-
throw new Error(
|
|
1124
|
-
`DDBModel.subscribe: no model named '${modelName}' is registered. Did you import the model module (so its @model decorator ran) and spell the handler key exactly as the class name?`
|
|
1125
|
-
);
|
|
1126
|
-
}
|
|
1127
|
-
if (!entry.meta.cdcProjected) {
|
|
1128
|
-
throw new Error(
|
|
1129
|
-
`DDBModel.subscribe: model '${modelName}' is not @cdcProjected, so its change events cannot be parsed. Add @cdcProjected() to the model, or remove its handler.`
|
|
1130
|
-
);
|
|
1131
|
-
}
|
|
1132
|
-
routable.set(modelName, {
|
|
1133
|
-
modelClass: entry.cls,
|
|
1134
|
-
metadata: entry.meta,
|
|
1135
|
-
modelName
|
|
1136
|
-
});
|
|
1137
|
-
}
|
|
1138
|
-
return routable;
|
|
1139
|
-
}
|
|
1140
|
-
async function dispatchEvent(event, routable, handlers) {
|
|
1141
|
-
for (const { modelClass, metadata, modelName } of routable.values()) {
|
|
1142
|
-
const [oldRecord, newRecord] = parseChange(
|
|
1143
|
-
event,
|
|
1144
|
-
metadata,
|
|
1145
|
-
modelName,
|
|
1146
|
-
modelClass
|
|
1147
|
-
);
|
|
1148
|
-
if (oldRecord === null && newRecord === null) continue;
|
|
1149
|
-
const handler = handlers[modelName];
|
|
1150
|
-
await handler(oldRecord, newRecord);
|
|
1151
|
-
return true;
|
|
1152
|
-
}
|
|
1153
|
-
return false;
|
|
1154
|
-
}
|
|
1155
|
-
function buildSubscribeHandler(handlers) {
|
|
1156
|
-
const routable = resolveRoutableModels(handlers);
|
|
1157
|
-
return async (batch) => {
|
|
1158
|
-
const batchItemFailures = [];
|
|
1159
|
-
for (const event of batch.records) {
|
|
1160
|
-
try {
|
|
1161
|
-
await dispatchEvent(event, routable, handlers);
|
|
1162
|
-
} catch {
|
|
1163
|
-
batchItemFailures.push(event.sequenceNumber);
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
return { batchItemFailures };
|
|
1167
|
-
};
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
1162
|
export {
|
|
1171
1163
|
SELECT_SPEC,
|
|
1172
1164
|
isSelectBuilder,
|
|
@@ -1179,18 +1171,13 @@ export {
|
|
|
1179
1171
|
validateInlineSnapshotSelect,
|
|
1180
1172
|
getImplicitKeyFields,
|
|
1181
1173
|
hydrate,
|
|
1182
|
-
maintainTrigger,
|
|
1183
|
-
isMaintainTrigger,
|
|
1184
1174
|
preview,
|
|
1185
1175
|
identity,
|
|
1186
|
-
LIFECYCLE_CONTRACT_MARKER,
|
|
1187
1176
|
isLifecycleContract,
|
|
1188
|
-
ENTITY_WRITES_MARKER,
|
|
1189
1177
|
isEntityWritesDefinition,
|
|
1190
1178
|
entityWrites,
|
|
1191
1179
|
getEntityWrites,
|
|
1192
1180
|
lifecyclePhaseForIntent,
|
|
1193
|
-
collectViewDefinitions,
|
|
1194
1181
|
buildMaintenanceGraph,
|
|
1195
1182
|
parseChange,
|
|
1196
1183
|
buildSubscribeHandler
|