@eresearchqut/ddb-repository 1.2.0 → 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
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [1.4.0](https://github.com/eresearchqut/ddb-repository/compare/v1.3.0...v1.4.0) (2025-11-20)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* Add test for the tracking of the consumed capacity and rename test class ([d113a5a](https://github.com/eresearchqut/ddb-repository/commit/d113a5a948a7dffc80e9d3a65a11203c2249ed26))
|
|
7
|
+
|
|
8
|
+
# [1.3.0](https://github.com/eresearchqut/ddb-repository/compare/v1.2.0...v1.3.0) (2025-11-20)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* Add test for the tracking of the consumed capacity ([4a1b23c](https://github.com/eresearchqut/ddb-repository/commit/4a1b23cadadbbb02d78507ca9d34715219fc952c))
|
|
14
|
+
|
|
1
15
|
# [1.2.0](https://github.com/eresearchqut/ddb-repository/compare/v1.1.0...v1.2.0) (2025-11-19)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -27,7 +27,7 @@ var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
|
27
27
|
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
28
28
|
};
|
|
29
29
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
-
exports.DynamoDbRepository = exports.mapFilterExpressions = exports.mapFilterExpression = exports.FilterOperator = void 0;
|
|
30
|
+
exports.DynamoDbRepository = exports.consumedCapacityMiddleware = exports.mapFilterExpressions = exports.mapFilterExpression = exports.FilterOperator = void 0;
|
|
31
31
|
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
32
32
|
const util_dynamodb_1 = require("@aws-sdk/util-dynamodb");
|
|
33
33
|
const lodash_1 = require("lodash");
|
|
@@ -79,6 +79,21 @@ const paginate = (array, pageSize) => {
|
|
|
79
79
|
return acc;
|
|
80
80
|
}, []);
|
|
81
81
|
};
|
|
82
|
+
const consumedCapacityMiddleware = (consumedCapacityMiddlewareConfig) => (next, context) => (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
83
|
+
try {
|
|
84
|
+
const { input } = args;
|
|
85
|
+
const { ReturnConsumedCapacity } = input;
|
|
86
|
+
const response = yield next(args);
|
|
87
|
+
const { output } = response;
|
|
88
|
+
const consumedCapacity = (0, lodash_1.get)(output, "ConsumedCapacity");
|
|
89
|
+
yield consumedCapacityMiddlewareConfig.onConsumedCapacity({ ReturnConsumedCapacity, ConsumedCapacity: consumedCapacity });
|
|
90
|
+
return response;
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
exports.consumedCapacityMiddleware = consumedCapacityMiddleware;
|
|
82
97
|
class DynamoDbRepository {
|
|
83
98
|
constructor(dynamoDBClient, tableName, hashKey, rangKey, returnConsumedCapacity = client_dynamodb_1.ReturnConsumedCapacity.TOTAL) {
|
|
84
99
|
this.dynamoDBClient = dynamoDBClient;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eresearchqut/ddb-repository",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"@semantic-release/git": "^10.0.1",
|
|
24
24
|
"@semantic-release/github": "^12.0.2",
|
|
25
25
|
"@semantic-release/npm": "^13.1.2",
|
|
26
|
+
"@smithy/types": "^4.9.0",
|
|
26
27
|
"@testcontainers/localstack": "^10.15.0",
|
|
27
28
|
"@types/jest": "^29.5.0",
|
|
28
29
|
"@types/lodash": "^4.17.20",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BatchGetItemCommand,
|
|
3
3
|
BatchGetItemCommandInput,
|
|
4
|
+
ConsumedCapacity,
|
|
4
5
|
DeleteItemCommand,
|
|
5
6
|
DynamoDBClient,
|
|
6
7
|
GetItemCommand,
|
|
@@ -11,7 +12,14 @@ import {
|
|
|
11
12
|
UpdateItemCommand,
|
|
12
13
|
} from "@aws-sdk/client-dynamodb";
|
|
13
14
|
import {marshall, unmarshall} from "@aws-sdk/util-dynamodb";
|
|
14
|
-
import {replace, uniqWith, isEqual, pickBy} from "lodash";
|
|
15
|
+
import {replace, uniqWith, isEqual, pickBy, get} from "lodash";
|
|
16
|
+
import {
|
|
17
|
+
HandlerExecutionContext,
|
|
18
|
+
InitializeHandler,
|
|
19
|
+
InitializeHandlerArguments,
|
|
20
|
+
InitializeHandlerOutput,
|
|
21
|
+
MetadataBearer
|
|
22
|
+
} from "@smithy/types";
|
|
15
23
|
|
|
16
24
|
const expressionAttributeKey = (key: string) => replace(key, /-/g, "_");
|
|
17
25
|
|
|
@@ -119,6 +127,35 @@ const paginate = <T>(array: Array<T>, pageSize: number) => {
|
|
|
119
127
|
}, [] as Array<Array<T>>);
|
|
120
128
|
}
|
|
121
129
|
|
|
130
|
+
export interface ConsumedCapacityDetail {
|
|
131
|
+
ReturnConsumedCapacity: ReturnConsumedCapacity | undefined
|
|
132
|
+
ConsumedCapacity: ConsumedCapacity | ConsumedCapacity[] | undefined
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface ConsumedCapacityMiddlewareConfig {
|
|
136
|
+
onConsumedCapacity: (consumedCapacity: ConsumedCapacityDetail) => Promise<unknown>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export const consumedCapacityMiddleware =
|
|
140
|
+
(consumedCapacityMiddlewareConfig: ConsumedCapacityMiddlewareConfig) =>
|
|
141
|
+
<Output extends MetadataBearer = MetadataBearer>(
|
|
142
|
+
next: InitializeHandler<any, Output>,
|
|
143
|
+
context: HandlerExecutionContext
|
|
144
|
+
): InitializeHandler<any, Output> =>
|
|
145
|
+
async (args: InitializeHandlerArguments<any>): Promise<InitializeHandlerOutput<Output>> => {
|
|
146
|
+
try {
|
|
147
|
+
const {input} = args;
|
|
148
|
+
const {ReturnConsumedCapacity} = input;
|
|
149
|
+
const response = await next(args);
|
|
150
|
+
const {output} = response;
|
|
151
|
+
const consumedCapacity = get(output, "ConsumedCapacity") as ConsumedCapacity | undefined;
|
|
152
|
+
await consumedCapacityMiddlewareConfig.onConsumedCapacity({ReturnConsumedCapacity, ConsumedCapacity: consumedCapacity});
|
|
153
|
+
return response;
|
|
154
|
+
} catch (error) {
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
122
159
|
export class DynamoDbRepository<K, T> {
|
|
123
160
|
|
|
124
161
|
constructor(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import { DynamoDBClient, CreateTableCommand, DescribeTableCommand } from "@aws-sdk/client-dynamodb";
|
|
3
3
|
import { LocalstackContainer, StartedLocalStackContainer } from "@testcontainers/localstack";
|
|
4
|
-
import {DynamoDbRepository, FilterOperator} from "../src";
|
|
4
|
+
import {ConsumedCapacityDetail, consumedCapacityMiddleware, DynamoDbRepository, FilterOperator} from "../src";
|
|
5
5
|
|
|
6
6
|
describe('DynamoDbRepository Integration Tests', () => {
|
|
7
7
|
let container: StartedLocalStackContainer;
|
|
@@ -12,6 +12,19 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
12
12
|
const tableName = 'test-table';
|
|
13
13
|
const compositeTableName = 'test-composite-table';
|
|
14
14
|
const gsiTableName = 'test-gsi-table';
|
|
15
|
+
const consumedCapacityRegister = new Array<ConsumedCapacityDetail>() ;
|
|
16
|
+
|
|
17
|
+
const getConsumedCapacity = (consumedCapacity: ConsumedCapacityDetail) => {
|
|
18
|
+
if (Array.isArray(consumedCapacity.ConsumedCapacity)) {
|
|
19
|
+
return consumedCapacity.ConsumedCapacity
|
|
20
|
+
.reduce((total, capacity) => total + (capacity?.CapacityUnits || 0), 0);
|
|
21
|
+
}
|
|
22
|
+
return consumedCapacity.ConsumedCapacity?.CapacityUnits || 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const sumConsumedCapacity = () =>
|
|
26
|
+
consumedCapacityRegister.reduce((total, value) =>
|
|
27
|
+
total + getConsumedCapacity(value), 0);
|
|
15
28
|
|
|
16
29
|
beforeAll(async () => {
|
|
17
30
|
// Start LocalStack container with DynamoDB
|
|
@@ -28,7 +41,11 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
28
41
|
},
|
|
29
42
|
});
|
|
30
43
|
|
|
31
|
-
|
|
44
|
+
dynamoDBClient.middlewareStack
|
|
45
|
+
.add(consumedCapacityMiddleware({onConsumedCapacity: async (consumedCapacity) =>
|
|
46
|
+
consumedCapacityRegister.push(consumedCapacity)}));
|
|
47
|
+
|
|
48
|
+
// Create the test table with a simple key
|
|
32
49
|
await dynamoDBClient.send(
|
|
33
50
|
new CreateTableCommand({
|
|
34
51
|
TableName: tableName,
|
|
@@ -42,7 +59,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
42
59
|
})
|
|
43
60
|
);
|
|
44
61
|
|
|
45
|
-
// Create the test table with composite key (partition key + sort key)
|
|
62
|
+
// Create the test table with a composite key (partition key + sort key)
|
|
46
63
|
await dynamoDBClient.send(
|
|
47
64
|
new CreateTableCommand({
|
|
48
65
|
TableName: compositeTableName,
|
|
@@ -108,6 +125,10 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
108
125
|
gsiRepository = new DynamoDbRepository(dynamoDBClient, gsiTableName, "userId", "itemId");
|
|
109
126
|
});
|
|
110
127
|
|
|
128
|
+
beforeEach(async () => {
|
|
129
|
+
consumedCapacityRegister.splice(0, consumedCapacityRegister.length);
|
|
130
|
+
});
|
|
131
|
+
|
|
111
132
|
afterAll(async () => {
|
|
112
133
|
// Clean up
|
|
113
134
|
if (dynamoDBClient) {
|
|
@@ -122,6 +143,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
122
143
|
it('should return undefined when item does not exist', async () => {
|
|
123
144
|
const result = await repository.getItem({ id: 'non-existent' });
|
|
124
145
|
expect(result).toBeUndefined();
|
|
146
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
125
147
|
});
|
|
126
148
|
|
|
127
149
|
it('should return the item when it exists', async () => {
|
|
@@ -132,6 +154,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
132
154
|
const result = await repository.getItem(key);
|
|
133
155
|
|
|
134
156
|
expect(result).toEqual(record);
|
|
157
|
+
expect(sumConsumedCapacity()).toEqual(2);
|
|
135
158
|
});
|
|
136
159
|
});
|
|
137
160
|
|
|
@@ -143,6 +166,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
143
166
|
const result = await repository.putItem(key, record);
|
|
144
167
|
|
|
145
168
|
expect(result).toEqual(record);
|
|
169
|
+
expect(sumConsumedCapacity()).toEqual(1.5);
|
|
146
170
|
});
|
|
147
171
|
});
|
|
148
172
|
|
|
@@ -155,6 +179,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
155
179
|
await repository.deleteItem(key);
|
|
156
180
|
const afterDelete = await repository.getItem(key);
|
|
157
181
|
expect(afterDelete).toBeUndefined();
|
|
182
|
+
expect(sumConsumedCapacity()).toEqual(2);
|
|
158
183
|
});
|
|
159
184
|
});
|
|
160
185
|
|
|
@@ -171,6 +196,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
171
196
|
name: 'Updated Name',
|
|
172
197
|
email: 'original@example.com'
|
|
173
198
|
});
|
|
199
|
+
expect(sumConsumedCapacity()).toEqual(3);
|
|
174
200
|
});
|
|
175
201
|
});
|
|
176
202
|
|
|
@@ -183,6 +209,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
183
209
|
{ id: `batch-item-${i}`, name: `Item ${i}`, age: i * 10 }
|
|
184
210
|
);
|
|
185
211
|
}
|
|
212
|
+
consumedCapacityRegister.splice(0, consumedCapacityRegister.length);
|
|
186
213
|
});
|
|
187
214
|
|
|
188
215
|
it('should retrieve multiple items by keys', async () => {
|
|
@@ -203,6 +230,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
203
230
|
expect.objectContaining({ id: 'batch-item-3', name: 'Item 3', age: 30 }),
|
|
204
231
|
])
|
|
205
232
|
);
|
|
233
|
+
expect(sumConsumedCapacity()).toEqual(1.5);
|
|
206
234
|
});
|
|
207
235
|
|
|
208
236
|
it('should handle empty keys array', async () => {
|
|
@@ -210,6 +238,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
210
238
|
|
|
211
239
|
expect(results).toBeDefined();
|
|
212
240
|
expect(results?.length).toBe(0);
|
|
241
|
+
expect(sumConsumedCapacity()).toEqual(0);
|
|
213
242
|
});
|
|
214
243
|
|
|
215
244
|
it('should handle non-existent keys gracefully', async () => {
|
|
@@ -230,6 +259,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
230
259
|
const ids = existingItems?.map(item => item.id);
|
|
231
260
|
expect(ids).toContain('batch-item-1');
|
|
232
261
|
expect(ids).toContain('batch-item-2');
|
|
262
|
+
expect(sumConsumedCapacity()).toEqual(1);
|
|
233
263
|
});
|
|
234
264
|
|
|
235
265
|
it('should handle batch size over 100 items (pagination)', async () => {
|
|
@@ -254,6 +284,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
254
284
|
expect(item50).toBeDefined();
|
|
255
285
|
expect(item100).toBeDefined();
|
|
256
286
|
expect(item150).toBeDefined();
|
|
287
|
+
expect(sumConsumedCapacity()).toEqual(300);
|
|
257
288
|
}, 60000);
|
|
258
289
|
|
|
259
290
|
it('should retrieve composite key items', async () => {
|
|
@@ -288,6 +319,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
288
319
|
expect.objectContaining({ userId: 'user-batch-2', itemId: 'item-c', price: 300 }),
|
|
289
320
|
])
|
|
290
321
|
);
|
|
322
|
+
expect(sumConsumedCapacity()).toEqual(6);
|
|
291
323
|
});
|
|
292
324
|
|
|
293
325
|
it('should maintain order independence', async () => {
|
|
@@ -307,6 +339,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
307
339
|
expect(ids).toContain('batch-item-1');
|
|
308
340
|
expect(ids).toContain('batch-item-3');
|
|
309
341
|
expect(ids).toContain('batch-item-5');
|
|
342
|
+
expect(sumConsumedCapacity()).toEqual(1.5);
|
|
310
343
|
});
|
|
311
344
|
|
|
312
345
|
it('should handle duplicate keys in input', async () => {
|
|
@@ -328,6 +361,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
328
361
|
|
|
329
362
|
expect(item1Count).toBeGreaterThanOrEqual(1);
|
|
330
363
|
expect(item2Count).toBeGreaterThanOrEqual(1);
|
|
364
|
+
expect(sumConsumedCapacity()).toEqual(1);
|
|
331
365
|
});
|
|
332
366
|
|
|
333
367
|
it('should retrieve all attributes for batched items', async () => {
|
|
@@ -347,6 +381,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
347
381
|
age: 30,
|
|
348
382
|
status: 'active'
|
|
349
383
|
});
|
|
384
|
+
expect(sumConsumedCapacity()).toEqual(2);
|
|
350
385
|
});
|
|
351
386
|
});
|
|
352
387
|
|
|
@@ -365,7 +400,9 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
365
400
|
name: 'Test Item',
|
|
366
401
|
age: 25
|
|
367
402
|
});
|
|
403
|
+
expect(sumConsumedCapacity()).toEqual(2);
|
|
368
404
|
});
|
|
405
|
+
|
|
369
406
|
});
|
|
370
407
|
|
|
371
408
|
describe('with composite key (partition + sort)', () => {
|
|
@@ -383,6 +420,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
383
420
|
{ userId, itemId: 'item-3' },
|
|
384
421
|
{ userId, itemId: 'item-3', name: 'Item Three', category: 'electronics', price: 150 }
|
|
385
422
|
);
|
|
423
|
+
consumedCapacityRegister.splice(0, consumedCapacityRegister.length);
|
|
386
424
|
});
|
|
387
425
|
|
|
388
426
|
it('should retrieve all items for a partition key', async () => {
|
|
@@ -402,7 +440,9 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
402
440
|
expect(results).toBeDefined();
|
|
403
441
|
expect(results?.length).toBe(2);
|
|
404
442
|
expect(results?.every(item => item.category === 'electronics')).toBe(true);
|
|
443
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
405
444
|
});
|
|
445
|
+
|
|
406
446
|
});
|
|
407
447
|
|
|
408
448
|
describe('with GSI (Global Secondary Index)', () => {
|
|
@@ -468,6 +508,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
468
508
|
|
|
469
509
|
// Wait for GSI to be consistent
|
|
470
510
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
511
|
+
consumedCapacityRegister.splice(0, consumedCapacityRegister.length);
|
|
471
512
|
});
|
|
472
513
|
|
|
473
514
|
it('should query items using GSI and fetch full items via batchGetItems', async () => {
|
|
@@ -478,6 +519,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
478
519
|
expect(results).toBeDefined();
|
|
479
520
|
// When using index, it queries GSI then uses batchGetItems to fetch full items
|
|
480
521
|
expect(Array.isArray(results)).toBe(true);
|
|
522
|
+
expect(sumConsumedCapacity()).toEqual(2);
|
|
481
523
|
});
|
|
482
524
|
|
|
483
525
|
it('should query all items with specific status using GSI', async () => {
|
|
@@ -493,6 +535,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
493
535
|
expect(item.status).toBe('active');
|
|
494
536
|
});
|
|
495
537
|
}
|
|
538
|
+
expect(sumConsumedCapacity()).toEqual(2);
|
|
496
539
|
});
|
|
497
540
|
|
|
498
541
|
it('should combine GSI query with filter expressions', async () => {
|
|
@@ -511,6 +554,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
511
554
|
expect(item.category).toBe('electronics');
|
|
512
555
|
});
|
|
513
556
|
}
|
|
557
|
+
expect(sumConsumedCapacity()).toEqual(1.5);
|
|
514
558
|
});
|
|
515
559
|
|
|
516
560
|
it('should return full item attributes when querying via GSI', async () => {
|
|
@@ -532,6 +576,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
532
576
|
expect(item).toHaveProperty('createdAt');
|
|
533
577
|
}
|
|
534
578
|
}
|
|
579
|
+
expect(sumConsumedCapacity()).toEqual(2);
|
|
535
580
|
});
|
|
536
581
|
|
|
537
582
|
it('should handle GSI query with multiple items', async () => {
|
|
@@ -550,6 +595,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
550
595
|
expect(item).toHaveProperty('itemId');
|
|
551
596
|
});
|
|
552
597
|
}
|
|
598
|
+
expect(sumConsumedCapacity()).toEqual(2);
|
|
553
599
|
});
|
|
554
600
|
|
|
555
601
|
it('should respect projection when querying GSI', async () => {
|
|
@@ -568,6 +614,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
568
614
|
expect(item).toHaveProperty('status');
|
|
569
615
|
});
|
|
570
616
|
}
|
|
617
|
+
expect(sumConsumedCapacity()).toEqual(2);
|
|
571
618
|
});
|
|
572
619
|
|
|
573
620
|
it('should handle empty results from GSI query', async () => {
|
|
@@ -578,6 +625,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
578
625
|
|
|
579
626
|
expect(results).toBeDefined();
|
|
580
627
|
expect(results?.length).toBe(0);
|
|
628
|
+
expect(sumConsumedCapacity()).toEqual(0);
|
|
581
629
|
});
|
|
582
630
|
});
|
|
583
631
|
|
|
@@ -601,6 +649,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
601
649
|
}
|
|
602
650
|
|
|
603
651
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
652
|
+
consumedCapacityRegister.splice(0, consumedCapacityRegister.length);
|
|
604
653
|
});
|
|
605
654
|
|
|
606
655
|
it('should retrieve all items across multiple pages via GSI', async () => {
|
|
@@ -611,8 +660,10 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
611
660
|
|
|
612
661
|
expect(results).toBeDefined();
|
|
613
662
|
expect(Array.isArray(results)).toBe(true);
|
|
663
|
+
expect(sumConsumedCapacity()).toEqual(62);
|
|
614
664
|
// Should handle pagination internally via batchGetItems
|
|
615
665
|
}, 60000);
|
|
666
|
+
|
|
616
667
|
});
|
|
617
668
|
});
|
|
618
669
|
|
|
@@ -649,6 +700,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
649
700
|
for (const data of testData) {
|
|
650
701
|
await repository.putItem({ id: data.id }, data);
|
|
651
702
|
}
|
|
703
|
+
consumedCapacityRegister.splice(0, consumedCapacityRegister.length);
|
|
652
704
|
});
|
|
653
705
|
|
|
654
706
|
describe('EQUALS operator', () => {
|
|
@@ -662,6 +714,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
662
714
|
|
|
663
715
|
expect(results).toBeDefined();
|
|
664
716
|
expect(results?.every(item => item.status === 'active')).toBe(true);
|
|
717
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
665
718
|
});
|
|
666
719
|
|
|
667
720
|
it('should filter items with exact number match', async () => {
|
|
@@ -676,6 +729,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
676
729
|
if (results && results.length > 0) {
|
|
677
730
|
expect(results[0].age).toBe(30);
|
|
678
731
|
}
|
|
732
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
679
733
|
});
|
|
680
734
|
|
|
681
735
|
it('should return empty array when no match found', async () => {
|
|
@@ -688,6 +742,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
688
742
|
|
|
689
743
|
expect(results).toBeDefined();
|
|
690
744
|
expect(results?.length).toBe(0);
|
|
745
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
691
746
|
});
|
|
692
747
|
});
|
|
693
748
|
|
|
@@ -704,6 +759,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
704
759
|
if (results && results.length > 0) {
|
|
705
760
|
expect(results[0].status).not.toBe('inactive');
|
|
706
761
|
}
|
|
762
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
707
763
|
});
|
|
708
764
|
|
|
709
765
|
it('should filter items not matching number value', async () => {
|
|
@@ -718,6 +774,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
718
774
|
if (results && results.length > 0) {
|
|
719
775
|
expect(results[0].age).not.toBe(25);
|
|
720
776
|
}
|
|
777
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
721
778
|
});
|
|
722
779
|
});
|
|
723
780
|
|
|
@@ -734,6 +791,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
734
791
|
if (results && results.length > 0) {
|
|
735
792
|
expect(results.every(item => item.age && item.age > 30)).toBe(true);
|
|
736
793
|
}
|
|
794
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
737
795
|
});
|
|
738
796
|
|
|
739
797
|
it('should filter items greater than decimal value', async () => {
|
|
@@ -748,6 +806,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
748
806
|
if (results && results.length > 0) {
|
|
749
807
|
expect(results.every(item => item.score && item.score > 89.0)).toBe(true);
|
|
750
808
|
}
|
|
809
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
751
810
|
});
|
|
752
811
|
|
|
753
812
|
it('should return empty array when no items are greater', async () => {
|
|
@@ -760,6 +819,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
760
819
|
|
|
761
820
|
expect(results).toBeDefined();
|
|
762
821
|
expect(results?.length).toBe(0);
|
|
822
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
763
823
|
});
|
|
764
824
|
});
|
|
765
825
|
|
|
@@ -776,6 +836,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
776
836
|
if (results && results.length > 0) {
|
|
777
837
|
expect(results.every(item => item.age && item.age >= 30)).toBe(true);
|
|
778
838
|
}
|
|
839
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
779
840
|
});
|
|
780
841
|
|
|
781
842
|
it('should include items with exact value', async () => {
|
|
@@ -791,6 +852,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
791
852
|
const exactMatch = results.find(item => item.score === 95.5);
|
|
792
853
|
expect(exactMatch).toBeDefined();
|
|
793
854
|
}
|
|
855
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
794
856
|
});
|
|
795
857
|
});
|
|
796
858
|
|
|
@@ -807,6 +869,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
807
869
|
if (results && results.length > 0) {
|
|
808
870
|
expect(results.every(item => item.age && item.age < 30)).toBe(true);
|
|
809
871
|
}
|
|
872
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
810
873
|
});
|
|
811
874
|
|
|
812
875
|
it('should filter items less than decimal value', async () => {
|
|
@@ -821,6 +884,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
821
884
|
if (results && results.length > 0) {
|
|
822
885
|
expect(results.every(item => item.score && item.score < 75.0)).toBe(true);
|
|
823
886
|
}
|
|
887
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
824
888
|
});
|
|
825
889
|
});
|
|
826
890
|
|
|
@@ -837,6 +901,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
837
901
|
if (results && results.length > 0) {
|
|
838
902
|
expect(results.every(item => item.age && item.age <= 25)).toBe(true);
|
|
839
903
|
}
|
|
904
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
840
905
|
});
|
|
841
906
|
|
|
842
907
|
it('should include items with exact value', async () => {
|
|
@@ -852,6 +917,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
852
917
|
const exactMatch = results.find(item => item.score === 90.0);
|
|
853
918
|
expect(exactMatch).toBeDefined();
|
|
854
919
|
}
|
|
920
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
855
921
|
});
|
|
856
922
|
});
|
|
857
923
|
|
|
@@ -868,6 +934,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
868
934
|
if (results && results.length > 0) {
|
|
869
935
|
expect(results.every(item => ['active', 'pending'].includes(item.status || ''))).toBe(true);
|
|
870
936
|
}
|
|
937
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
871
938
|
});
|
|
872
939
|
|
|
873
940
|
it('should filter items with value in array of numbers', async () => {
|
|
@@ -882,6 +949,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
882
949
|
if (results && results.length > 0) {
|
|
883
950
|
expect(results.every(item => [25, 30, 35].includes(item.age || 0))).toBe(true);
|
|
884
951
|
}
|
|
952
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
885
953
|
});
|
|
886
954
|
|
|
887
955
|
it('should return empty array when value not in list', async () => {
|
|
@@ -894,6 +962,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
894
962
|
|
|
895
963
|
expect(results).toBeDefined();
|
|
896
964
|
expect(results?.length).toBe(0);
|
|
965
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
897
966
|
});
|
|
898
967
|
|
|
899
968
|
it('should handle single value in array', async () => {
|
|
@@ -908,6 +977,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
908
977
|
if (results && results.length > 0) {
|
|
909
978
|
expect(results[0].status).toBe('active');
|
|
910
979
|
}
|
|
980
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
911
981
|
});
|
|
912
982
|
});
|
|
913
983
|
|
|
@@ -924,6 +994,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
924
994
|
if (results && results.length > 0) {
|
|
925
995
|
expect(results.every(item => item.age && item.age >= 25 && item.age <= 35)).toBe(true);
|
|
926
996
|
}
|
|
997
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
927
998
|
});
|
|
928
999
|
|
|
929
1000
|
it('should filter items with decimal value between range', async () => {
|
|
@@ -938,6 +1009,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
938
1009
|
if (results && results.length > 0) {
|
|
939
1010
|
expect(results.every(item => item.score && item.score >= 80.0 && item.score <= 90.0)).toBe(true);
|
|
940
1011
|
}
|
|
1012
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
941
1013
|
});
|
|
942
1014
|
|
|
943
1015
|
it('should include boundary values', async () => {
|
|
@@ -954,6 +1026,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
954
1026
|
const hasUpperBound = results.some(item => item.age === 40);
|
|
955
1027
|
expect(hasLowerBound || hasUpperBound).toBe(true);
|
|
956
1028
|
}
|
|
1029
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
957
1030
|
});
|
|
958
1031
|
|
|
959
1032
|
it('should return empty array when no values in range', async () => {
|
|
@@ -966,6 +1039,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
966
1039
|
|
|
967
1040
|
expect(results).toBeDefined();
|
|
968
1041
|
expect(results?.length).toBe(0);
|
|
1042
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
969
1043
|
});
|
|
970
1044
|
|
|
971
1045
|
it('should filter items with string value between range (lexicographical)', async () => {
|
|
@@ -982,6 +1056,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
982
1056
|
item.name && item.name >= 'Alice' && item.name <= 'Diana'
|
|
983
1057
|
)).toBe(true);
|
|
984
1058
|
}
|
|
1059
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
985
1060
|
});
|
|
986
1061
|
});
|
|
987
1062
|
|
|
@@ -1021,6 +1096,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
1021
1096
|
item.score && item.score >= 80.0
|
|
1022
1097
|
)).toBe(true);
|
|
1023
1098
|
}
|
|
1099
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
1024
1100
|
});
|
|
1025
1101
|
});
|
|
1026
1102
|
|
|
@@ -1037,6 +1113,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
1037
1113
|
if (results && results.length > 0) {
|
|
1038
1114
|
expect(results.every(item => item.status !== 'inactive')).toBe(true);
|
|
1039
1115
|
}
|
|
1116
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
1040
1117
|
});
|
|
1041
1118
|
|
|
1042
1119
|
it('should negate IN operator', async () => {
|
|
@@ -1053,6 +1130,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
1053
1130
|
!['active', 'pending'].includes(item.status || '')
|
|
1054
1131
|
)).toBe(true);
|
|
1055
1132
|
}
|
|
1133
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
1056
1134
|
});
|
|
1057
1135
|
|
|
1058
1136
|
it('should negate BETWEEN operator', async () => {
|
|
@@ -1069,6 +1147,7 @@ describe('DynamoDbRepository Integration Tests', () => {
|
|
|
1069
1147
|
item.age && (item.age < 25 || item.age > 35)
|
|
1070
1148
|
)).toBe(true);
|
|
1071
1149
|
}
|
|
1150
|
+
expect(sumConsumedCapacity()).toEqual(0.5);
|
|
1072
1151
|
});
|
|
1073
1152
|
});
|
|
1074
1153
|
|