graphddb 0.8.1 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/behaviors-DDltNivc.d.ts +217 -0
- package/dist/cdc/index.d.ts +5 -4
- package/dist/cdc/index.js +3 -3
- package/dist/{chunk-HNY2EJPV.js → chunk-7OCXY4R6.js} +1 -1
- package/dist/{chunk-L2NEDS7U.js → chunk-GWWRXIHF.js} +260 -12
- package/dist/{chunk-T44OB5GU.js → chunk-HLFNCKFV.js} +105 -11
- package/dist/{chunk-LAT64YCZ.js → chunk-MBJ4JVRM.js} +680 -25
- package/dist/{chunk-S2NI4PBW.js → chunk-PHXUFAY2.js} +7 -5
- package/dist/{chunk-GS4C5VGO.js → chunk-VECUS35D.js} +2 -2
- package/dist/{chunk-L4QRCHRQ.js → chunk-WOFRHRXY.js} +6 -25
- package/dist/cli.js +366 -80
- package/dist/index.d.ts +131 -5
- package/dist/index.js +121 -5
- package/dist/internal/index.d.ts +6 -5
- package/dist/internal/index.js +7 -7
- package/dist/{key-DZtjAQDh.d.ts → key-CWytoEaE.d.ts} +93 -5
- package/dist/linter/index.d.ts +6 -5
- package/dist/{linter-DQY7gUEk.d.ts → linter-jEwmZotm.d.ts} +1 -1
- package/dist/{prepared-artifact-HFealr1q.d.ts → prepared-artifact-CwH5ezFq.d.ts} +4 -4
- package/dist/spec/index.d.ts +225 -24
- package/dist/spec/index.js +17 -9
- package/dist/testing/index.d.ts +3 -2
- package/dist/testing/index.js +32 -5
- package/dist/transform/index.d.ts +2 -1
- package/dist/transform/index.js +2 -2
- package/dist/{types-2PMXEn5x.d.ts → types-CgXS-4Ox.d.ts} +299 -28
- package/dist/{types-DW__-Icc.d.ts → types-nk5okD7d.d.ts} +1 -1
- package/docs/python-bridge.md +33 -49
- package/package.json +11 -3
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
normalizeTopLevelSelect,
|
|
18
18
|
parseChange,
|
|
19
19
|
validateInlineSnapshotSelect
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-7OCXY4R6.js";
|
|
21
21
|
import {
|
|
22
22
|
EXPR_VERSION,
|
|
23
23
|
MARKER_ROW_ENTITY,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
isScpExprConditionInput,
|
|
27
27
|
isTransactionDefinition,
|
|
28
28
|
isTransactionRef
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-WOFRHRXY.js";
|
|
30
30
|
import {
|
|
31
31
|
BATCH_GET_MAX_KEYS,
|
|
32
32
|
CONDITION_OPERATOR_KEYS,
|
|
@@ -61,7 +61,7 @@ import {
|
|
|
61
61
|
serializeFieldValue,
|
|
62
62
|
serializeRawCondition,
|
|
63
63
|
skTemplate
|
|
64
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-GWWRXIHF.js";
|
|
65
65
|
import {
|
|
66
66
|
TableMapping,
|
|
67
67
|
createColumnMap,
|
|
@@ -2520,7 +2520,12 @@ function renderWrite(op, key, params, contextLabel) {
|
|
|
2520
2520
|
return { ...base, item: renderRecord(op.item, key, params, `${contextLabel} item`) };
|
|
2521
2521
|
}
|
|
2522
2522
|
if (op.operation === "update") {
|
|
2523
|
-
|
|
2523
|
+
const add = op.add !== void 0 && Object.keys(op.add).length > 0 ? renderRecord(op.add, key, params, `${contextLabel} add`) : void 0;
|
|
2524
|
+
return {
|
|
2525
|
+
...base,
|
|
2526
|
+
changes: renderRecord(op.changes, key, params, `${contextLabel} changes`),
|
|
2527
|
+
...add !== void 0 ? { add } : {}
|
|
2528
|
+
};
|
|
2524
2529
|
}
|
|
2525
2530
|
return base;
|
|
2526
2531
|
}
|
|
@@ -2534,11 +2539,34 @@ async function executeSingleWrite(w, retry) {
|
|
|
2534
2539
|
return;
|
|
2535
2540
|
}
|
|
2536
2541
|
if (w.operation === "update") {
|
|
2542
|
+
if (w.add !== void 0) {
|
|
2543
|
+
const primaryOptions = { ...options ?? {}, add: w.add };
|
|
2544
|
+
if (w.condition === void 0) {
|
|
2545
|
+
await executeUpdate(w.modelClass, w.key, w.changes ?? {}, primaryOptions);
|
|
2546
|
+
return;
|
|
2547
|
+
}
|
|
2548
|
+
try {
|
|
2549
|
+
await executeUpdate(w.modelClass, w.key, w.changes ?? {}, primaryOptions);
|
|
2550
|
+
} catch (e) {
|
|
2551
|
+
if (!isConditionalCheckFailure(e)) throw e;
|
|
2552
|
+
const fallbackOptions = {
|
|
2553
|
+
add: w.add,
|
|
2554
|
+
...retry !== void 0 ? { retry } : {}
|
|
2555
|
+
};
|
|
2556
|
+
await executeUpdate(w.modelClass, w.key, {}, fallbackOptions);
|
|
2557
|
+
}
|
|
2558
|
+
return;
|
|
2559
|
+
}
|
|
2537
2560
|
await executeUpdate(w.modelClass, w.key, w.changes ?? {}, options);
|
|
2538
2561
|
return;
|
|
2539
2562
|
}
|
|
2540
2563
|
await executeDelete(w.modelClass, w.key, options);
|
|
2541
2564
|
}
|
|
2565
|
+
function isConditionalCheckFailure(e) {
|
|
2566
|
+
if (e === null || typeof e !== "object") return false;
|
|
2567
|
+
const name = e.name;
|
|
2568
|
+
return name === "ConditionalCheckFailedException" || name === "ConditionalCheckFailed";
|
|
2569
|
+
}
|
|
2542
2570
|
function renderConditionCheck(check, key, params, contextLabel) {
|
|
2543
2571
|
const modelClass = check.entity.modelClass;
|
|
2544
2572
|
const referencedKey = {};
|
|
@@ -4428,8 +4456,17 @@ function isConcreteLiteral(value) {
|
|
|
4428
4456
|
const t = typeof value;
|
|
4429
4457
|
return value === null || value instanceof Date || t === "string" || t === "number" || t === "boolean";
|
|
4430
4458
|
}
|
|
4431
|
-
function makeFragment(intent, entity, input, use, condition) {
|
|
4459
|
+
function makeFragment(intent, entity, input, use, condition, add) {
|
|
4432
4460
|
const checked = assertFaithfulInput(input ?? {}, intent, entity.name);
|
|
4461
|
+
let checkedAdd;
|
|
4462
|
+
if (add !== void 0 && Object.keys(add).length > 0) {
|
|
4463
|
+
if (intent !== "update") {
|
|
4464
|
+
throw new Error(
|
|
4465
|
+
`mutation: the '${intent}' fragment on '${entity.name}' declares \`add\`, but an atomic \`ADD\` (issue #301) is only valid on an \`update\` fragment.`
|
|
4466
|
+
);
|
|
4467
|
+
}
|
|
4468
|
+
checkedAdd = assertFaithfulInput(add, intent, entity.name);
|
|
4469
|
+
}
|
|
4433
4470
|
if (use !== void 0 && !isEntityWritesDefinition(use)) {
|
|
4434
4471
|
throw new Error(
|
|
4435
4472
|
`mutation: the '${intent}' fragment on '${entity.name}' was given a \`use:\` that is not an \`entityWrites(...)\` save contract. \`use:\` takes the WHOLE \`writes\` set (an \`entityWrites(...)\` value), never a single lifecycle (e.g. \`Model.writes.create\`) \u2014 the fragment's intent already selects the lifecycle.`
|
|
@@ -4441,6 +4478,7 @@ function makeFragment(intent, entity, input, use, condition) {
|
|
|
4441
4478
|
intent,
|
|
4442
4479
|
entity,
|
|
4443
4480
|
input: checked,
|
|
4481
|
+
...checkedAdd !== void 0 ? { add: checkedAdd } : {},
|
|
4444
4482
|
...use !== void 0 ? { use } : {},
|
|
4445
4483
|
...checkedCondition !== void 0 ? { condition: checkedCondition } : {}
|
|
4446
4484
|
};
|
|
@@ -4536,7 +4574,8 @@ function mutation(nameOrBody, maybeBody) {
|
|
|
4536
4574
|
const { intent, entity } = resolveDescriptorTarget(descriptor, alias);
|
|
4537
4575
|
const merged = mergeBindings(descriptor, intent, alias);
|
|
4538
4576
|
const resolved = resolveAliasRefs(merged, aliasToIndex, alias);
|
|
4539
|
-
|
|
4577
|
+
const add = descriptor.add !== void 0 ? resolveAliasRefs(descriptor.add, aliasToIndex, alias) : void 0;
|
|
4578
|
+
return makeFragment(intent, entity, resolved, descriptor.use, descriptor.condition, add);
|
|
4540
4579
|
});
|
|
4541
4580
|
return { [COMMAND_PLAN_BRAND]: true, name, fragments };
|
|
4542
4581
|
}
|
|
@@ -4680,8 +4719,16 @@ function buildCommandContract(methods) {
|
|
|
4680
4719
|
const resolved = {};
|
|
4681
4720
|
for (const [name, body] of Object.entries(methods)) {
|
|
4682
4721
|
if (isPublicWriteDescriptor(body)) {
|
|
4683
|
-
const { plan: plan2, select, condition, mode, description } = writeDescriptorToPlan(name, body);
|
|
4684
|
-
resolved[name] = finalizeDescriptorCommand(
|
|
4722
|
+
const { plan: plan2, select, condition, mode, batchWriteEligible, description } = writeDescriptorToPlan(name, body);
|
|
4723
|
+
resolved[name] = finalizeDescriptorCommand(
|
|
4724
|
+
name,
|
|
4725
|
+
plan2,
|
|
4726
|
+
select,
|
|
4727
|
+
condition,
|
|
4728
|
+
mode,
|
|
4729
|
+
description,
|
|
4730
|
+
batchWriteEligible
|
|
4731
|
+
);
|
|
4685
4732
|
continue;
|
|
4686
4733
|
}
|
|
4687
4734
|
if (isPublicCompositeDescriptor(body)) {
|
|
@@ -4771,7 +4818,7 @@ function buildPlannedCommandMethod(name, planned) {
|
|
|
4771
4818
|
...returnSelection !== void 0 ? { returnSelection } : {}
|
|
4772
4819
|
};
|
|
4773
4820
|
}
|
|
4774
|
-
function finalizeDescriptorCommand(name, plan2, select, condition,
|
|
4821
|
+
function finalizeDescriptorCommand(name, plan2, select, condition, declaredMode, description, batchWriteEligible = false) {
|
|
4775
4822
|
const planned = {
|
|
4776
4823
|
[PLANNED_COMMAND_BRAND]: true,
|
|
4777
4824
|
plan: plan2,
|
|
@@ -4779,6 +4826,13 @@ function finalizeDescriptorCommand(name, plan2, select, condition, mode, descrip
|
|
|
4779
4826
|
select
|
|
4780
4827
|
};
|
|
4781
4828
|
const built = buildPlannedCommandMethod(name, planned);
|
|
4829
|
+
const promoted = built.ops !== void 0 && built.ops.length > 1 || built.conditionChecks !== void 0 || built.edgeWrites !== void 0 || built.derivedUpdates !== void 0 || built.uniqueGuards !== void 0 || built.outboxEvents !== void 0 || built.idempotencyGuard !== void 0 || built.maintainWrites !== void 0 || built.maintainOutbox !== void 0;
|
|
4830
|
+
if (declaredMode === "batchWrite" && (!batchWriteEligible || promoted)) {
|
|
4831
|
+
throw new Error(
|
|
4832
|
+
`publishCommand: method '${name}' declares mode: 'batchWrite', but DynamoDB's BatchWriteItem carries no ConditionExpression, no Update and no composed derived effects \u2014 only an UNCONDITIONAL put/delete qualifies (an \`upsert\` or a condition-free \`remove\` with no derived effects). This method is ${!batchWriteEligible ? "conditional / not an unconditional put/delete" : "promoted to an atomic TransactWriteItems by its derived effects"}. Use mode: 'transaction' (atomic TransactWriteItems, condition-capable, \u226425) \u2014 or the transaction forEach form for atomic per-item values.`
|
|
4833
|
+
);
|
|
4834
|
+
}
|
|
4835
|
+
const mode = declaredMode ?? (batchWriteEligible && !promoted ? "batchWrite" : "transaction");
|
|
4782
4836
|
const builtOp = built.op;
|
|
4783
4837
|
const op = condition !== void 0 ? { ...builtOp, condition } : builtOp;
|
|
4784
4838
|
return {
|
|
@@ -4992,6 +5046,35 @@ function writeDescriptorToPlan(name, d) {
|
|
|
4992
5046
|
const model = resolveDescriptorModel(d[intent], name);
|
|
4993
5047
|
const keyFieldNames = Object.keys(d.key);
|
|
4994
5048
|
const inputFieldNames = d.input !== void 0 ? Object.keys(d.input) : [];
|
|
5049
|
+
const addFieldNames = d.add !== void 0 ? Object.keys(d.add) : [];
|
|
5050
|
+
if (addFieldNames.length > 0) {
|
|
5051
|
+
if (intent !== "update") {
|
|
5052
|
+
throw new Error(
|
|
5053
|
+
`publishCommand: method '${name}' declares \`add\` on a '${intent}' descriptor, but an atomic \`ADD\` (issue #301) is only valid on an \`update\` (a standalone UpdateItem). A create / upsert / remove cannot carry \`add\`.`
|
|
5054
|
+
);
|
|
5055
|
+
}
|
|
5056
|
+
if (d.add === null || typeof d.add !== "object") {
|
|
5057
|
+
throw new Error(`publishCommand: method '${name}' has a non-object \`add\`.`);
|
|
5058
|
+
}
|
|
5059
|
+
for (const field of addFieldNames) {
|
|
5060
|
+
const v = d.add[field];
|
|
5061
|
+
if (!isParam(v) || v.kind !== "number") {
|
|
5062
|
+
throw new Error(
|
|
5063
|
+
`publishCommand: method '${name}' binds \`add.${field}\` to a non-\`param.number()\` value. An atomic \`ADD\` delta (issue #301) is a caller \`param.number()\` \u2014 a compile-time constant or a non-numeric param is not a valid atomic increment.`
|
|
5064
|
+
);
|
|
5065
|
+
}
|
|
5066
|
+
if (keyFieldNames.includes(field)) {
|
|
5067
|
+
throw new Error(
|
|
5068
|
+
`publishCommand: method '${name}' binds field '${field}' in both \`key\` and \`add\`. A primary-key field cannot be atomically incremented \u2014 it belongs in \`key\` only.`
|
|
5069
|
+
);
|
|
5070
|
+
}
|
|
5071
|
+
if (inputFieldNames.includes(field)) {
|
|
5072
|
+
throw new Error(
|
|
5073
|
+
`publishCommand: method '${name}' binds field '${field}' in both \`input\` (SET) and \`add\` (ADD). A field is either overwritten (\`input\`) or atomically incremented (\`add\`), never both.`
|
|
5074
|
+
);
|
|
5075
|
+
}
|
|
5076
|
+
}
|
|
5077
|
+
}
|
|
4995
5078
|
const plan2 = mutation(name, ($) => {
|
|
4996
5079
|
const keyRefs = (fields) => {
|
|
4997
5080
|
const out = {};
|
|
@@ -5009,13 +5092,17 @@ function writeDescriptorToPlan(name, d) {
|
|
|
5009
5092
|
const descriptor = {
|
|
5010
5093
|
[intent]: (() => model),
|
|
5011
5094
|
key: keyRefs(keyFieldNames),
|
|
5012
|
-
...inputFieldNames.length > 0 ? { input: inputRefs(d.input) } : {}
|
|
5095
|
+
...inputFieldNames.length > 0 ? { input: inputRefs(d.input) } : {},
|
|
5096
|
+
// #301: `add` deltas are always `param.number()` (validated above), so each binds
|
|
5097
|
+
// to a same-named `$.field` placeholder — the runtime resolves the caller delta.
|
|
5098
|
+
...addFieldNames.length > 0 ? { add: keyRefs(addFieldNames) } : {}
|
|
5013
5099
|
};
|
|
5014
5100
|
return { [name]: descriptor };
|
|
5015
5101
|
});
|
|
5016
5102
|
const select = d.result !== void 0 && d.result.select !== void 0 ? d.result.select : void 0;
|
|
5017
5103
|
const condition = d.condition !== void 0 ? descriptorConditionRecord(d.condition, name) : void 0;
|
|
5018
|
-
|
|
5104
|
+
const batchWriteEligible = (intent === "upsert" || intent === "remove") && d.condition === void 0;
|
|
5105
|
+
return { plan: plan2, select, condition, mode: d.mode, batchWriteEligible, description: d.description };
|
|
5019
5106
|
}
|
|
5020
5107
|
|
|
5021
5108
|
// src/spec/mutation-command.ts
|
|
@@ -5782,6 +5869,12 @@ function compileFragment(fragment, index = 0, resolveEntityRef = null, maintenan
|
|
|
5782
5869
|
if (keyFieldSet.has(field)) continue;
|
|
5783
5870
|
changes[field] = renderInputLeaf(leaf, false, index, field, resolveEntityRef);
|
|
5784
5871
|
}
|
|
5872
|
+
const add = {};
|
|
5873
|
+
if (fragment.add !== void 0) {
|
|
5874
|
+
for (const [field, leaf] of Object.entries(fragment.add)) {
|
|
5875
|
+
add[field] = renderInputLeaf(leaf, false, index, field, resolveEntityRef);
|
|
5876
|
+
}
|
|
5877
|
+
}
|
|
5785
5878
|
op = {
|
|
5786
5879
|
__isContractMethodOp: true,
|
|
5787
5880
|
entity: fragment.entity,
|
|
@@ -5789,6 +5882,7 @@ function compileFragment(fragment, index = 0, resolveEntityRef = null, maintenan
|
|
|
5789
5882
|
keys: wholeKeysSentinel(),
|
|
5790
5883
|
keyFields,
|
|
5791
5884
|
...fragment.intent === "update" ? { changes } : {},
|
|
5885
|
+
...fragment.intent === "update" && Object.keys(add).length > 0 ? { add } : {},
|
|
5792
5886
|
// #242: a conditioned update / remove — the write is a CAS-style gate (the
|
|
5793
5887
|
// row must satisfy the condition or the write is rejected, not silently
|
|
5794
5888
|
// committed). Absent → an unconditional update / remove (unchanged).
|