@ftschopp/dynatable-core 1.2.5 → 1.4.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/CHANGELOG.md +14 -0
- package/dist/builders/query/create-query-builder.d.ts +1 -1
- package/dist/builders/query/create-query-builder.d.ts.map +1 -1
- package/dist/builders/query/create-query-builder.js +56 -10
- package/dist/builders/query/types.d.ts +16 -0
- package/dist/builders/query/types.d.ts.map +1 -1
- package/dist/builders/scan/create-scan-builder.d.ts.map +1 -1
- package/dist/builders/scan/create-scan-builder.js +32 -0
- package/dist/builders/scan/types.d.ts +35 -0
- package/dist/builders/scan/types.d.ts.map +1 -1
- package/dist/builders/shared/operators.d.ts.map +1 -1
- package/dist/builders/shared/operators.js +8 -0
- package/dist/builders/shared/types.d.ts +1 -0
- package/dist/builders/shared/types.d.ts.map +1 -1
- package/dist/builders/update/create-update-builder.d.ts +8 -2
- package/dist/builders/update/create-update-builder.d.ts.map +1 -1
- package/dist/builders/update/create-update-builder.js +45 -16
- package/dist/builders/update/types.d.ts +13 -0
- package/dist/builders/update/types.d.ts.map +1 -1
- package/dist/entity/create-entity-api.d.ts.map +1 -1
- package/dist/entity/create-entity-api.js +8 -4
- package/dist/utils/model-utils.d.ts +28 -0
- package/dist/utils/model-utils.d.ts.map +1 -1
- package/dist/utils/model-utils.js +34 -1
- package/package.json +1 -1
- package/src/builders/query/create-query-builder.test.ts +324 -0
- package/src/builders/query/create-query-builder.ts +73 -10
- package/src/builders/query/types.ts +17 -0
- package/src/builders/scan/create-scan-builder.test.ts +121 -0
- package/src/builders/scan/create-scan-builder.ts +35 -1
- package/src/builders/scan/types.ts +39 -0
- package/src/builders/shared/operators.ts +8 -0
- package/src/builders/shared/types.ts +1 -0
- package/src/builders/update/create-update-builder.test.ts +197 -0
- package/src/builders/update/create-update-builder.ts +72 -19
- package/src/builders/update/types.ts +14 -0
- package/src/entity/create-entity-api.ts +8 -4
- package/src/utils/model-utils.test.ts +91 -1
- package/src/utils/model-utils.ts +54 -0
- package/tests/integration/instagram-clone.integration.test.ts +23 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# @ftschopp/dynatable-core [1.4.0](https://github.com/ftschopp/dynatable/compare/@ftschopp/dynatable-core@1.3.0...@ftschopp/dynatable-core@1.4.0) (2026-05-08)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **core:** add iterate() async iterator and Scan executeWithPagination ([#21](https://github.com/ftschopp/dynatable/issues/21)) ([c31d458](https://github.com/ftschopp/dynatable/commit/c31d45861e92ba0c52240128084939128a6e4acc)), closes [#4](https://github.com/ftschopp/dynatable/issues/4)
|
|
7
|
+
|
|
8
|
+
# @ftschopp/dynatable-core [1.3.0](https://github.com/ftschopp/dynatable/compare/@ftschopp/dynatable-core@1.2.5...@ftschopp/dynatable-core@1.3.0) (2026-05-07)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **core:** auto-recompute index keys on update and improve composite-key queries ([ce4b7dc](https://github.com/ftschopp/dynatable/commit/ce4b7dc1d783ffe2d78fee7f43b999a179a9f9f4))
|
|
14
|
+
|
|
1
15
|
## @ftschopp/dynatable-core [1.2.5](https://github.com/ftschopp/dynatable/compare/@ftschopp/dynatable-core@1.2.4...@ftschopp/dynatable-core@1.2.5) (2026-05-05)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -5,5 +5,5 @@ import { DynamoDBLogger } from '../../utils/dynamodb-logger';
|
|
|
5
5
|
/**
|
|
6
6
|
* Creates a QueryBuilder for a table
|
|
7
7
|
*/
|
|
8
|
-
export declare function createQueryBuilder<Model>(tableName: string, client: DynamoDBClient, model?: ModelDefinition, logger?: DynamoDBLogger): QueryBuilder<Model>;
|
|
8
|
+
export declare function createQueryBuilder<Model>(tableName: string, client: DynamoDBClient, model?: ModelDefinition, logger?: DynamoDBLogger, entityType?: string): QueryBuilder<Model>;
|
|
9
9
|
//# sourceMappingURL=create-query-builder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-query-builder.d.ts","sourceRoot":"","sources":["../../../src/builders/query/create-query-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAK1D,OAAO,EAAE,YAAY,EAA8B,MAAM,SAAS,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"create-query-builder.d.ts","sourceRoot":"","sources":["../../../src/builders/query/create-query-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAK1D,OAAO,EAAE,YAAY,EAA8B,MAAM,SAAS,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAiX7D;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EACtC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,cAAc,EACtB,KAAK,CAAC,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,cAAc,EACvB,UAAU,CAAC,EAAE,MAAM,GAClB,YAAY,CAAC,KAAK,CAAC,CA6BrB"}
|
|
@@ -33,11 +33,24 @@ function getKeyNameForAttribute(fieldName, model, indexName) {
|
|
|
33
33
|
return null;
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
|
-
* Apply key template to transform attribute value to key value
|
|
37
|
-
*
|
|
36
|
+
* Apply key template to transform an attribute value to its key value.
|
|
37
|
+
*
|
|
38
|
+
* For multi-variable templates (e.g. "RES#${category}#${code}") we can only fill
|
|
39
|
+
* the variable matching `fieldName`. For `beginsWith` queries we truncate the
|
|
40
|
+
* result at the first remaining `${...}` placeholder so the prefix is usable.
|
|
41
|
+
* For other operators an exact match is required, so we throw a clear error.
|
|
38
42
|
*/
|
|
39
|
-
function applyKeyTemplate(template, fieldName, fieldValue) {
|
|
40
|
-
|
|
43
|
+
function applyKeyTemplate(template, fieldName, fieldValue, keyOperator) {
|
|
44
|
+
const substituted = template.replace(`\${${fieldName}}`, String(fieldValue));
|
|
45
|
+
const nextPlaceholder = substituted.indexOf('${');
|
|
46
|
+
if (nextPlaceholder === -1)
|
|
47
|
+
return substituted;
|
|
48
|
+
if (keyOperator === 'beginsWith') {
|
|
49
|
+
return substituted.slice(0, nextPlaceholder);
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`Cannot use operator "${keyOperator ?? 'unknown'}" on key template "${template}" ` +
|
|
52
|
+
`with only "${fieldName}" provided — the template still contains unfilled ` +
|
|
53
|
+
`variable(s). Use beginsWith for prefix queries on composite keys.`);
|
|
41
54
|
}
|
|
42
55
|
/**
|
|
43
56
|
* Separates a condition tree into key conditions and filter conditions
|
|
@@ -82,7 +95,7 @@ function separateConditions(condition, model, indexName) {
|
|
|
82
95
|
if (cond.values) {
|
|
83
96
|
for (const [valuePlaceholder, value] of Object.entries(cond.values)) {
|
|
84
97
|
// Apply the key template to transform the value
|
|
85
|
-
const transformedValue = applyKeyTemplate(keyInfo.template, fieldName, value);
|
|
98
|
+
const transformedValue = applyKeyTemplate(keyInfo.template, fieldName, value, cond.keyOperator);
|
|
86
99
|
newValues[valuePlaceholder] = transformedValue;
|
|
87
100
|
}
|
|
88
101
|
}
|
|
@@ -178,18 +191,29 @@ function createQueryExecutor(state) {
|
|
|
178
191
|
const { keyConditions, filterConditions } = separateConditions(state.condition, state.model, state.indexName);
|
|
179
192
|
// Build KeyConditionExpression (simple AND)
|
|
180
193
|
const keyExpr = buildSimpleAndExpression(keyConditions);
|
|
194
|
+
// Auto-inject an entity-type filter so query() only returns items
|
|
195
|
+
// belonging to this entity (single-table designs share PKs across
|
|
196
|
+
// entities, especially on GSIs).
|
|
197
|
+
const allFilters = [...filterConditions];
|
|
198
|
+
if (state.entityType) {
|
|
199
|
+
allFilters.push({
|
|
200
|
+
expression: '#_type = :_type',
|
|
201
|
+
names: { '#_type': '_type' },
|
|
202
|
+
values: { ':_type': state.entityType },
|
|
203
|
+
});
|
|
204
|
+
}
|
|
181
205
|
// Build FilterExpression (can be complex with OR, NOT, etc.)
|
|
182
206
|
let filterExpr = { expression: '', names: {}, values: {} };
|
|
183
|
-
if (
|
|
184
|
-
if (
|
|
185
|
-
filterExpr = (0, conditions_1.buildExpression)(
|
|
207
|
+
if (allFilters.length > 0) {
|
|
208
|
+
if (allFilters.length === 1 && allFilters[0]) {
|
|
209
|
+
filterExpr = (0, conditions_1.buildExpression)(allFilters[0]);
|
|
186
210
|
}
|
|
187
211
|
else {
|
|
188
212
|
// Multiple filter conditions - combine with AND
|
|
189
213
|
filterExpr = (0, conditions_1.buildExpression)({
|
|
190
214
|
expression: '',
|
|
191
215
|
operator: 'AND',
|
|
192
|
-
children:
|
|
216
|
+
children: allFilters,
|
|
193
217
|
});
|
|
194
218
|
}
|
|
195
219
|
}
|
|
@@ -231,6 +255,14 @@ function createQueryExecutor(state) {
|
|
|
231
255
|
}),
|
|
232
256
|
};
|
|
233
257
|
},
|
|
258
|
+
/**
|
|
259
|
+
* ⚠️ Returns only the FIRST page of results. DynamoDB caps each Query
|
|
260
|
+
* response at ~1MB (or `Limit` if set). If the matching set is larger,
|
|
261
|
+
* the remaining items are silently dropped.
|
|
262
|
+
*
|
|
263
|
+
* Use {@link executeWithPagination} when you need to drive pagination
|
|
264
|
+
* yourself, or {@link iterate} to walk every matching item lazily.
|
|
265
|
+
*/
|
|
234
266
|
async execute() {
|
|
235
267
|
const params = this.dbParams();
|
|
236
268
|
const result = await state.client.send(new lib_dynamodb_1.QueryCommand(params));
|
|
@@ -248,12 +280,25 @@ function createQueryExecutor(state) {
|
|
|
248
280
|
scannedCount: result.ScannedCount,
|
|
249
281
|
};
|
|
250
282
|
},
|
|
283
|
+
async *iterate() {
|
|
284
|
+
const baseParams = this.dbParams();
|
|
285
|
+
let cursor = baseParams.ExclusiveStartKey;
|
|
286
|
+
do {
|
|
287
|
+
const params = { ...baseParams, ExclusiveStartKey: cursor };
|
|
288
|
+
const result = await state.client.send(new lib_dynamodb_1.QueryCommand(params));
|
|
289
|
+
state.logger?.log('QueryCommand', params, result);
|
|
290
|
+
for (const item of (result.Items ?? [])) {
|
|
291
|
+
yield item;
|
|
292
|
+
}
|
|
293
|
+
cursor = result.LastEvaluatedKey;
|
|
294
|
+
} while (cursor);
|
|
295
|
+
},
|
|
251
296
|
};
|
|
252
297
|
}
|
|
253
298
|
/**
|
|
254
299
|
* Creates a QueryBuilder for a table
|
|
255
300
|
*/
|
|
256
|
-
function createQueryBuilder(tableName, client, model, logger) {
|
|
301
|
+
function createQueryBuilder(tableName, client, model, logger, entityType) {
|
|
257
302
|
return {
|
|
258
303
|
where(fn) {
|
|
259
304
|
// Create attribute builder proxy
|
|
@@ -273,6 +318,7 @@ function createQueryBuilder(tableName, client, model, logger) {
|
|
|
273
318
|
model,
|
|
274
319
|
condition,
|
|
275
320
|
logger,
|
|
321
|
+
entityType,
|
|
276
322
|
};
|
|
277
323
|
return createQueryExecutor(initialState);
|
|
278
324
|
},
|
|
@@ -60,6 +60,22 @@ export interface QueryExecutor<Model> extends ExecutableBuilder<Model[]> {
|
|
|
60
60
|
* Executes the query and returns result with pagination metadata
|
|
61
61
|
*/
|
|
62
62
|
executeWithPagination(): Promise<QueryResult<Model>>;
|
|
63
|
+
/**
|
|
64
|
+
* Returns an async iterator that paginates internally and yields one item at
|
|
65
|
+
* a time. Memory stays at one page; you can `break` out of the loop early.
|
|
66
|
+
*
|
|
67
|
+
* `Limit` set via `.limit()` is forwarded to DynamoDB as a *per-request*
|
|
68
|
+
* cap, not a total cap. To cap the total, count yourself inside the loop:
|
|
69
|
+
*
|
|
70
|
+
* ```ts
|
|
71
|
+
* let n = 0;
|
|
72
|
+
* for await (const item of builder.iterate()) {
|
|
73
|
+
* if (n++ >= 1000) break;
|
|
74
|
+
* process(item);
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
iterate(): AsyncIterableIterator<Model>;
|
|
63
79
|
}
|
|
64
80
|
/**
|
|
65
81
|
* Main Query Builder interface with type-safe where clause
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/builders/query/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEjF;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,KAAK;IAChC;;OAEG;IACH,KAAK,EAAE,KAAK,EAAE,CAAC;IAEf;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEvC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,CAAE,SAAQ,iBAAiB,CAAC,KAAK,EAAE,CAAC;IACtE;;OAEG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAE3C;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAEzD;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAElD;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAErD;;OAEG;IACH,cAAc,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC;IAEvC;;OAEG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAE1D;;OAEG;IACH,QAAQ,IAAI,GAAG,CAAC;IAEhB;;OAEG;IACH,OAAO,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAE5B;;OAEG;IACH,qBAAqB,IAAI,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/builders/query/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEjF;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,KAAK;IAChC;;OAEG;IACH,KAAK,EAAE,KAAK,EAAE,CAAC;IAEf;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEvC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,CAAE,SAAQ,iBAAiB,CAAC,KAAK,EAAE,CAAC;IACtE;;OAEG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAE3C;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAEzD;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAElD;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAErD;;OAEG;IACH,cAAc,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC;IAEvC;;OAEG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAE1D;;OAEG;IACH,QAAQ,IAAI,GAAG,CAAC;IAEhB;;OAEG;IACH,OAAO,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAE5B;;OAEG;IACH,qBAAqB,IAAI,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;IAErD;;;;;;;;;;;;;;OAcG;IACH,OAAO,IAAI,qBAAqB,CAAC,KAAK,CAAC,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,KAAK;IACjC;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,SAAS,KAAK,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;CACzF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-scan-builder.d.ts","sourceRoot":"","sources":["../../../src/builders/scan/create-scan-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAgC,SAAS,EAAmB,MAAM,WAAW,CAAC;AACrF,OAAO,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"create-scan-builder.d.ts","sourceRoot":"","sources":["../../../src/builders/scan/create-scan-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAgC,SAAS,EAAmB,MAAM,WAAW,CAAC;AACrF,OAAO,EAAE,WAAW,EAAc,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EACrC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,SAAS,EAAO,EACzB,eAAe,GAAE,CAAC,MAAM,KAAK,CAAC,EAAO,EACrC,UAAU,CAAC,EAAE,MAAM,EACnB,gBAAgB,UAAQ,EACxB,SAAS,CAAC,EAAE,MAAM,EAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACvC,aAAa,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,EAC1D,MAAM,CAAC,EAAE,cAAc,GACtB,WAAW,CAAC,KAAK,CAAC,CAqOpB"}
|
|
@@ -92,12 +92,44 @@ function createScanBuilder(tableName, client, filters = [], projectionAttrs = []
|
|
|
92
92
|
}
|
|
93
93
|
return params;
|
|
94
94
|
},
|
|
95
|
+
/**
|
|
96
|
+
* ⚠️ Returns only the FIRST page of results. DynamoDB caps each Scan
|
|
97
|
+
* response at ~1MB (or `Limit` if set). If the matching set is larger,
|
|
98
|
+
* the remaining items are silently dropped.
|
|
99
|
+
*
|
|
100
|
+
* Use {@link executeWithPagination} when you need to drive pagination
|
|
101
|
+
* yourself, or {@link iterate} to walk every matching item lazily.
|
|
102
|
+
*/
|
|
95
103
|
async execute() {
|
|
96
104
|
const params = build().dbParams();
|
|
97
105
|
const response = await client.send(new lib_dynamodb_1.ScanCommand(params));
|
|
98
106
|
logger?.log('ScanCommand', params, response);
|
|
99
107
|
return (response.Items || []);
|
|
100
108
|
},
|
|
109
|
+
async executeWithPagination() {
|
|
110
|
+
const params = build().dbParams();
|
|
111
|
+
const response = await client.send(new lib_dynamodb_1.ScanCommand(params));
|
|
112
|
+
logger?.log('ScanCommand', params, response);
|
|
113
|
+
return {
|
|
114
|
+
items: (response.Items ?? []),
|
|
115
|
+
lastEvaluatedKey: response.LastEvaluatedKey,
|
|
116
|
+
count: response.Count,
|
|
117
|
+
scannedCount: response.ScannedCount,
|
|
118
|
+
};
|
|
119
|
+
},
|
|
120
|
+
async *iterate() {
|
|
121
|
+
const baseParams = build().dbParams();
|
|
122
|
+
let cursor = baseParams.ExclusiveStartKey;
|
|
123
|
+
do {
|
|
124
|
+
const params = { ...baseParams, ExclusiveStartKey: cursor };
|
|
125
|
+
const response = await client.send(new lib_dynamodb_1.ScanCommand(params));
|
|
126
|
+
logger?.log('ScanCommand', params, response);
|
|
127
|
+
for (const item of (response.Items ?? [])) {
|
|
128
|
+
yield item;
|
|
129
|
+
}
|
|
130
|
+
cursor = response.LastEvaluatedKey;
|
|
131
|
+
} while (cursor);
|
|
132
|
+
},
|
|
101
133
|
});
|
|
102
134
|
return build();
|
|
103
135
|
}
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import { ExecutableBuilder, AttrBuilder, OpBuilder, Condition } from '../shared';
|
|
2
|
+
/**
|
|
3
|
+
* A single page of scan results plus metadata for manual pagination.
|
|
4
|
+
*/
|
|
5
|
+
export interface ScanResult<Model> {
|
|
6
|
+
/** Items returned in this page. */
|
|
7
|
+
items: Model[];
|
|
8
|
+
/** Cursor for the next page; `undefined` when there are no more results. */
|
|
9
|
+
lastEvaluatedKey?: Record<string, any>;
|
|
10
|
+
/** Number of items returned after applying the filter. */
|
|
11
|
+
count?: number;
|
|
12
|
+
/** Number of items examined before applying the filter. */
|
|
13
|
+
scannedCount?: number;
|
|
14
|
+
}
|
|
2
15
|
/**
|
|
3
16
|
* Builder for DynamoDB Scan operations.
|
|
4
17
|
* Scans the entire table or index without requiring key conditions.
|
|
@@ -39,5 +52,27 @@ export interface ScanBuilder<Model> extends ExecutableBuilder<Model[]> {
|
|
|
39
52
|
* Returns a new immutable builder.
|
|
40
53
|
*/
|
|
41
54
|
segment(segmentNumber: number, totalSegments: number): ScanBuilder<Model>;
|
|
55
|
+
/**
|
|
56
|
+
* Executes a single Scan request and returns the page along with the
|
|
57
|
+
* `lastEvaluatedKey` cursor and counts. Use this when you want to drive
|
|
58
|
+
* pagination yourself (e.g. expose a cursor to a client).
|
|
59
|
+
*/
|
|
60
|
+
executeWithPagination(): Promise<ScanResult<Model>>;
|
|
61
|
+
/**
|
|
62
|
+
* Returns an async iterator that paginates internally and yields one item at
|
|
63
|
+
* a time. Memory stays at one page; you can `break` out of the loop early.
|
|
64
|
+
*
|
|
65
|
+
* `Limit` set via `.limit()` is forwarded to DynamoDB as a *per-request*
|
|
66
|
+
* cap, not a total cap. To cap the total, count yourself inside the loop:
|
|
67
|
+
*
|
|
68
|
+
* ```ts
|
|
69
|
+
* let n = 0;
|
|
70
|
+
* for await (const item of builder.iterate()) {
|
|
71
|
+
* if (n++ >= 1000) break;
|
|
72
|
+
* process(item);
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
iterate(): AsyncIterableIterator<Model>;
|
|
42
77
|
}
|
|
43
78
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/builders/scan/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/builders/scan/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEjF;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,KAAK;IAC/B,mCAAmC;IACnC,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACvC,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW,CAAC,KAAK,CAAE,SAAQ,iBAAiB,CAAC,KAAK,EAAE,CAAC;IACpE;;;OAGG;IACH,MAAM,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,SAAS,KAAK,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAEvF;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAEnD;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAEzC;;;OAGG;IACH,cAAc,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC;IAErC;;;OAGG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAElD;;;OAGG;IACH,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAEtE;;;OAGG;IACH,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAE1E;;;;OAIG;IACH,qBAAqB,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAEpD;;;;;;;;;;;;;;OAcG;IACH,OAAO,IAAI,qBAAqB,CAAC,KAAK,CAAC,CAAC;CACzC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operators.d.ts","sourceRoot":"","sources":["../../../src/builders/shared/operators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC;;;GAGG;AACH,wBAAgB,eAAe,IAAI,SAAS,
|
|
1
|
+
{"version":3,"file":"operators.d.ts","sourceRoot":"","sources":["../../../src/builders/shared/operators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC;;;GAGG;AACH,wBAAgB,eAAe,IAAI,SAAS,CAmM3C;AAED;;;GAGG;AACH,eAAO,MAAM,SAAS,EAAE,SAA6B,CAAC"}
|
|
@@ -21,6 +21,7 @@ function createOpBuilder() {
|
|
|
21
21
|
expression: `#${attr.name} = :${valueName}`,
|
|
22
22
|
names: { [`#${attr.name}`]: attr.name },
|
|
23
23
|
values: { [`:${valueName}`]: value },
|
|
24
|
+
keyOperator: 'eq',
|
|
24
25
|
};
|
|
25
26
|
},
|
|
26
27
|
ne: (attr, value) => {
|
|
@@ -29,6 +30,7 @@ function createOpBuilder() {
|
|
|
29
30
|
expression: `#${attr.name} <> :${valueName}`,
|
|
30
31
|
names: { [`#${attr.name}`]: attr.name },
|
|
31
32
|
values: { [`:${valueName}`]: value },
|
|
33
|
+
keyOperator: 'ne',
|
|
32
34
|
};
|
|
33
35
|
},
|
|
34
36
|
lt: (attr, value) => {
|
|
@@ -37,6 +39,7 @@ function createOpBuilder() {
|
|
|
37
39
|
expression: `#${attr.name} < :${valueName}`,
|
|
38
40
|
names: { [`#${attr.name}`]: attr.name },
|
|
39
41
|
values: { [`:${valueName}`]: value },
|
|
42
|
+
keyOperator: 'lt',
|
|
40
43
|
};
|
|
41
44
|
},
|
|
42
45
|
lte: (attr, value) => {
|
|
@@ -45,6 +48,7 @@ function createOpBuilder() {
|
|
|
45
48
|
expression: `#${attr.name} <= :${valueName}`,
|
|
46
49
|
names: { [`#${attr.name}`]: attr.name },
|
|
47
50
|
values: { [`:${valueName}`]: value },
|
|
51
|
+
keyOperator: 'lte',
|
|
48
52
|
};
|
|
49
53
|
},
|
|
50
54
|
gt: (attr, value) => {
|
|
@@ -53,6 +57,7 @@ function createOpBuilder() {
|
|
|
53
57
|
expression: `#${attr.name} > :${valueName}`,
|
|
54
58
|
names: { [`#${attr.name}`]: attr.name },
|
|
55
59
|
values: { [`:${valueName}`]: value },
|
|
60
|
+
keyOperator: 'gt',
|
|
56
61
|
};
|
|
57
62
|
},
|
|
58
63
|
gte: (attr, value) => {
|
|
@@ -61,6 +66,7 @@ function createOpBuilder() {
|
|
|
61
66
|
expression: `#${attr.name} >= :${valueName}`,
|
|
62
67
|
names: { [`#${attr.name}`]: attr.name },
|
|
63
68
|
values: { [`:${valueName}`]: value },
|
|
69
|
+
keyOperator: 'gte',
|
|
64
70
|
};
|
|
65
71
|
},
|
|
66
72
|
between: (attr, low, high) => {
|
|
@@ -73,6 +79,7 @@ function createOpBuilder() {
|
|
|
73
79
|
[`:${lowName}`]: low,
|
|
74
80
|
[`:${highName}`]: high,
|
|
75
81
|
},
|
|
82
|
+
keyOperator: 'between',
|
|
76
83
|
};
|
|
77
84
|
},
|
|
78
85
|
beginsWith: (attr, value) => {
|
|
@@ -81,6 +88,7 @@ function createOpBuilder() {
|
|
|
81
88
|
expression: `begins_with(#${attr.name}, :${valueName})`,
|
|
82
89
|
names: { [`#${attr.name}`]: attr.name },
|
|
83
90
|
values: { [`:${valueName}`]: value },
|
|
91
|
+
keyOperator: 'beginsWith',
|
|
84
92
|
};
|
|
85
93
|
},
|
|
86
94
|
contains: (attr, value) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/builders/shared/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/builders/shared/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
2
2
|
import { Condition } from '../shared';
|
|
3
|
-
import { UpdateBuilder, UpdateAction } from './types';
|
|
3
|
+
import { UpdateBuilder, UpdateAction, IndexContext } from './types';
|
|
4
4
|
import { DynamoDBLogger } from '../../utils/dynamodb-logger';
|
|
5
5
|
/**
|
|
6
6
|
* Creates an UpdateBuilder for an item key and table.
|
|
7
|
+
*
|
|
8
|
+
* When `indexContext` is provided, fields written via `.set()` that participate
|
|
9
|
+
* in any secondary-index template are detected and the affected index keys are
|
|
10
|
+
* recomputed automatically and included in the SET expression. If a template
|
|
11
|
+
* cannot be fully resolved from the primary-key vars plus the updates, building
|
|
12
|
+
* the params throws — the caller must include the missing fields in `.set()`.
|
|
7
13
|
*/
|
|
8
14
|
export declare function createUpdateBuilder<Model>(tableName: string, key: Partial<Model>, client: DynamoDBClient, prevConditions?: Condition[], updateActions?: {
|
|
9
15
|
set: UpdateAction[];
|
|
10
16
|
remove: UpdateAction[];
|
|
11
17
|
add: UpdateAction[];
|
|
12
18
|
delete: UpdateAction[];
|
|
13
|
-
}, returnMode?: 'NONE' | 'ALL_OLD' | 'ALL_NEW' | 'UPDATED_OLD' | 'UPDATED_NEW', valueCounter?: number, enableTimestamps?: boolean, logger?: DynamoDBLogger): UpdateBuilder<Model>;
|
|
19
|
+
}, returnMode?: 'NONE' | 'ALL_OLD' | 'ALL_NEW' | 'UPDATED_OLD' | 'UPDATED_NEW', valueCounter?: number, enableTimestamps?: boolean, logger?: DynamoDBLogger, indexContext?: IndexContext, setInputs?: Record<string, any>): UpdateBuilder<Model>;
|
|
14
20
|
//# sourceMappingURL=create-update-builder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-update-builder.d.ts","sourceRoot":"","sources":["../../../src/builders/update/create-update-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAgC,SAAS,EAA4B,MAAM,WAAW,CAAC;AAC9F,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"create-update-builder.d.ts","sourceRoot":"","sources":["../../../src/builders/update/create-update-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAgC,SAAS,EAA4B,MAAM,WAAW,CAAC;AAC9F,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAG7D;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EACvC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,EACnB,MAAM,EAAE,cAAc,EACtB,cAAc,GAAE,SAAS,EAAO,EAChC,aAAa,GAAE;IACb,GAAG,EAAE,YAAY,EAAE,CAAC;IACpB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,GAAG,EAAE,YAAY,EAAE,CAAC;IACpB,MAAM,EAAE,YAAY,EAAE,CAAC;CACuB,EAChD,UAAU,GAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,aAAsB,EACnF,YAAY,SAAI,EAChB,gBAAgB,UAAQ,EACxB,MAAM,CAAC,EAAE,cAAc,EACvB,YAAY,CAAC,EAAE,YAAY,EAC3B,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GAClC,aAAa,CAAC,KAAK,CAAC,CAoVtB"}
|
|
@@ -3,10 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createUpdateBuilder = createUpdateBuilder;
|
|
4
4
|
const lib_dynamodb_1 = require("@aws-sdk/lib-dynamodb");
|
|
5
5
|
const shared_1 = require("../shared");
|
|
6
|
+
const model_utils_1 = require("../../utils/model-utils");
|
|
6
7
|
/**
|
|
7
8
|
* Creates an UpdateBuilder for an item key and table.
|
|
9
|
+
*
|
|
10
|
+
* When `indexContext` is provided, fields written via `.set()` that participate
|
|
11
|
+
* in any secondary-index template are detected and the affected index keys are
|
|
12
|
+
* recomputed automatically and included in the SET expression. If a template
|
|
13
|
+
* cannot be fully resolved from the primary-key vars plus the updates, building
|
|
14
|
+
* the params throws — the caller must include the missing fields in `.set()`.
|
|
8
15
|
*/
|
|
9
|
-
function createUpdateBuilder(tableName, key, client, prevConditions = [], updateActions = { set: [], remove: [], add: [], delete: [] }, returnMode = 'NONE', valueCounter = 0, enableTimestamps = false, logger) {
|
|
16
|
+
function createUpdateBuilder(tableName, key, client, prevConditions = [], updateActions = { set: [], remove: [], add: [], delete: [] }, returnMode = 'NONE', valueCounter = 0, enableTimestamps = false, logger, indexContext, setInputs = {}) {
|
|
10
17
|
const conditions = [...prevConditions];
|
|
11
18
|
const getUniqueValueName = (baseName) => {
|
|
12
19
|
return `${baseName}_${valueCounter++}`;
|
|
@@ -26,21 +33,19 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
|
|
|
26
33
|
});
|
|
27
34
|
const opBuilder = (0, shared_1.createOpBuilder)();
|
|
28
35
|
const condition = fn(attrs, opBuilder);
|
|
29
|
-
return createUpdateBuilder(tableName, key, client, [...conditions, condition], updateActions, returnMode, valueCounter, enableTimestamps, logger);
|
|
36
|
+
return createUpdateBuilder(tableName, key, client, [...conditions, condition], updateActions, returnMode, valueCounter, enableTimestamps, logger, indexContext, setInputs);
|
|
30
37
|
},
|
|
31
38
|
set(attrOrUpdates, value) {
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
39
|
+
// When no value is provided and the first arg is a plain object,
|
|
40
|
+
// treat it as a Partial<Model>. The AttrRef overload always passes
|
|
41
|
+
// a value, so it's handled by the single-update path below.
|
|
35
42
|
if (value === undefined &&
|
|
36
43
|
typeof attrOrUpdates === 'object' &&
|
|
37
|
-
attrOrUpdates !== null
|
|
38
|
-
!(Object.keys(attrOrUpdates).length === 1 &&
|
|
39
|
-
'name' in attrOrUpdates &&
|
|
40
|
-
typeof attrOrUpdates.name === 'string')) {
|
|
44
|
+
attrOrUpdates !== null) {
|
|
41
45
|
// Multiple updates case
|
|
42
46
|
const updates = attrOrUpdates;
|
|
43
47
|
const newActions = [];
|
|
48
|
+
const newSetInputs = { ...setInputs };
|
|
44
49
|
for (const [attr, val] of Object.entries(updates)) {
|
|
45
50
|
const attrName = attr;
|
|
46
51
|
const valueName = getUniqueValueName(attrName);
|
|
@@ -49,8 +54,9 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
|
|
|
49
54
|
names: { [`#${attrName}`]: attrName },
|
|
50
55
|
values: { [`:${valueName}`]: val },
|
|
51
56
|
});
|
|
57
|
+
newSetInputs[attrName] = val;
|
|
52
58
|
}
|
|
53
|
-
return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, set: [...updateActions.set, ...newActions] }, returnMode, valueCounter, enableTimestamps, logger);
|
|
59
|
+
return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, set: [...updateActions.set, ...newActions] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, newSetInputs);
|
|
54
60
|
}
|
|
55
61
|
// Single update case
|
|
56
62
|
const attrName = normalizeAttr(attrOrUpdates);
|
|
@@ -60,7 +66,7 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
|
|
|
60
66
|
names: { [`#${attrName}`]: attrName },
|
|
61
67
|
values: { [`:${valueName}`]: value },
|
|
62
68
|
};
|
|
63
|
-
return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, set: [...updateActions.set, action] }, returnMode, valueCounter, enableTimestamps, logger);
|
|
69
|
+
return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, set: [...updateActions.set, action] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, { ...setInputs, [attrName]: value });
|
|
64
70
|
},
|
|
65
71
|
remove(attr) {
|
|
66
72
|
const attrName = normalizeAttr(attr);
|
|
@@ -68,7 +74,7 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
|
|
|
68
74
|
expression: `#${attrName}`,
|
|
69
75
|
names: { [`#${attrName}`]: attrName },
|
|
70
76
|
};
|
|
71
|
-
return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, remove: [...updateActions.remove, action] }, returnMode, valueCounter, enableTimestamps, logger);
|
|
77
|
+
return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, remove: [...updateActions.remove, action] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, setInputs);
|
|
72
78
|
},
|
|
73
79
|
add(attr, value) {
|
|
74
80
|
const attrName = normalizeAttr(attr);
|
|
@@ -78,7 +84,7 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
|
|
|
78
84
|
names: { [`#${attrName}`]: attrName },
|
|
79
85
|
values: { [`:${valueName}`]: value },
|
|
80
86
|
};
|
|
81
|
-
return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, add: [...updateActions.add, action] }, returnMode, valueCounter, enableTimestamps, logger);
|
|
87
|
+
return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, add: [...updateActions.add, action] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, setInputs);
|
|
82
88
|
},
|
|
83
89
|
delete(attr, value) {
|
|
84
90
|
const attrName = normalizeAttr(attr);
|
|
@@ -88,10 +94,10 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
|
|
|
88
94
|
names: { [`#${attrName}`]: attrName },
|
|
89
95
|
values: { [`:${valueName}`]: value },
|
|
90
96
|
};
|
|
91
|
-
return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, delete: [...updateActions.delete, action] }, returnMode, valueCounter, enableTimestamps, logger);
|
|
97
|
+
return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, delete: [...updateActions.delete, action] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, setInputs);
|
|
92
98
|
},
|
|
93
99
|
returning(mode) {
|
|
94
|
-
return createUpdateBuilder(tableName, key, client, conditions, updateActions, mode, valueCounter, enableTimestamps, logger);
|
|
100
|
+
return createUpdateBuilder(tableName, key, client, conditions, updateActions, mode, valueCounter, enableTimestamps, logger, indexContext, setInputs);
|
|
95
101
|
},
|
|
96
102
|
dbParams() {
|
|
97
103
|
// Build UpdateExpression from actions
|
|
@@ -99,7 +105,30 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
|
|
|
99
105
|
const allNames = {};
|
|
100
106
|
const allValues = {};
|
|
101
107
|
// Clone updateActions to avoid mutation
|
|
102
|
-
const actionsToProcess = { ...updateActions };
|
|
108
|
+
const actionsToProcess = { ...updateActions, set: [...updateActions.set] };
|
|
109
|
+
// Auto-recompute secondary-index keys whose templates depend on any
|
|
110
|
+
// updated field. If a template can't be fully resolved from the primary
|
|
111
|
+
// key vars + the .set() payload, we throw — recomputing from the
|
|
112
|
+
// existing item would require an extra read the builder won't do.
|
|
113
|
+
if (indexContext) {
|
|
114
|
+
const { actions: idxActions, missing } = (0, model_utils_1.computeIndexUpdates)(indexContext.model, indexContext.keyVars, setInputs);
|
|
115
|
+
if (missing.length > 0) {
|
|
116
|
+
const details = missing
|
|
117
|
+
.map((m) => ` - ${m.index} ("${m.template}"): missing ${m.missing.join(', ')}`)
|
|
118
|
+
.join('\n');
|
|
119
|
+
throw new Error(`Update touches fields that participate in secondary index templates, ` +
|
|
120
|
+
`but the templates cannot be fully resolved from the update payload. ` +
|
|
121
|
+
`Include the missing fields in .set():\n${details}`);
|
|
122
|
+
}
|
|
123
|
+
for (const [indexName, resolved] of Object.entries(idxActions)) {
|
|
124
|
+
const valueName = getUniqueValueName(indexName);
|
|
125
|
+
actionsToProcess.set.push({
|
|
126
|
+
expression: `#${indexName} = :${valueName}`,
|
|
127
|
+
names: { [`#${indexName}`]: indexName },
|
|
128
|
+
values: { [`:${valueName}`]: resolved },
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
103
132
|
// Add updatedAt timestamp if enabled
|
|
104
133
|
if (enableTimestamps) {
|
|
105
134
|
const now = new Date().toISOString();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { UpdateCommandInput } from '@aws-sdk/lib-dynamodb';
|
|
2
|
+
import { ModelDefinition } from '../../core/types';
|
|
2
3
|
import { OperationBuilder, AttrRef } from '../shared';
|
|
3
4
|
/**
|
|
4
5
|
* Update actions that can be performed on attributes
|
|
@@ -8,6 +9,18 @@ export type UpdateAction = {
|
|
|
8
9
|
names?: Record<string, string>;
|
|
9
10
|
values?: Record<string, any>;
|
|
10
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* Context that lets the update builder auto-recompute secondary-index keys
|
|
14
|
+
* when a `.set()` touches a field that participates in their templates.
|
|
15
|
+
*
|
|
16
|
+
* `keyVars` carries the original template-variable values used to build the
|
|
17
|
+
* primary key (e.g. `{ id: '123' }` from `update({ id: '123' })`) so they can
|
|
18
|
+
* be combined with the user's `.set()` payload when resolving index templates.
|
|
19
|
+
*/
|
|
20
|
+
export type IndexContext = {
|
|
21
|
+
model: ModelDefinition;
|
|
22
|
+
keyVars: Record<string, any>;
|
|
23
|
+
};
|
|
11
24
|
/**
|
|
12
25
|
* Builder interface for DynamoDB UpdateItem operations
|
|
13
26
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/builders/update/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,CAAE,SAAQ,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IACrF;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACnE,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAEnD;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAE1D;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAEnE;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAEtE;;OAEG;IACH,SAAS,CACP,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,aAAa,GACnE,aAAa,CAAC,KAAK,CAAC,CAAC;IAExB;;OAEG;IACH,QAAQ,IAAI,kBAAkB,CAAC;CAChC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/builders/update/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,CAAE,SAAQ,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IACrF;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACnE,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAEnD;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAE1D;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAEnE;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAEtE;;OAEG;IACH,SAAS,CACP,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,aAAa,GACnE,aAAa,CAAC,KAAK,CAAC,CAAC;IAExB;;OAEG;IACH,QAAQ,IAAI,kBAAkB,CAAC;CAChC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-entity-api.d.ts","sourceRoot":"","sources":["../../src/entity/create-entity-api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AActF,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAMtD;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,GAAI,KAAK,SAAS,eAAe,EAC3D,WAAW,MAAM,EACjB,WAAW,MAAM,EACjB,OAAO,KAAK,EACZ,QAAQ,cAAc,EACtB,UAAS,gBAAqB,KAC7B,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"create-entity-api.d.ts","sourceRoot":"","sources":["../../src/entity/create-entity-api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AActF,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAMtD;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,GAAI,KAAK,SAAS,eAAe,EAC3D,WAAW,MAAM,EACjB,WAAW,MAAM,EACjB,OAAO,KAAK,EACZ,QAAQ,cAAc,EACtB,UAAS,gBAAqB,KAC7B,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,CAyLtE,CAAC"}
|
|
@@ -49,9 +49,10 @@ const createEntityAPI = (tableName, modelName, model, client, options = {}) => {
|
|
|
49
49
|
return (0, builders_1.createPutBuilder)(tableName, fullItem, client, [], false, 'NONE', false, logger);
|
|
50
50
|
},
|
|
51
51
|
query() {
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
|
|
52
|
+
// Auto-filter by entity type so query() only returns items for this
|
|
53
|
+
// entity. Without this, queries on shared GSIs return items from other
|
|
54
|
+
// entities that share the same partition key.
|
|
55
|
+
return (0, builders_1.createQueryBuilder)(tableName, client, model, logger, modelName);
|
|
55
56
|
},
|
|
56
57
|
scan() {
|
|
57
58
|
// Auto-filter by entity type so scan only returns items for this entity
|
|
@@ -68,7 +69,10 @@ const createEntityAPI = (tableName, modelName, model, client, options = {}) => {
|
|
|
68
69
|
(0, key_validation_1.validateKeyFields)(modelName, model, key, 'update()');
|
|
69
70
|
// Resolve any key defaults or computed keys
|
|
70
71
|
const fullKey = (0, model_utils_1.resolveKeys)(model, key);
|
|
71
|
-
const builder = (0, builders_1.createUpdateBuilder)(tableName, fullKey, client, [], { set: [], remove: [], add: [], delete: [] }, 'NONE', 0, timestamps, logger
|
|
72
|
+
const builder = (0, builders_1.createUpdateBuilder)(tableName, fullKey, client, [], { set: [], remove: [], add: [], delete: [] }, 'NONE', 0, timestamps, logger,
|
|
73
|
+
// Carry the original template-vars-bearing key (e.g. { username: 'jane' })
|
|
74
|
+
// so the builder can recompute index keys when .set() touches their template fields.
|
|
75
|
+
{ model, keyVars: key });
|
|
72
76
|
return (0, with_middleware_1.withMiddleware)(builder, (0, factories_1.createCleanKeysMiddleware)(cleanInternalKeys));
|
|
73
77
|
},
|
|
74
78
|
delete(key) {
|