graphddb 0.7.8 → 0.7.10
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/cdc/index.d.ts +3 -2
- package/dist/cdc/index.js +3 -2
- package/dist/chunk-3UD3XIF2.js +860 -0
- package/dist/{chunk-HFFIB77D.js → chunk-3ZU2VW3L.js} +2 -1189
- package/dist/{chunk-IA6MW2HP.js → chunk-AD6ZQTTE.js} +4 -2
- package/dist/chunk-DFUKGU2Q.js +1197 -0
- package/dist/{chunk-NZRCBEWS.js → chunk-EOJDN3SA.js} +302 -728
- package/dist/cli.js +389 -29
- package/dist/{from-change-w2Ih8fkm.d.ts → from-change-Ty95KA8C.d.ts} +1 -1
- package/dist/{index-Deugy2sa.d.ts → index-Dc7d8mWI.d.ts} +161 -6
- package/dist/index.d.ts +127 -115
- package/dist/index.js +196 -59
- package/dist/linter/index.d.ts +5 -4
- package/dist/{maintenance-view-adapter-BCbgKG5d.d.ts → maintenance-view-adapter-BAZ9uBGe.d.ts} +122 -1091
- package/dist/{registry-pAnFcc62.d.ts → registry-LWE54Sdc.d.ts} +1 -1
- package/dist/{relation-depth-C9t4s9bt.d.ts → relation-depth-BRS513Tq.d.ts} +1 -1
- package/dist/spec/index.d.ts +4 -3
- package/dist/spec/index.js +18 -3
- package/dist/testing/index.d.ts +2 -1
- package/dist/testing/index.js +3 -2
- package/dist/transform/index.d.ts +460 -1
- package/dist/transform/index.js +2084 -1
- package/dist/types-BQLzTEqh.d.ts +1207 -0
- package/docs/python-bridge.md +17 -1
- package/package.json +7 -1
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SELECT_SPEC,
|
|
3
|
+
buildMaintenanceGraph,
|
|
4
|
+
buildProject,
|
|
5
|
+
buildRelation,
|
|
6
|
+
buildSubscribeHandler,
|
|
7
|
+
detectRelationFields,
|
|
8
|
+
getEntityWrites,
|
|
9
|
+
getImplicitKeyFields,
|
|
10
|
+
hydrate,
|
|
11
|
+
isEntityWritesDefinition,
|
|
12
|
+
isInlineSnapshotSpec,
|
|
13
|
+
isLifecycleContract,
|
|
14
|
+
isSelectBuilder,
|
|
15
|
+
lifecyclePhaseForIntent,
|
|
16
|
+
normalizeSelectSpec,
|
|
17
|
+
normalizeTopLevelSelect,
|
|
18
|
+
parseChange,
|
|
19
|
+
validateInlineSnapshotSelect
|
|
20
|
+
} from "./chunk-DFUKGU2Q.js";
|
|
21
|
+
import {
|
|
22
|
+
EXPR_VERSION,
|
|
23
|
+
MARKER_ROW_ENTITY,
|
|
24
|
+
SPEC_VERSION,
|
|
25
|
+
canonicalizeExpressionSpec,
|
|
26
|
+
isScpExprConditionInput,
|
|
27
|
+
isTransactionRef,
|
|
28
|
+
operationsSpecVersion
|
|
29
|
+
} from "./chunk-3UD3XIF2.js";
|
|
1
30
|
import {
|
|
2
31
|
BATCH_GET_MAX_KEYS,
|
|
3
32
|
CONDITION_OPERATOR_KEYS,
|
|
@@ -10,12 +39,8 @@ import {
|
|
|
10
39
|
attachModelClass,
|
|
11
40
|
buildConditionExpression,
|
|
12
41
|
buildDeleteInput,
|
|
13
|
-
buildMaintenanceGraph,
|
|
14
|
-
buildProject,
|
|
15
42
|
buildPutInput,
|
|
16
43
|
buildReadRuntime,
|
|
17
|
-
buildRelation,
|
|
18
|
-
buildSubscribeHandler,
|
|
19
44
|
buildUpdateInput,
|
|
20
45
|
buildWriteRuntime,
|
|
21
46
|
captureWrite,
|
|
@@ -24,34 +49,21 @@ import {
|
|
|
24
49
|
compileRawCondition,
|
|
25
50
|
condParamName,
|
|
26
51
|
ctxModelFor,
|
|
27
|
-
detectRelationFields,
|
|
28
52
|
execItemKeySignature,
|
|
29
53
|
executeDelete,
|
|
30
54
|
executePut,
|
|
31
55
|
executeTransaction,
|
|
32
56
|
executeUpdate,
|
|
33
|
-
getEntityWrites,
|
|
34
|
-
getImplicitKeyFields,
|
|
35
|
-
hydrate,
|
|
36
|
-
isEntityWritesDefinition,
|
|
37
|
-
isInlineSnapshotSpec,
|
|
38
|
-
isLifecycleContract,
|
|
39
57
|
isParam,
|
|
40
58
|
isRawCondition,
|
|
41
|
-
isSelectBuilder,
|
|
42
|
-
lifecyclePhaseForIntent,
|
|
43
|
-
normalizeSelectSpec,
|
|
44
|
-
normalizeTopLevelSelect,
|
|
45
59
|
param,
|
|
46
|
-
parseChange,
|
|
47
60
|
pkTemplate,
|
|
48
61
|
resolveModelClass,
|
|
49
62
|
resolveSegmentedKey,
|
|
50
63
|
serializeFieldValue,
|
|
51
64
|
serializeRawCondition,
|
|
52
|
-
skTemplate
|
|
53
|
-
|
|
54
|
-
} from "./chunk-HFFIB77D.js";
|
|
65
|
+
skTemplate
|
|
66
|
+
} from "./chunk-3ZU2VW3L.js";
|
|
55
67
|
import {
|
|
56
68
|
TableMapping,
|
|
57
69
|
createColumnMap,
|
|
@@ -68,10 +80,6 @@ function evaluateKey(segmented, scope, presentFields, nameOf = (f) => f, partial
|
|
|
68
80
|
return { pk, sk: sk?.template };
|
|
69
81
|
}
|
|
70
82
|
|
|
71
|
-
// src/spec/types.ts
|
|
72
|
-
var SPEC_VERSION = "1.1";
|
|
73
|
-
var MARKER_ROW_ENTITY = "__marker__";
|
|
74
|
-
|
|
75
83
|
// src/spec/manifest.ts
|
|
76
84
|
var DYNAMO_TYPE_TO_FIELD_TYPE = {
|
|
77
85
|
S: "string",
|
|
@@ -219,6 +227,18 @@ function conditionInputToSpec(condition, context, renderLeaf2, renderTreeLeaf, r
|
|
|
219
227
|
);
|
|
220
228
|
}
|
|
221
229
|
const obj = condition;
|
|
230
|
+
if (isScpExprConditionInput(obj)) {
|
|
231
|
+
const siblings = Object.keys(obj).filter((k) => k !== "scpExpr");
|
|
232
|
+
if (siblings.length > 0) {
|
|
233
|
+
throw new Error(
|
|
234
|
+
`${context}: a \`scpExpr\` write condition must be the WHOLE condition object; it cannot be mixed with sibling clauses [${siblings.join(", ")}] (they would be silently dropped). Fold the other clauses into the expression itself (e.g. \`{and: [...]}\`), or keep the condition fully declarative.`
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
kind: "scpExpr",
|
|
239
|
+
expression: canonicalizeExpressionSpec(obj.scpExpr, `${context} (scpExpr)`)
|
|
240
|
+
};
|
|
241
|
+
}
|
|
222
242
|
if (obj.notExists === true) return { kind: "notExists" };
|
|
223
243
|
if ("attributeExists" in obj && typeof obj.attributeExists === "string") {
|
|
224
244
|
if (obj.attributeExists.length === 0) {
|
|
@@ -253,6 +273,13 @@ function assertNotNestedRaw(sub, context) {
|
|
|
253
273
|
);
|
|
254
274
|
}
|
|
255
275
|
}
|
|
276
|
+
function assertNotNestedScpExpr(sub, context) {
|
|
277
|
+
if (sub !== null && typeof sub === "object" && !Array.isArray(sub) && "scpExpr" in sub) {
|
|
278
|
+
throw new Error(
|
|
279
|
+
`${context}: a \`scpExpr\` write condition may be used as a whole condition, but not nested inside an \`and\` / \`or\` / \`not\` group of a declarative condition tree. Lift the expression to the top level and express the group inside the expression (e.g. \`{and: [...]}\`), or keep the group fully declarative.`
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
256
283
|
var LOGICAL_KEYS = /* @__PURE__ */ new Set(["and", "or", "not"]);
|
|
257
284
|
var OPERATOR_KEYS = /* @__PURE__ */ new Set([
|
|
258
285
|
"eq",
|
|
@@ -309,12 +336,14 @@ function buildTree(obj, context, renderTreeLeaf) {
|
|
|
309
336
|
if (key === "and" || key === "or") {
|
|
310
337
|
out[key] = value.map((sub) => {
|
|
311
338
|
assertNotNestedRaw(sub, context);
|
|
339
|
+
assertNotNestedScpExpr(sub, context);
|
|
312
340
|
return buildTree(sub, context, renderTreeLeaf);
|
|
313
341
|
});
|
|
314
342
|
continue;
|
|
315
343
|
}
|
|
316
344
|
if (key === "not") {
|
|
317
345
|
assertNotNestedRaw(value, context);
|
|
346
|
+
assertNotNestedScpExpr(value, context);
|
|
318
347
|
out[key] = buildTree(
|
|
319
348
|
value,
|
|
320
349
|
context,
|
|
@@ -395,6 +424,15 @@ function assertSupportedCondition(commandName, condition) {
|
|
|
395
424
|
}
|
|
396
425
|
return;
|
|
397
426
|
}
|
|
427
|
+
if (condition.kind === "scpExpr") {
|
|
428
|
+
const expression = condition.expression;
|
|
429
|
+
if (!expression || expression.exprVersion !== EXPR_VERSION || expression.expr === void 0) {
|
|
430
|
+
throw new Error(
|
|
431
|
+
`Command '${commandName}' has a malformed scpExpr write condition \u2014 expected \`{ exprVersion: ${EXPR_VERSION}, expr: <node> }\`.`
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
398
436
|
throw new Error(
|
|
399
437
|
`Command '${commandName}' has an unsupported write condition.`
|
|
400
438
|
);
|
|
@@ -1754,6 +1792,154 @@ async function executeQueryInner(modelClass, key, selectSpec, options, mw) {
|
|
|
1754
1792
|
return hydratedItem;
|
|
1755
1793
|
}
|
|
1756
1794
|
|
|
1795
|
+
// src/runtime/read-plan.ts
|
|
1796
|
+
function bindSlots(slots, params) {
|
|
1797
|
+
const out = {};
|
|
1798
|
+
for (const [field, slot] of Object.entries(slots)) {
|
|
1799
|
+
out[field] = slot.kind === "param" ? params[slot.name] : slot.value;
|
|
1800
|
+
}
|
|
1801
|
+
return out;
|
|
1802
|
+
}
|
|
1803
|
+
function bindOptionalSlot(slot, params) {
|
|
1804
|
+
if (slot === void 0) return void 0;
|
|
1805
|
+
return slot.kind === "param" ? params[slot.name] : slot.value;
|
|
1806
|
+
}
|
|
1807
|
+
function executeCompiledReadRoute(route, params, options) {
|
|
1808
|
+
const key = bindSlots(route.keySlots, params);
|
|
1809
|
+
const opts = { ...options ?? {} };
|
|
1810
|
+
if (route.kind === "query") {
|
|
1811
|
+
if (route.consistentReadSlot !== void 0) {
|
|
1812
|
+
opts.consistentRead = bindOptionalSlot(route.consistentReadSlot, params);
|
|
1813
|
+
}
|
|
1814
|
+
if (route.maxDepth !== void 0) opts.maxDepth = route.maxDepth;
|
|
1815
|
+
return executeQuery(route.modelClass, key, route.select, opts);
|
|
1816
|
+
}
|
|
1817
|
+
if (route.limitSlot !== void 0) {
|
|
1818
|
+
opts.limit = bindOptionalSlot(route.limitSlot, params);
|
|
1819
|
+
}
|
|
1820
|
+
if (route.afterSlot !== void 0) {
|
|
1821
|
+
opts.after = bindOptionalSlot(route.afterSlot, params);
|
|
1822
|
+
}
|
|
1823
|
+
if (route.order !== void 0) opts.order = route.order;
|
|
1824
|
+
if (route.filter !== void 0) opts.filter = route.filter;
|
|
1825
|
+
return executeList(route.modelClass, key, route.select, opts);
|
|
1826
|
+
}
|
|
1827
|
+
var MODEL_CLASS_IDS = /* @__PURE__ */ new WeakMap();
|
|
1828
|
+
var nextModelClassId = 1;
|
|
1829
|
+
function modelClassIdentity(cls) {
|
|
1830
|
+
let id = MODEL_CLASS_IDS.get(cls);
|
|
1831
|
+
if (id === void 0) {
|
|
1832
|
+
id = nextModelClassId++;
|
|
1833
|
+
MODEL_CLASS_IDS.set(cls, id);
|
|
1834
|
+
}
|
|
1835
|
+
return `model#${id}`;
|
|
1836
|
+
}
|
|
1837
|
+
var BoundedLru = class {
|
|
1838
|
+
constructor(max) {
|
|
1839
|
+
this.max = max;
|
|
1840
|
+
}
|
|
1841
|
+
max;
|
|
1842
|
+
map = /* @__PURE__ */ new Map();
|
|
1843
|
+
get(key) {
|
|
1844
|
+
const v = this.map.get(key);
|
|
1845
|
+
if (v !== void 0) {
|
|
1846
|
+
this.map.delete(key);
|
|
1847
|
+
this.map.set(key, v);
|
|
1848
|
+
}
|
|
1849
|
+
return v;
|
|
1850
|
+
}
|
|
1851
|
+
set(key, value) {
|
|
1852
|
+
if (this.map.has(key)) this.map.delete(key);
|
|
1853
|
+
this.map.set(key, value);
|
|
1854
|
+
if (this.map.size > this.max) {
|
|
1855
|
+
const oldest = this.map.keys().next().value;
|
|
1856
|
+
if (oldest !== void 0) this.map.delete(oldest);
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
get size() {
|
|
1860
|
+
return this.map.size;
|
|
1861
|
+
}
|
|
1862
|
+
clear() {
|
|
1863
|
+
this.map.clear();
|
|
1864
|
+
}
|
|
1865
|
+
};
|
|
1866
|
+
var ADHOC_READ_PLAN_CACHE_MAX = 256;
|
|
1867
|
+
var ADHOC_READ_PLAN_CACHE = new BoundedLru(ADHOC_READ_PLAN_CACHE_MAX);
|
|
1868
|
+
var adHocCompileCount = 0;
|
|
1869
|
+
function shapeToken(value) {
|
|
1870
|
+
if (value === null) return "null";
|
|
1871
|
+
const t = typeof value;
|
|
1872
|
+
if (t === "string") return JSON.stringify(value);
|
|
1873
|
+
if (t === "number" || t === "boolean") return String(value);
|
|
1874
|
+
if (t === "undefined") return "u";
|
|
1875
|
+
if (t === "bigint") return `n${String(value)}`;
|
|
1876
|
+
if (t === "function" || t === "symbol") return null;
|
|
1877
|
+
if (value instanceof Date) return `D${value.getTime()}`;
|
|
1878
|
+
if (Array.isArray(value)) {
|
|
1879
|
+
const parts2 = [];
|
|
1880
|
+
for (const v of value) {
|
|
1881
|
+
const p = shapeToken(v);
|
|
1882
|
+
if (p === null) return null;
|
|
1883
|
+
parts2.push(p);
|
|
1884
|
+
}
|
|
1885
|
+
return `[${parts2.join(",")}]`;
|
|
1886
|
+
}
|
|
1887
|
+
if (isSelectBuilder(value)) {
|
|
1888
|
+
const spec = value[SELECT_SPEC];
|
|
1889
|
+
const inner = shapeToken({
|
|
1890
|
+
select: spec.select,
|
|
1891
|
+
filter: spec.filter,
|
|
1892
|
+
limit: spec.limit,
|
|
1893
|
+
after: spec.after,
|
|
1894
|
+
order: spec.order
|
|
1895
|
+
});
|
|
1896
|
+
return inner === null ? null : `B${inner}`;
|
|
1897
|
+
}
|
|
1898
|
+
const proto = Object.getPrototypeOf(value);
|
|
1899
|
+
if (proto !== Object.prototype && proto !== null) return null;
|
|
1900
|
+
const rec = value;
|
|
1901
|
+
const parts = [];
|
|
1902
|
+
for (const k of Object.keys(rec).sort()) {
|
|
1903
|
+
const p = shapeToken(rec[k]);
|
|
1904
|
+
if (p === null) return null;
|
|
1905
|
+
parts.push(`${JSON.stringify(k)}:${p}`);
|
|
1906
|
+
}
|
|
1907
|
+
return `{${parts.join(",")}}`;
|
|
1908
|
+
}
|
|
1909
|
+
function adHocStructureKey(kind, modelClass, key, select) {
|
|
1910
|
+
const selectToken = shapeToken(select);
|
|
1911
|
+
if (selectToken === null) return null;
|
|
1912
|
+
const fields = Object.keys(key).map((f) => JSON.stringify(f)).join(",");
|
|
1913
|
+
return `${kind}|${modelClassIdentity(modelClass)}|${fields}|${selectToken}`;
|
|
1914
|
+
}
|
|
1915
|
+
function lowerAdHocReadRoute(kind, modelClass, key, select) {
|
|
1916
|
+
const cacheKey = adHocStructureKey(kind, modelClass, key, select);
|
|
1917
|
+
if (cacheKey !== null) {
|
|
1918
|
+
const cached = ADHOC_READ_PLAN_CACHE.get(cacheKey);
|
|
1919
|
+
if (cached !== void 0) return cached;
|
|
1920
|
+
}
|
|
1921
|
+
adHocCompileCount++;
|
|
1922
|
+
const keySlots = {};
|
|
1923
|
+
for (const field of Object.keys(key)) {
|
|
1924
|
+
keySlots[field] = { kind: "param", name: field };
|
|
1925
|
+
}
|
|
1926
|
+
const route = { alias: "$adhoc", kind, modelClass, select, keySlots };
|
|
1927
|
+
if (cacheKey !== null) ADHOC_READ_PLAN_CACHE.set(cacheKey, route);
|
|
1928
|
+
return route;
|
|
1929
|
+
}
|
|
1930
|
+
function runAdHoc(route, select, key, options) {
|
|
1931
|
+
const effective = route.select === select ? route : { ...route, select };
|
|
1932
|
+
return executeCompiledReadRoute(effective, key, options);
|
|
1933
|
+
}
|
|
1934
|
+
function executeAdHocQuery(modelClass, key, selectSpec, options) {
|
|
1935
|
+
const route = lowerAdHocReadRoute("query", modelClass, key, selectSpec);
|
|
1936
|
+
return runAdHoc(route, selectSpec, key, options);
|
|
1937
|
+
}
|
|
1938
|
+
function executeAdHocList(modelClass, key, selectSpec, options) {
|
|
1939
|
+
const route = lowerAdHocReadRoute("list", modelClass, key, selectSpec);
|
|
1940
|
+
return runAdHoc(route, selectSpec, key, options);
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1757
1943
|
// src/operations/explain.ts
|
|
1758
1944
|
function executeExplain(modelClass, key, options) {
|
|
1759
1945
|
const metadata = MetadataRegistry.get(modelClass);
|
|
@@ -2828,14 +3014,14 @@ function renderInputLeaf(leaf, isKeyFieldInPut, consumerIndex, consumerField, re
|
|
|
2828
3014
|
if (isMutationInputRef(leaf)) {
|
|
2829
3015
|
return isKeyFieldInPut ? mintContractKeyFieldRef(leaf.field) : mintContractParamRef(leaf.field);
|
|
2830
3016
|
}
|
|
2831
|
-
const
|
|
2832
|
-
if (
|
|
3017
|
+
const entityRef2 = parseEntityRef(leaf);
|
|
3018
|
+
if (entityRef2 !== void 0) {
|
|
2833
3019
|
if (resolveEntityRef === null) {
|
|
2834
3020
|
throw new Error(
|
|
2835
|
-
`mutation: the cross-fragment reference '${
|
|
3021
|
+
`mutation: the cross-fragment reference '${entityRef2.path}' is only valid in a MULTI-fragment mutation \u2014 it names a value produced by an earlier fragment, but this mutation has a single fragment (there is no fragment #${entityRef2.fragmentIndex} to read from). Bind '${consumerField}' to a \`$.field\` input reference or a literal instead.`
|
|
2836
3022
|
);
|
|
2837
3023
|
}
|
|
2838
|
-
return resolveEntityRef(
|
|
3024
|
+
return resolveEntityRef(entityRef2, consumerIndex, consumerField);
|
|
2839
3025
|
}
|
|
2840
3026
|
return leaf;
|
|
2841
3027
|
}
|
|
@@ -3117,6 +3303,11 @@ function renderCondition(condition, key, params, context) {
|
|
|
3117
3303
|
}
|
|
3118
3304
|
if (typeof condition === "object" && condition !== null) {
|
|
3119
3305
|
const obj = condition;
|
|
3306
|
+
if ("scpExpr" in obj) {
|
|
3307
|
+
throw new Error(
|
|
3308
|
+
`Contract runtime: ${context} \u2014 this runtime does not evaluate scpExpr write conditions yet (spec 1.2 expression vocabulary, issue #261); evaluation lands with Phase 3 S5 (#265). Refusing to execute the write with its condition ignored.`
|
|
3309
|
+
);
|
|
3310
|
+
}
|
|
3120
3311
|
if (obj.notExists === true) return { notExists: true };
|
|
3121
3312
|
if (typeof obj.attributeExists === "string") {
|
|
3122
3313
|
return { attributeExists: obj.attributeExists };
|
|
@@ -4273,13 +4464,13 @@ async function executeReadRoute(alias, route) {
|
|
|
4273
4464
|
);
|
|
4274
4465
|
const opt = route.options ?? {};
|
|
4275
4466
|
if (isQuery) {
|
|
4276
|
-
return
|
|
4467
|
+
return executeAdHocQuery(modelClass, route.key, route.select, {
|
|
4277
4468
|
consistentRead: opt.consistentRead,
|
|
4278
4469
|
maxDepth: opt.maxDepth,
|
|
4279
4470
|
context: opt.context
|
|
4280
4471
|
});
|
|
4281
4472
|
}
|
|
4282
|
-
return
|
|
4473
|
+
return executeAdHocList(modelClass, route.key, route.select, {
|
|
4283
4474
|
limit: opt.limit,
|
|
4284
4475
|
after: opt.after,
|
|
4285
4476
|
order: opt.order,
|
|
@@ -4514,17 +4705,6 @@ function recordSlots(binding, where) {
|
|
|
4514
4705
|
}
|
|
4515
4706
|
return { fields, slots };
|
|
4516
4707
|
}
|
|
4517
|
-
function bindSlots(slots, params) {
|
|
4518
|
-
const out = {};
|
|
4519
|
-
for (const [field, slot] of Object.entries(slots)) {
|
|
4520
|
-
out[field] = slot.kind === "param" ? params[slot.name] : slot.value;
|
|
4521
|
-
}
|
|
4522
|
-
return out;
|
|
4523
|
-
}
|
|
4524
|
-
function bindOptionalSlot(slot, params) {
|
|
4525
|
-
if (slot === void 0) return void 0;
|
|
4526
|
-
return slot.kind === "param" ? params[slot.name] : slot.value;
|
|
4527
|
-
}
|
|
4528
4708
|
function recordOptionSlot(value, where) {
|
|
4529
4709
|
if (value === void 0) return void 0;
|
|
4530
4710
|
if (isPreparedParamRef(value)) return { kind: "param", name: value.name };
|
|
@@ -4584,23 +4764,7 @@ var PreparedReadStatement = class {
|
|
|
4584
4764
|
return out;
|
|
4585
4765
|
}
|
|
4586
4766
|
runRoute(route, params, options) {
|
|
4587
|
-
|
|
4588
|
-
const consistentRead = bindOptionalSlot(route.consistentReadSlot, params);
|
|
4589
|
-
if (route.kind === "query") {
|
|
4590
|
-
return executeQuery(route.modelClass, key, route.select, {
|
|
4591
|
-
consistentRead,
|
|
4592
|
-
maxDepth: route.maxDepth,
|
|
4593
|
-
...options.retry !== void 0 ? { retry: options.retry } : {},
|
|
4594
|
-
...options.context !== void 0 ? { context: options.context } : {}
|
|
4595
|
-
});
|
|
4596
|
-
}
|
|
4597
|
-
const limit = bindOptionalSlot(route.limitSlot, params);
|
|
4598
|
-
const after = bindOptionalSlot(route.afterSlot, params);
|
|
4599
|
-
return executeList(route.modelClass, key, route.select, {
|
|
4600
|
-
limit,
|
|
4601
|
-
after,
|
|
4602
|
-
order: route.order,
|
|
4603
|
-
filter: route.filter,
|
|
4767
|
+
return executeCompiledReadRoute(route, params, {
|
|
4604
4768
|
...options.retry !== void 0 ? { retry: options.retry } : {},
|
|
4605
4769
|
...options.context !== void 0 ? { context: options.context } : {}
|
|
4606
4770
|
});
|
|
@@ -4764,35 +4928,6 @@ function assertStaticTemplate(value, where) {
|
|
|
4764
4928
|
}
|
|
4765
4929
|
}
|
|
4766
4930
|
var PREPARE_CACHE_MAX = 256;
|
|
4767
|
-
var BoundedLru = class {
|
|
4768
|
-
constructor(max) {
|
|
4769
|
-
this.max = max;
|
|
4770
|
-
}
|
|
4771
|
-
max;
|
|
4772
|
-
map = /* @__PURE__ */ new Map();
|
|
4773
|
-
get(key) {
|
|
4774
|
-
const v = this.map.get(key);
|
|
4775
|
-
if (v !== void 0) {
|
|
4776
|
-
this.map.delete(key);
|
|
4777
|
-
this.map.set(key, v);
|
|
4778
|
-
}
|
|
4779
|
-
return v;
|
|
4780
|
-
}
|
|
4781
|
-
set(key, value) {
|
|
4782
|
-
if (this.map.has(key)) this.map.delete(key);
|
|
4783
|
-
this.map.set(key, value);
|
|
4784
|
-
if (this.map.size > this.max) {
|
|
4785
|
-
const oldest = this.map.keys().next().value;
|
|
4786
|
-
if (oldest !== void 0) this.map.delete(oldest);
|
|
4787
|
-
}
|
|
4788
|
-
}
|
|
4789
|
-
get size() {
|
|
4790
|
-
return this.map.size;
|
|
4791
|
-
}
|
|
4792
|
-
clear() {
|
|
4793
|
-
this.map.clear();
|
|
4794
|
-
}
|
|
4795
|
-
};
|
|
4796
4931
|
var PREPARE_CACHE = new BoundedLru(PREPARE_CACHE_MAX);
|
|
4797
4932
|
function structureKey(routes) {
|
|
4798
4933
|
const parts = routes.map(({ alias, route }) => {
|
|
@@ -4808,18 +4943,11 @@ function structureKey(routes) {
|
|
|
4808
4943
|
});
|
|
4809
4944
|
return parts.join("||");
|
|
4810
4945
|
}
|
|
4811
|
-
var MODEL_IDENTITY_IDS = /* @__PURE__ */ new WeakMap();
|
|
4812
|
-
var nextModelIdentityId = 1;
|
|
4813
4946
|
function modelIdentity(ref, alias) {
|
|
4814
4947
|
try {
|
|
4815
4948
|
const model = resolveModelStatic(ref, alias);
|
|
4816
4949
|
const cls = resolveModelClass(model);
|
|
4817
|
-
|
|
4818
|
-
if (id === void 0) {
|
|
4819
|
-
id = nextModelIdentityId++;
|
|
4820
|
-
MODEL_IDENTITY_IDS.set(cls, id);
|
|
4821
|
-
}
|
|
4822
|
-
return `model#${id}`;
|
|
4950
|
+
return modelClassIdentity(cls);
|
|
4823
4951
|
} catch {
|
|
4824
4952
|
return "unresolved";
|
|
4825
4953
|
}
|
|
@@ -5119,10 +5247,10 @@ var DDBModel = class {
|
|
|
5119
5247
|
// method type — the public overloads (the only caller-visible surface)
|
|
5120
5248
|
// are untouched.
|
|
5121
5249
|
query: ((key, select, options) => {
|
|
5122
|
-
return
|
|
5250
|
+
return executeAdHocQuery(modelClass, key, select, options);
|
|
5123
5251
|
}),
|
|
5124
5252
|
list: ((key, select, options) => {
|
|
5125
|
-
return
|
|
5253
|
+
return executeAdHocList(modelClass, key, select, options);
|
|
5126
5254
|
}),
|
|
5127
5255
|
explain(key, options) {
|
|
5128
5256
|
return executeExplain(
|
|
@@ -5946,618 +6074,6 @@ function writeDescriptorToPlan(name, d) {
|
|
|
5946
6074
|
return { plan: plan2, select, condition, mode: d.mode ?? "transaction", description: d.description };
|
|
5947
6075
|
}
|
|
5948
6076
|
|
|
5949
|
-
// src/define/transaction.ts
|
|
5950
|
-
var TX_REF_BRAND = /* @__PURE__ */ Symbol("graphddb:txref");
|
|
5951
|
-
function isTransactionRef(value) {
|
|
5952
|
-
return typeof value === "object" && value !== null && value[TX_REF_BRAND] === true;
|
|
5953
|
-
}
|
|
5954
|
-
var MARKER_TAGS = [
|
|
5955
|
-
// pass 0: short, begins with 'A'.
|
|
5956
|
-
"Axqv",
|
|
5957
|
-
// pass 1: long, begins with 'Z'. The two tags share NO common prefix and NO
|
|
5958
|
-
// common substring of length >= 2 (their alphabets are disjoint), and differ
|
|
5959
|
-
// in length, so any fragment-extracting / length-dependent transform
|
|
5960
|
-
// (`slice(0,n)`, `[i]`, `charAt`, `padStart`, `padEnd`) yields *different*
|
|
5961
|
-
// fragments across the two passes -- the differential check then rejects it.
|
|
5962
|
-
// (Convergence-to-constant escapes that even disjoint markers cannot separate
|
|
5963
|
-
// -- `slice(0,0)` -> '' in both passes, `includes('x')` -> a constant boolean
|
|
5964
|
-
// -- are caught instead by the per-access coercion ledger; see
|
|
5965
|
-
// {@link makeFieldRef} and {@link defineTransaction}.)
|
|
5966
|
-
"Zmnoprstuwy0123456789WIDEMARKERBODYFILLERZ"
|
|
5967
|
-
];
|
|
5968
|
-
var MARKER_PASS_COUNT = MARKER_TAGS.length;
|
|
5969
|
-
function markerValue(pass, field) {
|
|
5970
|
-
const tag = MARKER_TAGS[pass];
|
|
5971
|
-
return `${tag}::${field}::${tag}`;
|
|
5972
|
-
}
|
|
5973
|
-
function makeValueSentinel(fields, tokenFor, originFor, markerFor, containerOrigin, onAccess, onCoerce) {
|
|
5974
|
-
const cache = /* @__PURE__ */ new Map();
|
|
5975
|
-
return new Proxy(/* @__PURE__ */ Object.create(null), {
|
|
5976
|
-
get(_t, key) {
|
|
5977
|
-
if (typeof key === "symbol") {
|
|
5978
|
-
if (key === Symbol.iterator || key === Symbol.asyncIterator || key === Symbol.toStringTag || typeof Symbol.for === "function" && (key === /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom") || key.description === "nodejs.util.inspect.custom")) {
|
|
5979
|
-
return void 0;
|
|
5980
|
-
}
|
|
5981
|
-
throw new Error(
|
|
5982
|
-
`defineTransaction: unsupported symbol access on ${containerOrigin}. Only declarative field references are allowed; any JS transform / branching / coercion on a parameter is not representable as a declarative transaction template.`
|
|
5983
|
-
);
|
|
5984
|
-
}
|
|
5985
|
-
if (!fields.has(key)) {
|
|
5986
|
-
throw new Error(
|
|
5987
|
-
`defineTransaction: ${containerOrigin} has no field '${key}'. Reference only declared fields; arbitrary property access (or any JS transform / branching on a parameter) is not representable as a declarative transaction template.`
|
|
5988
|
-
);
|
|
5989
|
-
}
|
|
5990
|
-
onAccess(key);
|
|
5991
|
-
let ref = cache.get(key);
|
|
5992
|
-
if (!ref) {
|
|
5993
|
-
ref = makeFieldRef(
|
|
5994
|
-
tokenFor(key),
|
|
5995
|
-
originFor(key),
|
|
5996
|
-
markerFor(key),
|
|
5997
|
-
() => onCoerce(key)
|
|
5998
|
-
);
|
|
5999
|
-
cache.set(key, ref);
|
|
6000
|
-
}
|
|
6001
|
-
return ref;
|
|
6002
|
-
},
|
|
6003
|
-
set() {
|
|
6004
|
-
throw new Error(
|
|
6005
|
-
`defineTransaction: cannot assign to a field of ${containerOrigin}.`
|
|
6006
|
-
);
|
|
6007
|
-
},
|
|
6008
|
-
defineProperty() {
|
|
6009
|
-
throw new Error(
|
|
6010
|
-
`defineTransaction: cannot define a property on ${containerOrigin}.`
|
|
6011
|
-
);
|
|
6012
|
-
},
|
|
6013
|
-
deleteProperty() {
|
|
6014
|
-
throw new Error(
|
|
6015
|
-
`defineTransaction: cannot delete a field of ${containerOrigin}.`
|
|
6016
|
-
);
|
|
6017
|
-
}
|
|
6018
|
-
});
|
|
6019
|
-
}
|
|
6020
|
-
function makeFieldRef(token, origin, marker, onCoerce) {
|
|
6021
|
-
const target = /* @__PURE__ */ Object.create(null);
|
|
6022
|
-
const proxy = new Proxy(target, {
|
|
6023
|
-
get(_t, key) {
|
|
6024
|
-
if (key === TX_REF_BRAND) return true;
|
|
6025
|
-
if (key === "token") return token;
|
|
6026
|
-
if (key === "origin") return origin;
|
|
6027
|
-
if (key === Symbol.toPrimitive) {
|
|
6028
|
-
return (hint) => {
|
|
6029
|
-
onCoerce();
|
|
6030
|
-
return hint === "number" ? NaN : marker;
|
|
6031
|
-
};
|
|
6032
|
-
}
|
|
6033
|
-
if (key === "toString" || key === Symbol.toStringTag) {
|
|
6034
|
-
return () => {
|
|
6035
|
-
onCoerce();
|
|
6036
|
-
return marker;
|
|
6037
|
-
};
|
|
6038
|
-
}
|
|
6039
|
-
if (key === "valueOf") {
|
|
6040
|
-
return () => {
|
|
6041
|
-
onCoerce();
|
|
6042
|
-
return NaN;
|
|
6043
|
-
};
|
|
6044
|
-
}
|
|
6045
|
-
if (key === Symbol.iterator || key === Symbol.asyncIterator || key === "then" || key === "constructor" || key === "prototype" || typeof key === "symbol" && typeof Symbol.for === "function" && (key === /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom") || key.description === "nodejs.util.inspect.custom")) {
|
|
6046
|
-
return void 0;
|
|
6047
|
-
}
|
|
6048
|
-
const name = typeof key === "symbol" ? key.toString() : String(key);
|
|
6049
|
-
throw new Error(
|
|
6050
|
-
`defineTransaction: unsupported operation '${name}' on ${origin}. The static planner (Python bridge) only supports direct field references (\`p.field\` / \`el.field\`) or concrete literals at value positions; any string transform, property access (e.g. \`.length\`, \`[i]\`, \`.toUpperCase()\`), arithmetic, or value branching on a parameter is not representable as a declarative transaction template.`
|
|
6051
|
-
);
|
|
6052
|
-
},
|
|
6053
|
-
set() {
|
|
6054
|
-
throw new Error(`defineTransaction: cannot assign on ${origin}.`);
|
|
6055
|
-
},
|
|
6056
|
-
defineProperty() {
|
|
6057
|
-
throw new Error(`defineTransaction: cannot define a property on ${origin}.`);
|
|
6058
|
-
},
|
|
6059
|
-
deleteProperty() {
|
|
6060
|
-
throw new Error(`defineTransaction: cannot delete on ${origin}.`);
|
|
6061
|
-
}
|
|
6062
|
-
});
|
|
6063
|
-
return proxy;
|
|
6064
|
-
}
|
|
6065
|
-
var when = {
|
|
6066
|
-
eq(left, right) {
|
|
6067
|
-
assertRef(left, "when.eq");
|
|
6068
|
-
return { op: "eq", left, right };
|
|
6069
|
-
},
|
|
6070
|
-
ne(left, right) {
|
|
6071
|
-
assertRef(left, "when.ne");
|
|
6072
|
-
return { op: "ne", left, right };
|
|
6073
|
-
}
|
|
6074
|
-
};
|
|
6075
|
-
function assertRef(value, context) {
|
|
6076
|
-
if (!isTransactionRef(value)) {
|
|
6077
|
-
throw new Error(
|
|
6078
|
-
`defineTransaction: ${context} expects a field reference (e.g. \`p.status\` or an element field) on its left-hand side.`
|
|
6079
|
-
);
|
|
6080
|
-
}
|
|
6081
|
-
}
|
|
6082
|
-
function entityRef2(model) {
|
|
6083
|
-
const modelClass = resolveModelClass(model);
|
|
6084
|
-
return { name: modelClass.name, modelClass };
|
|
6085
|
-
}
|
|
6086
|
-
function descriptorOf(p) {
|
|
6087
|
-
if (p.kind === "array") {
|
|
6088
|
-
const element = {};
|
|
6089
|
-
for (const [field, fieldParam] of Object.entries(p.element ?? {})) {
|
|
6090
|
-
element[field] = descriptorOf(fieldParam);
|
|
6091
|
-
}
|
|
6092
|
-
return { kind: "array", required: true, element };
|
|
6093
|
-
}
|
|
6094
|
-
return p.literals === void 0 ? { kind: p.kind, required: true } : { kind: p.kind, literals: p.literals, required: true };
|
|
6095
|
-
}
|
|
6096
|
-
function runBuildPass(params, build, scalarFields, arrayParams, pass, accessed, coerced) {
|
|
6097
|
-
const noteAccess = (token, origin) => {
|
|
6098
|
-
if (!accessed.has(token)) accessed.set(token, { token, origin });
|
|
6099
|
-
};
|
|
6100
|
-
const noteCoerce = (token, origin) => {
|
|
6101
|
-
if (!coerced.has(token)) coerced.set(token, { token, origin });
|
|
6102
|
-
};
|
|
6103
|
-
const scalarSentinel = makeValueSentinel(
|
|
6104
|
-
scalarFields,
|
|
6105
|
-
(f) => `{${f}}`,
|
|
6106
|
-
(f) => `param '${f}'`,
|
|
6107
|
-
(f) => markerValue(pass, f),
|
|
6108
|
-
"params",
|
|
6109
|
-
(f) => noteAccess(`{${f}}`, `param '${f}'`),
|
|
6110
|
-
(f) => noteCoerce(`{${f}}`, `param '${f}'`)
|
|
6111
|
-
);
|
|
6112
|
-
const pProxy = new Proxy(/* @__PURE__ */ Object.create(null), {
|
|
6113
|
-
get(_t, key) {
|
|
6114
|
-
if (typeof key === "symbol") {
|
|
6115
|
-
if (key === Symbol.iterator || key === Symbol.asyncIterator || key === Symbol.toStringTag || typeof Symbol.for === "function" && (key === /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom") || key.description === "nodejs.util.inspect.custom")) {
|
|
6116
|
-
return void 0;
|
|
6117
|
-
}
|
|
6118
|
-
throw new Error("defineTransaction: unsupported symbol access on params.");
|
|
6119
|
-
}
|
|
6120
|
-
if (arrayParams.has(key)) return params[key];
|
|
6121
|
-
if (scalarFields.has(key)) return scalarSentinel[key];
|
|
6122
|
-
throw new Error(
|
|
6123
|
-
`defineTransaction: unknown parameter '${key}'. Declare it in the params map passed to defineTransaction.`
|
|
6124
|
-
);
|
|
6125
|
-
}
|
|
6126
|
-
});
|
|
6127
|
-
const instructions = [];
|
|
6128
|
-
let currentBody = instructions;
|
|
6129
|
-
let insideForEach = false;
|
|
6130
|
-
const recordWrite = (instr) => {
|
|
6131
|
-
currentBody.push(instr);
|
|
6132
|
-
};
|
|
6133
|
-
const recorder2 = {
|
|
6134
|
-
put(model, item, options) {
|
|
6135
|
-
recordWrite({
|
|
6136
|
-
kind: "write",
|
|
6137
|
-
operation: "put",
|
|
6138
|
-
entity: entityRef2(model),
|
|
6139
|
-
item,
|
|
6140
|
-
...options?.condition !== void 0 ? { condition: options.condition } : {},
|
|
6141
|
-
...options?.when !== void 0 ? { when: options.when } : {}
|
|
6142
|
-
});
|
|
6143
|
-
},
|
|
6144
|
-
update(model, key, changes, options) {
|
|
6145
|
-
recordWrite({
|
|
6146
|
-
kind: "write",
|
|
6147
|
-
operation: "update",
|
|
6148
|
-
entity: entityRef2(model),
|
|
6149
|
-
key,
|
|
6150
|
-
changes,
|
|
6151
|
-
...options?.condition !== void 0 ? { condition: options.condition } : {},
|
|
6152
|
-
...options?.when !== void 0 ? { when: options.when } : {}
|
|
6153
|
-
});
|
|
6154
|
-
},
|
|
6155
|
-
delete(model, key, options) {
|
|
6156
|
-
recordWrite({
|
|
6157
|
-
kind: "write",
|
|
6158
|
-
operation: "delete",
|
|
6159
|
-
entity: entityRef2(model),
|
|
6160
|
-
key,
|
|
6161
|
-
...options?.condition !== void 0 ? { condition: options.condition } : {},
|
|
6162
|
-
...options?.when !== void 0 ? { when: options.when } : {}
|
|
6163
|
-
});
|
|
6164
|
-
},
|
|
6165
|
-
conditionCheck(model, key, options) {
|
|
6166
|
-
if (options?.condition === void 0 || options.condition === null) {
|
|
6167
|
-
throw new Error(
|
|
6168
|
-
"defineTransaction: tx.conditionCheck requires a `condition` (the read-only assertion it makes); e.g. `{ condition: { attributeExists: 'PK' } }`."
|
|
6169
|
-
);
|
|
6170
|
-
}
|
|
6171
|
-
recordWrite({
|
|
6172
|
-
kind: "write",
|
|
6173
|
-
operation: "conditionCheck",
|
|
6174
|
-
entity: entityRef2(model),
|
|
6175
|
-
key,
|
|
6176
|
-
condition: options.condition,
|
|
6177
|
-
...options.when !== void 0 ? { when: options.when } : {}
|
|
6178
|
-
});
|
|
6179
|
-
},
|
|
6180
|
-
forEach(source, body, options) {
|
|
6181
|
-
if (insideForEach) {
|
|
6182
|
-
throw new Error(
|
|
6183
|
-
"defineTransaction: nested forEach is not supported; flatten the loop."
|
|
6184
|
-
);
|
|
6185
|
-
}
|
|
6186
|
-
if (!isParam(source) || source.kind !== "array") {
|
|
6187
|
-
throw new Error(
|
|
6188
|
-
"defineTransaction: forEach source must be a `param.array(...)` parameter accessed via `p.<name>`."
|
|
6189
|
-
);
|
|
6190
|
-
}
|
|
6191
|
-
const arrayParam = source;
|
|
6192
|
-
const sourceName = arrayParams.size ? Object.keys(params).find((k) => params[k] === arrayParam) : void 0;
|
|
6193
|
-
if (sourceName === void 0) {
|
|
6194
|
-
throw new Error(
|
|
6195
|
-
"defineTransaction: forEach source is not a declared array param."
|
|
6196
|
-
);
|
|
6197
|
-
}
|
|
6198
|
-
const elementFields = new Set(Object.keys(arrayParam.element ?? {}));
|
|
6199
|
-
const elementProxy = makeValueSentinel(
|
|
6200
|
-
elementFields,
|
|
6201
|
-
(f) => `{item.${f}}`,
|
|
6202
|
-
(f) => `element field '${f}' of '${sourceName}'`,
|
|
6203
|
-
(f) => markerValue(pass, `item.${f}`),
|
|
6204
|
-
`element of '${sourceName}'`,
|
|
6205
|
-
(f) => noteAccess(`{item.${f}}`, `element field '${f}' of '${sourceName}'`),
|
|
6206
|
-
(f) => noteCoerce(`{item.${f}}`, `element field '${f}' of '${sourceName}'`)
|
|
6207
|
-
);
|
|
6208
|
-
const block = {
|
|
6209
|
-
kind: "forEach",
|
|
6210
|
-
source: sourceName,
|
|
6211
|
-
...options?.when !== void 0 ? { when: options.when } : {},
|
|
6212
|
-
body: []
|
|
6213
|
-
};
|
|
6214
|
-
const prevBody = currentBody;
|
|
6215
|
-
currentBody = block.body;
|
|
6216
|
-
insideForEach = true;
|
|
6217
|
-
try {
|
|
6218
|
-
body(elementProxy);
|
|
6219
|
-
} finally {
|
|
6220
|
-
insideForEach = false;
|
|
6221
|
-
currentBody = prevBody;
|
|
6222
|
-
}
|
|
6223
|
-
currentBody.push(block);
|
|
6224
|
-
}
|
|
6225
|
-
};
|
|
6226
|
-
build(recorder2, pProxy);
|
|
6227
|
-
return instructions;
|
|
6228
|
-
}
|
|
6229
|
-
function defineTransaction(params, build) {
|
|
6230
|
-
const descriptors = {};
|
|
6231
|
-
for (const [name, value] of Object.entries(params)) {
|
|
6232
|
-
if (!isParam(value)) {
|
|
6233
|
-
throw new Error(
|
|
6234
|
-
`defineTransaction: param '${name}' is not a param.* placeholder.`
|
|
6235
|
-
);
|
|
6236
|
-
}
|
|
6237
|
-
descriptors[name] = descriptorOf(value);
|
|
6238
|
-
}
|
|
6239
|
-
const scalarFields = new Set(
|
|
6240
|
-
Object.keys(params).filter((k) => params[k].kind !== "array")
|
|
6241
|
-
);
|
|
6242
|
-
const arrayParams = new Set(
|
|
6243
|
-
Object.keys(params).filter((k) => params[k].kind === "array")
|
|
6244
|
-
);
|
|
6245
|
-
const accessed = /* @__PURE__ */ new Map();
|
|
6246
|
-
const coerced = /* @__PURE__ */ new Map();
|
|
6247
|
-
const passes = [];
|
|
6248
|
-
for (let pass = 0; pass < MARKER_PASS_COUNT; pass++) {
|
|
6249
|
-
passes.push(
|
|
6250
|
-
runBuildPass(
|
|
6251
|
-
params,
|
|
6252
|
-
build,
|
|
6253
|
-
scalarFields,
|
|
6254
|
-
arrayParams,
|
|
6255
|
-
pass,
|
|
6256
|
-
accessed,
|
|
6257
|
-
coerced
|
|
6258
|
-
)
|
|
6259
|
-
);
|
|
6260
|
-
}
|
|
6261
|
-
if (coerced.size > 0) {
|
|
6262
|
-
const info = [...coerced.values()][0];
|
|
6263
|
-
throw new Error(
|
|
6264
|
-
`defineTransaction: ${info.origin} is coerced to a primitive (e.g. via \`String(${info.origin.includes("element") ? "el" : "p"}.x)\`, a template literal \`\${\u2026}\`, string concatenation, or a comparison) and then consumed by a transform or branch \u2014 for example \`String(p.x).slice(0, n)\`, \`String(p.x)[0]\`, \`String(p.x).includes('\u2026')\`, or \`\${p.x}-suffix\`. At a value position the static planner (Python bridge) only supports a *direct* field reference (stored without coercion) or a concrete literal; a coerced / transformed parameter is not representable as a declarative transaction template, and (because the transform may converge to a constant or a shared marker fragment) could otherwise be silently emitted as a wrong spec. Reference the field directly (\`p.x\` / \`el.x\`) or use a literal.`
|
|
6265
|
-
);
|
|
6266
|
-
}
|
|
6267
|
-
const surfaced = /* @__PURE__ */ new Set();
|
|
6268
|
-
verifyInstructions(passes, surfaced);
|
|
6269
|
-
for (const [token, info] of accessed) {
|
|
6270
|
-
if (!surfaced.has(token)) {
|
|
6271
|
-
throw new Error(
|
|
6272
|
-
`defineTransaction: ${info.origin} is accessed but never appears as a field reference in the recorded transaction. This happens when a parameter is consumed by a value branch (e.g. \`p.role === 'admin' ? 'A' : 'B'\`) or a string transform (e.g. \`String(p.role).toUpperCase()\`) instead of being referenced directly. The static planner (Python bridge) only supports direct field references or concrete literals at value positions; branching or transforming a parameter is not representable as a declarative transaction template.`
|
|
6273
|
-
);
|
|
6274
|
-
}
|
|
6275
|
-
}
|
|
6276
|
-
return {
|
|
6277
|
-
__isTransactionDefinition: true,
|
|
6278
|
-
params: descriptors,
|
|
6279
|
-
instructions: passes[0]
|
|
6280
|
-
};
|
|
6281
|
-
}
|
|
6282
|
-
function verifyInstructions(passes, surfaced) {
|
|
6283
|
-
const first = passes[0];
|
|
6284
|
-
for (let i = 0; i < first.length; i++) {
|
|
6285
|
-
const instrs = passes.map((p) => p[i]);
|
|
6286
|
-
const kind = first[i].kind;
|
|
6287
|
-
if (instrs.some((x) => x.kind !== kind)) {
|
|
6288
|
-
throw new Error(
|
|
6289
|
-
"defineTransaction: build is not deterministic across evaluation (instruction shape diverged between passes). The callback must be a pure, declarative description of the writes."
|
|
6290
|
-
);
|
|
6291
|
-
}
|
|
6292
|
-
if (kind === "write") {
|
|
6293
|
-
verifyWrite(instrs, surfaced);
|
|
6294
|
-
} else {
|
|
6295
|
-
const blocks = instrs;
|
|
6296
|
-
verifyWhen(
|
|
6297
|
-
blocks.map((b) => b.when),
|
|
6298
|
-
surfaced,
|
|
6299
|
-
`forEach '${blocks[0].source}' when`
|
|
6300
|
-
);
|
|
6301
|
-
verifyInstructions(
|
|
6302
|
-
blocks.map((b) => b.body),
|
|
6303
|
-
surfaced
|
|
6304
|
-
);
|
|
6305
|
-
}
|
|
6306
|
-
}
|
|
6307
|
-
}
|
|
6308
|
-
function verifyWrite(instrs, surfaced) {
|
|
6309
|
-
const op = instrs[0].operation;
|
|
6310
|
-
if (instrs.some((x) => x.operation !== op)) {
|
|
6311
|
-
throw new Error(
|
|
6312
|
-
"defineTransaction: write operation diverged between evaluation passes; the callback must be a pure, declarative description of the writes."
|
|
6313
|
-
);
|
|
6314
|
-
}
|
|
6315
|
-
verifyRecord(instrs.map((x) => x.item), surfaced, `${op} item`);
|
|
6316
|
-
verifyRecord(instrs.map((x) => x.key), surfaced, `${op} key`);
|
|
6317
|
-
verifyRecord(instrs.map((x) => x.changes), surfaced, `${op} changes`);
|
|
6318
|
-
verifyCondition(
|
|
6319
|
-
instrs.map((x) => x.condition),
|
|
6320
|
-
surfaced,
|
|
6321
|
-
`${op} condition`
|
|
6322
|
-
);
|
|
6323
|
-
verifyWhen(instrs.map((x) => x.when), surfaced, `${op} when`);
|
|
6324
|
-
}
|
|
6325
|
-
function verifyRecord(records, surfaced, context) {
|
|
6326
|
-
const present = records.filter((r) => r !== void 0);
|
|
6327
|
-
if (present.length === 0) return;
|
|
6328
|
-
if (present.length !== records.length) {
|
|
6329
|
-
throw new Error(
|
|
6330
|
-
`defineTransaction: ${context} present in some evaluation passes but not others; the callback must be a pure, declarative description.`
|
|
6331
|
-
);
|
|
6332
|
-
}
|
|
6333
|
-
const keys = Object.keys(present[0]).sort();
|
|
6334
|
-
for (const r of present) {
|
|
6335
|
-
const k = Object.keys(r).sort();
|
|
6336
|
-
if (k.length !== keys.length || k.some((x, i) => x !== keys[i])) {
|
|
6337
|
-
throw new Error(
|
|
6338
|
-
`defineTransaction: ${context} field set diverged between evaluation passes; the callback must be a pure, declarative description.`
|
|
6339
|
-
);
|
|
6340
|
-
}
|
|
6341
|
-
}
|
|
6342
|
-
for (const field of keys) {
|
|
6343
|
-
verifyLeaf(
|
|
6344
|
-
present.map((r) => r[field]),
|
|
6345
|
-
surfaced,
|
|
6346
|
-
`${context} field '${field}'`
|
|
6347
|
-
);
|
|
6348
|
-
}
|
|
6349
|
-
}
|
|
6350
|
-
function isConditionOperatorObject5(value) {
|
|
6351
|
-
if (typeof value !== "object" || value === null || Array.isArray(value) || value instanceof Date || isTransactionRef(value)) {
|
|
6352
|
-
return false;
|
|
6353
|
-
}
|
|
6354
|
-
const keys = Object.keys(value);
|
|
6355
|
-
if (keys.length === 0) return false;
|
|
6356
|
-
return keys.every((k) => CONDITION_OPERATOR_KEYS.has(k));
|
|
6357
|
-
}
|
|
6358
|
-
function verifyCondition(conditions, surfaced, context) {
|
|
6359
|
-
const present = conditions.filter(
|
|
6360
|
-
(c) => c !== void 0 && c !== null
|
|
6361
|
-
);
|
|
6362
|
-
if (present.length === 0) return;
|
|
6363
|
-
if (present.length !== conditions.length) {
|
|
6364
|
-
throw new Error(
|
|
6365
|
-
`defineTransaction: ${context} present in some evaluation passes but not others; the callback must be a pure, declarative description.`
|
|
6366
|
-
);
|
|
6367
|
-
}
|
|
6368
|
-
if (present.some((c) => isRawCondition(c))) return;
|
|
6369
|
-
if (present.some((c) => typeof c !== "object" || Array.isArray(c))) {
|
|
6370
|
-
throw new Error(
|
|
6371
|
-
`defineTransaction: ${context} must be a declarative condition object (field clause / operator object / \`and\` / \`or\` / \`not\` group).`
|
|
6372
|
-
);
|
|
6373
|
-
}
|
|
6374
|
-
verifyConditionTree(
|
|
6375
|
-
present.map((c) => c),
|
|
6376
|
-
surfaced,
|
|
6377
|
-
context
|
|
6378
|
-
);
|
|
6379
|
-
}
|
|
6380
|
-
function verifyConditionTree(nodes, surfaced, context) {
|
|
6381
|
-
const keys = Object.keys(nodes[0]).sort();
|
|
6382
|
-
for (const n of nodes) {
|
|
6383
|
-
const k = Object.keys(n).sort();
|
|
6384
|
-
if (k.length !== keys.length || k.some((x, i) => x !== keys[i])) {
|
|
6385
|
-
throw new Error(
|
|
6386
|
-
`defineTransaction: ${context} key set diverged between evaluation passes; the callback must be a pure, declarative description.`
|
|
6387
|
-
);
|
|
6388
|
-
}
|
|
6389
|
-
}
|
|
6390
|
-
for (const key of keys) {
|
|
6391
|
-
const values = nodes.map((n) => n[key]);
|
|
6392
|
-
if (key === "and" || key === "or") {
|
|
6393
|
-
const arrays = values.map((v) => {
|
|
6394
|
-
if (!Array.isArray(v) || v.length === 0) {
|
|
6395
|
-
throw new Error(
|
|
6396
|
-
`defineTransaction: ${context} \`${key}\` must be a non-empty array of sub-conditions.`
|
|
6397
|
-
);
|
|
6398
|
-
}
|
|
6399
|
-
return v;
|
|
6400
|
-
});
|
|
6401
|
-
const len = arrays[0].length;
|
|
6402
|
-
if (arrays.some((a) => a.length !== len)) {
|
|
6403
|
-
throw new Error(
|
|
6404
|
-
`defineTransaction: ${context} \`${key}\` length diverged between evaluation passes; the callback must be declarative.`
|
|
6405
|
-
);
|
|
6406
|
-
}
|
|
6407
|
-
for (let i = 0; i < len; i++) {
|
|
6408
|
-
verifyCondition(
|
|
6409
|
-
arrays.map((a) => a[i]),
|
|
6410
|
-
surfaced,
|
|
6411
|
-
`${context} ${key}[${i}]`
|
|
6412
|
-
);
|
|
6413
|
-
}
|
|
6414
|
-
continue;
|
|
6415
|
-
}
|
|
6416
|
-
if (key === "not") {
|
|
6417
|
-
verifyCondition(
|
|
6418
|
-
values,
|
|
6419
|
-
surfaced,
|
|
6420
|
-
`${context} not`
|
|
6421
|
-
);
|
|
6422
|
-
continue;
|
|
6423
|
-
}
|
|
6424
|
-
if (!values.every((v) => isConditionOperatorObject5(v))) {
|
|
6425
|
-
if (values.some((v) => isConditionOperatorObject5(v))) {
|
|
6426
|
-
throw new Error(
|
|
6427
|
-
`defineTransaction: ${context} field '${key}' is an operator object in some evaluation passes but a bare value in others; the callback must be declarative.`
|
|
6428
|
-
);
|
|
6429
|
-
}
|
|
6430
|
-
verifyLeaf(values, surfaced, `${context} field '${key}'`);
|
|
6431
|
-
continue;
|
|
6432
|
-
}
|
|
6433
|
-
verifyOperatorObject(
|
|
6434
|
-
values.map((v) => v),
|
|
6435
|
-
surfaced,
|
|
6436
|
-
`${context} field '${key}'`
|
|
6437
|
-
);
|
|
6438
|
-
}
|
|
6439
|
-
}
|
|
6440
|
-
function verifyOperatorObject(objs, surfaced, context) {
|
|
6441
|
-
const ops = Object.keys(objs[0]).sort();
|
|
6442
|
-
for (const o of objs) {
|
|
6443
|
-
const k = Object.keys(o).sort();
|
|
6444
|
-
if (k.length !== ops.length || k.some((x, i) => x !== ops[i])) {
|
|
6445
|
-
throw new Error(
|
|
6446
|
-
`defineTransaction: ${context} operator set diverged between evaluation passes; the callback must be a pure, declarative description.`
|
|
6447
|
-
);
|
|
6448
|
-
}
|
|
6449
|
-
}
|
|
6450
|
-
for (const op of ops) {
|
|
6451
|
-
const opVals = objs.map((o) => o[op]);
|
|
6452
|
-
if (op === "between") {
|
|
6453
|
-
const pairs = opVals.map((v) => {
|
|
6454
|
-
if (!Array.isArray(v) || v.length !== 2) {
|
|
6455
|
-
throw new Error(
|
|
6456
|
-
`defineTransaction: ${context} \`between\` takes a \`[lo, hi]\` pair.`
|
|
6457
|
-
);
|
|
6458
|
-
}
|
|
6459
|
-
return v;
|
|
6460
|
-
});
|
|
6461
|
-
verifyLeaf(pairs.map((p) => p[0]), surfaced, `${context} between[0]`);
|
|
6462
|
-
verifyLeaf(pairs.map((p) => p[1]), surfaced, `${context} between[1]`);
|
|
6463
|
-
} else if (op === "in") {
|
|
6464
|
-
const arrays = opVals.map((v) => {
|
|
6465
|
-
if (!Array.isArray(v) || v.length === 0) {
|
|
6466
|
-
throw new Error(
|
|
6467
|
-
`defineTransaction: ${context} \`in\` takes a non-empty array of operands.`
|
|
6468
|
-
);
|
|
6469
|
-
}
|
|
6470
|
-
return v;
|
|
6471
|
-
});
|
|
6472
|
-
const len = arrays[0].length;
|
|
6473
|
-
if (arrays.some((a) => a.length !== len)) {
|
|
6474
|
-
throw new Error(
|
|
6475
|
-
`defineTransaction: ${context} \`in\` length diverged between evaluation passes; the callback must be declarative.`
|
|
6476
|
-
);
|
|
6477
|
-
}
|
|
6478
|
-
for (let i = 0; i < len; i++) {
|
|
6479
|
-
verifyLeaf(arrays.map((a) => a[i]), surfaced, `${context} in[${i}]`);
|
|
6480
|
-
}
|
|
6481
|
-
} else if (op === "attributeExists" || op === "attributeType") {
|
|
6482
|
-
if (opVals.some((v) => isTransactionRef(v))) {
|
|
6483
|
-
throw new Error(
|
|
6484
|
-
`defineTransaction: ${context} \`${op}\` was given a field reference. \`${op}\` takes a ${op === "attributeExists" ? "concrete boolean" : "concrete DynamoDB type-code string"} (a structural operand, not a value-bound param); use a literal.`
|
|
6485
|
-
);
|
|
6486
|
-
}
|
|
6487
|
-
} else {
|
|
6488
|
-
verifyLeaf(opVals, surfaced, `${context} ${op}`);
|
|
6489
|
-
}
|
|
6490
|
-
}
|
|
6491
|
-
}
|
|
6492
|
-
function verifyWhen(whens, surfaced, context) {
|
|
6493
|
-
const present = whens.filter((w) => w !== void 0);
|
|
6494
|
-
if (present.length === 0) return;
|
|
6495
|
-
if (present.length !== whens.length) {
|
|
6496
|
-
throw new Error(
|
|
6497
|
-
`defineTransaction: ${context} present in some evaluation passes but not others; the callback must be a pure, declarative description.`
|
|
6498
|
-
);
|
|
6499
|
-
}
|
|
6500
|
-
for (const w of present) {
|
|
6501
|
-
if (isTransactionRef(w.left)) surfaced.add(w.left.token);
|
|
6502
|
-
}
|
|
6503
|
-
verifyLeaf(present.map((w) => w.right), surfaced, `${context} right-hand value`);
|
|
6504
|
-
}
|
|
6505
|
-
function verifyLeaf(values, surfaced, context) {
|
|
6506
|
-
const refTokens = values.map((v) => isTransactionRef(v) ? v.token : void 0);
|
|
6507
|
-
const anyRef = refTokens.some((t) => t !== void 0);
|
|
6508
|
-
if (anyRef) {
|
|
6509
|
-
if (refTokens.some((t) => t === void 0)) {
|
|
6510
|
-
throw new Error(
|
|
6511
|
-
`defineTransaction: ${context} is a field reference in some evaluation passes but a transformed value in others \u2014 a coercion/transform escape (e.g. \`String(p.x).toUpperCase()\`) was applied. Use a direct field reference or a concrete literal.`
|
|
6512
|
-
);
|
|
6513
|
-
}
|
|
6514
|
-
const token = refTokens[0];
|
|
6515
|
-
if (refTokens.some((t) => t !== token)) {
|
|
6516
|
-
throw new Error(
|
|
6517
|
-
`defineTransaction: ${context} resolves to different field references across evaluation passes \u2014 the value is not a stable, declarative reference.`
|
|
6518
|
-
);
|
|
6519
|
-
}
|
|
6520
|
-
surfaced.add(token);
|
|
6521
|
-
return;
|
|
6522
|
-
}
|
|
6523
|
-
const norm = values.map(normalizeLiteral);
|
|
6524
|
-
for (let i = 1; i < norm.length; i++) {
|
|
6525
|
-
if (norm[i] !== norm[0]) {
|
|
6526
|
-
throw new Error(
|
|
6527
|
-
`defineTransaction: ${context} is not a stable concrete literal \u2014 evaluating the callback twice produced different values ('${norm[0]}' vs '${norm[i]}'). This means a parameter was coerced or transformed into the value (e.g. \`String(p.x).toUpperCase()\`, \`\${p.x}-suffix\`, or arithmetic). The static planner (Python bridge) only supports a direct field reference or a concrete literal at a value position.`
|
|
6528
|
-
);
|
|
6529
|
-
}
|
|
6530
|
-
}
|
|
6531
|
-
}
|
|
6532
|
-
function normalizeLiteral(value) {
|
|
6533
|
-
if (value === null) return "t:null";
|
|
6534
|
-
if (value instanceof Date) return `t:date:${value.toISOString()}`;
|
|
6535
|
-
const t = typeof value;
|
|
6536
|
-
if (t === "string") return `t:s:${value}`;
|
|
6537
|
-
if (t === "boolean") return `t:b:${String(value)}`;
|
|
6538
|
-
if (t === "number") {
|
|
6539
|
-
if (Number.isNaN(value)) {
|
|
6540
|
-
throw new Error(
|
|
6541
|
-
"defineTransaction: a value leaf coerced to NaN, which means arithmetic was performed on a parameter. Only direct field references or concrete literals are allowed at value positions."
|
|
6542
|
-
);
|
|
6543
|
-
}
|
|
6544
|
-
return `t:n:${String(value)}`;
|
|
6545
|
-
}
|
|
6546
|
-
throw new Error(
|
|
6547
|
-
`defineTransaction: a value leaf has unsupported type '${t}'. Only a direct field reference (\`p.field\` / \`el.field\`) or a concrete literal (string / number / boolean / Date) is allowed at a value position.`
|
|
6548
|
-
);
|
|
6549
|
-
}
|
|
6550
|
-
function defineTransactions(definitions) {
|
|
6551
|
-
for (const [name, def] of Object.entries(definitions)) {
|
|
6552
|
-
if (def === null || typeof def !== "object" || def.__isTransactionDefinition !== true) {
|
|
6553
|
-
throw new Error(
|
|
6554
|
-
`defineTransactions: '${name}' is not a transaction definition. Use defineTransaction(...) to build entries.`
|
|
6555
|
-
);
|
|
6556
|
-
}
|
|
6557
|
-
}
|
|
6558
|
-
return definitions;
|
|
6559
|
-
}
|
|
6560
|
-
|
|
6561
6077
|
// src/spec/transaction.ts
|
|
6562
6078
|
function paramSpec(d) {
|
|
6563
6079
|
if (d.kind === "array") {
|
|
@@ -6644,10 +6160,66 @@ function keyConditionTemplate2(metadata, keyStructure, context) {
|
|
|
6644
6160
|
if (sk !== void 0) out.SK = sk;
|
|
6645
6161
|
return out;
|
|
6646
6162
|
}
|
|
6647
|
-
function
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6163
|
+
function walkExpressionRefs(node, visit) {
|
|
6164
|
+
if (node === null || typeof node !== "object") return;
|
|
6165
|
+
if (Array.isArray(node)) {
|
|
6166
|
+
for (const el of node) walkExpressionRefs(el, visit);
|
|
6167
|
+
return;
|
|
6168
|
+
}
|
|
6169
|
+
const [key] = Object.keys(node);
|
|
6170
|
+
const arg = node[key];
|
|
6171
|
+
if (key === "ref" || key === "refOpt") {
|
|
6172
|
+
visit(arg);
|
|
6173
|
+
return;
|
|
6174
|
+
}
|
|
6175
|
+
if (key === "obj") {
|
|
6176
|
+
for (const v of Object.values(arg)) {
|
|
6177
|
+
walkExpressionRefs(v, visit);
|
|
6178
|
+
}
|
|
6179
|
+
return;
|
|
6180
|
+
}
|
|
6181
|
+
if (key === "int" || key === "float") return;
|
|
6182
|
+
walkExpressionRefs(arg, visit);
|
|
6183
|
+
}
|
|
6184
|
+
function assertGuardRefsBound(guard, params, forEachSource, context) {
|
|
6185
|
+
walkExpressionRefs(guard.expr, (path) => {
|
|
6186
|
+
const [scope, field] = path;
|
|
6187
|
+
const rendered = JSON.stringify(path);
|
|
6188
|
+
if (scope !== "input" && scope !== "item") {
|
|
6189
|
+
throw new Error(
|
|
6190
|
+
`${context}: guard reference ${rendered} uses unknown scope '${scope}' \u2014 expression references use the FIXED scope names 'input' (declared params) and 'item' (the forEach element), mirroring the {param} / {item.<field>} template scopes (issue #264).`
|
|
6191
|
+
);
|
|
6192
|
+
}
|
|
6193
|
+
if (field === void 0) {
|
|
6194
|
+
throw new Error(
|
|
6195
|
+
`${context}: guard reference ${rendered} names no field \u2014 a reference path is [scope, field, \u2026] (issue #264).`
|
|
6196
|
+
);
|
|
6197
|
+
}
|
|
6198
|
+
if (scope === "input") {
|
|
6199
|
+
if (params[field] === void 0) {
|
|
6200
|
+
throw new Error(
|
|
6201
|
+
`${context}: guard reference ${rendered} names undeclared input '${field}' \u2014 declared params: ${Object.keys(params).sort().map((p) => `'${p}'`).join(", ") || "(none)"}. Expression input refs and the ParamSpec names are one namespace (issue #264); an unbound reference is a build error, never a runtime leak (#243).`
|
|
6202
|
+
);
|
|
6203
|
+
}
|
|
6204
|
+
return;
|
|
6205
|
+
}
|
|
6206
|
+
if (forEachSource === void 0) {
|
|
6207
|
+
throw new Error(
|
|
6208
|
+
`${context}: guard reference ${rendered} uses the 'item' scope outside a forEach fan-out \u2014 an element reference only exists inside a forEach block (issue #264).`
|
|
6209
|
+
);
|
|
6210
|
+
}
|
|
6211
|
+
const element = params[forEachSource]?.element;
|
|
6212
|
+
if (element === void 0 || element[field] === void 0) {
|
|
6213
|
+
throw new Error(
|
|
6214
|
+
`${context}: guard reference ${rendered} names '${field}', which is not a declared element field of the forEach source '${forEachSource}' \u2014 declared element fields: ${Object.keys(element ?? {}).sort().map((f) => `'${f}'`).join(", ") || "(none)"} (issue #264 single namespace; #243: unbound references are build errors).`
|
|
6215
|
+
);
|
|
6216
|
+
}
|
|
6217
|
+
});
|
|
6218
|
+
}
|
|
6219
|
+
function whenSpec(when) {
|
|
6220
|
+
const left = when.left.token;
|
|
6221
|
+
const right = leafTemplate(when.right, "when right-hand value");
|
|
6222
|
+
return { op: when.op, left, right };
|
|
6651
6223
|
}
|
|
6652
6224
|
function conditionSpec(condition, commandName) {
|
|
6653
6225
|
const spec = conditionInputToSpec(
|
|
@@ -6669,18 +6241,23 @@ var ITEM_TYPE = {
|
|
|
6669
6241
|
delete: "Delete",
|
|
6670
6242
|
conditionCheck: "ConditionCheck"
|
|
6671
6243
|
};
|
|
6672
|
-
function buildWriteItem(instr, forEachSource, txName) {
|
|
6244
|
+
function buildWriteItem(instr, forEachSource, txName, params) {
|
|
6673
6245
|
const metadata = MetadataRegistry.get(instr.entity.modelClass);
|
|
6674
6246
|
const tableName = TableMapping.resolve(metadata.tableName);
|
|
6675
6247
|
const entity = instr.entity.name;
|
|
6676
6248
|
const condition = conditionSpec(instr.condition, `${txName} (${entity})`);
|
|
6677
|
-
const
|
|
6249
|
+
const when = instr.when ? whenSpec(instr.when) : void 0;
|
|
6250
|
+
const guard = instr.guard !== void 0 ? canonicalizeExpressionSpec(instr.guard, `${txName} (${entity}) guard`) : void 0;
|
|
6251
|
+
if (guard !== void 0) {
|
|
6252
|
+
assertGuardRefsBound(guard, params, forEachSource, `${txName} (${entity})`);
|
|
6253
|
+
}
|
|
6678
6254
|
const base = {
|
|
6679
6255
|
type: ITEM_TYPE[instr.operation],
|
|
6680
6256
|
tableName,
|
|
6681
6257
|
entity,
|
|
6682
6258
|
...condition ? { condition } : {},
|
|
6683
|
-
...
|
|
6259
|
+
...when ? { when } : {},
|
|
6260
|
+
...guard ? { guard } : {},
|
|
6684
6261
|
...forEachSource ? { forEach: { source: forEachSource } } : {}
|
|
6685
6262
|
};
|
|
6686
6263
|
if (instr.operation === "put") {
|
|
@@ -6760,13 +6337,13 @@ function buildTransactionSpec(txName, def) {
|
|
|
6760
6337
|
let hasForEach = false;
|
|
6761
6338
|
for (const instr of def.instructions) {
|
|
6762
6339
|
if (instr.kind === "write") {
|
|
6763
|
-
items.push(buildWriteItem(instr, void 0, txName));
|
|
6340
|
+
items.push(buildWriteItem(instr, void 0, txName, def.params));
|
|
6764
6341
|
} else {
|
|
6765
6342
|
hasForEach = true;
|
|
6766
6343
|
const block = instr;
|
|
6767
6344
|
const blockWhen = block.when ? whenSpec(block.when) : void 0;
|
|
6768
6345
|
for (const w of block.body) {
|
|
6769
|
-
const item = buildWriteItem(w, block.source, txName);
|
|
6346
|
+
const item = buildWriteItem(w, block.source, txName, def.params);
|
|
6770
6347
|
items.push(blockWhen && !item.when ? { ...item, when: blockWhen } : item);
|
|
6771
6348
|
}
|
|
6772
6349
|
}
|
|
@@ -7042,7 +6619,7 @@ function convertCondition(condition, place, context) {
|
|
|
7042
6619
|
return out;
|
|
7043
6620
|
}
|
|
7044
6621
|
var CONDITION_LOGICAL_KEYS = /* @__PURE__ */ new Set(["and", "or", "not"]);
|
|
7045
|
-
function
|
|
6622
|
+
function isConditionOperatorObject5(value) {
|
|
7046
6623
|
if (typeof value !== "object" || value === null || Array.isArray(value) || value instanceof Date || isContractParamRef(value) || isContractKeyFieldRef(value)) {
|
|
7047
6624
|
return false;
|
|
7048
6625
|
}
|
|
@@ -7053,7 +6630,7 @@ function isConditionOperatorObject6(value) {
|
|
|
7053
6630
|
function usesConditionTree(obj) {
|
|
7054
6631
|
for (const [key, value] of Object.entries(obj)) {
|
|
7055
6632
|
if (CONDITION_LOGICAL_KEYS.has(key)) return true;
|
|
7056
|
-
if (
|
|
6633
|
+
if (isConditionOperatorObject5(value)) return true;
|
|
7057
6634
|
}
|
|
7058
6635
|
return false;
|
|
7059
6636
|
}
|
|
@@ -7071,7 +6648,7 @@ function convertConditionTree(obj, place, context) {
|
|
|
7071
6648
|
out[key] = convertConditionTree(value, place, `${context} not`);
|
|
7072
6649
|
continue;
|
|
7073
6650
|
}
|
|
7074
|
-
if (!
|
|
6651
|
+
if (!isConditionOperatorObject5(value)) {
|
|
7075
6652
|
out[key] = convertLeaf(value, key, place, `${context} field '${key}'`);
|
|
7076
6653
|
continue;
|
|
7077
6654
|
}
|
|
@@ -8422,14 +7999,17 @@ function buildOperations(queries = {}, commands = {}, transactions = {}, contrac
|
|
|
8422
7999
|
mergeSpecs(transactionSpecs, built.transactions, "transaction");
|
|
8423
8000
|
const contractSpecs = built.contracts;
|
|
8424
8001
|
const contextSpecs = buildContexts(contextInputMap);
|
|
8425
|
-
|
|
8426
|
-
version: SPEC_VERSION,
|
|
8002
|
+
const content = {
|
|
8427
8003
|
queries: querySpecs,
|
|
8428
8004
|
commands: commandSpecs,
|
|
8429
8005
|
...Object.keys(transactionSpecs).length > 0 ? { transactions: transactionSpecs } : {},
|
|
8430
8006
|
...Object.keys(contractSpecs).length > 0 ? { contracts: contractSpecs } : {},
|
|
8431
8007
|
...Object.keys(contextSpecs).length > 0 ? { contexts: contextSpecs } : {}
|
|
8432
8008
|
};
|
|
8009
|
+
return {
|
|
8010
|
+
version: operationsSpecVersion(content),
|
|
8011
|
+
...content
|
|
8012
|
+
};
|
|
8433
8013
|
}
|
|
8434
8014
|
|
|
8435
8015
|
// src/spec/prepared-artifact.ts
|
|
@@ -8668,8 +8248,6 @@ function buildBridgeBundle(queries = {}, commands = {}, registry = MetadataRegis
|
|
|
8668
8248
|
}
|
|
8669
8249
|
|
|
8670
8250
|
export {
|
|
8671
|
-
SPEC_VERSION,
|
|
8672
|
-
MARKER_ROW_ENTITY,
|
|
8673
8251
|
buildManifestEntity,
|
|
8674
8252
|
buildManifest,
|
|
8675
8253
|
conditionParamName,
|
|
@@ -8743,10 +8321,6 @@ export {
|
|
|
8743
8321
|
publicQueryModel,
|
|
8744
8322
|
publicCommandModel,
|
|
8745
8323
|
isPlannedCommandMethod,
|
|
8746
|
-
isTransactionRef,
|
|
8747
|
-
when,
|
|
8748
|
-
defineTransaction,
|
|
8749
|
-
defineTransactions,
|
|
8750
8324
|
buildTransactionSpec,
|
|
8751
8325
|
buildTransactions,
|
|
8752
8326
|
collectContractN1Violations,
|