@ftschopp/dynatable-core 1.5.1 → 1.6.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.
Files changed (28) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/builders/delete/create-delete-builder.d.ts +1 -1
  3. package/dist/builders/delete/create-delete-builder.d.ts.map +1 -1
  4. package/dist/builders/delete/create-delete-builder.js +7 -3
  5. package/dist/builders/delete/types.d.ts +9 -0
  6. package/dist/builders/delete/types.d.ts.map +1 -1
  7. package/dist/builders/put/create-put-builder.d.ts +1 -1
  8. package/dist/builders/put/create-put-builder.d.ts.map +1 -1
  9. package/dist/builders/put/create-put-builder.js +8 -4
  10. package/dist/builders/put/types.d.ts +10 -0
  11. package/dist/builders/put/types.d.ts.map +1 -1
  12. package/dist/builders/query/create-query-builder.d.ts.map +1 -1
  13. package/dist/builders/query/create-query-builder.js +25 -1
  14. package/dist/builders/query/types.d.ts +10 -0
  15. package/dist/builders/query/types.d.ts.map +1 -1
  16. package/dist/builders/scan/create-scan-builder.d.ts +1 -1
  17. package/dist/builders/scan/create-scan-builder.d.ts.map +1 -1
  18. package/dist/builders/scan/create-scan-builder.js +14 -8
  19. package/dist/builders/scan/types.d.ts +10 -0
  20. package/dist/builders/scan/types.d.ts.map +1 -1
  21. package/dist/builders/update/create-update-builder.d.ts +1 -1
  22. package/dist/builders/update/create-update-builder.d.ts.map +1 -1
  23. package/dist/builders/update/create-update-builder.js +86 -8
  24. package/dist/builders/update/types.d.ts +10 -0
  25. package/dist/builders/update/types.d.ts.map +1 -1
  26. package/dist/entity/create-entity-api.d.ts.map +1 -1
  27. package/dist/entity/create-entity-api.js +15 -1
  28. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # @ftschopp/dynatable-core [1.6.0](https://github.com/ftschopp/dynatable/compare/@ftschopp/dynatable-core@1.5.2...@ftschopp/dynatable-core@1.6.0) (2026-05-10)
