graphddb 0.7.9 → 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-PFFPLD4B.js → chunk-3ZU2VW3L.js} +2 -1190
- package/dist/{chunk-ZPNRLOKA.js → chunk-AD6ZQTTE.js} +4 -2
- package/dist/chunk-DFUKGU2Q.js +1197 -0
- package/dist/{chunk-NYM7K2ST.js → chunk-EOJDN3SA.js} +148 -660
- package/dist/cli.js +4 -2
- package/dist/{from-change-DanwjE5b.d.ts → from-change-Ty95KA8C.d.ts} +1 -1
- package/dist/{index-CtPJSMrc.d.ts → index-Dc7d8mWI.d.ts} +161 -6
- package/dist/index.d.ts +9 -7
- package/dist/index.js +108 -30
- package/dist/linter/index.d.ts +5 -4
- package/dist/{maintenance-view-adapter-BATUh_I8.d.ts → maintenance-view-adapter-BAZ9uBGe.d.ts} +20 -1051
- package/dist/{registry-CXhP4TaE.d.ts → registry-LWE54Sdc.d.ts} +1 -1
- package/dist/{relation-depth-Dg3yhl7S.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 -2
|
@@ -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,
|
|
@@ -6,17 +35,12 @@ import {
|
|
|
6
35
|
MAX_TRANSACT_ITEMS,
|
|
7
36
|
MetadataRegistry,
|
|
8
37
|
NO_MIDDLEWARE,
|
|
9
|
-
SELECT_SPEC,
|
|
10
38
|
attachHiddenKey,
|
|
11
39
|
attachModelClass,
|
|
12
40
|
buildConditionExpression,
|
|
13
41
|
buildDeleteInput,
|
|
14
|
-
buildMaintenanceGraph,
|
|
15
|
-
buildProject,
|
|
16
42
|
buildPutInput,
|
|
17
43
|
buildReadRuntime,
|
|
18
|
-
buildRelation,
|
|
19
|
-
buildSubscribeHandler,
|
|
20
44
|
buildUpdateInput,
|
|
21
45
|
buildWriteRuntime,
|
|
22
46
|
captureWrite,
|
|
@@ -25,34 +49,21 @@ import {
|
|
|
25
49
|
compileRawCondition,
|
|
26
50
|
condParamName,
|
|
27
51
|
ctxModelFor,
|
|
28
|
-
detectRelationFields,
|
|
29
52
|
execItemKeySignature,
|
|
30
53
|
executeDelete,
|
|
31
54
|
executePut,
|
|
32
55
|
executeTransaction,
|
|
33
56
|
executeUpdate,
|
|
34
|
-
getEntityWrites,
|
|
35
|
-
getImplicitKeyFields,
|
|
36
|
-
hydrate,
|
|
37
|
-
isEntityWritesDefinition,
|
|
38
|
-
isInlineSnapshotSpec,
|
|
39
|
-
isLifecycleContract,
|
|
40
57
|
isParam,
|
|
41
58
|
isRawCondition,
|
|
42
|
-
isSelectBuilder,
|
|
43
|
-
lifecyclePhaseForIntent,
|
|
44
|
-
normalizeSelectSpec,
|
|
45
|
-
normalizeTopLevelSelect,
|
|
46
59
|
param,
|
|
47
|
-
parseChange,
|
|
48
60
|
pkTemplate,
|
|
49
61
|
resolveModelClass,
|
|
50
62
|
resolveSegmentedKey,
|
|
51
63
|
serializeFieldValue,
|
|
52
64
|
serializeRawCondition,
|
|
53
|
-
skTemplate
|
|
54
|
-
|
|
55
|
-
} from "./chunk-PFFPLD4B.js";
|
|
65
|
+
skTemplate
|
|
66
|
+
} from "./chunk-3ZU2VW3L.js";
|
|
56
67
|
import {
|
|
57
68
|
TableMapping,
|
|
58
69
|
createColumnMap,
|
|
@@ -69,10 +80,6 @@ function evaluateKey(segmented, scope, presentFields, nameOf = (f) => f, partial
|
|
|
69
80
|
return { pk, sk: sk?.template };
|
|
70
81
|
}
|
|
71
82
|
|
|
72
|
-
// src/spec/types.ts
|
|
73
|
-
var SPEC_VERSION = "1.1";
|
|
74
|
-
var MARKER_ROW_ENTITY = "__marker__";
|
|
75
|
-
|
|
76
83
|
// src/spec/manifest.ts
|
|
77
84
|
var DYNAMO_TYPE_TO_FIELD_TYPE = {
|
|
78
85
|
S: "string",
|
|
@@ -220,6 +227,18 @@ function conditionInputToSpec(condition, context, renderLeaf2, renderTreeLeaf, r
|
|
|
220
227
|
);
|
|
221
228
|
}
|
|
222
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
|
+
}
|
|
223
242
|
if (obj.notExists === true) return { kind: "notExists" };
|
|
224
243
|
if ("attributeExists" in obj && typeof obj.attributeExists === "string") {
|
|
225
244
|
if (obj.attributeExists.length === 0) {
|
|
@@ -254,6 +273,13 @@ function assertNotNestedRaw(sub, context) {
|
|
|
254
273
|
);
|
|
255
274
|
}
|
|
256
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
|
+
}
|
|
257
283
|
var LOGICAL_KEYS = /* @__PURE__ */ new Set(["and", "or", "not"]);
|
|
258
284
|
var OPERATOR_KEYS = /* @__PURE__ */ new Set([
|
|
259
285
|
"eq",
|
|
@@ -310,12 +336,14 @@ function buildTree(obj, context, renderTreeLeaf) {
|
|
|
310
336
|
if (key === "and" || key === "or") {
|
|
311
337
|
out[key] = value.map((sub) => {
|
|
312
338
|
assertNotNestedRaw(sub, context);
|
|
339
|
+
assertNotNestedScpExpr(sub, context);
|
|
313
340
|
return buildTree(sub, context, renderTreeLeaf);
|
|
314
341
|
});
|
|
315
342
|
continue;
|
|
316
343
|
}
|
|
317
344
|
if (key === "not") {
|
|
318
345
|
assertNotNestedRaw(value, context);
|
|
346
|
+
assertNotNestedScpExpr(value, context);
|
|
319
347
|
out[key] = buildTree(
|
|
320
348
|
value,
|
|
321
349
|
context,
|
|
@@ -396,6 +424,15 @@ function assertSupportedCondition(commandName, condition) {
|
|
|
396
424
|
}
|
|
397
425
|
return;
|
|
398
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
|
+
}
|
|
399
436
|
throw new Error(
|
|
400
437
|
`Command '${commandName}' has an unsupported write condition.`
|
|
401
438
|
);
|
|
@@ -2977,14 +3014,14 @@ function renderInputLeaf(leaf, isKeyFieldInPut, consumerIndex, consumerField, re
|
|
|
2977
3014
|
if (isMutationInputRef(leaf)) {
|
|
2978
3015
|
return isKeyFieldInPut ? mintContractKeyFieldRef(leaf.field) : mintContractParamRef(leaf.field);
|
|
2979
3016
|
}
|
|
2980
|
-
const
|
|
2981
|
-
if (
|
|
3017
|
+
const entityRef2 = parseEntityRef(leaf);
|
|
3018
|
+
if (entityRef2 !== void 0) {
|
|
2982
3019
|
if (resolveEntityRef === null) {
|
|
2983
3020
|
throw new Error(
|
|
2984
|
-
`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.`
|
|
2985
3022
|
);
|
|
2986
3023
|
}
|
|
2987
|
-
return resolveEntityRef(
|
|
3024
|
+
return resolveEntityRef(entityRef2, consumerIndex, consumerField);
|
|
2988
3025
|
}
|
|
2989
3026
|
return leaf;
|
|
2990
3027
|
}
|
|
@@ -3266,6 +3303,11 @@ function renderCondition(condition, key, params, context) {
|
|
|
3266
3303
|
}
|
|
3267
3304
|
if (typeof condition === "object" && condition !== null) {
|
|
3268
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
|
+
}
|
|
3269
3311
|
if (obj.notExists === true) return { notExists: true };
|
|
3270
3312
|
if (typeof obj.attributeExists === "string") {
|
|
3271
3313
|
return { attributeExists: obj.attributeExists };
|
|
@@ -6032,618 +6074,6 @@ function writeDescriptorToPlan(name, d) {
|
|
|
6032
6074
|
return { plan: plan2, select, condition, mode: d.mode ?? "transaction", description: d.description };
|
|
6033
6075
|
}
|
|
6034
6076
|
|
|
6035
|
-
// src/define/transaction.ts
|
|
6036
|
-
var TX_REF_BRAND = /* @__PURE__ */ Symbol("graphddb:txref");
|
|
6037
|
-
function isTransactionRef(value) {
|
|
6038
|
-
return typeof value === "object" && value !== null && value[TX_REF_BRAND] === true;
|
|
6039
|
-
}
|
|
6040
|
-
var MARKER_TAGS = [
|
|
6041
|
-
// pass 0: short, begins with 'A'.
|
|
6042
|
-
"Axqv",
|
|
6043
|
-
// pass 1: long, begins with 'Z'. The two tags share NO common prefix and NO
|
|
6044
|
-
// common substring of length >= 2 (their alphabets are disjoint), and differ
|
|
6045
|
-
// in length, so any fragment-extracting / length-dependent transform
|
|
6046
|
-
// (`slice(0,n)`, `[i]`, `charAt`, `padStart`, `padEnd`) yields *different*
|
|
6047
|
-
// fragments across the two passes -- the differential check then rejects it.
|
|
6048
|
-
// (Convergence-to-constant escapes that even disjoint markers cannot separate
|
|
6049
|
-
// -- `slice(0,0)` -> '' in both passes, `includes('x')` -> a constant boolean
|
|
6050
|
-
// -- are caught instead by the per-access coercion ledger; see
|
|
6051
|
-
// {@link makeFieldRef} and {@link defineTransaction}.)
|
|
6052
|
-
"Zmnoprstuwy0123456789WIDEMARKERBODYFILLERZ"
|
|
6053
|
-
];
|
|
6054
|
-
var MARKER_PASS_COUNT = MARKER_TAGS.length;
|
|
6055
|
-
function markerValue(pass, field) {
|
|
6056
|
-
const tag = MARKER_TAGS[pass];
|
|
6057
|
-
return `${tag}::${field}::${tag}`;
|
|
6058
|
-
}
|
|
6059
|
-
function makeValueSentinel(fields, tokenFor, originFor, markerFor, containerOrigin, onAccess, onCoerce) {
|
|
6060
|
-
const cache = /* @__PURE__ */ new Map();
|
|
6061
|
-
return new Proxy(/* @__PURE__ */ Object.create(null), {
|
|
6062
|
-
get(_t, key) {
|
|
6063
|
-
if (typeof key === "symbol") {
|
|
6064
|
-
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")) {
|
|
6065
|
-
return void 0;
|
|
6066
|
-
}
|
|
6067
|
-
throw new Error(
|
|
6068
|
-
`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.`
|
|
6069
|
-
);
|
|
6070
|
-
}
|
|
6071
|
-
if (!fields.has(key)) {
|
|
6072
|
-
throw new Error(
|
|
6073
|
-
`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.`
|
|
6074
|
-
);
|
|
6075
|
-
}
|
|
6076
|
-
onAccess(key);
|
|
6077
|
-
let ref = cache.get(key);
|
|
6078
|
-
if (!ref) {
|
|
6079
|
-
ref = makeFieldRef(
|
|
6080
|
-
tokenFor(key),
|
|
6081
|
-
originFor(key),
|
|
6082
|
-
markerFor(key),
|
|
6083
|
-
() => onCoerce(key)
|
|
6084
|
-
);
|
|
6085
|
-
cache.set(key, ref);
|
|
6086
|
-
}
|
|
6087
|
-
return ref;
|
|
6088
|
-
},
|
|
6089
|
-
set() {
|
|
6090
|
-
throw new Error(
|
|
6091
|
-
`defineTransaction: cannot assign to a field of ${containerOrigin}.`
|
|
6092
|
-
);
|
|
6093
|
-
},
|
|
6094
|
-
defineProperty() {
|
|
6095
|
-
throw new Error(
|
|
6096
|
-
`defineTransaction: cannot define a property on ${containerOrigin}.`
|
|
6097
|
-
);
|
|
6098
|
-
},
|
|
6099
|
-
deleteProperty() {
|
|
6100
|
-
throw new Error(
|
|
6101
|
-
`defineTransaction: cannot delete a field of ${containerOrigin}.`
|
|
6102
|
-
);
|
|
6103
|
-
}
|
|
6104
|
-
});
|
|
6105
|
-
}
|
|
6106
|
-
function makeFieldRef(token, origin, marker, onCoerce) {
|
|
6107
|
-
const target = /* @__PURE__ */ Object.create(null);
|
|
6108
|
-
const proxy = new Proxy(target, {
|
|
6109
|
-
get(_t, key) {
|
|
6110
|
-
if (key === TX_REF_BRAND) return true;
|
|
6111
|
-
if (key === "token") return token;
|
|
6112
|
-
if (key === "origin") return origin;
|
|
6113
|
-
if (key === Symbol.toPrimitive) {
|
|
6114
|
-
return (hint) => {
|
|
6115
|
-
onCoerce();
|
|
6116
|
-
return hint === "number" ? NaN : marker;
|
|
6117
|
-
};
|
|
6118
|
-
}
|
|
6119
|
-
if (key === "toString" || key === Symbol.toStringTag) {
|
|
6120
|
-
return () => {
|
|
6121
|
-
onCoerce();
|
|
6122
|
-
return marker;
|
|
6123
|
-
};
|
|
6124
|
-
}
|
|
6125
|
-
if (key === "valueOf") {
|
|
6126
|
-
return () => {
|
|
6127
|
-
onCoerce();
|
|
6128
|
-
return NaN;
|
|
6129
|
-
};
|
|
6130
|
-
}
|
|
6131
|
-
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")) {
|
|
6132
|
-
return void 0;
|
|
6133
|
-
}
|
|
6134
|
-
const name = typeof key === "symbol" ? key.toString() : String(key);
|
|
6135
|
-
throw new Error(
|
|
6136
|
-
`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.`
|
|
6137
|
-
);
|
|
6138
|
-
},
|
|
6139
|
-
set() {
|
|
6140
|
-
throw new Error(`defineTransaction: cannot assign on ${origin}.`);
|
|
6141
|
-
},
|
|
6142
|
-
defineProperty() {
|
|
6143
|
-
throw new Error(`defineTransaction: cannot define a property on ${origin}.`);
|
|
6144
|
-
},
|
|
6145
|
-
deleteProperty() {
|
|
6146
|
-
throw new Error(`defineTransaction: cannot delete on ${origin}.`);
|
|
6147
|
-
}
|
|
6148
|
-
});
|
|
6149
|
-
return proxy;
|
|
6150
|
-
}
|
|
6151
|
-
var when = {
|
|
6152
|
-
eq(left, right) {
|
|
6153
|
-
assertRef(left, "when.eq");
|
|
6154
|
-
return { op: "eq", left, right };
|
|
6155
|
-
},
|
|
6156
|
-
ne(left, right) {
|
|
6157
|
-
assertRef(left, "when.ne");
|
|
6158
|
-
return { op: "ne", left, right };
|
|
6159
|
-
}
|
|
6160
|
-
};
|
|
6161
|
-
function assertRef(value, context) {
|
|
6162
|
-
if (!isTransactionRef(value)) {
|
|
6163
|
-
throw new Error(
|
|
6164
|
-
`defineTransaction: ${context} expects a field reference (e.g. \`p.status\` or an element field) on its left-hand side.`
|
|
6165
|
-
);
|
|
6166
|
-
}
|
|
6167
|
-
}
|
|
6168
|
-
function entityRef2(model) {
|
|
6169
|
-
const modelClass = resolveModelClass(model);
|
|
6170
|
-
return { name: modelClass.name, modelClass };
|
|
6171
|
-
}
|
|
6172
|
-
function descriptorOf(p) {
|
|
6173
|
-
if (p.kind === "array") {
|
|
6174
|
-
const element = {};
|
|
6175
|
-
for (const [field, fieldParam] of Object.entries(p.element ?? {})) {
|
|
6176
|
-
element[field] = descriptorOf(fieldParam);
|
|
6177
|
-
}
|
|
6178
|
-
return { kind: "array", required: true, element };
|
|
6179
|
-
}
|
|
6180
|
-
return p.literals === void 0 ? { kind: p.kind, required: true } : { kind: p.kind, literals: p.literals, required: true };
|
|
6181
|
-
}
|
|
6182
|
-
function runBuildPass(params, build, scalarFields, arrayParams, pass, accessed, coerced) {
|
|
6183
|
-
const noteAccess = (token, origin) => {
|
|
6184
|
-
if (!accessed.has(token)) accessed.set(token, { token, origin });
|
|
6185
|
-
};
|
|
6186
|
-
const noteCoerce = (token, origin) => {
|
|
6187
|
-
if (!coerced.has(token)) coerced.set(token, { token, origin });
|
|
6188
|
-
};
|
|
6189
|
-
const scalarSentinel = makeValueSentinel(
|
|
6190
|
-
scalarFields,
|
|
6191
|
-
(f) => `{${f}}`,
|
|
6192
|
-
(f) => `param '${f}'`,
|
|
6193
|
-
(f) => markerValue(pass, f),
|
|
6194
|
-
"params",
|
|
6195
|
-
(f) => noteAccess(`{${f}}`, `param '${f}'`),
|
|
6196
|
-
(f) => noteCoerce(`{${f}}`, `param '${f}'`)
|
|
6197
|
-
);
|
|
6198
|
-
const pProxy = new Proxy(/* @__PURE__ */ Object.create(null), {
|
|
6199
|
-
get(_t, key) {
|
|
6200
|
-
if (typeof key === "symbol") {
|
|
6201
|
-
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")) {
|
|
6202
|
-
return void 0;
|
|
6203
|
-
}
|
|
6204
|
-
throw new Error("defineTransaction: unsupported symbol access on params.");
|
|
6205
|
-
}
|
|
6206
|
-
if (arrayParams.has(key)) return params[key];
|
|
6207
|
-
if (scalarFields.has(key)) return scalarSentinel[key];
|
|
6208
|
-
throw new Error(
|
|
6209
|
-
`defineTransaction: unknown parameter '${key}'. Declare it in the params map passed to defineTransaction.`
|
|
6210
|
-
);
|
|
6211
|
-
}
|
|
6212
|
-
});
|
|
6213
|
-
const instructions = [];
|
|
6214
|
-
let currentBody = instructions;
|
|
6215
|
-
let insideForEach = false;
|
|
6216
|
-
const recordWrite = (instr) => {
|
|
6217
|
-
currentBody.push(instr);
|
|
6218
|
-
};
|
|
6219
|
-
const recorder2 = {
|
|
6220
|
-
put(model, item, options) {
|
|
6221
|
-
recordWrite({
|
|
6222
|
-
kind: "write",
|
|
6223
|
-
operation: "put",
|
|
6224
|
-
entity: entityRef2(model),
|
|
6225
|
-
item,
|
|
6226
|
-
...options?.condition !== void 0 ? { condition: options.condition } : {},
|
|
6227
|
-
...options?.when !== void 0 ? { when: options.when } : {}
|
|
6228
|
-
});
|
|
6229
|
-
},
|
|
6230
|
-
update(model, key, changes, options) {
|
|
6231
|
-
recordWrite({
|
|
6232
|
-
kind: "write",
|
|
6233
|
-
operation: "update",
|
|
6234
|
-
entity: entityRef2(model),
|
|
6235
|
-
key,
|
|
6236
|
-
changes,
|
|
6237
|
-
...options?.condition !== void 0 ? { condition: options.condition } : {},
|
|
6238
|
-
...options?.when !== void 0 ? { when: options.when } : {}
|
|
6239
|
-
});
|
|
6240
|
-
},
|
|
6241
|
-
delete(model, key, options) {
|
|
6242
|
-
recordWrite({
|
|
6243
|
-
kind: "write",
|
|
6244
|
-
operation: "delete",
|
|
6245
|
-
entity: entityRef2(model),
|
|
6246
|
-
key,
|
|
6247
|
-
...options?.condition !== void 0 ? { condition: options.condition } : {},
|
|
6248
|
-
...options?.when !== void 0 ? { when: options.when } : {}
|
|
6249
|
-
});
|
|
6250
|
-
},
|
|
6251
|
-
conditionCheck(model, key, options) {
|
|
6252
|
-
if (options?.condition === void 0 || options.condition === null) {
|
|
6253
|
-
throw new Error(
|
|
6254
|
-
"defineTransaction: tx.conditionCheck requires a `condition` (the read-only assertion it makes); e.g. `{ condition: { attributeExists: 'PK' } }`."
|
|
6255
|
-
);
|
|
6256
|
-
}
|
|
6257
|
-
recordWrite({
|
|
6258
|
-
kind: "write",
|
|
6259
|
-
operation: "conditionCheck",
|
|
6260
|
-
entity: entityRef2(model),
|
|
6261
|
-
key,
|
|
6262
|
-
condition: options.condition,
|
|
6263
|
-
...options.when !== void 0 ? { when: options.when } : {}
|
|
6264
|
-
});
|
|
6265
|
-
},
|
|
6266
|
-
forEach(source, body, options) {
|
|
6267
|
-
if (insideForEach) {
|
|
6268
|
-
throw new Error(
|
|
6269
|
-
"defineTransaction: nested forEach is not supported; flatten the loop."
|
|
6270
|
-
);
|
|
6271
|
-
}
|
|
6272
|
-
if (!isParam(source) || source.kind !== "array") {
|
|
6273
|
-
throw new Error(
|
|
6274
|
-
"defineTransaction: forEach source must be a `param.array(...)` parameter accessed via `p.<name>`."
|
|
6275
|
-
);
|
|
6276
|
-
}
|
|
6277
|
-
const arrayParam = source;
|
|
6278
|
-
const sourceName = arrayParams.size ? Object.keys(params).find((k) => params[k] === arrayParam) : void 0;
|
|
6279
|
-
if (sourceName === void 0) {
|
|
6280
|
-
throw new Error(
|
|
6281
|
-
"defineTransaction: forEach source is not a declared array param."
|
|
6282
|
-
);
|
|
6283
|
-
}
|
|
6284
|
-
const elementFields = new Set(Object.keys(arrayParam.element ?? {}));
|
|
6285
|
-
const elementProxy = makeValueSentinel(
|
|
6286
|
-
elementFields,
|
|
6287
|
-
(f) => `{item.${f}}`,
|
|
6288
|
-
(f) => `element field '${f}' of '${sourceName}'`,
|
|
6289
|
-
(f) => markerValue(pass, `item.${f}`),
|
|
6290
|
-
`element of '${sourceName}'`,
|
|
6291
|
-
(f) => noteAccess(`{item.${f}}`, `element field '${f}' of '${sourceName}'`),
|
|
6292
|
-
(f) => noteCoerce(`{item.${f}}`, `element field '${f}' of '${sourceName}'`)
|
|
6293
|
-
);
|
|
6294
|
-
const block = {
|
|
6295
|
-
kind: "forEach",
|
|
6296
|
-
source: sourceName,
|
|
6297
|
-
...options?.when !== void 0 ? { when: options.when } : {},
|
|
6298
|
-
body: []
|
|
6299
|
-
};
|
|
6300
|
-
const prevBody = currentBody;
|
|
6301
|
-
currentBody = block.body;
|
|
6302
|
-
insideForEach = true;
|
|
6303
|
-
try {
|
|
6304
|
-
body(elementProxy);
|
|
6305
|
-
} finally {
|
|
6306
|
-
insideForEach = false;
|
|
6307
|
-
currentBody = prevBody;
|
|
6308
|
-
}
|
|
6309
|
-
currentBody.push(block);
|
|
6310
|
-
}
|
|
6311
|
-
};
|
|
6312
|
-
build(recorder2, pProxy);
|
|
6313
|
-
return instructions;
|
|
6314
|
-
}
|
|
6315
|
-
function defineTransaction(params, build) {
|
|
6316
|
-
const descriptors = {};
|
|
6317
|
-
for (const [name, value] of Object.entries(params)) {
|
|
6318
|
-
if (!isParam(value)) {
|
|
6319
|
-
throw new Error(
|
|
6320
|
-
`defineTransaction: param '${name}' is not a param.* placeholder.`
|
|
6321
|
-
);
|
|
6322
|
-
}
|
|
6323
|
-
descriptors[name] = descriptorOf(value);
|
|
6324
|
-
}
|
|
6325
|
-
const scalarFields = new Set(
|
|
6326
|
-
Object.keys(params).filter((k) => params[k].kind !== "array")
|
|
6327
|
-
);
|
|
6328
|
-
const arrayParams = new Set(
|
|
6329
|
-
Object.keys(params).filter((k) => params[k].kind === "array")
|
|
6330
|
-
);
|
|
6331
|
-
const accessed = /* @__PURE__ */ new Map();
|
|
6332
|
-
const coerced = /* @__PURE__ */ new Map();
|
|
6333
|
-
const passes = [];
|
|
6334
|
-
for (let pass = 0; pass < MARKER_PASS_COUNT; pass++) {
|
|
6335
|
-
passes.push(
|
|
6336
|
-
runBuildPass(
|
|
6337
|
-
params,
|
|
6338
|
-
build,
|
|
6339
|
-
scalarFields,
|
|
6340
|
-
arrayParams,
|
|
6341
|
-
pass,
|
|
6342
|
-
accessed,
|
|
6343
|
-
coerced
|
|
6344
|
-
)
|
|
6345
|
-
);
|
|
6346
|
-
}
|
|
6347
|
-
if (coerced.size > 0) {
|
|
6348
|
-
const info = [...coerced.values()][0];
|
|
6349
|
-
throw new Error(
|
|
6350
|
-
`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.`
|
|
6351
|
-
);
|
|
6352
|
-
}
|
|
6353
|
-
const surfaced = /* @__PURE__ */ new Set();
|
|
6354
|
-
verifyInstructions(passes, surfaced);
|
|
6355
|
-
for (const [token, info] of accessed) {
|
|
6356
|
-
if (!surfaced.has(token)) {
|
|
6357
|
-
throw new Error(
|
|
6358
|
-
`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.`
|
|
6359
|
-
);
|
|
6360
|
-
}
|
|
6361
|
-
}
|
|
6362
|
-
return {
|
|
6363
|
-
__isTransactionDefinition: true,
|
|
6364
|
-
params: descriptors,
|
|
6365
|
-
instructions: passes[0]
|
|
6366
|
-
};
|
|
6367
|
-
}
|
|
6368
|
-
function verifyInstructions(passes, surfaced) {
|
|
6369
|
-
const first = passes[0];
|
|
6370
|
-
for (let i = 0; i < first.length; i++) {
|
|
6371
|
-
const instrs = passes.map((p) => p[i]);
|
|
6372
|
-
const kind = first[i].kind;
|
|
6373
|
-
if (instrs.some((x) => x.kind !== kind)) {
|
|
6374
|
-
throw new Error(
|
|
6375
|
-
"defineTransaction: build is not deterministic across evaluation (instruction shape diverged between passes). The callback must be a pure, declarative description of the writes."
|
|
6376
|
-
);
|
|
6377
|
-
}
|
|
6378
|
-
if (kind === "write") {
|
|
6379
|
-
verifyWrite(instrs, surfaced);
|
|
6380
|
-
} else {
|
|
6381
|
-
const blocks = instrs;
|
|
6382
|
-
verifyWhen(
|
|
6383
|
-
blocks.map((b) => b.when),
|
|
6384
|
-
surfaced,
|
|
6385
|
-
`forEach '${blocks[0].source}' when`
|
|
6386
|
-
);
|
|
6387
|
-
verifyInstructions(
|
|
6388
|
-
blocks.map((b) => b.body),
|
|
6389
|
-
surfaced
|
|
6390
|
-
);
|
|
6391
|
-
}
|
|
6392
|
-
}
|
|
6393
|
-
}
|
|
6394
|
-
function verifyWrite(instrs, surfaced) {
|
|
6395
|
-
const op = instrs[0].operation;
|
|
6396
|
-
if (instrs.some((x) => x.operation !== op)) {
|
|
6397
|
-
throw new Error(
|
|
6398
|
-
"defineTransaction: write operation diverged between evaluation passes; the callback must be a pure, declarative description of the writes."
|
|
6399
|
-
);
|
|
6400
|
-
}
|
|
6401
|
-
verifyRecord(instrs.map((x) => x.item), surfaced, `${op} item`);
|
|
6402
|
-
verifyRecord(instrs.map((x) => x.key), surfaced, `${op} key`);
|
|
6403
|
-
verifyRecord(instrs.map((x) => x.changes), surfaced, `${op} changes`);
|
|
6404
|
-
verifyCondition(
|
|
6405
|
-
instrs.map((x) => x.condition),
|
|
6406
|
-
surfaced,
|
|
6407
|
-
`${op} condition`
|
|
6408
|
-
);
|
|
6409
|
-
verifyWhen(instrs.map((x) => x.when), surfaced, `${op} when`);
|
|
6410
|
-
}
|
|
6411
|
-
function verifyRecord(records, surfaced, context) {
|
|
6412
|
-
const present = records.filter((r) => r !== void 0);
|
|
6413
|
-
if (present.length === 0) return;
|
|
6414
|
-
if (present.length !== records.length) {
|
|
6415
|
-
throw new Error(
|
|
6416
|
-
`defineTransaction: ${context} present in some evaluation passes but not others; the callback must be a pure, declarative description.`
|
|
6417
|
-
);
|
|
6418
|
-
}
|
|
6419
|
-
const keys = Object.keys(present[0]).sort();
|
|
6420
|
-
for (const r of present) {
|
|
6421
|
-
const k = Object.keys(r).sort();
|
|
6422
|
-
if (k.length !== keys.length || k.some((x, i) => x !== keys[i])) {
|
|
6423
|
-
throw new Error(
|
|
6424
|
-
`defineTransaction: ${context} field set diverged between evaluation passes; the callback must be a pure, declarative description.`
|
|
6425
|
-
);
|
|
6426
|
-
}
|
|
6427
|
-
}
|
|
6428
|
-
for (const field of keys) {
|
|
6429
|
-
verifyLeaf(
|
|
6430
|
-
present.map((r) => r[field]),
|
|
6431
|
-
surfaced,
|
|
6432
|
-
`${context} field '${field}'`
|
|
6433
|
-
);
|
|
6434
|
-
}
|
|
6435
|
-
}
|
|
6436
|
-
function isConditionOperatorObject5(value) {
|
|
6437
|
-
if (typeof value !== "object" || value === null || Array.isArray(value) || value instanceof Date || isTransactionRef(value)) {
|
|
6438
|
-
return false;
|
|
6439
|
-
}
|
|
6440
|
-
const keys = Object.keys(value);
|
|
6441
|
-
if (keys.length === 0) return false;
|
|
6442
|
-
return keys.every((k) => CONDITION_OPERATOR_KEYS.has(k));
|
|
6443
|
-
}
|
|
6444
|
-
function verifyCondition(conditions, surfaced, context) {
|
|
6445
|
-
const present = conditions.filter(
|
|
6446
|
-
(c) => c !== void 0 && c !== null
|
|
6447
|
-
);
|
|
6448
|
-
if (present.length === 0) return;
|
|
6449
|
-
if (present.length !== conditions.length) {
|
|
6450
|
-
throw new Error(
|
|
6451
|
-
`defineTransaction: ${context} present in some evaluation passes but not others; the callback must be a pure, declarative description.`
|
|
6452
|
-
);
|
|
6453
|
-
}
|
|
6454
|
-
if (present.some((c) => isRawCondition(c))) return;
|
|
6455
|
-
if (present.some((c) => typeof c !== "object" || Array.isArray(c))) {
|
|
6456
|
-
throw new Error(
|
|
6457
|
-
`defineTransaction: ${context} must be a declarative condition object (field clause / operator object / \`and\` / \`or\` / \`not\` group).`
|
|
6458
|
-
);
|
|
6459
|
-
}
|
|
6460
|
-
verifyConditionTree(
|
|
6461
|
-
present.map((c) => c),
|
|
6462
|
-
surfaced,
|
|
6463
|
-
context
|
|
6464
|
-
);
|
|
6465
|
-
}
|
|
6466
|
-
function verifyConditionTree(nodes, surfaced, context) {
|
|
6467
|
-
const keys = Object.keys(nodes[0]).sort();
|
|
6468
|
-
for (const n of nodes) {
|
|
6469
|
-
const k = Object.keys(n).sort();
|
|
6470
|
-
if (k.length !== keys.length || k.some((x, i) => x !== keys[i])) {
|
|
6471
|
-
throw new Error(
|
|
6472
|
-
`defineTransaction: ${context} key set diverged between evaluation passes; the callback must be a pure, declarative description.`
|
|
6473
|
-
);
|
|
6474
|
-
}
|
|
6475
|
-
}
|
|
6476
|
-
for (const key of keys) {
|
|
6477
|
-
const values = nodes.map((n) => n[key]);
|
|
6478
|
-
if (key === "and" || key === "or") {
|
|
6479
|
-
const arrays = values.map((v) => {
|
|
6480
|
-
if (!Array.isArray(v) || v.length === 0) {
|
|
6481
|
-
throw new Error(
|
|
6482
|
-
`defineTransaction: ${context} \`${key}\` must be a non-empty array of sub-conditions.`
|
|
6483
|
-
);
|
|
6484
|
-
}
|
|
6485
|
-
return v;
|
|
6486
|
-
});
|
|
6487
|
-
const len = arrays[0].length;
|
|
6488
|
-
if (arrays.some((a) => a.length !== len)) {
|
|
6489
|
-
throw new Error(
|
|
6490
|
-
`defineTransaction: ${context} \`${key}\` length diverged between evaluation passes; the callback must be declarative.`
|
|
6491
|
-
);
|
|
6492
|
-
}
|
|
6493
|
-
for (let i = 0; i < len; i++) {
|
|
6494
|
-
verifyCondition(
|
|
6495
|
-
arrays.map((a) => a[i]),
|
|
6496
|
-
surfaced,
|
|
6497
|
-
`${context} ${key}[${i}]`
|
|
6498
|
-
);
|
|
6499
|
-
}
|
|
6500
|
-
continue;
|
|
6501
|
-
}
|
|
6502
|
-
if (key === "not") {
|
|
6503
|
-
verifyCondition(
|
|
6504
|
-
values,
|
|
6505
|
-
surfaced,
|
|
6506
|
-
`${context} not`
|
|
6507
|
-
);
|
|
6508
|
-
continue;
|
|
6509
|
-
}
|
|
6510
|
-
if (!values.every((v) => isConditionOperatorObject5(v))) {
|
|
6511
|
-
if (values.some((v) => isConditionOperatorObject5(v))) {
|
|
6512
|
-
throw new Error(
|
|
6513
|
-
`defineTransaction: ${context} field '${key}' is an operator object in some evaluation passes but a bare value in others; the callback must be declarative.`
|
|
6514
|
-
);
|
|
6515
|
-
}
|
|
6516
|
-
verifyLeaf(values, surfaced, `${context} field '${key}'`);
|
|
6517
|
-
continue;
|
|
6518
|
-
}
|
|
6519
|
-
verifyOperatorObject(
|
|
6520
|
-
values.map((v) => v),
|
|
6521
|
-
surfaced,
|
|
6522
|
-
`${context} field '${key}'`
|
|
6523
|
-
);
|
|
6524
|
-
}
|
|
6525
|
-
}
|
|
6526
|
-
function verifyOperatorObject(objs, surfaced, context) {
|
|
6527
|
-
const ops = Object.keys(objs[0]).sort();
|
|
6528
|
-
for (const o of objs) {
|
|
6529
|
-
const k = Object.keys(o).sort();
|
|
6530
|
-
if (k.length !== ops.length || k.some((x, i) => x !== ops[i])) {
|
|
6531
|
-
throw new Error(
|
|
6532
|
-
`defineTransaction: ${context} operator set diverged between evaluation passes; the callback must be a pure, declarative description.`
|
|
6533
|
-
);
|
|
6534
|
-
}
|
|
6535
|
-
}
|
|
6536
|
-
for (const op of ops) {
|
|
6537
|
-
const opVals = objs.map((o) => o[op]);
|
|
6538
|
-
if (op === "between") {
|
|
6539
|
-
const pairs = opVals.map((v) => {
|
|
6540
|
-
if (!Array.isArray(v) || v.length !== 2) {
|
|
6541
|
-
throw new Error(
|
|
6542
|
-
`defineTransaction: ${context} \`between\` takes a \`[lo, hi]\` pair.`
|
|
6543
|
-
);
|
|
6544
|
-
}
|
|
6545
|
-
return v;
|
|
6546
|
-
});
|
|
6547
|
-
verifyLeaf(pairs.map((p) => p[0]), surfaced, `${context} between[0]`);
|
|
6548
|
-
verifyLeaf(pairs.map((p) => p[1]), surfaced, `${context} between[1]`);
|
|
6549
|
-
} else if (op === "in") {
|
|
6550
|
-
const arrays = opVals.map((v) => {
|
|
6551
|
-
if (!Array.isArray(v) || v.length === 0) {
|
|
6552
|
-
throw new Error(
|
|
6553
|
-
`defineTransaction: ${context} \`in\` takes a non-empty array of operands.`
|
|
6554
|
-
);
|
|
6555
|
-
}
|
|
6556
|
-
return v;
|
|
6557
|
-
});
|
|
6558
|
-
const len = arrays[0].length;
|
|
6559
|
-
if (arrays.some((a) => a.length !== len)) {
|
|
6560
|
-
throw new Error(
|
|
6561
|
-
`defineTransaction: ${context} \`in\` length diverged between evaluation passes; the callback must be declarative.`
|
|
6562
|
-
);
|
|
6563
|
-
}
|
|
6564
|
-
for (let i = 0; i < len; i++) {
|
|
6565
|
-
verifyLeaf(arrays.map((a) => a[i]), surfaced, `${context} in[${i}]`);
|
|
6566
|
-
}
|
|
6567
|
-
} else if (op === "attributeExists" || op === "attributeType") {
|
|
6568
|
-
if (opVals.some((v) => isTransactionRef(v))) {
|
|
6569
|
-
throw new Error(
|
|
6570
|
-
`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.`
|
|
6571
|
-
);
|
|
6572
|
-
}
|
|
6573
|
-
} else {
|
|
6574
|
-
verifyLeaf(opVals, surfaced, `${context} ${op}`);
|
|
6575
|
-
}
|
|
6576
|
-
}
|
|
6577
|
-
}
|
|
6578
|
-
function verifyWhen(whens, surfaced, context) {
|
|
6579
|
-
const present = whens.filter((w) => w !== void 0);
|
|
6580
|
-
if (present.length === 0) return;
|
|
6581
|
-
if (present.length !== whens.length) {
|
|
6582
|
-
throw new Error(
|
|
6583
|
-
`defineTransaction: ${context} present in some evaluation passes but not others; the callback must be a pure, declarative description.`
|
|
6584
|
-
);
|
|
6585
|
-
}
|
|
6586
|
-
for (const w of present) {
|
|
6587
|
-
if (isTransactionRef(w.left)) surfaced.add(w.left.token);
|
|
6588
|
-
}
|
|
6589
|
-
verifyLeaf(present.map((w) => w.right), surfaced, `${context} right-hand value`);
|
|
6590
|
-
}
|
|
6591
|
-
function verifyLeaf(values, surfaced, context) {
|
|
6592
|
-
const refTokens = values.map((v) => isTransactionRef(v) ? v.token : void 0);
|
|
6593
|
-
const anyRef = refTokens.some((t) => t !== void 0);
|
|
6594
|
-
if (anyRef) {
|
|
6595
|
-
if (refTokens.some((t) => t === void 0)) {
|
|
6596
|
-
throw new Error(
|
|
6597
|
-
`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.`
|
|
6598
|
-
);
|
|
6599
|
-
}
|
|
6600
|
-
const token = refTokens[0];
|
|
6601
|
-
if (refTokens.some((t) => t !== token)) {
|
|
6602
|
-
throw new Error(
|
|
6603
|
-
`defineTransaction: ${context} resolves to different field references across evaluation passes \u2014 the value is not a stable, declarative reference.`
|
|
6604
|
-
);
|
|
6605
|
-
}
|
|
6606
|
-
surfaced.add(token);
|
|
6607
|
-
return;
|
|
6608
|
-
}
|
|
6609
|
-
const norm = values.map(normalizeLiteral);
|
|
6610
|
-
for (let i = 1; i < norm.length; i++) {
|
|
6611
|
-
if (norm[i] !== norm[0]) {
|
|
6612
|
-
throw new Error(
|
|
6613
|
-
`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.`
|
|
6614
|
-
);
|
|
6615
|
-
}
|
|
6616
|
-
}
|
|
6617
|
-
}
|
|
6618
|
-
function normalizeLiteral(value) {
|
|
6619
|
-
if (value === null) return "t:null";
|
|
6620
|
-
if (value instanceof Date) return `t:date:${value.toISOString()}`;
|
|
6621
|
-
const t = typeof value;
|
|
6622
|
-
if (t === "string") return `t:s:${value}`;
|
|
6623
|
-
if (t === "boolean") return `t:b:${String(value)}`;
|
|
6624
|
-
if (t === "number") {
|
|
6625
|
-
if (Number.isNaN(value)) {
|
|
6626
|
-
throw new Error(
|
|
6627
|
-
"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."
|
|
6628
|
-
);
|
|
6629
|
-
}
|
|
6630
|
-
return `t:n:${String(value)}`;
|
|
6631
|
-
}
|
|
6632
|
-
throw new Error(
|
|
6633
|
-
`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.`
|
|
6634
|
-
);
|
|
6635
|
-
}
|
|
6636
|
-
function defineTransactions(definitions) {
|
|
6637
|
-
for (const [name, def] of Object.entries(definitions)) {
|
|
6638
|
-
if (def === null || typeof def !== "object" || def.__isTransactionDefinition !== true) {
|
|
6639
|
-
throw new Error(
|
|
6640
|
-
`defineTransactions: '${name}' is not a transaction definition. Use defineTransaction(...) to build entries.`
|
|
6641
|
-
);
|
|
6642
|
-
}
|
|
6643
|
-
}
|
|
6644
|
-
return definitions;
|
|
6645
|
-
}
|
|
6646
|
-
|
|
6647
6077
|
// src/spec/transaction.ts
|
|
6648
6078
|
function paramSpec(d) {
|
|
6649
6079
|
if (d.kind === "array") {
|
|
@@ -6730,10 +6160,66 @@ function keyConditionTemplate2(metadata, keyStructure, context) {
|
|
|
6730
6160
|
if (sk !== void 0) out.SK = sk;
|
|
6731
6161
|
return out;
|
|
6732
6162
|
}
|
|
6733
|
-
function
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
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 };
|
|
6737
6223
|
}
|
|
6738
6224
|
function conditionSpec(condition, commandName) {
|
|
6739
6225
|
const spec = conditionInputToSpec(
|
|
@@ -6755,18 +6241,23 @@ var ITEM_TYPE = {
|
|
|
6755
6241
|
delete: "Delete",
|
|
6756
6242
|
conditionCheck: "ConditionCheck"
|
|
6757
6243
|
};
|
|
6758
|
-
function buildWriteItem(instr, forEachSource, txName) {
|
|
6244
|
+
function buildWriteItem(instr, forEachSource, txName, params) {
|
|
6759
6245
|
const metadata = MetadataRegistry.get(instr.entity.modelClass);
|
|
6760
6246
|
const tableName = TableMapping.resolve(metadata.tableName);
|
|
6761
6247
|
const entity = instr.entity.name;
|
|
6762
6248
|
const condition = conditionSpec(instr.condition, `${txName} (${entity})`);
|
|
6763
|
-
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
|
+
}
|
|
6764
6254
|
const base = {
|
|
6765
6255
|
type: ITEM_TYPE[instr.operation],
|
|
6766
6256
|
tableName,
|
|
6767
6257
|
entity,
|
|
6768
6258
|
...condition ? { condition } : {},
|
|
6769
|
-
...
|
|
6259
|
+
...when ? { when } : {},
|
|
6260
|
+
...guard ? { guard } : {},
|
|
6770
6261
|
...forEachSource ? { forEach: { source: forEachSource } } : {}
|
|
6771
6262
|
};
|
|
6772
6263
|
if (instr.operation === "put") {
|
|
@@ -6846,13 +6337,13 @@ function buildTransactionSpec(txName, def) {
|
|
|
6846
6337
|
let hasForEach = false;
|
|
6847
6338
|
for (const instr of def.instructions) {
|
|
6848
6339
|
if (instr.kind === "write") {
|
|
6849
|
-
items.push(buildWriteItem(instr, void 0, txName));
|
|
6340
|
+
items.push(buildWriteItem(instr, void 0, txName, def.params));
|
|
6850
6341
|
} else {
|
|
6851
6342
|
hasForEach = true;
|
|
6852
6343
|
const block = instr;
|
|
6853
6344
|
const blockWhen = block.when ? whenSpec(block.when) : void 0;
|
|
6854
6345
|
for (const w of block.body) {
|
|
6855
|
-
const item = buildWriteItem(w, block.source, txName);
|
|
6346
|
+
const item = buildWriteItem(w, block.source, txName, def.params);
|
|
6856
6347
|
items.push(blockWhen && !item.when ? { ...item, when: blockWhen } : item);
|
|
6857
6348
|
}
|
|
6858
6349
|
}
|
|
@@ -7128,7 +6619,7 @@ function convertCondition(condition, place, context) {
|
|
|
7128
6619
|
return out;
|
|
7129
6620
|
}
|
|
7130
6621
|
var CONDITION_LOGICAL_KEYS = /* @__PURE__ */ new Set(["and", "or", "not"]);
|
|
7131
|
-
function
|
|
6622
|
+
function isConditionOperatorObject5(value) {
|
|
7132
6623
|
if (typeof value !== "object" || value === null || Array.isArray(value) || value instanceof Date || isContractParamRef(value) || isContractKeyFieldRef(value)) {
|
|
7133
6624
|
return false;
|
|
7134
6625
|
}
|
|
@@ -7139,7 +6630,7 @@ function isConditionOperatorObject6(value) {
|
|
|
7139
6630
|
function usesConditionTree(obj) {
|
|
7140
6631
|
for (const [key, value] of Object.entries(obj)) {
|
|
7141
6632
|
if (CONDITION_LOGICAL_KEYS.has(key)) return true;
|
|
7142
|
-
if (
|
|
6633
|
+
if (isConditionOperatorObject5(value)) return true;
|
|
7143
6634
|
}
|
|
7144
6635
|
return false;
|
|
7145
6636
|
}
|
|
@@ -7157,7 +6648,7 @@ function convertConditionTree(obj, place, context) {
|
|
|
7157
6648
|
out[key] = convertConditionTree(value, place, `${context} not`);
|
|
7158
6649
|
continue;
|
|
7159
6650
|
}
|
|
7160
|
-
if (!
|
|
6651
|
+
if (!isConditionOperatorObject5(value)) {
|
|
7161
6652
|
out[key] = convertLeaf(value, key, place, `${context} field '${key}'`);
|
|
7162
6653
|
continue;
|
|
7163
6654
|
}
|
|
@@ -8508,14 +7999,17 @@ function buildOperations(queries = {}, commands = {}, transactions = {}, contrac
|
|
|
8508
7999
|
mergeSpecs(transactionSpecs, built.transactions, "transaction");
|
|
8509
8000
|
const contractSpecs = built.contracts;
|
|
8510
8001
|
const contextSpecs = buildContexts(contextInputMap);
|
|
8511
|
-
|
|
8512
|
-
version: SPEC_VERSION,
|
|
8002
|
+
const content = {
|
|
8513
8003
|
queries: querySpecs,
|
|
8514
8004
|
commands: commandSpecs,
|
|
8515
8005
|
...Object.keys(transactionSpecs).length > 0 ? { transactions: transactionSpecs } : {},
|
|
8516
8006
|
...Object.keys(contractSpecs).length > 0 ? { contracts: contractSpecs } : {},
|
|
8517
8007
|
...Object.keys(contextSpecs).length > 0 ? { contexts: contextSpecs } : {}
|
|
8518
8008
|
};
|
|
8009
|
+
return {
|
|
8010
|
+
version: operationsSpecVersion(content),
|
|
8011
|
+
...content
|
|
8012
|
+
};
|
|
8519
8013
|
}
|
|
8520
8014
|
|
|
8521
8015
|
// src/spec/prepared-artifact.ts
|
|
@@ -8754,8 +8248,6 @@ function buildBridgeBundle(queries = {}, commands = {}, registry = MetadataRegis
|
|
|
8754
8248
|
}
|
|
8755
8249
|
|
|
8756
8250
|
export {
|
|
8757
|
-
SPEC_VERSION,
|
|
8758
|
-
MARKER_ROW_ENTITY,
|
|
8759
8251
|
buildManifestEntity,
|
|
8760
8252
|
buildManifest,
|
|
8761
8253
|
conditionParamName,
|
|
@@ -8829,10 +8321,6 @@ export {
|
|
|
8829
8321
|
publicQueryModel,
|
|
8830
8322
|
publicCommandModel,
|
|
8831
8323
|
isPlannedCommandMethod,
|
|
8832
|
-
isTransactionRef,
|
|
8833
|
-
when,
|
|
8834
|
-
defineTransaction,
|
|
8835
|
-
defineTransactions,
|
|
8836
8324
|
buildTransactionSpec,
|
|
8837
8325
|
buildTransactions,
|
|
8838
8326
|
collectContractN1Violations,
|