effect-dynamodb 1.14.0 → 1.16.0
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/Aggregate.d.ts +17 -1
- package/dist/Aggregate.d.ts.map +1 -1
- package/dist/Aggregate.js +413 -82
- package/dist/Aggregate.js.map +1 -1
- package/dist/Batch.d.ts +10 -2
- package/dist/Batch.d.ts.map +1 -1
- package/dist/Batch.js +45 -6
- package/dist/Batch.js.map +1 -1
- package/dist/Collection.d.ts +0 -7
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Collection.js +84 -2
- package/dist/Collection.js.map +1 -1
- package/dist/DynamoClient.d.ts +3 -1
- package/dist/DynamoClient.d.ts.map +1 -1
- package/dist/DynamoClient.js +253 -26
- package/dist/DynamoClient.js.map +1 -1
- package/dist/Entity.d.ts +87 -6
- package/dist/Entity.d.ts.map +1 -1
- package/dist/Entity.js +413 -144
- package/dist/Entity.js.map +1 -1
- package/dist/EventStore.d.ts.map +1 -1
- package/dist/EventStore.js +49 -17
- package/dist/EventStore.js.map +1 -1
- package/dist/Query.d.ts +56 -5
- package/dist/Query.d.ts.map +1 -1
- package/dist/Query.js +206 -30
- package/dist/Query.js.map +1 -1
- package/dist/Transaction.d.ts +2 -2
- package/dist/Transaction.d.ts.map +1 -1
- package/dist/Transaction.js +29 -9
- package/dist/Transaction.js.map +1 -1
- package/dist/internal/BoundCrud.d.ts +76 -9
- package/dist/internal/BoundCrud.d.ts.map +1 -1
- package/dist/internal/BoundCrud.js +22 -1
- package/dist/internal/BoundCrud.js.map +1 -1
- package/dist/internal/BoundQuery.d.ts +75 -13
- package/dist/internal/BoundQuery.d.ts.map +1 -1
- package/dist/internal/BoundQuery.js +85 -11
- package/dist/internal/BoundQuery.js.map +1 -1
- package/dist/internal/BoundVectorQuery.d.ts +9 -0
- package/dist/internal/BoundVectorQuery.d.ts.map +1 -1
- package/dist/internal/BoundVectorQuery.js +3 -2
- package/dist/internal/BoundVectorQuery.js.map +1 -1
- package/dist/internal/EntityCombinators.d.ts +31 -5
- package/dist/internal/EntityCombinators.d.ts.map +1 -1
- package/dist/internal/EntityCombinators.js +7 -7
- package/dist/internal/EntityCombinators.js.map +1 -1
- package/dist/internal/EntityOps.d.ts +14 -1
- package/dist/internal/EntityOps.d.ts.map +1 -1
- package/dist/internal/EntityOps.js +4 -1
- package/dist/internal/EntityOps.js.map +1 -1
- package/dist/internal/TransactWriteOps.d.ts +44 -5
- package/dist/internal/TransactWriteOps.d.ts.map +1 -1
- package/dist/internal/TransactWriteOps.js +98 -20
- package/dist/internal/TransactWriteOps.js.map +1 -1
- package/dist/internal/TransactableOps.d.ts +69 -1
- package/dist/internal/TransactableOps.d.ts.map +1 -1
- package/dist/internal/TransactableOps.js +138 -4
- package/dist/internal/TransactableOps.js.map +1 -1
- package/package.json +2 -2
|
@@ -14,34 +14,68 @@ import { ValidationError } from "@effect-dynamodb/schema/Errors.js";
|
|
|
14
14
|
import { Effect } from "effect";
|
|
15
15
|
import { extractTransactable } from "../Entity.js";
|
|
16
16
|
import { toAttributeMap } from "../Marshaller.js";
|
|
17
|
-
import {
|
|
17
|
+
import { resolveTtlAttributeName } from "../Table.js";
|
|
18
|
+
import { compileExpr, isExpr, parseShorthand } from "./Expr.js";
|
|
19
|
+
import { composePrimaryKey, rejectUnsupportedOp, resolveTableNames, validateAndBuildPutItem, } from "./TransactableOps.js";
|
|
18
20
|
// ---------------------------------------------------------------------------
|
|
19
21
|
// ConditionCheck — composable from EntityGet + condition expression
|
|
20
22
|
// ---------------------------------------------------------------------------
|
|
21
23
|
/** @internal */
|
|
22
24
|
export const ConditionCheckTypeId = Symbol.for("effect-dynamodb/ConditionCheck");
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Compile an op-attached condition (`Entity.create()`'s `attribute_not_exists`,
|
|
27
|
+
* `.condition(...)`, `Entity.condition(...)`) into a DynamoDB expression.
|
|
28
|
+
* `resolveDbName` maps domain field names to their stored attribute names.
|
|
29
|
+
*/
|
|
30
|
+
const compileOpCondition = (entity, cond) => {
|
|
31
|
+
if (cond === undefined)
|
|
32
|
+
return undefined;
|
|
33
|
+
const expr = isExpr(cond) ? cond : parseShorthand(cond);
|
|
34
|
+
return compileExpr(expr, entity._resolveDbName);
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Spread a compiled condition onto a `Put` / `Delete` / `ConditionCheck` entry.
|
|
38
|
+
* `ExpressionAttributeValues` is omitted when empty — DynamoDB rejects an empty
|
|
39
|
+
* map, and value-free conditions (`attribute_not_exists`, `attribute_exists`)
|
|
40
|
+
* produce one.
|
|
41
|
+
*/
|
|
42
|
+
const conditionFields = (condition) => condition === undefined
|
|
43
|
+
? {}
|
|
44
|
+
: {
|
|
45
|
+
ConditionExpression: condition.expression,
|
|
46
|
+
ExpressionAttributeNames: condition.names,
|
|
47
|
+
...(Object.keys(condition.values).length > 0
|
|
48
|
+
? { ExpressionAttributeValues: condition.values }
|
|
49
|
+
: {}),
|
|
50
|
+
};
|
|
26
51
|
/**
|
|
27
52
|
* Compile a list of Entity write ops into marshalled `TransactWriteItems` entries,
|
|
28
|
-
* preserving caller order
|
|
29
|
-
*
|
|
53
|
+
* preserving caller order.
|
|
54
|
+
*
|
|
55
|
+
* **One caller op may emit several items.** A `put` of an entity with `unique`
|
|
56
|
+
* constraints or `versioned: { retain: true }` expands into the main item plus
|
|
57
|
+
* one guarded sentinel per satisfiable constraint plus the v1 snapshot — all
|
|
58
|
+
* derived from the payload, so no read is needed (#113). `provenance` records
|
|
59
|
+
* which caller op each emitted item belongs to; consumers that map cancellation
|
|
60
|
+
* reasons positionally MUST use it instead of assuming 1:1.
|
|
30
61
|
*
|
|
31
62
|
* Does NOT enforce `TRANSACT_WRITE_ITEMS_LIMIT` — the caller counts, because the
|
|
32
63
|
* total may include items this builder never sees (event puts, dedup sentinels).
|
|
64
|
+
* Callers must count the EXPANDED `items.length`, not `operations.length`.
|
|
33
65
|
*/
|
|
34
66
|
export const buildTransactWriteItems = (operations, operation) => Effect.gen(function* () {
|
|
35
67
|
if (operations.length === 0)
|
|
36
|
-
return [];
|
|
68
|
+
return { items: [], provenance: [] };
|
|
37
69
|
const opInfos = [];
|
|
38
|
-
for (
|
|
70
|
+
for (let opIndex = 0; opIndex < operations.length; opIndex++) {
|
|
71
|
+
const op = operations[opIndex];
|
|
39
72
|
// Check for ConditionCheckOp first (has its own TypeId)
|
|
40
73
|
if (op != null && typeof op === "object" && ConditionCheckTypeId in op) {
|
|
41
74
|
const checkOp = op;
|
|
42
75
|
opInfos.push({
|
|
43
76
|
type: "conditionCheck",
|
|
44
77
|
entity: checkOp._entity,
|
|
78
|
+
opIndex,
|
|
45
79
|
key: checkOp._key,
|
|
46
80
|
condition: checkOp._condition,
|
|
47
81
|
});
|
|
@@ -56,10 +90,24 @@ export const buildTransactWriteItems = (operations, operation) => Effect.gen(fun
|
|
|
56
90
|
});
|
|
57
91
|
}
|
|
58
92
|
if (info.opType === "put") {
|
|
59
|
-
|
|
93
|
+
yield* rejectUnsupportedOp(info.entity, operation, "put", info.putKind);
|
|
94
|
+
opInfos.push({
|
|
95
|
+
type: "put",
|
|
96
|
+
entity: info.entity,
|
|
97
|
+
opIndex,
|
|
98
|
+
input: info.input,
|
|
99
|
+
condition: compileOpCondition(info.entity, info.condition),
|
|
100
|
+
});
|
|
60
101
|
}
|
|
61
102
|
else if (info.opType === "delete") {
|
|
62
|
-
|
|
103
|
+
yield* rejectUnsupportedOp(info.entity, operation, "delete", undefined);
|
|
104
|
+
opInfos.push({
|
|
105
|
+
type: "delete",
|
|
106
|
+
entity: info.entity,
|
|
107
|
+
opIndex,
|
|
108
|
+
key: info.key,
|
|
109
|
+
condition: compileOpCondition(info.entity, info.condition),
|
|
110
|
+
});
|
|
63
111
|
}
|
|
64
112
|
else {
|
|
65
113
|
return yield* new ValidationError({
|
|
@@ -70,33 +118,63 @@ export const buildTransactWriteItems = (operations, operation) => Effect.gen(fun
|
|
|
70
118
|
}
|
|
71
119
|
}
|
|
72
120
|
const tableNames = yield* resolveTableNames(opInfos);
|
|
73
|
-
const
|
|
121
|
+
const items = [];
|
|
122
|
+
const provenance = [];
|
|
123
|
+
const push = (item, from) => {
|
|
124
|
+
items.push(item);
|
|
125
|
+
provenance.push(from);
|
|
126
|
+
};
|
|
74
127
|
for (const op of opInfos) {
|
|
75
128
|
const tableName = tableNames.get(op.entity);
|
|
76
129
|
if (op.type === "put") {
|
|
77
|
-
const
|
|
78
|
-
|
|
130
|
+
const built = yield* validateAndBuildPutItem(op.entity, op.input, `${operation}.put`);
|
|
131
|
+
push({
|
|
132
|
+
Put: {
|
|
133
|
+
TableName: tableName,
|
|
134
|
+
Item: built.marshalled,
|
|
135
|
+
...conditionFields(op.condition),
|
|
136
|
+
},
|
|
137
|
+
}, { opIndex: op.opIndex, kind: "main", entityType: op.entity.entityType });
|
|
138
|
+
// Uniqueness sentinels + the v1 retain snapshot. Emitted immediately
|
|
139
|
+
// after their item so a reader of the request sees them as one group;
|
|
140
|
+
// `provenance` is what actually carries the association.
|
|
141
|
+
const ttlAttrName = resolveTtlAttributeName(yield* op.entity._tableTag);
|
|
142
|
+
for (const side of op.entity._buildPutSideItems(built.item, built.now, ttlAttrName)) {
|
|
143
|
+
push({
|
|
144
|
+
Put: {
|
|
145
|
+
TableName: tableName,
|
|
146
|
+
Item: toAttributeMap(side.item),
|
|
147
|
+
...(side.guard ?? {}),
|
|
148
|
+
},
|
|
149
|
+
}, {
|
|
150
|
+
opIndex: op.opIndex,
|
|
151
|
+
kind: side.kind,
|
|
152
|
+
constraintName: side.constraintName,
|
|
153
|
+
fields: side.fields,
|
|
154
|
+
entityType: op.entity.entityType,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
79
157
|
}
|
|
80
158
|
else if (op.type === "delete") {
|
|
81
|
-
|
|
159
|
+
push({
|
|
82
160
|
Delete: {
|
|
83
161
|
TableName: tableName,
|
|
84
162
|
Key: toAttributeMap(composePrimaryKey(op.entity, op.key)),
|
|
163
|
+
...conditionFields(op.condition),
|
|
85
164
|
},
|
|
86
|
-
});
|
|
165
|
+
}, { opIndex: op.opIndex, kind: "main", entityType: op.entity.entityType });
|
|
87
166
|
}
|
|
88
167
|
else {
|
|
89
|
-
|
|
168
|
+
push({
|
|
90
169
|
ConditionCheck: {
|
|
91
170
|
TableName: tableName,
|
|
92
171
|
Key: toAttributeMap(composePrimaryKey(op.entity, op.key)),
|
|
93
172
|
ConditionExpression: op.condition.expression,
|
|
94
|
-
|
|
95
|
-
ExpressionAttributeValues: op.condition.values,
|
|
173
|
+
...conditionFields(op.condition),
|
|
96
174
|
},
|
|
97
|
-
});
|
|
175
|
+
}, { opIndex: op.opIndex, kind: "main", entityType: op.entity.entityType });
|
|
98
176
|
}
|
|
99
177
|
}
|
|
100
|
-
return
|
|
178
|
+
return { items, provenance };
|
|
101
179
|
});
|
|
102
180
|
//# sourceMappingURL=TransactWriteOps.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactWriteOps.js","sourceRoot":"","sources":["../../src/internal/TransactWriteOps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAA;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAElD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"TransactWriteOps.js","sourceRoot":"","sources":["../../src/internal/TransactWriteOps.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,6 +20,64 @@ import type { Entity } from "../Entity.js";
|
|
|
20
20
|
* Batch/Transaction path so both produce identical timestamps.
|
|
21
21
|
*/
|
|
22
22
|
export declare const generateTimestampPrimitive: (now: DateTime.Utc, encoding: DynamoEncoding | null) => string | number;
|
|
23
|
+
/**
|
|
24
|
+
* `Batch.write` cannot host the multi-item lifecycle features that apply to the
|
|
25
|
+
* direction being written (EDD-9049). This is a different judgement from the
|
|
26
|
+
* transact path's: there, a `put`'s side items are derivable and get emitted;
|
|
27
|
+
* here `BatchWriteItem` structurally cannot express them at all.
|
|
28
|
+
*
|
|
29
|
+
* - **No `ConditionExpression`.** A uniqueness sentinel is only a constraint
|
|
30
|
+
* because of `attribute_not_exists(pk)`. Writing one without the guard would
|
|
31
|
+
* overwrite another row's reservation and enforce nothing — strictly worse
|
|
32
|
+
* than writing none, because the table would then *look* guarded.
|
|
33
|
+
* - **No atomicity.** A sentinel or snapshot that lands without its item (or
|
|
34
|
+
* an item without them) is a corrupt partition, and `Batch.write` chunks at
|
|
35
|
+
* 25, so related items can even land in different requests.
|
|
36
|
+
* - **No `UpdateRequest`.** A soft-delete tombstone is a relocation
|
|
37
|
+
* (delete + put at a new sort key); a batch cannot make that one unit.
|
|
38
|
+
*
|
|
39
|
+
* **Direction matters.** `softDelete` changes only the delete path — a `put` of
|
|
40
|
+
* a soft-deletable entity is an ordinary single-item put and is allowed. Gating
|
|
41
|
+
* it on the put side would reject writes that have always been correct.
|
|
42
|
+
*
|
|
43
|
+
* Returns `undefined` when the entity is safe for `Batch.write` in `opType`.
|
|
44
|
+
*/
|
|
45
|
+
export declare const batchRejectReason: (entity: Entity, opType: "put" | "delete") => string | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Reject an op whose semantics the `TransactWriteItems` / `BatchWriteItem`
|
|
48
|
+
* compile path cannot faithfully reproduce.
|
|
49
|
+
*
|
|
50
|
+
* Both paths turn an entity op into a single self-contained `Put` / `Delete`
|
|
51
|
+
* built from the encoded input. That is exactly right for a plain `put` /
|
|
52
|
+
* `delete`, and wrong — silently — for anything whose contract needs a
|
|
53
|
+
* different DynamoDB verb, extra items, or a service the compile step does not
|
|
54
|
+
* have. Loud beats silent (#100).
|
|
55
|
+
*
|
|
56
|
+
* **What this gate covers.** Cases that are silently wrong (`upsert` — see
|
|
57
|
+
* `PutKind`) or that cannot be working for anyone today: a `refs` entity writes
|
|
58
|
+
* an item whose ref attribute is absent, so every later read fails to decode; a
|
|
59
|
+
* `generatedId` entity dies outright (no `Crypto` in scope); a vector-indexed
|
|
60
|
+
* entity writes an item with no embedding, so it silently drops out of the index.
|
|
61
|
+
*
|
|
62
|
+
* **The multi-item lifecycle features split by direction (#113).** `unique`,
|
|
63
|
+
* `versioned: { retain }` and `softDelete` all need MORE than one item per write.
|
|
64
|
+
* The line between "expand" and "reject" is whether the extra items are
|
|
65
|
+
* derivable from the caller's payload or only from stored state:
|
|
66
|
+
*
|
|
67
|
+
* - **put** — the sentinel and the v1 snapshot come from the payload being
|
|
68
|
+
* written. `transactWrite` expands into them (`Entity._buildPutSideItems`).
|
|
69
|
+
* - **delete** — the sentinel to release is keyed by the *stored* item's unique
|
|
70
|
+
* values, a retain snapshot copies the *stored* row, and a soft-delete
|
|
71
|
+
* tombstone IS the stored row relocated to a new sort key. All three need a
|
|
72
|
+
* read this path does not do (and a read would introduce a TOCTOU window that
|
|
73
|
+
* only another ConditionCheck could close). Rejected with **EDD-9048**.
|
|
74
|
+
*
|
|
75
|
+
* `Batch.write` rejects BOTH directions (**EDD-9049**) — see `batchRejectReason`.
|
|
76
|
+
*
|
|
77
|
+
* `capability` names what the caller would have to give up, so the message can
|
|
78
|
+
* say why rather than just "unsupported".
|
|
79
|
+
*/
|
|
80
|
+
export declare const rejectUnsupportedOp: (entity: Entity, operation: string, opType: "put" | "delete", putKind: "put" | "create" | "upsert" | undefined) => Effect.Effect<void, ValidationError>;
|
|
23
81
|
/**
|
|
24
82
|
* Resolve table names for a set of entity infos, deduplicating by entity reference.
|
|
25
83
|
*/
|
|
@@ -37,6 +95,16 @@ export declare const composePrimaryKey: (entity: Entity, key: Record<string, unk
|
|
|
37
95
|
* `Schema.encode(inputSchema)`, then assembles the DynamoDB item with system
|
|
38
96
|
* fields and composite keys. Substituted self-date schemas + RedactedFromValue
|
|
39
97
|
* are handled in the encode pass — no per-field serialization needed.
|
|
98
|
+
*
|
|
99
|
+
* Returns the unmarshalled `item` alongside the marshalled one, plus the `now`
|
|
100
|
+
* the timestamps were generated from. `Entity._buildPutSideItems` needs both to
|
|
101
|
+
* derive uniqueness sentinels and the v1 version snapshot from the same values
|
|
102
|
+
* that were written (#113), and re-deriving `now` there would risk a skew
|
|
103
|
+
* between an item's `createdAt` and its snapshot's TTL.
|
|
40
104
|
*/
|
|
41
|
-
export declare const validateAndBuildPutItem: (entity: Entity, input: Record<string, unknown>, operation: string) => Effect.Effect<
|
|
105
|
+
export declare const validateAndBuildPutItem: (entity: Entity, input: Record<string, unknown>, operation: string) => Effect.Effect<{
|
|
106
|
+
readonly item: Record<string, unknown>;
|
|
107
|
+
readonly marshalled: Record<string, import("@aws-sdk/client-dynamodb").AttributeValue>;
|
|
108
|
+
readonly now: DateTime.Utc;
|
|
109
|
+
}, ValidationError>;
|
|
42
110
|
//# sourceMappingURL=TransactableOps.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactableOps.d.ts","sourceRoot":"","sources":["../../src/internal/TransactableOps.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAA;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAA;AACnE,OAAO,KAAK,WAAW,MAAM,wCAAwC,CAAA;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAG1C;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,GACrC,KAAK,QAAQ,CAAC,GAAG,EACjB,UAAU,cAAc,GAAG,IAAI,KAC9B,MAAM,GAAG,MAaX,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,aAAa,CAAC;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,wiBAU/E,CAAA;AAEJ;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,EACd,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"TransactableOps.d.ts","sourceRoot":"","sources":["../../src/internal/TransactableOps.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAA;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAA;AACnE,OAAO,KAAK,WAAW,MAAM,wCAAwC,CAAA;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAG1C;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,GACrC,KAAK,QAAQ,CAAC,GAAG,EACjB,UAAU,cAAc,GAAG,IAAI,KAC9B,MAAM,GAAG,MAaX,CAAA;AAYD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,EAAE,QAAQ,KAAK,GAAG,QAAQ,KAAG,MAAM,GAAG,SAcrF,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,MAAM,EACd,WAAW,MAAM,EACjB,QAAQ,KAAK,GAAG,QAAQ,EACxB,SAAS,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,KAC/C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CA4DrC,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,aAAa,CAAC;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,wiBAU/E,CAAA;AAEJ;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,EACd,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAaxB,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,uBAAuB,GAClC,QAAQ,MAAM,EACd,OAAO,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,WAAW,MAAM,KAChB,MAAM,CAAC,MAAM,CACd;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,0BAA0B,EAAE,cAAc,CAAC,CAAA;IACtF,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAA;CAC3B,EACD,eAAe,CA8Eb,CAAA"}
|
|
@@ -33,6 +33,117 @@ export const generateTimestampPrimitive = (now, encoding) => {
|
|
|
33
33
|
return Math.floor(ms / 1000);
|
|
34
34
|
}
|
|
35
35
|
};
|
|
36
|
+
/** Render the configured multi-item features for an error message. */
|
|
37
|
+
const describeFeatures = (features) => {
|
|
38
|
+
const labels = features.map((f) => f === "unique" ? "`unique`" : f === "retain" ? "`versioned: { retain: true }`" : "`softDelete`");
|
|
39
|
+
return labels.length === 1
|
|
40
|
+
? labels[0]
|
|
41
|
+
: `${labels.slice(0, -1).join(", ")} and ${labels[labels.length - 1]}`;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* `Batch.write` cannot host the multi-item lifecycle features that apply to the
|
|
45
|
+
* direction being written (EDD-9049). This is a different judgement from the
|
|
46
|
+
* transact path's: there, a `put`'s side items are derivable and get emitted;
|
|
47
|
+
* here `BatchWriteItem` structurally cannot express them at all.
|
|
48
|
+
*
|
|
49
|
+
* - **No `ConditionExpression`.** A uniqueness sentinel is only a constraint
|
|
50
|
+
* because of `attribute_not_exists(pk)`. Writing one without the guard would
|
|
51
|
+
* overwrite another row's reservation and enforce nothing — strictly worse
|
|
52
|
+
* than writing none, because the table would then *look* guarded.
|
|
53
|
+
* - **No atomicity.** A sentinel or snapshot that lands without its item (or
|
|
54
|
+
* an item without them) is a corrupt partition, and `Batch.write` chunks at
|
|
55
|
+
* 25, so related items can even land in different requests.
|
|
56
|
+
* - **No `UpdateRequest`.** A soft-delete tombstone is a relocation
|
|
57
|
+
* (delete + put at a new sort key); a batch cannot make that one unit.
|
|
58
|
+
*
|
|
59
|
+
* **Direction matters.** `softDelete` changes only the delete path — a `put` of
|
|
60
|
+
* a soft-deletable entity is an ordinary single-item put and is allowed. Gating
|
|
61
|
+
* it on the put side would reject writes that have always been correct.
|
|
62
|
+
*
|
|
63
|
+
* Returns `undefined` when the entity is safe for `Batch.write` in `opType`.
|
|
64
|
+
*/
|
|
65
|
+
export const batchRejectReason = (entity, opType) => {
|
|
66
|
+
const features = entity._multiItemWriteFeatures.filter((f) =>
|
|
67
|
+
// `unique` and `retain` add items to BOTH directions (sentinel write /
|
|
68
|
+
// release, snapshot on create / on overwrite-and-delete). `softDelete` only
|
|
69
|
+
// ever changes a delete.
|
|
70
|
+
f === "softDelete" ? opType === "delete" : true);
|
|
71
|
+
if (features.length === 0)
|
|
72
|
+
return undefined;
|
|
73
|
+
return (`[EDD-9049] Batch.write cannot ${opType} an entity configured with ${describeFeatures(features)} — ` +
|
|
74
|
+
"BatchWriteItem has no ConditionExpression (which is the whole of a uniqueness " +
|
|
75
|
+
"sentinel's correctness), no UpdateRequest, and no atomicity across its 25-item " +
|
|
76
|
+
"chunks. Use Transaction.transactWrite, or the entity's own operation.");
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Reject an op whose semantics the `TransactWriteItems` / `BatchWriteItem`
|
|
80
|
+
* compile path cannot faithfully reproduce.
|
|
81
|
+
*
|
|
82
|
+
* Both paths turn an entity op into a single self-contained `Put` / `Delete`
|
|
83
|
+
* built from the encoded input. That is exactly right for a plain `put` /
|
|
84
|
+
* `delete`, and wrong — silently — for anything whose contract needs a
|
|
85
|
+
* different DynamoDB verb, extra items, or a service the compile step does not
|
|
86
|
+
* have. Loud beats silent (#100).
|
|
87
|
+
*
|
|
88
|
+
* **What this gate covers.** Cases that are silently wrong (`upsert` — see
|
|
89
|
+
* `PutKind`) or that cannot be working for anyone today: a `refs` entity writes
|
|
90
|
+
* an item whose ref attribute is absent, so every later read fails to decode; a
|
|
91
|
+
* `generatedId` entity dies outright (no `Crypto` in scope); a vector-indexed
|
|
92
|
+
* entity writes an item with no embedding, so it silently drops out of the index.
|
|
93
|
+
*
|
|
94
|
+
* **The multi-item lifecycle features split by direction (#113).** `unique`,
|
|
95
|
+
* `versioned: { retain }` and `softDelete` all need MORE than one item per write.
|
|
96
|
+
* The line between "expand" and "reject" is whether the extra items are
|
|
97
|
+
* derivable from the caller's payload or only from stored state:
|
|
98
|
+
*
|
|
99
|
+
* - **put** — the sentinel and the v1 snapshot come from the payload being
|
|
100
|
+
* written. `transactWrite` expands into them (`Entity._buildPutSideItems`).
|
|
101
|
+
* - **delete** — the sentinel to release is keyed by the *stored* item's unique
|
|
102
|
+
* values, a retain snapshot copies the *stored* row, and a soft-delete
|
|
103
|
+
* tombstone IS the stored row relocated to a new sort key. All three need a
|
|
104
|
+
* read this path does not do (and a read would introduce a TOCTOU window that
|
|
105
|
+
* only another ConditionCheck could close). Rejected with **EDD-9048**.
|
|
106
|
+
*
|
|
107
|
+
* `Batch.write` rejects BOTH directions (**EDD-9049**) — see `batchRejectReason`.
|
|
108
|
+
*
|
|
109
|
+
* `capability` names what the caller would have to give up, so the message can
|
|
110
|
+
* say why rather than just "unsupported".
|
|
111
|
+
*/
|
|
112
|
+
export const rejectUnsupportedOp = (entity, operation, opType, putKind) => {
|
|
113
|
+
const fail = (capability, reason) => new ValidationError({
|
|
114
|
+
entityType: entity.entityType,
|
|
115
|
+
operation,
|
|
116
|
+
cause: `${operation}: ${capability} is not supported here — ${reason}`,
|
|
117
|
+
});
|
|
118
|
+
// --- op-kind level -------------------------------------------------------
|
|
119
|
+
if (opType === "put" && putKind === "upsert") {
|
|
120
|
+
return Effect.fail(fail("upsert", "upsert is an UpdateItem whose SET clause uses if_not_exists for createdAt, " +
|
|
121
|
+
"immutable fields and the version counter. Compiling it as a Put would reset " +
|
|
122
|
+
"them. Use put() or create() here, or run the upsert as its own operation."));
|
|
123
|
+
}
|
|
124
|
+
// --- multi-item lifecycle, delete direction (EDD-9048) -------------------
|
|
125
|
+
// The put direction is EXPANDED instead — see the doc comment.
|
|
126
|
+
if (opType === "delete" && entity._multiItemWriteFeatures.length > 0) {
|
|
127
|
+
return Effect.fail(fail(`[EDD-9048] deleting an entity configured with ${describeFeatures(entity._multiItemWriteFeatures)}`, "the extra items a delete must write are derived from the STORED item — the sentinel " +
|
|
128
|
+
"to release is keyed by its unique values, a retain snapshot copies it, and a " +
|
|
129
|
+
"soft-delete tombstone is that row relocated to a new sort key. This path never " +
|
|
130
|
+
"reads, so it cannot build them. Run the delete as its own operation " +
|
|
131
|
+
"(db.entities.X.delete(...)), which reads the item first."));
|
|
132
|
+
}
|
|
133
|
+
// --- entity-configuration level -----------------------------------------
|
|
134
|
+
if (opType === "put" && entity._resolvedRefs.length > 0) {
|
|
135
|
+
return Effect.fail(fail("a ref", "write-time ref hydration reads the referenced entity, which this compile step " +
|
|
136
|
+
"cannot do; the ref attribute would be written empty."));
|
|
137
|
+
}
|
|
138
|
+
if (opType === "put" && entity.generatedId != null) {
|
|
139
|
+
return Effect.fail(fail("a generated id", "id generation needs the Crypto service, which is not in scope here."));
|
|
140
|
+
}
|
|
141
|
+
if (opType === "put" && Object.keys(entity._vectorIndexes ?? {}).length > 0) {
|
|
142
|
+
return Effect.fail(fail("a vector index", "computing the embedding needs the Embedder service, which is not in scope here; " +
|
|
143
|
+
"the item would be written without its vector and drop out of the index."));
|
|
144
|
+
}
|
|
145
|
+
return Effect.void;
|
|
146
|
+
};
|
|
36
147
|
/**
|
|
37
148
|
* Resolve table names for a set of entity infos, deduplicating by entity reference.
|
|
38
149
|
*/
|
|
@@ -52,9 +163,15 @@ export const resolveTableNames = (infos) => Effect.gen(function* () {
|
|
|
52
163
|
export const composePrimaryKey = (entity, key) => {
|
|
53
164
|
const primary = entity.indexes.primary;
|
|
54
165
|
const schema = entity._schema;
|
|
166
|
+
// The caller's key is a DOMAIN record (`{ takenAt: DateTime }`), and every
|
|
167
|
+
// `KeyComposer` input must first go through the composite key-form rule or it
|
|
168
|
+
// composes a different string than `Entity.put` wrote — a `DateEpochMs` PK
|
|
169
|
+
// composite made `Batch.get` return null and `Batch.write(delete)` report
|
|
170
|
+
// success against a row it never touched (#111).
|
|
171
|
+
const recordKeyForm = entity._keyForm(key);
|
|
55
172
|
return {
|
|
56
|
-
[primary.pk.field]: KeyComposer.composePk(schema, entity.entityType, primary,
|
|
57
|
-
[primary.sk.field]: KeyComposer.composeSk(schema, entity.entityType, 1, primary,
|
|
173
|
+
[primary.pk.field]: KeyComposer.composePk(schema, entity.entityType, primary, recordKeyForm),
|
|
174
|
+
[primary.sk.field]: KeyComposer.composeSk(schema, entity.entityType, 1, primary, recordKeyForm),
|
|
58
175
|
};
|
|
59
176
|
};
|
|
60
177
|
/**
|
|
@@ -64,6 +181,12 @@ export const composePrimaryKey = (entity, key) => {
|
|
|
64
181
|
* `Schema.encode(inputSchema)`, then assembles the DynamoDB item with system
|
|
65
182
|
* fields and composite keys. Substituted self-date schemas + RedactedFromValue
|
|
66
183
|
* are handled in the encode pass — no per-field serialization needed.
|
|
184
|
+
*
|
|
185
|
+
* Returns the unmarshalled `item` alongside the marshalled one, plus the `now`
|
|
186
|
+
* the timestamps were generated from. `Entity._buildPutSideItems` needs both to
|
|
187
|
+
* derive uniqueness sentinels and the v1 version snapshot from the same values
|
|
188
|
+
* that were written (#113), and re-deriving `now` there would risk a skew
|
|
189
|
+
* between an item's `createdAt` and its snapshot's TTL.
|
|
67
190
|
*/
|
|
68
191
|
export const validateAndBuildPutItem = (entity, input, operation) => Effect.gen(function* () {
|
|
69
192
|
// Clock-backed time source resolved once per op; threaded into the sync
|
|
@@ -78,7 +201,11 @@ export const validateAndBuildPutItem = (entity, input, operation) => Effect.gen(
|
|
|
78
201
|
})));
|
|
79
202
|
const item = { ...encoded };
|
|
80
203
|
item.__edd_e__ = entity.entityType;
|
|
81
|
-
|
|
204
|
+
// Same normalisation `Entity.put` applies. Without it a `BigIntFromString`
|
|
205
|
+
// composite composed `txn_420` here and `txn_000…0420` there, so the two
|
|
206
|
+
// APIs wrote two different rows for the same logical item and neither
|
|
207
|
+
// accessor could read the transact-written one (#111).
|
|
208
|
+
const keys = KeyComposer.composeAllKeys(entity._schema, entity.entityType, 1, entity.indexes, entity._keyForm(encoded));
|
|
82
209
|
Object.assign(item, keys);
|
|
83
210
|
// System fields (collision-aware). When a timestamp field collides with a
|
|
84
211
|
// model-declared field, the user may have supplied their own value
|
|
@@ -97,6 +224,13 @@ export const validateAndBuildPutItem = (entity, input, operation) => Effect.gen(
|
|
|
97
224
|
}
|
|
98
225
|
if (sf.version)
|
|
99
226
|
item[sf.version] = 1;
|
|
227
|
+
// Rename domain fields to their stored attribute names, in the same
|
|
228
|
+
// position `Entity.put` does (after keys + system fields, before sparse
|
|
229
|
+
// flattening). Omitting it gave a `field:`-renamed entity a differently
|
|
230
|
+
// shaped item depending on whether `put` or `transactWrite` wrote it — and
|
|
231
|
+
// `_buildPutSideItems` derives the v1 retain snapshot from this same item,
|
|
232
|
+
// so the snapshot inherited the wrong shape too (#111).
|
|
233
|
+
entity._renameToDynamo(item);
|
|
100
234
|
// Flatten sparse-map fields into per-entry top-level attributes. Throws
|
|
101
235
|
// on invalid keys; surface as ValidationError at the entity boundary.
|
|
102
236
|
try {
|
|
@@ -109,6 +243,6 @@ export const validateAndBuildPutItem = (entity, input, operation) => Effect.gen(
|
|
|
109
243
|
cause: e instanceof Error ? e.message : String(e),
|
|
110
244
|
});
|
|
111
245
|
}
|
|
112
|
-
return toAttributeMap(item);
|
|
246
|
+
return { item, marshalled: toAttributeMap(item), now };
|
|
113
247
|
});
|
|
114
248
|
//# sourceMappingURL=TransactableOps.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactableOps.js","sourceRoot":"","sources":["../../src/internal/TransactableOps.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAA;AACnE,OAAO,KAAK,WAAW,MAAM,wCAAwC,CAAA;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEjD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEjD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CACxC,GAAiB,EACjB,QAA+B,EACd,EAAE;IACnB,IAAI,CAAC,QAAQ;QAAE,OAAO,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;IAC7C,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA;IACtC,QAAQ,QAAQ,CAAC,OAAO,EAAE,CAAC;QACzB,KAAK,QAAQ;YACX,iEAAiE;YACjE,mEAAmE;YACnE,OAAO,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QAChC,KAAK,SAAS;YACZ,OAAO,EAAE,CAAA;QACX,KAAK,cAAc;YACjB,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,CAAA;IAChC,CAAC;AACH,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAiD,EAAE,EAAE,CACrF,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC5C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACjC,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAA;YAC7C,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QACnC,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC,CAAC,CAAA;AAEJ;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,MAAc,EACd,GAA4B,EACH,EAAE;IAC3B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,OAAQ,CAAA;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAA;IAC7B,OAAO;QACL,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"TransactableOps.js","sourceRoot":"","sources":["../../src/internal/TransactableOps.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-dynamodb",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.0",
|
|
4
4
|
"description": "Effect TS ORM for DynamoDB — schema-driven entity modeling, single-table design, composite keys, transactions, and Stream-based pagination",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@aws-sdk/client-dynamodb": "^3.1104.0",
|
|
50
50
|
"@aws-sdk/util-dynamodb": "^3.700.0",
|
|
51
|
-
"@effect-dynamodb/schema": "^1.
|
|
51
|
+
"@effect-dynamodb/schema": "^1.16.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"effect": "^4.0.0-rc.112"
|