2
+
3
+
4
+ ### Features
5
+
6
+ * **core:** expose ReturnConsumedCapacity on query/scan/update/put/delete ([#44](https://github.com/ftschopp/dynatable/issues/44)) ([048e52f](https://github.com/ftschopp/dynatable/commit/048e52f8172cd13a0ad1720e8c701af8bf20603d))
7
+
8
+ ## @ftschopp/dynatable-core [1.5.2](https://github.com/ftschopp/dynatable/compare/@ftschopp/dynatable-core@1.5.1...@ftschopp/dynatable-core@1.5.2) (2026-05-10)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **core:** guard primary-key template fields and non-set ops on GSI templates in update builder ([#42](https://github.com/ftschopp/dynatable/issues/42)) ([4487ff2](https://github.com/ftschopp/dynatable/commit/4487ff22ad507b37aa0e2e279a602a4813afddba))
14
+
1
15
  ## @ftschopp/dynatable-core [1.5.1](https://github.com/ftschopp/dynatable/compare/@ftschopp/dynatable-core@1.5.0...@ftschopp/dynatable-core@1.5.1) (2026-05-10)
2
16
 
3
17
 
@@ -5,5 +5,5 @@ import { DynamoDBLogger } from '../../utils/dynamodb-logger';
5
5
  /**
6
6
  * Creates a DeleteBuilder for an item key and table.
7
7
  */
8
- export declare function createDeleteBuilder<Model>(tableName: string, key: Partial<Model>, client: DynamoDBClient, prevConditions?: Condition[], returnMode?: 'NONE' | 'ALL_OLD', logger?: DynamoDBLogger): DeleteBuilder<Model>;
8
+ export declare function createDeleteBuilder<Model>(tableName: string, key: Partial<Model>, client: DynamoDBClient, prevConditions?: Condition[], returnMode?: 'NONE' | 'ALL_OLD', logger?: DynamoDBLogger, consumedCapacity?: 'INDEXES' | 'TOTAL' | 'NONE'): DeleteBuilder<Model>;
9
9
  //# sourceMappingURL=create-delete-builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-delete-builder.d.ts","sourceRoot":"","sources":["../../../src/builders/delete/create-delete-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAgC,SAAS,EAAmB,MAAM,WAAW,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D;;GAEG;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,UAAU,GAAE,MAAM,GAAG,SAAkB,EACvC,MAAM,CAAC,EAAE,cAAc,GACtB,aAAa,CAAC,KAAK,CAAC,CAkFtB"}
1
+ {"version":3,"file":"create-delete-builder.d.ts","sourceRoot":"","sources":["../../../src/builders/delete/create-delete-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAgC,SAAS,EAAmB,MAAM,WAAW,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D;;GAEG;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,UAAU,GAAE,MAAM,GAAG,SAAkB,EACvC,MAAM,CAAC,EAAE,cAAc,EACvB,gBAAgB,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAC9C,aAAa,CAAC,KAAK,CAAC,CAwGtB"}
@@ -6,7 +6,7 @@ const shared_1 = require("../shared");
6
6
  /**
7
7
  * Creates a DeleteBuilder for an item key and table.
8
8
  */
9
- function createDeleteBuilder(tableName, key, client, prevConditions = [], returnMode = 'NONE', logger) {
9
+ function createDeleteBuilder(tableName, key, client, prevConditions = [], returnMode = 'NONE', logger, consumedCapacity) {
10
10
  const conditions = [...prevConditions];
11
11
  const build = () => ({
12
12
  where(fn) {
@@ -17,10 +17,13 @@ function createDeleteBuilder(tableName, key, client, prevConditions = [], return
17
17
  });
18
18
  const opBuilder = (0, shared_1.createOpBuilder)();
19
19
  const condition = fn(attrs, opBuilder);
20
- return createDeleteBuilder(tableName, key, client, [...conditions, condition], returnMode, logger);
20
+ return createDeleteBuilder(tableName, key, client, [...conditions, condition], returnMode, logger, consumedCapacity);
21
21
  },
22
22
  returning(mode) {
23
- return createDeleteBuilder(tableName, key, client, conditions, mode, logger);
23
+ return createDeleteBuilder(tableName, key, client, conditions, mode, logger, consumedCapacity);
24
+ },
25
+ returnConsumedCapacity(mode) {
26
+ return createDeleteBuilder(tableName, key, client, conditions, returnMode, logger, mode);
24
27
  },
25
28
  dbParams() {
26
29
  // Build ConditionExpression from condition tree
@@ -53,6 +56,7 @@ function createDeleteBuilder(tableName, key, client, prevConditions = [], return
53
56
  ...(Object.keys(expressionAttributeValues).length && {
54
57
  ExpressionAttributeValues: expressionAttributeValues,
55
58
  }),
59
+ ...(consumedCapacity && { ReturnConsumedCapacity: consumedCapacity }),
56
60
  ...extra,
57
61
  };
58
62
  },
@@ -8,6 +8,15 @@ export interface DeleteBuilder<Model> extends Omit<OperationBuilder<Model>, 'dbP
8
8
  * Configures what values should be returned after the delete operation
9
9
  */
10
10
  returning(mode: 'NONE' | 'ALL_OLD'): DeleteBuilder<Model>;
11
+ /**
12
+ * Configures the ReturnConsumedCapacity parameter so DynamoDB reports
13
+ * how many WCUs the delete consumed. Useful for diagnosing throttling.
14
+ *
15
+ * - INDEXES: Returns consumed capacity for table and indexes
16
+ * - TOTAL: Returns total consumed capacity
17
+ * - NONE: No consumed capacity data returned (default)
18
+ */
19
+ returnConsumedCapacity(mode: 'INDEXES' | 'TOTAL' | 'NONE'): DeleteBuilder<Model>;
11
20
  /**
12
21
  * Converts the builder state to DynamoDB DeleteItem parameters
13
22
  */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/builders/delete/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,CAAE,SAAQ,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IACrF;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAE1D;;OAEG;IACH,QAAQ,IAAI,kBAAkB,CAAC;CAChC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/builders/delete/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,CAAE,SAAQ,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IACrF;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAE1D;;;;;;;OAOG;IACH,sBAAsB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAEjF;;OAEG;IACH,QAAQ,IAAI,kBAAkB,CAAC;CAChC"}
@@ -5,5 +5,5 @@ import { DynamoDBLogger } from '../../utils/dynamodb-logger';
5
5
  /**
6
6
  * Creates a PutBuilder for an item and table.
7
7
  */
8
- export declare function createPutBuilder<Model>(tableName: string, item: Model, client: DynamoDBClient, prevConditions?: Condition[], shouldCheckNotExists?: boolean, returnMode?: 'NONE' | 'ALL_OLD', enableTimestamps?: boolean, logger?: DynamoDBLogger): PutBuilder<Model>;
8
+ export declare function createPutBuilder<Model>(tableName: string, item: Model, client: DynamoDBClient, prevConditions?: Condition[], shouldCheckNotExists?: boolean, returnMode?: 'NONE' | 'ALL_OLD', enableTimestamps?: boolean, logger?: DynamoDBLogger, consumedCapacity?: 'INDEXES' | 'TOTAL' | 'NONE'): PutBuilder<Model>;
9
9
  //# sourceMappingURL=create-put-builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-put-builder.d.ts","sourceRoot":"","sources":["../../../src/builders/put/create-put-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAgC,SAAS,EAAmB,MAAM,WAAW,CAAC;AACrF,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAgB7D;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EACpC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,KAAK,EACX,MAAM,EAAE,cAAc,EACtB,cAAc,GAAE,SAAS,EAAO,EAChC,oBAAoB,UAAQ,EAC5B,UAAU,GAAE,MAAM,GAAG,SAAkB,EACvC,gBAAgB,UAAQ,EACxB,MAAM,CAAC,EAAE,cAAc,GACtB,UAAU,CAAC,KAAK,CAAC,CA8HnB"}
1
+ {"version":3,"file":"create-put-builder.d.ts","sourceRoot":"","sources":["../../../src/builders/put/create-put-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAgC,SAAS,EAAmB,MAAM,WAAW,CAAC;AACrF,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAgB7D;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EACpC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,KAAK,EACX,MAAM,EAAE,cAAc,EACtB,cAAc,GAAE,SAAS,EAAO,EAChC,oBAAoB,UAAQ,EAC5B,UAAU,GAAE,MAAM,GAAG,SAAkB,EACvC,gBAAgB,UAAQ,EACxB,MAAM,CAAC,EAAE,cAAc,EACvB,gBAAgB,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAC9C,UAAU,CAAC,KAAK,CAAC,CAgJnB"}
@@ -18,7 +18,7 @@ function buildNotExistsConditions(item) {
18
18
  /**
19
19
  * Creates a PutBuilder for an item and table.
20
20
  */
21
- function createPutBuilder(tableName, item, client, prevConditions = [], shouldCheckNotExists = false, returnMode = 'NONE', enableTimestamps = false, logger) {
21
+ function createPutBuilder(tableName, item, client, prevConditions = [], shouldCheckNotExists = false, returnMode = 'NONE', enableTimestamps = false, logger, consumedCapacity) {
22
22
  const conditions = [...prevConditions];
23
23
  const build = () => ({
24
24
  where(fn) {
@@ -30,13 +30,16 @@ function createPutBuilder(tableName, item, client, prevConditions = [], shouldCh
30
30
  // Create a scoped opBuilder for this operation to avoid global state
31
31
  const opBuilder = (0, shared_1.createOpBuilder)();
32
32
  const condition = fn(attrs, opBuilder);
33
- return createPutBuilder(tableName, item, client, [...conditions, condition], shouldCheckNotExists, returnMode, enableTimestamps, logger);
33
+ return createPutBuilder(tableName, item, client, [...conditions, condition], shouldCheckNotExists, returnMode, enableTimestamps, logger, consumedCapacity);
34
34
  },
35
35
  ifNotExists() {
36
- return createPutBuilder(tableName, item, client, conditions, true, returnMode, enableTimestamps, logger);
36
+ return createPutBuilder(tableName, item, client, conditions, true, returnMode, enableTimestamps, logger, consumedCapacity);
37
37
  },
38
38
  returning(mode) {
39
- return createPutBuilder(tableName, item, client, conditions, shouldCheckNotExists, mode, enableTimestamps, logger);
39
+ return createPutBuilder(tableName, item, client, conditions, shouldCheckNotExists, mode, enableTimestamps, logger, consumedCapacity);
40
+ },
41
+ returnConsumedCapacity(mode) {
42
+ return createPutBuilder(tableName, item, client, conditions, shouldCheckNotExists, returnMode, enableTimestamps, logger, mode);
40
43
  },
41
44
  dbParams() {
42
45
  let finalConditions = [...conditions];
@@ -85,6 +88,7 @@ function createPutBuilder(tableName, item, client, prevConditions = [], shouldCh
85
88
  ...(Object.keys(expressionAttributeValues).length && {
86
89
  ExpressionAttributeValues: expressionAttributeValues,
87
90
  }),
91
+ ...(consumedCapacity && { ReturnConsumedCapacity: consumedCapacity }),
88
92
  ...extra,
89
93
  };
90
94
  },
@@ -14,6 +14,16 @@ export interface PutBuilder<Model> extends Omit<OperationBuilder<Model>, 'dbPara
14
14
  * - ALL_OLD: Returns the item as it was before being replaced (if it existed)
15
15
  */
16
16
  returning(mode: 'NONE' | 'ALL_OLD'): PutBuilder<Model>;
17
+ /**
18
+ * Configures the ReturnConsumedCapacity parameter so DynamoDB reports
19
+ * how many WCUs the put consumed. Useful for diagnosing throttling and
20
+ * accounting for index amplification on tables with multiple GSIs.
21
+ *
22
+ * - INDEXES: Returns consumed capacity for table and indexes
23
+ * - TOTAL: Returns total consumed capacity
24
+ * - NONE: No consumed capacity data returned (default)
25
+ */
26
+ returnConsumedCapacity(mode: 'INDEXES' | 'TOTAL' | 'NONE'): PutBuilder<Model>;
17
27
  /**
18
28
  * Converts the builder state to DynamoDB PutItem parameters
19
29
  */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/builders/put/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,KAAK,CAAE,SAAQ,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAClF;;OAEG;IACH,WAAW,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IAEjC;;;;OAIG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAEvD;;OAEG;IACH,QAAQ,IAAI,eAAe,CAAC;CAC7B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/builders/put/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,KAAK,CAAE,SAAQ,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAClF;;OAEG;IACH,WAAW,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IAEjC;;;;OAIG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAEvD;;;;;;;;OAQG;IACH,sBAAsB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAE9E;;OAEG;IACH,QAAQ,IAAI,eAAe,CAAC;CAC7B"}
@@ -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;AAM1D,OAAO,EAAE,YAAY,EAA8B,MAAM,SAAS,CAAC;AACnE,OAAO,EAAiB,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAElE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAub7D;;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"}
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;AAM1D,OAAO,EAAE,YAAY,EAA8B,MAAM,SAAS,CAAC;AACnE,OAAO,EAAiB,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAElE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAkd7D;;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"}
@@ -23,6 +23,21 @@ function keyBelongsToIndex(keyName, keyDef, indexName) {
23
23
  }
24
24
  return keyName === `${indexName}PK` || keyName === `${indexName}SK`;
25
25
  }
26
+ /**
27
+ * Cache of compiled `#<fieldName>\b` regexes used to rewrite a leaf
28
+ * condition's expression when its field maps onto a key. Without this,
29
+ * `separateConditions` allocates a fresh `RegExp` per AND-leaf per query —
30
+ * cheap individually, noisy under load on multi-condition queries.
31
+ */
32
+ const fieldPlaceholderRegexCache = new Map();
33
+ function fieldPlaceholderRegex(fieldName) {
34
+ let re = fieldPlaceholderRegexCache.get(fieldName);
35
+ if (!re) {
36
+ re = new RegExp(`#${fieldName}\\b`, 'g');
37
+ fieldPlaceholderRegexCache.set(fieldName, re);
38
+ }
39
+ return re;
40
+ }
26
41
  /**
27
42
  * Maps a model attribute name to its corresponding DynamoDB key name (PK/SK)
28
43
  * Also returns the key template for value transformation
@@ -127,7 +142,7 @@ function separateConditions(condition, model, indexName) {
127
142
  }
128
143
  const rewrittenCond = {
129
144
  ...cond,
130
- expression: cond.expression.replace(new RegExp(`#${fieldName}\\b`, 'g'), `#${keyInfo.keyName}`),
145
+ expression: cond.expression.replace(fieldPlaceholderRegex(fieldName), `#${keyInfo.keyName}`),
131
146
  names: {
132
147
  [`#${keyInfo.keyName}`]: keyInfo.keyName,
133
148
  },
@@ -209,6 +224,12 @@ function createQueryExecutor(state) {
209
224
  exclusiveStartKey: key,
210
225
  });
211
226
  },
227
+ returnConsumedCapacity(mode) {
228
+ return createQueryExecutor({
229
+ ...state,
230
+ returnConsumedCapacity: mode,
231
+ });
232
+ },
212
233
  dbParams() {
213
234
  if (!state.condition) {
214
235
  throw new Error('No where condition specified');
@@ -307,6 +328,9 @@ function createQueryExecutor(state) {
307
328
  ...(state.exclusiveStartKey && {
308
329
  ExclusiveStartKey: state.exclusiveStartKey,
309
330
  }),
331
+ ...(state.returnConsumedCapacity && {
332
+ ReturnConsumedCapacity: state.returnConsumedCapacity,
333
+ }),
310
334
  };
311
335
  },
312
336
  /**
@@ -48,6 +48,16 @@ export interface QueryExecutor<Model> extends ExecutableBuilder<Model[]> {
48
48
  * Start query from a specific key (for pagination)
49
49
  */
50
50
  startFrom(key: Record<string, any>): QueryExecutor<Model>;
51
+ /**
52
+ * Configures the ReturnConsumedCapacity parameter so DynamoDB reports
53
+ * how many RCUs the query consumed. Useful for diagnosing throttling
54
+ * and confirming a query hit the expected (G)SI.
55
+ *
56
+ * - INDEXES: Returns consumed capacity for table and indexes
57
+ * - TOTAL: Returns total consumed capacity
58
+ * - NONE: No consumed capacity data returned (default)
59
+ */
60
+ returnConsumedCapacity(mode: 'INDEXES' | 'TOTAL' | 'NONE'): QueryExecutor<Model>;
51
61
  /**
52
62
  * Returns the raw DynamoDB query parameters
53
63
  */
@@ -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;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
+ {"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;;;;;;;;OAQG;IACH,sBAAsB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAEjF;;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"}
@@ -8,5 +8,5 @@ import { DynamoDBLogger } from '../../utils/dynamodb-logger';
8
8
  export declare function createScanBuilder<Model>(tableName: string, client: DynamoDBClient, filters?: Condition[], projectionAttrs?: (keyof Model)[], limitValue?: number, isConsistentRead?: boolean, indexName?: string, exclusiveStartKey?: Record<string, any>, segmentConfig?: {
9
9
  segment: number;
10
10
  totalSegments: number;
11
- }, logger?: DynamoDBLogger): ScanBuilder<Model>;
11
+ }, logger?: DynamoDBLogger, consumedCapacity?: 'INDEXES' | 'TOTAL' | 'NONE'): ScanBuilder<Model>;
12
12
  //# sourceMappingURL=create-scan-builder.d.ts.map
@@ -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,EAGL,SAAS,EAGV,MAAM,WAAW,CAAC;AACnB,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,CA6OpB"}
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,EAGL,SAAS,EAGV,MAAM,WAAW,CAAC;AACnB,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,EACvB,gBAAgB,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAC9C,WAAW,CAAC,KAAK,CAAC,CAwQpB"}
@@ -6,7 +6,7 @@ const shared_1 = require("../shared");
6
6
  /**
7
7
  * Creates a ScanBuilder for scanning a table or index.
8
8
  */
9
- function createScanBuilder(tableName, client, filters = [], projectionAttrs = [], limitValue, isConsistentRead = false, indexName, exclusiveStartKey, segmentConfig, logger) {
9
+ function createScanBuilder(tableName, client, filters = [], projectionAttrs = [], limitValue, isConsistentRead = false, indexName, exclusiveStartKey, segmentConfig, logger, consumedCapacity) {
10
10
  const build = () => ({
11
11
  filter(fn) {
12
12
  const attrs = new Proxy({}, {
@@ -16,25 +16,28 @@ function createScanBuilder(tableName, client, filters = [], projectionAttrs = []
16
16
  });
17
17
  const opBuilder = (0, shared_1.createOpBuilder)();
18
18
  const condition = fn(attrs, opBuilder);
19
- return createScanBuilder(tableName, client, [...filters, condition], projectionAttrs, limitValue, isConsistentRead, indexName, exclusiveStartKey, segmentConfig, logger);
19
+ return createScanBuilder(tableName, client, [...filters, condition], projectionAttrs, limitValue, isConsistentRead, indexName, exclusiveStartKey, segmentConfig, logger, consumedCapacity);
20
20
  },
21
21
  select(attrs) {
22
- return createScanBuilder(tableName, client, filters, attrs, limitValue, isConsistentRead, indexName, exclusiveStartKey, segmentConfig, logger);
22
+ return createScanBuilder(tableName, client, filters, attrs, limitValue, isConsistentRead, indexName, exclusiveStartKey, segmentConfig, logger, consumedCapacity);
23
23
  },
24
24
  limit(count) {
25
- return createScanBuilder(tableName, client, filters, projectionAttrs, count, isConsistentRead, indexName, exclusiveStartKey, segmentConfig, logger);
25
+ return createScanBuilder(tableName, client, filters, projectionAttrs, count, isConsistentRead, indexName, exclusiveStartKey, segmentConfig, logger, consumedCapacity);
26
26
  },
27
27
  consistentRead() {
28
- return createScanBuilder(tableName, client, filters, projectionAttrs, limitValue, true, indexName, exclusiveStartKey, segmentConfig, logger);
28
+ return createScanBuilder(tableName, client, filters, projectionAttrs, limitValue, true, indexName, exclusiveStartKey, segmentConfig, logger, consumedCapacity);
29
29
  },
30
30
  usingIndex(index) {
31
- return createScanBuilder(tableName, client, filters, projectionAttrs, limitValue, isConsistentRead, index, exclusiveStartKey, segmentConfig, logger);
31
+ return createScanBuilder(tableName, client, filters, projectionAttrs, limitValue, isConsistentRead, index, exclusiveStartKey, segmentConfig, logger, consumedCapacity);
32
32
  },
33
33
  startFrom(key) {
34
- return createScanBuilder(tableName, client, filters, projectionAttrs, limitValue, isConsistentRead, indexName, key, segmentConfig, logger);
34
+ return createScanBuilder(tableName, client, filters, projectionAttrs, limitValue, isConsistentRead, indexName, key, segmentConfig, logger, consumedCapacity);
35
35
  },
36
36
  segment(segmentNumber, totalSegments) {
37
- return createScanBuilder(tableName, client, filters, projectionAttrs, limitValue, isConsistentRead, indexName, exclusiveStartKey, { segment: segmentNumber, totalSegments }, logger);
37
+ return createScanBuilder(tableName, client, filters, projectionAttrs, limitValue, isConsistentRead, indexName, exclusiveStartKey, { segment: segmentNumber, totalSegments }, logger, consumedCapacity);
38
+ },
39
+ returnConsumedCapacity(mode) {
40
+ return createScanBuilder(tableName, client, filters, projectionAttrs, limitValue, isConsistentRead, indexName, exclusiveStartKey, segmentConfig, logger, mode);
38
41
  },
39
42
  dbParams() {
40
43
  let filterExpression = '';
@@ -98,6 +101,9 @@ function createScanBuilder(tableName, client, filters = [], projectionAttrs = []
98
101
  params.Segment = segmentConfig.segment;
99
102
  params.TotalSegments = segmentConfig.totalSegments;
100
103
  }
104
+ if (consumedCapacity) {
105
+ params.ReturnConsumedCapacity = consumedCapacity;
106
+ }
101
107
  return params;
102
108
  },
103
109
  /**
@@ -52,6 +52,16 @@ export interface ScanBuilder<Model> extends ExecutableBuilder<Model[]> {
52
52
  * Returns a new immutable builder.
53
53
  */
54
54
  segment(segmentNumber: number, totalSegments: number): ScanBuilder<Model>;
55
+ /**
56
+ * Configures the ReturnConsumedCapacity parameter so DynamoDB reports
57
+ * how many RCUs the scan consumed. Useful for diagnosing throttling
58
+ * and confirming filter selectivity.
59
+ *
60
+ * - INDEXES: Returns consumed capacity for table and indexes
61
+ * - TOTAL: Returns total consumed capacity
62
+ * - NONE: No consumed capacity data returned (default)
63
+ */
64
+ returnConsumedCapacity(mode: 'INDEXES' | 'TOTAL' | 'NONE'): ScanBuilder<Model>;
55
65
  /**
56
66
  * Executes a single Scan request and returns the page along with the
57
67
  * `lastEvaluatedKey` cursor and counts. Use this when you want to drive
@@ -1 +1 @@
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
+ {"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;;;;;;;;OAQG;IACH,sBAAsB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAE/E;;;;OAIG;IACH,qBAAqB,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAEpD;;;;;;;;;;;;;;OAcG;IACH,OAAO,IAAI,qBAAqB,CAAC,KAAK,CAAC,CAAC;CACzC"}
@@ -16,5 +16,5 @@ export declare function createUpdateBuilder<Model>(tableName: string, key: Parti
16
16
  remove: UpdateAction[];
17
17
  add: UpdateAction[];
18
18
  delete: UpdateAction[];
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>;
19
+ }, returnMode?: 'NONE' | 'ALL_OLD' | 'ALL_NEW' | 'UPDATED_OLD' | 'UPDATED_NEW', valueCounter?: number, enableTimestamps?: boolean, logger?: DynamoDBLogger, indexContext?: IndexContext, setInputs?: Record<string, any>, consumedCapacity?: 'INDEXES' | 'TOTAL' | 'NONE'): UpdateBuilder<Model>;
20
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,YAAY,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAa7D;;;;;;;;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,CAmXtB"}
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;AAyB7D;;;;;;;;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,EACnC,gBAAgB,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAC9C,aAAa,CAAC,KAAK,CAAC,CAidtB"}
@@ -13,6 +13,18 @@ function extractAttrName(action) {
13
13
  const m = action.expression.match(/^\s*#([A-Za-z0-9_]+)\s*=/);
14
14
  return m?.[1];
15
15
  }
16
+ /**
17
+ * Pull the attribute name from any update action (set / remove / add / delete).
18
+ * Each action emitted by this builder carries exactly one entry in `names`
19
+ * mapping `#<attr>` → `<attr>`, so the value side of that map is the source
20
+ * of truth regardless of the surrounding expression syntax.
21
+ */
22
+ function actionAttrName(action) {
23
+ if (!action.names)
24
+ return undefined;
25
+ const values = Object.values(action.names);
26
+ return values[0];
27
+ }
16
28
  /**
17
29
  * Creates an UpdateBuilder for an item key and table.
18
30
  *
@@ -22,7 +34,7 @@ function extractAttrName(action) {
22
34
  * cannot be fully resolved from the primary-key vars plus the updates, building
23
35
  * the params throws — the caller must include the missing fields in `.set()`.
24
36
  */
25
- function createUpdateBuilder(tableName, key, client, prevConditions = [], updateActions = { set: [], remove: [], add: [], delete: [] }, returnMode = 'NONE', valueCounter = 0, enableTimestamps = false, logger, indexContext, setInputs = {}) {
37
+ function createUpdateBuilder(tableName, key, client, prevConditions = [], updateActions = { set: [], remove: [], add: [], delete: [] }, returnMode = 'NONE', valueCounter = 0, enableTimestamps = false, logger, indexContext, setInputs = {}, consumedCapacity) {
26
38
  const conditions = [...prevConditions];
27
39
  const getUniqueValueName = (baseName) => {
28
40
  return `${baseName}_${valueCounter++}`;
@@ -42,7 +54,7 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
42
54
  });
43
55
  const opBuilder = (0, shared_1.createOpBuilder)();
44
56
  const condition = fn(attrs, opBuilder);
45
- return createUpdateBuilder(tableName, key, client, [...conditions, condition], updateActions, returnMode, valueCounter, enableTimestamps, logger, indexContext, setInputs);
57
+ return createUpdateBuilder(tableName, key, client, [...conditions, condition], updateActions, returnMode, valueCounter, enableTimestamps, logger, indexContext, setInputs, consumedCapacity);
46
58
  },
47
59
  set(attrOrUpdates, value) {
48
60
  // When no value is provided and the first arg is a plain object,
@@ -65,7 +77,7 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
65
77
  });
66
78
  newSetInputs[attrName] = val;
67
79
  }
68
- return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, set: [...updateActions.set, ...newActions] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, newSetInputs);
80
+ return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, set: [...updateActions.set, ...newActions] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, newSetInputs, consumedCapacity);
69
81
  }
70
82
  // Single update case
71
83
  const attrName = normalizeAttr(attrOrUpdates);
@@ -75,7 +87,7 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
75
87
  names: { [`#${attrName}`]: attrName },
76
88
  values: { [`:${valueName}`]: value },
77
89
  };
78
- return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, set: [...updateActions.set, action] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, { ...setInputs, [attrName]: value });
90
+ return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, set: [...updateActions.set, action] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, { ...setInputs, [attrName]: value }, consumedCapacity);
79
91
  },
80
92
  remove(attr) {
81
93
  const attrName = normalizeAttr(attr);
@@ -83,7 +95,7 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
83
95
  expression: `#${attrName}`,
84
96
  names: { [`#${attrName}`]: attrName },
85
97
  };
86
- return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, remove: [...updateActions.remove, action] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, setInputs);
98
+ return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, remove: [...updateActions.remove, action] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, setInputs, consumedCapacity);
87
99
  },
88
100
  add(attr, value) {
89
101
  const attrName = normalizeAttr(attr);
@@ -93,7 +105,7 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
93
105
  names: { [`#${attrName}`]: attrName },
94
106
  values: { [`:${valueName}`]: value },
95
107
  };
96
- return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, add: [...updateActions.add, action] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, setInputs);
108
+ return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, add: [...updateActions.add, action] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, setInputs, consumedCapacity);
97
109
  },
