dyno-table 1.0.0-alpha.1 → 1.0.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/README.md +751 -172
- package/dist/builder-types-C_PDZhnP.d.ts +118 -0
- package/dist/builder-types-DtwbqMeF.d.cts +118 -0
- package/dist/builders/condition-check-builder.cjs +394 -0
- package/dist/builders/condition-check-builder.cjs.map +1 -0
- package/dist/builders/condition-check-builder.d.cts +157 -0
- package/dist/builders/condition-check-builder.d.ts +157 -0
- package/dist/builders/condition-check-builder.js +392 -0
- package/dist/builders/condition-check-builder.js.map +1 -0
- package/dist/builders/delete-builder.cjs +405 -0
- package/dist/builders/delete-builder.cjs.map +1 -0
- package/dist/builders/delete-builder.d.cts +166 -0
- package/dist/builders/delete-builder.d.ts +166 -0
- package/dist/builders/delete-builder.js +403 -0
- package/dist/builders/delete-builder.js.map +1 -0
- package/dist/builders/paginator.cjs +199 -0
- package/dist/builders/paginator.cjs.map +1 -0
- package/dist/builders/paginator.d.cts +179 -0
- package/dist/builders/paginator.d.ts +179 -0
- package/dist/builders/paginator.js +197 -0
- package/dist/builders/paginator.js.map +1 -0
- package/dist/builders/put-builder.cjs +476 -0
- package/dist/builders/put-builder.cjs.map +1 -0
- package/dist/builders/put-builder.d.cts +274 -0
- package/dist/builders/put-builder.d.ts +274 -0
- package/dist/builders/put-builder.js +474 -0
- package/dist/builders/put-builder.js.map +1 -0
- package/dist/builders/query-builder.cjs +674 -0
- package/dist/builders/query-builder.cjs.map +1 -0
- package/dist/builders/query-builder.d.cts +6 -0
- package/dist/builders/query-builder.d.ts +6 -0
- package/dist/builders/query-builder.js +672 -0
- package/dist/builders/query-builder.js.map +1 -0
- package/dist/builders/transaction-builder.cjs +894 -0
- package/dist/builders/transaction-builder.cjs.map +1 -0
- package/dist/builders/transaction-builder.d.cts +511 -0
- package/dist/builders/transaction-builder.d.ts +511 -0
- package/dist/builders/transaction-builder.js +892 -0
- package/dist/builders/transaction-builder.js.map +1 -0
- package/dist/builders/update-builder.cjs +627 -0
- package/dist/builders/update-builder.cjs.map +1 -0
- package/dist/builders/update-builder.d.cts +365 -0
- package/dist/builders/update-builder.d.ts +365 -0
- package/dist/builders/update-builder.js +625 -0
- package/dist/builders/update-builder.js.map +1 -0
- package/dist/conditions--ld9a78i.d.ts +331 -0
- package/dist/conditions-ChhQWd6z.d.cts +331 -0
- package/dist/conditions.cjs +59 -0
- package/dist/conditions.cjs.map +1 -0
- package/dist/conditions.d.cts +3 -0
- package/dist/conditions.d.ts +3 -0
- package/dist/conditions.js +43 -0
- package/dist/conditions.js.map +1 -0
- package/dist/entity.cjs +228 -0
- package/dist/entity.cjs.map +1 -0
- package/dist/entity.d.cts +149 -0
- package/dist/entity.d.ts +149 -0
- package/dist/entity.js +224 -0
- package/dist/entity.js.map +1 -0
- package/dist/query-builder-Csror9Iu.d.ts +507 -0
- package/dist/query-builder-D2FM9rsu.d.cts +507 -0
- package/dist/standard-schema.cjs +4 -0
- package/dist/standard-schema.cjs.map +1 -0
- package/dist/standard-schema.d.cts +57 -0
- package/dist/standard-schema.d.ts +57 -0
- package/dist/standard-schema.js +3 -0
- package/dist/standard-schema.js.map +1 -0
- package/dist/table-BEhBPy2G.d.cts +364 -0
- package/dist/table-BW3cmUqr.d.ts +364 -0
- package/dist/{index.js → table.cjs} +88 -127
- package/dist/table.cjs.map +1 -0
- package/dist/table.d.cts +12 -0
- package/dist/table.d.ts +12 -0
- package/dist/{index.cjs → table.js} +86 -176
- package/dist/table.js.map +1 -0
- package/dist/types.cjs +4 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +22 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/partition-key-template.cjs +19 -0
- package/dist/utils/partition-key-template.cjs.map +1 -0
- package/dist/utils/partition-key-template.d.cts +32 -0
- package/dist/utils/partition-key-template.d.ts +32 -0
- package/dist/utils/partition-key-template.js +17 -0
- package/dist/utils/partition-key-template.js.map +1 -0
- package/dist/utils/sort-key-template.cjs +19 -0
- package/dist/utils/sort-key-template.cjs.map +1 -0
- package/dist/utils/sort-key-template.d.cts +35 -0
- package/dist/utils/sort-key-template.d.ts +35 -0
- package/dist/utils/sort-key-template.js +17 -0
- package/dist/utils/sort-key-template.js.map +1 -0
- package/package.json +77 -7
- package/dist/index.d.cts +0 -2971
- package/dist/index.d.ts +0 -2971
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
// src/conditions.ts
|
|
2
|
+
var createComparisonCondition = (type) => (attr, value) => ({
|
|
3
|
+
type,
|
|
4
|
+
attr,
|
|
5
|
+
value
|
|
6
|
+
});
|
|
7
|
+
var eq = createComparisonCondition("eq");
|
|
8
|
+
var ne = createComparisonCondition("ne");
|
|
9
|
+
var lt = createComparisonCondition("lt");
|
|
10
|
+
var lte = createComparisonCondition("lte");
|
|
11
|
+
var gt = createComparisonCondition("gt");
|
|
12
|
+
var gte = createComparisonCondition("gte");
|
|
13
|
+
var between = (attr, lower, upper) => ({
|
|
14
|
+
type: "between",
|
|
15
|
+
attr,
|
|
16
|
+
value: [lower, upper]
|
|
17
|
+
});
|
|
18
|
+
var beginsWith = createComparisonCondition("beginsWith");
|
|
19
|
+
var contains = createComparisonCondition("contains");
|
|
20
|
+
var attributeExists = (attr) => ({
|
|
21
|
+
type: "attributeExists",
|
|
22
|
+
attr
|
|
23
|
+
});
|
|
24
|
+
var attributeNotExists = (attr) => ({
|
|
25
|
+
type: "attributeNotExists",
|
|
26
|
+
attr
|
|
27
|
+
});
|
|
28
|
+
var and = (...conditions) => ({
|
|
29
|
+
type: "and",
|
|
30
|
+
conditions
|
|
31
|
+
});
|
|
32
|
+
var or = (...conditions) => ({
|
|
33
|
+
type: "or",
|
|
34
|
+
conditions
|
|
35
|
+
});
|
|
36
|
+
var not = (condition) => ({
|
|
37
|
+
type: "not",
|
|
38
|
+
condition
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// src/expression.ts
|
|
42
|
+
var generateAttributeName = (params, attr) => {
|
|
43
|
+
for (const [existingName, existingAttr] of Object.entries(params.expressionAttributeNames)) {
|
|
44
|
+
if (existingAttr === attr) {
|
|
45
|
+
return existingName;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const attrName = `#${Object.keys(params.expressionAttributeNames).length}`;
|
|
49
|
+
params.expressionAttributeNames[attrName] = attr;
|
|
50
|
+
return attrName;
|
|
51
|
+
};
|
|
52
|
+
var generateValueName = (params, value) => {
|
|
53
|
+
const valueName = `:${params.valueCounter.count++}`;
|
|
54
|
+
params.expressionAttributeValues[valueName] = value;
|
|
55
|
+
return valueName;
|
|
56
|
+
};
|
|
57
|
+
var validateCondition = (condition, requiresAttr = true, requiresValue = true) => {
|
|
58
|
+
if (requiresAttr && !condition.attr) {
|
|
59
|
+
throw new Error(`Attribute is required for ${condition.type} condition`);
|
|
60
|
+
}
|
|
61
|
+
if (requiresValue && condition.value === void 0) {
|
|
62
|
+
throw new Error(`Value is required for ${condition.type} condition`);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var buildComparisonExpression = (condition, operator, params) => {
|
|
66
|
+
validateCondition(condition);
|
|
67
|
+
if (!condition.attr) {
|
|
68
|
+
throw new Error(`Attribute is required for ${condition.type} condition`);
|
|
69
|
+
}
|
|
70
|
+
const attrName = generateAttributeName(params, condition.attr);
|
|
71
|
+
const valueName = generateValueName(params, condition.value);
|
|
72
|
+
return `${attrName} ${operator} ${valueName}`;
|
|
73
|
+
};
|
|
74
|
+
var buildBetweenExpression = (condition, params) => {
|
|
75
|
+
validateCondition(condition);
|
|
76
|
+
if (!condition.attr) {
|
|
77
|
+
throw new Error(`Attribute is required for ${condition.type} condition`);
|
|
78
|
+
}
|
|
79
|
+
if (!Array.isArray(condition.value) || condition.value.length !== 2) {
|
|
80
|
+
throw new Error("Between condition requires an array of two values");
|
|
81
|
+
}
|
|
82
|
+
const attrName = generateAttributeName(params, condition.attr);
|
|
83
|
+
const lowerName = generateValueName(params, condition.value[0]);
|
|
84
|
+
const upperName = generateValueName(params, condition.value[1]);
|
|
85
|
+
return `${attrName} BETWEEN ${lowerName} AND ${upperName}`;
|
|
86
|
+
};
|
|
87
|
+
var buildFunctionExpression = (functionName, condition, params) => {
|
|
88
|
+
validateCondition(condition);
|
|
89
|
+
if (!condition.attr) {
|
|
90
|
+
throw new Error(`Attribute is required for ${condition.type} condition`);
|
|
91
|
+
}
|
|
92
|
+
const attrName = generateAttributeName(params, condition.attr);
|
|
93
|
+
const valueName = generateValueName(params, condition.value);
|
|
94
|
+
return `${functionName}(${attrName}, ${valueName})`;
|
|
95
|
+
};
|
|
96
|
+
var buildAttributeFunction = (functionName, condition, params) => {
|
|
97
|
+
validateCondition(condition, true, false);
|
|
98
|
+
if (!condition.attr) {
|
|
99
|
+
throw new Error(`Attribute is required for ${condition.type} condition`);
|
|
100
|
+
}
|
|
101
|
+
const attrName = generateAttributeName(params, condition.attr);
|
|
102
|
+
return `${functionName}(${attrName})`;
|
|
103
|
+
};
|
|
104
|
+
var buildLogicalExpression = (operator, conditions, params) => {
|
|
105
|
+
if (!conditions || conditions.length === 0) {
|
|
106
|
+
throw new Error(`At least one condition is required for ${operator} expression`);
|
|
107
|
+
}
|
|
108
|
+
const expressions = conditions.map((c) => buildExpression(c, params));
|
|
109
|
+
return `(${expressions.join(` ${operator} `)})`;
|
|
110
|
+
};
|
|
111
|
+
var buildExpression = (condition, params) => {
|
|
112
|
+
if (!condition) return "";
|
|
113
|
+
try {
|
|
114
|
+
const expressionBuilders = {
|
|
115
|
+
eq: () => buildComparisonExpression(condition, "=", params),
|
|
116
|
+
ne: () => buildComparisonExpression(condition, "<>", params),
|
|
117
|
+
lt: () => buildComparisonExpression(condition, "<", params),
|
|
118
|
+
lte: () => buildComparisonExpression(condition, "<=", params),
|
|
119
|
+
gt: () => buildComparisonExpression(condition, ">", params),
|
|
120
|
+
gte: () => buildComparisonExpression(condition, ">=", params),
|
|
121
|
+
between: () => buildBetweenExpression(condition, params),
|
|
122
|
+
beginsWith: () => buildFunctionExpression("begins_with", condition, params),
|
|
123
|
+
contains: () => buildFunctionExpression("contains", condition, params),
|
|
124
|
+
attributeExists: () => buildAttributeFunction("attribute_exists", condition, params),
|
|
125
|
+
attributeNotExists: () => buildAttributeFunction("attribute_not_exists", condition, params),
|
|
126
|
+
and: () => {
|
|
127
|
+
if (!condition.conditions) {
|
|
128
|
+
throw new Error("Conditions array is required for AND operator");
|
|
129
|
+
}
|
|
130
|
+
return buildLogicalExpression("AND", condition.conditions, params);
|
|
131
|
+
},
|
|
132
|
+
or: () => {
|
|
133
|
+
if (!condition.conditions) {
|
|
134
|
+
throw new Error("Conditions array is required for OR operator");
|
|
135
|
+
}
|
|
136
|
+
return buildLogicalExpression("OR", condition.conditions, params);
|
|
137
|
+
},
|
|
138
|
+
not: () => {
|
|
139
|
+
if (!condition.condition) {
|
|
140
|
+
throw new Error("Condition is required for NOT operator");
|
|
141
|
+
}
|
|
142
|
+
return `NOT (${buildExpression(condition.condition, params)})`;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const builder = expressionBuilders[condition.type];
|
|
146
|
+
if (!builder) {
|
|
147
|
+
throw new Error(`Unknown condition type: ${condition.type}`);
|
|
148
|
+
}
|
|
149
|
+
return builder();
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (error instanceof Error) {
|
|
152
|
+
console.error(`Error building expression for condition type ${condition.type}:`, error.message);
|
|
153
|
+
} else {
|
|
154
|
+
console.error(`Error building expression for condition type ${condition.type}:`, error);
|
|
155
|
+
}
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// src/utils/debug-expression.ts
|
|
161
|
+
function debugCommand(command) {
|
|
162
|
+
const result = {};
|
|
163
|
+
function replaceAliases(expressionString) {
|
|
164
|
+
if (!expressionString) {
|
|
165
|
+
return expressionString;
|
|
166
|
+
}
|
|
167
|
+
let replacedString = expressionString;
|
|
168
|
+
for (const alias in command.expressionAttributeNames) {
|
|
169
|
+
const attributeName = command.expressionAttributeNames[alias];
|
|
170
|
+
const regex = new RegExp(alias, "g");
|
|
171
|
+
replacedString = replacedString.replace(regex, attributeName);
|
|
172
|
+
}
|
|
173
|
+
for (const alias in command.expressionAttributeValues) {
|
|
174
|
+
let attributeValue = command.expressionAttributeValues[alias];
|
|
175
|
+
if (attributeValue instanceof Set) {
|
|
176
|
+
const array = Array.from(attributeValue);
|
|
177
|
+
attributeValue = `Set(${array.length}){${array.map((v) => JSON.stringify(v)).join(", ")}}`;
|
|
178
|
+
} else {
|
|
179
|
+
attributeValue = JSON.stringify(attributeValue);
|
|
180
|
+
}
|
|
181
|
+
const regex = new RegExp(alias, "g");
|
|
182
|
+
replacedString = replacedString.replace(regex, attributeValue);
|
|
183
|
+
}
|
|
184
|
+
return replacedString;
|
|
185
|
+
}
|
|
186
|
+
if (command.updateExpression) {
|
|
187
|
+
result.updateExpression = replaceAliases(command.updateExpression);
|
|
188
|
+
}
|
|
189
|
+
if (command.conditionExpression) {
|
|
190
|
+
result.conditionExpression = replaceAliases(command.conditionExpression);
|
|
191
|
+
}
|
|
192
|
+
if (command.filterExpression) {
|
|
193
|
+
result.filterExpression = replaceAliases(command.filterExpression);
|
|
194
|
+
}
|
|
195
|
+
if (command.keyConditionExpression) {
|
|
196
|
+
result.keyConditionExpression = replaceAliases(command.keyConditionExpression);
|
|
197
|
+
}
|
|
198
|
+
if (command.projectionExpression) {
|
|
199
|
+
result.projectionExpression = replaceAliases(command.projectionExpression);
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
raw: command,
|
|
203
|
+
readable: result
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// src/builders/update-builder.ts
|
|
208
|
+
var UpdateBuilder = class {
|
|
209
|
+
updates = [];
|
|
210
|
+
options = {
|
|
211
|
+
returnValues: "ALL_NEW"
|
|
212
|
+
};
|
|
213
|
+
executor;
|
|
214
|
+
tableName;
|
|
215
|
+
key;
|
|
216
|
+
constructor(executor, tableName, key) {
|
|
217
|
+
this.executor = executor;
|
|
218
|
+
this.tableName = tableName;
|
|
219
|
+
this.key = key;
|
|
220
|
+
}
|
|
221
|
+
set(valuesOrPath, value) {
|
|
222
|
+
if (typeof valuesOrPath === "object") {
|
|
223
|
+
for (const [key, value2] of Object.entries(valuesOrPath)) {
|
|
224
|
+
this.updates.push({
|
|
225
|
+
type: "SET",
|
|
226
|
+
path: key,
|
|
227
|
+
value: value2
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
} else {
|
|
231
|
+
this.updates.push({
|
|
232
|
+
type: "SET",
|
|
233
|
+
path: valuesOrPath,
|
|
234
|
+
value
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
return this;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Removes an attribute from the item.
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```typescript
|
|
244
|
+
* // Remove simple attributes
|
|
245
|
+
* builder
|
|
246
|
+
* .remove('temporaryTag')
|
|
247
|
+
* .remove('previousLocation');
|
|
248
|
+
*
|
|
249
|
+
* // Remove nested attributes
|
|
250
|
+
* builder
|
|
251
|
+
* .remove('metadata.testData')
|
|
252
|
+
* .remove('stats.experimentalMetrics');
|
|
253
|
+
* ```
|
|
254
|
+
*
|
|
255
|
+
* @param path - The path to the attribute to remove
|
|
256
|
+
* @returns The builder instance for method chaining
|
|
257
|
+
*/
|
|
258
|
+
remove(path) {
|
|
259
|
+
this.updates.push({
|
|
260
|
+
type: "REMOVE",
|
|
261
|
+
path
|
|
262
|
+
});
|
|
263
|
+
return this;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Adds a value to a number attribute or adds elements to a set.
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```typescript
|
|
270
|
+
* // Increment counters
|
|
271
|
+
* builder
|
|
272
|
+
* .add('escapeAttempts', 1)
|
|
273
|
+
* .add('feedingCount', 1);
|
|
274
|
+
*
|
|
275
|
+
* // Add to sets
|
|
276
|
+
* builder
|
|
277
|
+
* .add('knownBehaviors', new Set(['PACK_HUNTING', 'AMBUSH_TACTICS']))
|
|
278
|
+
* .add('visitedZones', new Set(['ZONE_A', 'ZONE_B']));
|
|
279
|
+
* ```
|
|
280
|
+
*
|
|
281
|
+
* @param path - The path to the attribute to update
|
|
282
|
+
* @param value - The value to add (number or set)
|
|
283
|
+
* @returns The builder instance for method chaining
|
|
284
|
+
*/
|
|
285
|
+
add(path, value) {
|
|
286
|
+
this.updates.push({
|
|
287
|
+
type: "ADD",
|
|
288
|
+
path,
|
|
289
|
+
value
|
|
290
|
+
});
|
|
291
|
+
return this;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Removes elements from a set attribute.
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* ```typescript
|
|
298
|
+
* // Remove from sets using arrays
|
|
299
|
+
* builder.deleteElementsFromSet(
|
|
300
|
+
* 'allowedHabitats',
|
|
301
|
+
* ['JUNGLE', 'COASTAL']
|
|
302
|
+
* );
|
|
303
|
+
*
|
|
304
|
+
* // Remove from sets using Set DynamoItems
|
|
305
|
+
* builder.deleteElementsFromSet(
|
|
306
|
+
* 'knownBehaviors',
|
|
307
|
+
* new Set(['NOCTURNAL', 'TERRITORIAL'])
|
|
308
|
+
* );
|
|
309
|
+
*
|
|
310
|
+
* // Remove from nested sets
|
|
311
|
+
* builder.deleteElementsFromSet(
|
|
312
|
+
* 'stats.compatibleSpecies',
|
|
313
|
+
* ['VELOCIRAPTOR', 'DILOPHOSAURUS']
|
|
314
|
+
* );
|
|
315
|
+
* ```
|
|
316
|
+
*
|
|
317
|
+
* @param path - The path to the set attribute
|
|
318
|
+
* @param value - Elements to remove (array or Set)
|
|
319
|
+
* @returns The builder instance for method chaining
|
|
320
|
+
*/
|
|
321
|
+
deleteElementsFromSet(path, value) {
|
|
322
|
+
let valuesToDelete;
|
|
323
|
+
if (Array.isArray(value)) {
|
|
324
|
+
valuesToDelete = new Set(value);
|
|
325
|
+
} else {
|
|
326
|
+
valuesToDelete = value;
|
|
327
|
+
}
|
|
328
|
+
this.updates.push({
|
|
329
|
+
type: "DELETE",
|
|
330
|
+
path,
|
|
331
|
+
value: valuesToDelete
|
|
332
|
+
});
|
|
333
|
+
return this;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Adds a condition that must be satisfied for the update to succeed.
|
|
337
|
+
*
|
|
338
|
+
* @example
|
|
339
|
+
* ```typescript
|
|
340
|
+
* // Simple condition
|
|
341
|
+
* builder.condition(op =>
|
|
342
|
+
* op.eq('status', 'ACTIVE')
|
|
343
|
+
* );
|
|
344
|
+
*
|
|
345
|
+
* // Health check condition
|
|
346
|
+
* builder.condition(op =>
|
|
347
|
+
* op.and([
|
|
348
|
+
* op.gt('health', 50),
|
|
349
|
+
* op.eq('status', 'HUNTING')
|
|
350
|
+
* ])
|
|
351
|
+
* );
|
|
352
|
+
*
|
|
353
|
+
* // Complex security condition
|
|
354
|
+
* builder.condition(op =>
|
|
355
|
+
* op.and([
|
|
356
|
+
* op.attributeExists('securitySystem'),
|
|
357
|
+
* op.eq('containmentStatus', 'SECURE'),
|
|
358
|
+
* op.lt('aggressionLevel', 8)
|
|
359
|
+
* ])
|
|
360
|
+
* );
|
|
361
|
+
*
|
|
362
|
+
* // Version check (optimistic locking)
|
|
363
|
+
* builder.condition(op =>
|
|
364
|
+
* op.eq('version', currentVersion)
|
|
365
|
+
* );
|
|
366
|
+
* ```
|
|
367
|
+
*
|
|
368
|
+
* @param condition - Either a Condition DynamoItem or a callback function that builds the condition
|
|
369
|
+
* @returns The builder instance for method chaining
|
|
370
|
+
*/
|
|
371
|
+
condition(condition) {
|
|
372
|
+
if (typeof condition === "function") {
|
|
373
|
+
const conditionOperator = {
|
|
374
|
+
eq,
|
|
375
|
+
ne,
|
|
376
|
+
lt,
|
|
377
|
+
lte,
|
|
378
|
+
gt,
|
|
379
|
+
gte,
|
|
380
|
+
between,
|
|
381
|
+
beginsWith,
|
|
382
|
+
contains,
|
|
383
|
+
attributeExists,
|
|
384
|
+
attributeNotExists,
|
|
385
|
+
and,
|
|
386
|
+
or,
|
|
387
|
+
not
|
|
388
|
+
};
|
|
389
|
+
this.options.condition = condition(conditionOperator);
|
|
390
|
+
} else {
|
|
391
|
+
this.options.condition = condition;
|
|
392
|
+
}
|
|
393
|
+
return this;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Sets which item attributes to include in the response.
|
|
397
|
+
*
|
|
398
|
+
* Available options:
|
|
399
|
+
* - ALL_NEW: All attributes after the update
|
|
400
|
+
* - UPDATED_NEW: Only updated attributes, new values
|
|
401
|
+
* - ALL_OLD: All attributes before the update
|
|
402
|
+
* - UPDATED_OLD: Only updated attributes, old values
|
|
403
|
+
* - NONE: No attributes returned (default)
|
|
404
|
+
*
|
|
405
|
+
* @example
|
|
406
|
+
* ```typescript
|
|
407
|
+
* // Get complete updated dinosaur
|
|
408
|
+
* const result = await builder
|
|
409
|
+
* .set('status', 'SLEEPING')
|
|
410
|
+
* .returnValues('ALL_NEW')
|
|
411
|
+
* .execute();
|
|
412
|
+
*
|
|
413
|
+
* // Track specific attribute changes
|
|
414
|
+
* const result = await builder
|
|
415
|
+
* .set({
|
|
416
|
+
* 'stats.health': 100,
|
|
417
|
+
* 'stats.energy': 95
|
|
418
|
+
* })
|
|
419
|
+
* .returnValues('UPDATED_OLD')
|
|
420
|
+
* .execute();
|
|
421
|
+
*
|
|
422
|
+
* if (result.item) {
|
|
423
|
+
* console.log('Previous health:', result.item.stats?.health);
|
|
424
|
+
* }
|
|
425
|
+
* ```
|
|
426
|
+
*
|
|
427
|
+
* @param returnValues - Which attributes to return in the response
|
|
428
|
+
* @returns The builder instance for method chaining
|
|
429
|
+
*/
|
|
430
|
+
returnValues(returnValues) {
|
|
431
|
+
this.options.returnValues = returnValues;
|
|
432
|
+
return this;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Generate the DynamoDB command parameters
|
|
436
|
+
*/
|
|
437
|
+
toDynamoCommand() {
|
|
438
|
+
if (this.updates.length === 0) {
|
|
439
|
+
throw new Error("No update actions specified");
|
|
440
|
+
}
|
|
441
|
+
const expressionParams = {
|
|
442
|
+
expressionAttributeNames: {},
|
|
443
|
+
expressionAttributeValues: {},
|
|
444
|
+
valueCounter: { count: 0 }
|
|
445
|
+
};
|
|
446
|
+
let updateExpression = "";
|
|
447
|
+
const setUpdates = [];
|
|
448
|
+
const removeUpdates = [];
|
|
449
|
+
const addUpdates = [];
|
|
450
|
+
const deleteUpdates = [];
|
|
451
|
+
for (const update of this.updates) {
|
|
452
|
+
switch (update.type) {
|
|
453
|
+
case "SET":
|
|
454
|
+
setUpdates.push(update);
|
|
455
|
+
break;
|
|
456
|
+
case "REMOVE":
|
|
457
|
+
removeUpdates.push(update);
|
|
458
|
+
break;
|
|
459
|
+
case "ADD":
|
|
460
|
+
addUpdates.push(update);
|
|
461
|
+
break;
|
|
462
|
+
case "DELETE":
|
|
463
|
+
deleteUpdates.push(update);
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
if (setUpdates.length > 0) {
|
|
468
|
+
updateExpression += "SET ";
|
|
469
|
+
updateExpression += setUpdates.map((update) => {
|
|
470
|
+
const attrName = generateAttributeName(expressionParams, update.path);
|
|
471
|
+
const valueName = generateValueName(expressionParams, update.value);
|
|
472
|
+
expressionParams.expressionAttributeValues[valueName] = update.value;
|
|
473
|
+
return `${attrName} = ${valueName}`;
|
|
474
|
+
}).join(", ");
|
|
475
|
+
}
|
|
476
|
+
if (removeUpdates.length > 0) {
|
|
477
|
+
if (updateExpression) {
|
|
478
|
+
updateExpression += " ";
|
|
479
|
+
}
|
|
480
|
+
updateExpression += "REMOVE ";
|
|
481
|
+
updateExpression += removeUpdates.map((update) => {
|
|
482
|
+
return generateAttributeName(expressionParams, update.path);
|
|
483
|
+
}).join(", ");
|
|
484
|
+
}
|
|
485
|
+
if (addUpdates.length > 0) {
|
|
486
|
+
if (updateExpression) {
|
|
487
|
+
updateExpression += " ";
|
|
488
|
+
}
|
|
489
|
+
updateExpression += "ADD ";
|
|
490
|
+
updateExpression += addUpdates.map((update) => {
|
|
491
|
+
const attrName = generateAttributeName(expressionParams, update.path);
|
|
492
|
+
const valueName = generateValueName(expressionParams, update.value);
|
|
493
|
+
return `${attrName} ${valueName}`;
|
|
494
|
+
}).join(", ");
|
|
495
|
+
}
|
|
496
|
+
if (deleteUpdates.length > 0) {
|
|
497
|
+
if (updateExpression) {
|
|
498
|
+
updateExpression += " ";
|
|
499
|
+
}
|
|
500
|
+
updateExpression += "DELETE ";
|
|
501
|
+
updateExpression += deleteUpdates.map((update) => {
|
|
502
|
+
const attrName = generateAttributeName(expressionParams, update.path);
|
|
503
|
+
const valueName = generateValueName(expressionParams, update.value);
|
|
504
|
+
return `${attrName} ${valueName}`;
|
|
505
|
+
}).join(", ");
|
|
506
|
+
}
|
|
507
|
+
let conditionExpression;
|
|
508
|
+
if (this.options.condition) {
|
|
509
|
+
conditionExpression = buildExpression(this.options.condition, expressionParams);
|
|
510
|
+
}
|
|
511
|
+
const { expressionAttributeNames, expressionAttributeValues } = expressionParams;
|
|
512
|
+
return {
|
|
513
|
+
tableName: this.tableName,
|
|
514
|
+
key: this.key,
|
|
515
|
+
updateExpression,
|
|
516
|
+
conditionExpression,
|
|
517
|
+
expressionAttributeNames: Object.keys(expressionAttributeNames).length > 0 ? expressionAttributeNames : void 0,
|
|
518
|
+
expressionAttributeValues: Object.keys(expressionAttributeValues).length > 0 ? expressionAttributeValues : void 0,
|
|
519
|
+
returnValues: this.options.returnValues
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Adds this update operation to a transaction.
|
|
524
|
+
*
|
|
525
|
+
* @example
|
|
526
|
+
* ```typescript
|
|
527
|
+
* const transaction = new TransactionBuilder(executor);
|
|
528
|
+
*
|
|
529
|
+
* // Update dinosaur status and habitat occupancy atomically
|
|
530
|
+
* new UpdateBuilder(executor, 'dinosaurs', { id: 'TREX-001' })
|
|
531
|
+
* .set('location', 'PADDOCK_A')
|
|
532
|
+
* .set('status', 'CONTAINED')
|
|
533
|
+
* .withTransaction(transaction);
|
|
534
|
+
*
|
|
535
|
+
* new UpdateBuilder(executor, 'habitats', { id: 'PADDOCK-A' })
|
|
536
|
+
* .add('occupants', 1)
|
|
537
|
+
* .set('lastOccupied', new Date().toISOString())
|
|
538
|
+
* .withTransaction(transaction);
|
|
539
|
+
*
|
|
540
|
+
* // Execute all operations atomically
|
|
541
|
+
* await transaction.execute();
|
|
542
|
+
* ```
|
|
543
|
+
*
|
|
544
|
+
* @param transaction - The transaction builder to add this operation to
|
|
545
|
+
* @returns The builder instance for method chaining
|
|
546
|
+
*/
|
|
547
|
+
withTransaction(transaction) {
|
|
548
|
+
const command = this.toDynamoCommand();
|
|
549
|
+
transaction.updateWithCommand(command);
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Gets a human-readable representation of the update command.
|
|
553
|
+
*
|
|
554
|
+
* @example
|
|
555
|
+
* ```typescript
|
|
556
|
+
* // Create complex update
|
|
557
|
+
* const builder = new UpdateBuilder(executor, 'dinosaurs', { id: 'RAPTOR-001' })
|
|
558
|
+
* .set({
|
|
559
|
+
* status: 'HUNTING',
|
|
560
|
+
* 'stats.health': 95,
|
|
561
|
+
* 'behavior.lastObserved': new Date().toISOString()
|
|
562
|
+
* })
|
|
563
|
+
* .add('huntingSuccesses', 1)
|
|
564
|
+
* .condition(op => op.gt('health', 50));
|
|
565
|
+
*
|
|
566
|
+
* // Debug the update
|
|
567
|
+
* const debugInfo = builder.debug();
|
|
568
|
+
* console.log('Update operation:', debugInfo);
|
|
569
|
+
* ```
|
|
570
|
+
*
|
|
571
|
+
* @returns A readable representation of the update command with resolved expressions
|
|
572
|
+
*/
|
|
573
|
+
debug() {
|
|
574
|
+
const command = this.toDynamoCommand();
|
|
575
|
+
return debugCommand(command);
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Executes the update operation against DynamoDB.
|
|
579
|
+
*
|
|
580
|
+
* @example
|
|
581
|
+
* ```typescript
|
|
582
|
+
* try {
|
|
583
|
+
* // Update dinosaur status with conditions
|
|
584
|
+
* const result = await new UpdateBuilder(executor, 'dinosaurs', { id: 'TREX-001' })
|
|
585
|
+
* .set({
|
|
586
|
+
* status: 'FEEDING',
|
|
587
|
+
* lastMeal: new Date().toISOString(),
|
|
588
|
+
* 'stats.hunger': 0
|
|
589
|
+
* })
|
|
590
|
+
* .add('feedingCount', 1)
|
|
591
|
+
* .condition(op =>
|
|
592
|
+
* op.and([
|
|
593
|
+
* op.gt('stats.hunger', 80),
|
|
594
|
+
* op.eq('status', 'HUNTING')
|
|
595
|
+
* ])
|
|
596
|
+
* )
|
|
597
|
+
* .returnValues('ALL_NEW')
|
|
598
|
+
* .execute();
|
|
599
|
+
*
|
|
600
|
+
* if (result.item) {
|
|
601
|
+
* console.log('Updated dinosaur:', result.item);
|
|
602
|
+
* }
|
|
603
|
+
* } catch (error) {
|
|
604
|
+
* // Handle condition check failure
|
|
605
|
+
* console.error('Failed to update dinosaur:', error);
|
|
606
|
+
* // Check if dinosaur wasn't hungry enough
|
|
607
|
+
* if (error.name === 'ConditionalCheckFailedException') {
|
|
608
|
+
* console.log('Dinosaur not ready for feeding');
|
|
609
|
+
* }
|
|
610
|
+
* }
|
|
611
|
+
* ```
|
|
612
|
+
*
|
|
613
|
+
* @returns A promise that resolves to an DynamoItem containing the updated item (if returnValues is set)
|
|
614
|
+
* @throws {ConditionalCheckFailedException} If the condition check fails
|
|
615
|
+
* @throws {Error} If the update operation fails for other reasons
|
|
616
|
+
*/
|
|
617
|
+
async execute() {
|
|
618
|
+
const params = this.toDynamoCommand();
|
|
619
|
+
return this.executor(params);
|
|
620
|
+
}
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
export { UpdateBuilder };
|
|
624
|
+
//# sourceMappingURL=update-builder.js.map
|
|
625
|
+
//# sourceMappingURL=update-builder.js.map
|