graphddb 0.6.0 → 0.7.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/dist/index.js CHANGED
@@ -5,8 +5,13 @@ import {
5
5
  BatchGetResult,
6
6
  DDBModel,
7
7
  EDGE_WRITES_MARKER,
8
+ LOGICAL_EFFECT_CATEGORIES,
8
9
  MARKER_ROW_ENTITY,
9
10
  OLD_VALUE_NAMESPACE,
11
+ PREPARED_FORMAT_VERSION,
12
+ PREPARE_CACHE_MAX,
13
+ PreparedReadStatement,
14
+ PreparedWriteStatement,
10
15
  RELATION_TRAVERSAL_CONCURRENCY,
11
16
  SPEC_VERSION,
12
17
  assertBundleSerializable,
@@ -18,6 +23,7 @@ import {
18
23
  buildContexts,
19
24
  buildContracts,
20
25
  buildManifest,
26
+ buildManifestEntity,
21
27
  buildOperations,
22
28
  buildProjection,
23
29
  buildQuerySpec,
@@ -41,6 +47,7 @@ import {
41
47
  deriveModelEdgeWriteItems,
42
48
  edgeWrites,
43
49
  encodeCursor,
50
+ entityFingerprint,
44
51
  evaluateFilter,
45
52
  execute,
46
53
  executeBatchGet,
@@ -49,6 +56,8 @@ import {
49
56
  executeExplain,
50
57
  executeList,
51
58
  executeListInternal,
59
+ executeLogicalParallelWrites,
60
+ executeLogicalWriteOps,
52
61
  executeQuery,
53
62
  from,
54
63
  getEdgeWrites,
@@ -63,6 +72,7 @@ import {
63
72
  isMutationFragment,
64
73
  isMutationInputRef,
65
74
  isPlannedCommandMethod,
75
+ isPreparedParamRef,
66
76
  isQueryModelContract,
67
77
  isTransactionRef,
68
78
  mapWithConcurrency,
@@ -70,6 +80,7 @@ import {
70
80
  mintContractParamRef,
71
81
  mutation,
72
82
  plan,
83
+ prepare,
73
84
  publicCommandModel,
74
85
  publicQueryModel,
75
86
  query,
@@ -78,7 +89,7 @@ import {
78
89
  validateDepth,
79
90
  when,
80
91
  wholeKeysSentinel
81
- } from "./chunk-N5NQM3SO.js";
92
+ } from "./chunk-C5Q2NMRW.js";
82
93
  import {
83
94
  CdcEmulator,
84
95
  MAINT_OUTBOX_PK_PREFIX,
@@ -1277,6 +1288,256 @@ async function executeRangeFanout(op, keys, params = {}) {
1277
1288
  return out;
1278
1289
  }
1279
1290
 
1291
+ // src/runtime/prepared-loader.ts
1292
+ var LOAD_LABEL = "graphddb.loadPreparedPlan";
1293
+ function slotOfBind(bind) {
1294
+ if ("param" in bind) return { kind: "param", name: bind.param };
1295
+ if ("literal" in bind) return { kind: "literal", value: bind.literal };
1296
+ if ("literalDate" in bind) return { kind: "literal", value: new Date(bind.literalDate) };
1297
+ return { kind: "literal", value: BigInt(bind.literalBigInt) };
1298
+ }
1299
+ function slotsOfBindMap(map2) {
1300
+ const out = {};
1301
+ for (const [field2, bind] of Object.entries(map2 ?? {})) out[field2] = slotOfBind(bind);
1302
+ return out;
1303
+ }
1304
+ function bindValues(slots, params) {
1305
+ const out = {};
1306
+ for (const [field2, slot] of Object.entries(slots)) {
1307
+ out[field2] = slot.kind === "param" ? params[slot.name] : slot.value;
1308
+ }
1309
+ return out;
1310
+ }
1311
+ function resolveModelByName(name, planId) {
1312
+ for (const modelClass of MetadataRegistry.getAll().keys()) {
1313
+ if (modelClass.name === name) return modelClass;
1314
+ }
1315
+ throw new Error(
1316
+ `${LOAD_LABEL}: static plan '${planId}' targets entity '${name}', which is not a registered model in this process. Ensure the model module is imported before the plan executes, or regenerate the artifact (graphddb transform prepared --aot).`
1317
+ );
1318
+ }
1319
+ function bindEntities(plan2, planId) {
1320
+ const classes = /* @__PURE__ */ new Map();
1321
+ const entities = {};
1322
+ const tables = {};
1323
+ for (const [name, expected] of Object.entries(plan2.entities)) {
1324
+ const modelClass = resolveModelByName(name, planId);
1325
+ const metadata = MetadataRegistry.get(modelClass);
1326
+ const actual = entityFingerprint(metadata);
1327
+ if (actual !== expected) {
1328
+ throw new Error(
1329
+ `${LOAD_LABEL}: static plan '${planId}' is STALE \u2014 entity '${name}' has changed since the plan artifact was generated (declaration fingerprint mismatch: expected ${expected.slice(0, 12)}\u2026, live ${actual.slice(0, 12)}\u2026). A stale static plan never executes. Regenerate the artifact: \`graphddb transform prepared --aot <artifact> --write\` (CI: run the check mode to catch this at build time).`
1330
+ );
1331
+ }
1332
+ classes.set(name, modelClass);
1333
+ const entity = buildManifestEntity(metadata);
1334
+ entities[name] = entity;
1335
+ tables[metadata.tableName] = { physicalName: TableMapping.resolve(metadata.tableName) };
1336
+ }
1337
+ return { classes, manifest: { version: SPEC_VERSION, tables, entities } };
1338
+ }
1339
+ function templateParams(values) {
1340
+ const out = {};
1341
+ for (const [k2, v] of Object.entries(values)) {
1342
+ out[k2] = v instanceof Date ? v.toISOString() : v;
1343
+ }
1344
+ return out;
1345
+ }
1346
+ function renderSpecItem(transaction, index, manifest, params) {
1347
+ const single = {
1348
+ params: transaction.params,
1349
+ items: [transaction.items[index]]
1350
+ };
1351
+ return expandTransactionItems(single, manifest, params);
1352
+ }
1353
+ function renderEffectsForOp(op, boundParams) {
1354
+ const rendered = templateParams(boundParams);
1355
+ const effects = {};
1356
+ const checks = [];
1357
+ const modelBySignature = /* @__PURE__ */ new Map();
1358
+ const { transaction, categories } = op.spec;
1359
+ for (let i = 0; i < transaction.items.length; i++) {
1360
+ const category = categories[i];
1361
+ if (category === "base") continue;
1362
+ for (const out of renderSpecItem(transaction, i, op.manifest, rendered)) {
1363
+ const item = out.item;
1364
+ if (category === "check") {
1365
+ if (item.ConditionCheck !== void 0) checks.push(item.ConditionCheck);
1366
+ continue;
1367
+ }
1368
+ const family = category;
1369
+ if (!LOGICAL_EFFECT_CATEGORIES.includes(family)) {
1370
+ throw new Error(
1371
+ `${LOAD_LABEL}: unknown effect category '${String(category)}' in a static plan (artifact format skew \u2014 regenerate the artifact).`
1372
+ );
1373
+ }
1374
+ (effects[family] ??= []).push(item);
1375
+ if (out.model !== void 0) {
1376
+ modelBySignature.set(execItemKeySignature(item), out.model);
1377
+ }
1378
+ }
1379
+ }
1380
+ return { effects, checks, modelBySignature };
1381
+ }
1382
+ var INTENT_TO_KIND = { create: "put", update: "update", remove: "delete" };
1383
+ var AotPreparedWriteStatement = class {
1384
+ /** @internal */
1385
+ constructor(ops) {
1386
+ this.ops = ops;
1387
+ }
1388
+ ops;
1389
+ async execute(params = {}, options = {}) {
1390
+ const logical = this.ops.map((op) => {
1391
+ const bound = {
1392
+ ...bindValues(op.inputSlots, params),
1393
+ ...bindValues(op.keySlots, params)
1394
+ };
1395
+ const condition = op.conditionSlots !== void 0 ? bindValues(op.conditionSlots, params) : void 0;
1396
+ return {
1397
+ kind: INTENT_TO_KIND[op.spec.intent],
1398
+ modelClass: op.modelClass,
1399
+ modelStatic: op.modelStatic,
1400
+ keyFields: op.spec.keyFields,
1401
+ params: bound,
1402
+ // A `create` guards with attribute_not_exists — the same condition the
1403
+ // compiled base op carries; an explicit gate on a create was rejected at
1404
+ // BUILD time (mirroring the compiled core's `withCondition` reject).
1405
+ ...op.spec.intent === "create" ? { condition: { notExists: true } } : condition !== void 0 ? { condition } : {},
1406
+ ...op.spec.result !== void 0 ? { result: op.spec.result } : {},
1407
+ renderEffects: (postW1) => renderEffectsForOp(op, postW1)
1408
+ };
1409
+ });
1410
+ const mode = options.mode ?? "transaction";
1411
+ const runOpts = {
1412
+ label: LOAD_LABEL,
1413
+ ...options.retry !== void 0 ? { retry: options.retry } : {},
1414
+ ...options.context !== void 0 ? { context: options.context } : {}
1415
+ };
1416
+ if (mode === "transaction") {
1417
+ const { readBacks } = await executeLogicalWriteOps(logical, runOpts);
1418
+ const out2 = {};
1419
+ this.ops.forEach((op, i) => {
1420
+ if (op.spec.result !== void 0) out2[op.alias] = readBacks[i];
1421
+ });
1422
+ return out2;
1423
+ }
1424
+ const settled = await executeLogicalParallelWrites(logical, runOpts);
1425
+ const out = {};
1426
+ this.ops.forEach((op, i) => {
1427
+ const res = settled[i];
1428
+ out[op.alias] = res.ok ? { ok: true, value: op.spec.result !== void 0 ? res.value : void 0 } : { ok: false, error: res.error };
1429
+ });
1430
+ return out;
1431
+ }
1432
+ };
1433
+ function bindReadPlan(plan2, planId) {
1434
+ const { classes } = bindEntities(plan2, planId);
1435
+ const routes = (plan2.reads ?? []).map((r) => {
1436
+ const modelClass = classes.get(r.entity);
1437
+ if (modelClass === void 0) {
1438
+ throw new Error(
1439
+ `${LOAD_LABEL}: static plan '${planId}' route '${r.alias}' targets entity '${r.entity}', which the plan does not fingerprint (artifact skew \u2014 regenerate).`
1440
+ );
1441
+ }
1442
+ const consistentReadSlot = r.consistentRead !== void 0 ? slotOfBind(r.consistentRead) : void 0;
1443
+ const limitSlot = r.limit !== void 0 ? slotOfBind(r.limit) : void 0;
1444
+ const afterSlot = r.after !== void 0 ? slotOfBind(r.after) : void 0;
1445
+ return {
1446
+ alias: r.alias,
1447
+ kind: r.op,
1448
+ modelClass,
1449
+ select: r.select,
1450
+ keySlots: slotsOfBindMap(r.key),
1451
+ ...r.maxDepth !== void 0 ? { maxDepth: r.maxDepth } : {},
1452
+ ...r.order !== void 0 ? { order: r.order } : {},
1453
+ ...r.filter !== void 0 ? { filter: r.filter } : {},
1454
+ ...consistentReadSlot !== void 0 ? { consistentReadSlot } : {},
1455
+ ...limitSlot !== void 0 ? { limitSlot } : {},
1456
+ ...afterSlot !== void 0 ? { afterSlot } : {}
1457
+ };
1458
+ });
1459
+ return new PreparedReadStatement(routes);
1460
+ }
1461
+ function bindWritePlan(plan2, planId) {
1462
+ const { classes, manifest } = bindEntities(plan2, planId);
1463
+ const ops = (plan2.writes ?? []).map((w) => {
1464
+ const modelClass = classes.get(w.entity);
1465
+ if (modelClass === void 0) {
1466
+ throw new Error(
1467
+ `${LOAD_LABEL}: static plan '${planId}' op '${w.alias}' targets entity '${w.entity}', which the plan does not fingerprint (artifact skew \u2014 regenerate).`
1468
+ );
1469
+ }
1470
+ const modelStatic = modelClass.asModel();
1471
+ return {
1472
+ alias: w.alias,
1473
+ spec: w,
1474
+ modelClass,
1475
+ modelStatic,
1476
+ keySlots: slotsOfBindMap(w.key),
1477
+ inputSlots: slotsOfBindMap(w.input),
1478
+ ...w.condition !== void 0 ? { conditionSlots: slotsOfBindMap(w.condition) } : {},
1479
+ manifest
1480
+ };
1481
+ });
1482
+ return new AotPreparedWriteStatement(ops);
1483
+ }
1484
+ function bindPlan(doc, planId) {
1485
+ if (doc === null || typeof doc !== "object" || doc.plans === void 0) {
1486
+ throw new Error(`${LOAD_LABEL}: not a prepared-plan document.`);
1487
+ }
1488
+ if (doc.formatVersion !== PREPARED_FORMAT_VERSION) {
1489
+ throw new Error(
1490
+ `${LOAD_LABEL}: unsupported artifact format version '${String(doc.formatVersion)}' (this runtime supports '${PREPARED_FORMAT_VERSION}'). Regenerate the artifact with the installed graphddb version.`
1491
+ );
1492
+ }
1493
+ if (doc.specVersion !== SPEC_VERSION) {
1494
+ throw new Error(
1495
+ `${LOAD_LABEL}: the artifact was compiled against operation-IR version '${String(doc.specVersion)}' but this runtime speaks '${SPEC_VERSION}'. A version-skewed static plan never executes \u2014 regenerate the artifact.`
1496
+ );
1497
+ }
1498
+ const plan2 = doc.plans[planId];
1499
+ if (plan2 === void 0) {
1500
+ const available = Object.keys(doc.plans).sort().slice(0, 8).join(", ");
1501
+ throw new Error(
1502
+ `${LOAD_LABEL}: the artifact carries no plan '${planId}' (available: ${available}${Object.keys(doc.plans).length > 8 ? ", \u2026" : ""}). The source and the artifact have drifted \u2014 regenerate: \`graphddb transform prepared --aot <artifact> --write\`.`
1503
+ );
1504
+ }
1505
+ return plan2.kind === "read" ? bindReadPlan(plan2, planId) : bindWritePlan(plan2, planId);
1506
+ }
1507
+ var BOUND = /* @__PURE__ */ new WeakMap();
1508
+ var LazyAotHandle = class {
1509
+ constructor(doc, planId) {
1510
+ this.doc = doc;
1511
+ this.planId = planId;
1512
+ }
1513
+ doc;
1514
+ planId;
1515
+ bound;
1516
+ resolve() {
1517
+ if (this.bound !== void 0) return this.bound;
1518
+ let perDoc = BOUND.get(this.doc);
1519
+ if (perDoc === void 0) {
1520
+ perDoc = /* @__PURE__ */ new Map();
1521
+ BOUND.set(this.doc, perDoc);
1522
+ }
1523
+ let handle = perDoc.get(this.planId);
1524
+ if (handle === void 0) {
1525
+ handle = bindPlan(this.doc, this.planId);
1526
+ perDoc.set(this.planId, handle);
1527
+ }
1528
+ this.bound = handle;
1529
+ return handle;
1530
+ }
1531
+ async execute(params, options) {
1532
+ const target = this.resolve();
1533
+ return target.execute(params, options);
1534
+ }
1535
+ };
1536
+ function loadPreparedPlan(doc, planId, body) {
1537
+ void body;
1538
+ return new LazyAotHandle(doc, planId);
1539
+ }
1540
+
1280
1541
  // src/relation/maintenance-rebuild.ts
1281
1542
  function toClass(m) {
1282
1543
  try {
@@ -1853,6 +2114,7 @@ function assertDefinition(name, def) {
1853
2114
  }
1854
2115
  }
1855
2116
  export {
2117
+ AotPreparedWriteStatement,
1856
2118
  BATCH_GET_MAX_KEYS,
1857
2119
  BATCH_WRITE_MAX_ITEMS,
1858
2120
  BatchGetResult,
@@ -1873,6 +2135,9 @@ export {
1873
2135
  MaintenanceRebuilder,
1874
2136
  MetadataRegistry,
1875
2137
  OLD_VALUE_NAMESPACE,
2138
+ PREPARE_CACHE_MAX,
2139
+ PreparedReadStatement,
2140
+ PreparedWriteStatement,
1876
2141
  RetryingExecutor,
1877
2142
  SPEC_VERSION,
1878
2143
  TableMapping,
@@ -1987,6 +2252,7 @@ export {
1987
2252
  isMutationInputRef,
1988
2253
  isParam,
1989
2254
  isPlannedCommandMethod,
2255
+ isPreparedParamRef,
1990
2256
  isQueryModelContract,
1991
2257
  isRetryableError,
1992
2258
  isRetryableTransactionCancellation,
@@ -1997,6 +2263,7 @@ export {
1997
2263
  lifecyclePhaseForIntent,
1998
2264
  list,
1999
2265
  literal,
2266
+ loadPreparedPlan,
2000
2267
  maintainTrigger,
2001
2268
  maintainedFrom,
2002
2269
  map,
@@ -2012,6 +2279,7 @@ export {
2012
2279
  param,
2013
2280
  parseChange,
2014
2281
  plan,
2282
+ prepare,
2015
2283
  preview,
2016
2284
  publicCommandModel,
2017
2285
  publicQueryModel,
@@ -1,7 +1,7 @@
1
- import { L as LintRule } from '../registry-DbqmFyab.js';
2
- export { a as LintResult, b as Linter } from '../registry-DbqmFyab.js';
3
- export { c as createDefaultLinter, g as gsiAmbiguityRule, m as missingGsiRule, n as noScanRule, q as queryBoundaryRule, r as relationDepthRule, a as requireLimitRule } from '../relation-depth-0TiWr5OW.js';
4
- import '../maintenance-view-adapter-CFeasCKo.js';
1
+ import { L as LintRule } from '../registry-BndKbZbg.js';
2
+ export { a as LintResult, b as Linter } from '../registry-BndKbZbg.js';
3
+ export { c as createDefaultLinter, g as gsiAmbiguityRule, m as missingGsiRule, n as noScanRule, q as queryBoundaryRule, r as relationDepthRule, a as requireLimitRule } from '../relation-depth-CCGHLTOv.js';
4
+ import '../maintenance-view-adapter-NBTZbE8-.js';
5
5
  import '@aws-sdk/client-dynamodb';
6
6
 
7
7
  /**