98
110
  delete(attr, value) {
99
111
  const attrName = normalizeAttr(attr);
@@ -103,10 +115,13 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
103
115
  names: { [`#${attrName}`]: attrName },
104
116
  values: { [`:${valueName}`]: value },
105
117
  };
106
- return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, delete: [...updateActions.delete, action] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, setInputs);
118
+ return createUpdateBuilder(tableName, key, client, conditions, { ...updateActions, delete: [...updateActions.delete, action] }, returnMode, valueCounter, enableTimestamps, logger, indexContext, setInputs, consumedCapacity);
107
119
  },
108
120
  returning(mode) {
109
- return createUpdateBuilder(tableName, key, client, conditions, updateActions, mode, valueCounter, enableTimestamps, logger, indexContext, setInputs);
121
+ return createUpdateBuilder(tableName, key, client, conditions, updateActions, mode, valueCounter, enableTimestamps, logger, indexContext, setInputs, consumedCapacity);
122
+ },
123
+ returnConsumedCapacity(mode) {
124
+ return createUpdateBuilder(tableName, key, client, conditions, updateActions, returnMode, valueCounter, enableTimestamps, logger, indexContext, setInputs, mode);
110
125
  },
111
126
  dbParams() {
112
127
  // Build UpdateExpression from actions
@@ -120,6 +135,68 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
120
135
  // key vars + the .set() payload, we throw — recomputing from the
121
136
  // existing item would require an extra read the builder won't do.
122
137
  if (indexContext) {
138
+ // Collect the attribute name targeted by every update action,
139
+ // grouped by op. `setInputs` carries the .set() payload (already
140
+ // structured) — for remove/add/delete we read from the action's
141
+ // attribute-name map.
142
+ const setFields = Object.keys(setInputs);
143
+ const removeFields = updateActions.remove
144
+ .map(actionAttrName)
145
+ .filter((n) => !!n);
146
+ const addFields = updateActions.add
147
+ .map(actionAttrName)
148
+ .filter((n) => !!n);
149
+ const deleteFields = updateActions.delete
150
+ .map(actionAttrName)
151
+ .filter((n) => !!n);
152
+ // Guard 1: primary-key template fields are immutable in DynamoDB.
153
+ // The Key on the UpdateItem request fixes the row to operate on; if
154
+ // the user changes a field that participates in the PK/SK template,
155
+ // the row's PK doesn't move (DynamoDB doesn't allow that) but the
156
+ // attribute does — leaving an inconsistent row whose PK encodes the
157
+ // old value. Catch this on every op (.set / .remove / .add / .delete)
158
+ // before it leaves the process.
159
+ const primaryKeyTemplateVars = new Set();
160
+ for (const keyDef of Object.values(indexContext.model.key)) {
161
+ for (const v of (0, model_utils_1.extractTemplateVars)(keyDef.value)) {
162
+ primaryKeyTemplateVars.add(v);
163
+ }
164
+ }
165
+ const allTouched = [...setFields, ...removeFields, ...addFields, ...deleteFields];
166
+ const pkConflicts = [
167
+ ...new Set(allTouched.filter((f) => primaryKeyTemplateVars.has(f))),
168
+ ];
169
+ if (pkConflicts.length > 0) {
170
+ throw new Error(`Cannot update field(s) [${pkConflicts.join(', ')}] — they participate ` +
171
+ `in the primary key template, which is immutable in DynamoDB. To ` +
172
+ `"rename" a primary-key value, delete the old item and put a new one ` +
173
+ `(ideally inside a transactWrite for atomicity).`);
174
+ }
175
+ // Guard 2: .add() / .remove() / .delete() against a field used in a
176
+ // SECONDARY-index template. The recompute path needs an explicit new
177
+ // value to resolve the template — ADD increments without exposing
178
+ // the new value, REMOVE strips the field entirely, and DELETE
179
+ // mutates a Set without naming a scalar. Switching to .set(field,
180
+ // newValue) lets the recompute path handle it correctly.
181
+ if (indexContext.model.index) {
182
+ const indexTemplateVars = new Set();
183
+ for (const indexDef of Object.values(indexContext.model.index)) {
184
+ for (const v of (0, model_utils_1.extractTemplateVars)(indexDef.value)) {
185
+ indexTemplateVars.add(v);
186
+ }
187
+ }
188
+ const nonSetTouches = [...removeFields, ...addFields, ...deleteFields];
189
+ const gsiConflicts = [
190
+ ...new Set(nonSetTouches.filter((f) => indexTemplateVars.has(f))),
191
+ ];
192
+ if (gsiConflicts.length > 0) {
193
+ throw new Error(`Cannot use .add() / .remove() / .delete() on field(s) ` +
194
+ `[${gsiConflicts.join(', ')}] — they participate in a ` +
195
+ `secondary-index template, and the affected index key cannot be ` +
196
+ `recomputed without an explicit new value. Use .set(field, ` +
197
+ `newValue) instead so the index key is recomputed atomically.`);
198
+ }
199
+ }
123
200
  const { actions: idxActions, missing } = (0, model_utils_1.computeIndexUpdates)(indexContext.model, indexContext.keyVars, setInputs);
124
201
  if (missing.length > 0) {
125
202
  const details = missing
@@ -246,6 +323,7 @@ function createUpdateBuilder(tableName, key, client, prevConditions = [], update
246
323
  ...(Object.keys(expressionAttributeValues).length && {
247
324
  ExpressionAttributeValues: expressionAttributeValues,
248
325
  }),
326
+ ...(consumedCapacity && { ReturnConsumedCapacity: consumedCapacity }),
249
327
  ...extra,
250
328
  };
251
329
  },
@@ -46,6 +46,16 @@ export interface UpdateBuilder<Model> extends Omit<OperationBuilder<Model>, 'dbP
46
46
  * Configures what values should be returned after the update operation
47
47
  */
48
48
  returning(mode: 'NONE' | 'ALL_OLD' | 'ALL_NEW' | 'UPDATED_OLD' | 'UPDATED_NEW'): UpdateBuilder<Model>;
49
+ /**
50
+ * Configures the ReturnConsumedCapacity parameter so DynamoDB reports
51
+ * how many WCUs the update consumed. Useful for diagnosing throttling
52
+ * and validating cost when index keys are auto-recomputed.
53
+ *
54
+ * - INDEXES: Returns consumed capacity for table and indexes
55
+ * - TOTAL: Returns total consumed capacity
56
+ * - NONE: No consumed capacity data returned (default)
57
+ */
58
+ returnConsumedCapacity(mode: 'INDEXES' | 'TOTAL' | 'NONE'): UpdateBuilder<Model>;
49
59
  /**
50
60
  * Converts the builder state to DynamoDB UpdateItem parameters
51
61
  */
@@ -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,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
+ {"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;;;;;;;;OAQG;IACH,sBAAsB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAEjF;;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,CA4NtE,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,CA0OtE,CAAC"}
@@ -54,6 +54,14 @@ const createEntityAPI = (tableName, modelName, model, client, options = {}) => {
54
54
  // Auto-filter by entity type so query() only returns items for this
55
55
  // entity. Without this, queries on shared GSIs return items from other
56
56
  // entities that share the same partition key.
57
+ //
58
+ // GOTCHA: this is implemented as a `FilterExpression` (`_type = …`),
59
+ // and DynamoDB applies `Limit` BEFORE filtering. On a single-table
60
+ // design where many entities share PKs, a `.limit(10)` query can
61
+ // return 0 items and a non-empty `LastEvaluatedKey` if none of the
62
+ // first 10 scanned items happen to belong to this entity. Either
63
+ // ignore Limit when type-mixing is heavy, or paginate via
64
+ // `iterate()` / `executeWithPagination()` and accumulate yourself.
57
65
  const builder = (0, builders_1.createQueryBuilder)(tableName, client, model, logger, modelName);
58
66
  // QueryBuilder exposes only `where()` — the executable surface lives
59
67
  // on the QueryExecutor it returns. Wrap that executor's `execute()`
@@ -72,7 +80,13 @@ const createEntityAPI = (tableName, modelName, model, client, options = {}) => {
72
80
  };
73
81
  },
74
82
  scan() {
75
- // Auto-filter by entity type so scan only returns items for this entity
83
+ // Auto-filter by entity type so scan only returns items for this entity.
84
+ //
85
+ // Same Limit-vs-Filter gotcha as `query()`: DynamoDB applies `Limit`
86
+ // before the FilterExpression, so on a multi-entity table a
87
+ // `.limit(N)` scan may return fewer than N items of THIS entity even
88
+ // when more exist deeper in the table. Use `iterate()` for "give me
89
+ // every item of this entity" semantics.
76
90
  const typeFilter = {
77
91
  expression: '#_type = :_type',
78
92
  names: { '#_type': '_type' },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ftschopp/dynatable-core",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "description": "Core library for DynamoDB single table design",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",