@model-ts/dynamodb 4.1.0 → 4.2.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 (91) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cjs/__test__/client-env-guard.test.d.ts +1 -0
  3. package/dist/cjs/__test__/client-env-guard.test.js +28 -0
  4. package/dist/cjs/__test__/client-env-guard.test.js.map +1 -0
  5. package/dist/cjs/__test__/conformance.test.d.ts +1 -0
  6. package/dist/cjs/__test__/conformance.test.js +1835 -0
  7. package/dist/cjs/__test__/conformance.test.js.map +1 -0
  8. package/dist/cjs/__test__/in-memory.spec.test.d.ts +1 -0
  9. package/dist/cjs/__test__/in-memory.spec.test.js +185 -0
  10. package/dist/cjs/__test__/in-memory.spec.test.js.map +1 -0
  11. package/dist/cjs/client.d.ts +2 -2
  12. package/dist/cjs/client.js +14 -6
  13. package/dist/cjs/client.js.map +1 -1
  14. package/dist/cjs/errors.d.ts +13 -1
  15. package/dist/cjs/errors.js +12 -1
  16. package/dist/cjs/errors.js.map +1 -1
  17. package/dist/cjs/in-memory/document-client.d.ts +45 -0
  18. package/dist/cjs/in-memory/document-client.js +795 -0
  19. package/dist/cjs/in-memory/document-client.js.map +1 -0
  20. package/dist/cjs/in-memory/expression.d.ts +42 -0
  21. package/dist/cjs/in-memory/expression.js +585 -0
  22. package/dist/cjs/in-memory/expression.js.map +1 -0
  23. package/dist/cjs/in-memory/index.d.ts +2 -0
  24. package/dist/cjs/in-memory/index.js +6 -0
  25. package/dist/cjs/in-memory/index.js.map +1 -0
  26. package/dist/cjs/in-memory/spec.d.ts +23 -0
  27. package/dist/cjs/in-memory/spec.js +141 -0
  28. package/dist/cjs/in-memory/spec.js.map +1 -0
  29. package/dist/cjs/in-memory/store.d.ts +73 -0
  30. package/dist/cjs/in-memory/store.js +267 -0
  31. package/dist/cjs/in-memory/store.js.map +1 -0
  32. package/dist/cjs/in-memory/treap.d.ts +31 -0
  33. package/dist/cjs/in-memory/treap.js +187 -0
  34. package/dist/cjs/in-memory/treap.js.map +1 -0
  35. package/dist/cjs/in-memory/utils.d.ts +10 -0
  36. package/dist/cjs/in-memory/utils.js +38 -0
  37. package/dist/cjs/in-memory/utils.js.map +1 -0
  38. package/dist/cjs/sandbox.js +44 -0
  39. package/dist/cjs/sandbox.js.map +1 -1
  40. package/dist/esm/__test__/client-env-guard.test.d.ts +1 -0
  41. package/dist/esm/__test__/client-env-guard.test.js +26 -0
  42. package/dist/esm/__test__/client-env-guard.test.js.map +1 -0
  43. package/dist/esm/__test__/conformance.test.d.ts +1 -0
  44. package/dist/esm/__test__/conformance.test.js +1833 -0
  45. package/dist/esm/__test__/conformance.test.js.map +1 -0
  46. package/dist/esm/__test__/in-memory.spec.test.d.ts +1 -0
  47. package/dist/esm/__test__/in-memory.spec.test.js +183 -0
  48. package/dist/esm/__test__/in-memory.spec.test.js.map +1 -0
  49. package/dist/esm/client.d.ts +2 -2
  50. package/dist/esm/client.js +14 -6
  51. package/dist/esm/client.js.map +1 -1
  52. package/dist/esm/errors.d.ts +13 -1
  53. package/dist/esm/errors.js +10 -0
  54. package/dist/esm/errors.js.map +1 -1
  55. package/dist/esm/in-memory/document-client.d.ts +45 -0
  56. package/dist/esm/in-memory/document-client.js +791 -0
  57. package/dist/esm/in-memory/document-client.js.map +1 -0
  58. package/dist/esm/in-memory/expression.d.ts +42 -0
  59. package/dist/esm/in-memory/expression.js +577 -0
  60. package/dist/esm/in-memory/expression.js.map +1 -0
  61. package/dist/esm/in-memory/index.d.ts +2 -0
  62. package/dist/esm/in-memory/index.js +3 -0
  63. package/dist/esm/in-memory/index.js.map +1 -0
  64. package/dist/esm/in-memory/spec.d.ts +23 -0
  65. package/dist/esm/in-memory/spec.js +138 -0
  66. package/dist/esm/in-memory/spec.js.map +1 -0
  67. package/dist/esm/in-memory/store.d.ts +73 -0
  68. package/dist/esm/in-memory/store.js +258 -0
  69. package/dist/esm/in-memory/store.js.map +1 -0
  70. package/dist/esm/in-memory/treap.d.ts +31 -0
  71. package/dist/esm/in-memory/treap.js +183 -0
  72. package/dist/esm/in-memory/treap.js.map +1 -0
  73. package/dist/esm/in-memory/utils.d.ts +10 -0
  74. package/dist/esm/in-memory/utils.js +28 -0
  75. package/dist/esm/in-memory/utils.js.map +1 -0
  76. package/dist/esm/sandbox.js +44 -0
  77. package/dist/esm/sandbox.js.map +1 -1
  78. package/package.json +2 -1
  79. package/src/__test__/client-env-guard.test.ts +31 -0
  80. package/src/__test__/conformance.test.ts +2042 -0
  81. package/src/__test__/in-memory.spec.test.ts +230 -0
  82. package/src/client.ts +17 -4
  83. package/src/errors.ts +24 -0
  84. package/src/in-memory/document-client.ts +1140 -0
  85. package/src/in-memory/expression.ts +730 -0
  86. package/src/in-memory/index.ts +2 -0
  87. package/src/in-memory/spec.ts +159 -0
  88. package/src/in-memory/store.ts +360 -0
  89. package/src/in-memory/treap.ts +239 -0
  90. package/src/in-memory/utils.ts +45 -0
  91. package/src/sandbox.ts +56 -0
@@ -0,0 +1,1835 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const client_1 = require("../client");
5
+ const sandbox_1 = require("../sandbox");
6
+ const spec_1 = require("../in-memory/spec");
7
+ const dynamodb_1 = tslib_1.__importDefault(require("aws-sdk/clients/dynamodb"));
8
+ const LOCAL_DDB = new dynamodb_1.default({
9
+ accessKeyId: "xxx",
10
+ secretAccessKey: "xxx",
11
+ endpoint: process.env.LOCAL_ENDPOINT,
12
+ region: "local",
13
+ });
14
+ const withEngine = (engine, run) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
15
+ const previous = process.env.EXPERIMENTAL_DYNAMODB_IN_MEMORY;
16
+ if (engine === "memory")
17
+ process.env.EXPERIMENTAL_DYNAMODB_IN_MEMORY = "1";
18
+ else
19
+ delete process.env.EXPERIMENTAL_DYNAMODB_IN_MEMORY;
20
+ const client = new client_1.Client({ tableName: "table" });
21
+ const sandbox = yield sandbox_1.createSandbox(client);
22
+ try {
23
+ return yield run({
24
+ engine,
25
+ client,
26
+ sandbox,
27
+ tableName: client.tableName,
28
+ });
29
+ }
30
+ finally {
31
+ yield sandbox.destroy();
32
+ if (typeof previous === "undefined")
33
+ delete process.env.EXPERIMENTAL_DYNAMODB_IN_MEMORY;
34
+ else
35
+ process.env.EXPERIMENTAL_DYNAMODB_IN_MEMORY = previous;
36
+ }
37
+ });
38
+ const normalizeScalar = (value) => {
39
+ if (typeof value === "string") {
40
+ return value.replace(/[0-9a-f]{40}/gi, "<table>");
41
+ }
42
+ return value;
43
+ };
44
+ const normalizeObject = (value) => {
45
+ if (value === undefined)
46
+ return undefined;
47
+ if (Array.isArray(value))
48
+ return value.map(normalizeObject);
49
+ if (value && typeof value === "object") {
50
+ return Object.fromEntries(Object.keys(value)
51
+ .sort()
52
+ .filter((key) => typeof value[key] !== "undefined")
53
+ .map((key) => [normalizeScalar(key), normalizeObject(value[key])]));
54
+ }
55
+ return normalizeScalar(value);
56
+ };
57
+ const normalizeSnapshot = (snapshot) => Object.fromEntries(Object.keys(snapshot)
58
+ .sort()
59
+ .map((key) => [key, normalizeObject(snapshot[key])]));
60
+ const sanitizeErrorMessage = (message) => canonicalizeValidationMessage(message
61
+ .replace(/[0-9a-f]{40}/gi, "<table>")
62
+ .replace(/\s+/g, " ")
63
+ .trim()
64
+ .replace(/\.$/, "")
65
+ .replace(/\([^)]*\)/g, (match) => {
66
+ if (match.includes("<table>"))
67
+ return "(<table>)";
68
+ return match;
69
+ }));
70
+ const canonicalizeValidationMessage = (message) => {
71
+ if (message ===
72
+ "Consistent read cannot be true when querying a GSI" ||
73
+ message ===
74
+ "Consistent reads are not supported on global secondary indexes") {
75
+ return "Consistent reads are not supported on global secondary indexes";
76
+ }
77
+ if (message === "The provided starting key is invalid" ||
78
+ message === "Exclusive Start Key must have same size as table's key schema") {
79
+ return "The provided starting key is invalid";
80
+ }
81
+ return message;
82
+ };
83
+ const normalizeError = (error) => {
84
+ var _a, _b, _c;
85
+ const code = (_a = error === null || error === void 0 ? void 0 : error.code) !== null && _a !== void 0 ? _a : (typeof (error === null || error === void 0 ? void 0 : error.name) === "string" && error.name !== "Error"
86
+ ? error.name
87
+ : "UnknownError");
88
+ if (code === "NotSupportedError") {
89
+ return {
90
+ code,
91
+ message: sanitizeErrorMessage(String((_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : "")),
92
+ method: error === null || error === void 0 ? void 0 : error.method,
93
+ featurePath: error === null || error === void 0 ? void 0 : error.featurePath,
94
+ reason: error === null || error === void 0 ? void 0 : error.reason,
95
+ };
96
+ }
97
+ return {
98
+ code,
99
+ message: sanitizeErrorMessage(String((_c = error === null || error === void 0 ? void 0 : error.message) !== null && _c !== void 0 ? _c : "")),
100
+ };
101
+ };
102
+ const normalizeResult = (method, value) => {
103
+ var _a, _b, _c, _d, _e;
104
+ if (!value || typeof value !== "object")
105
+ return value;
106
+ if (method === "batchGet") {
107
+ const responses = (_a = value.Responses) !== null && _a !== void 0 ? _a : {};
108
+ const normalizedResponses = Object.fromEntries(Object.keys(responses)
109
+ .sort()
110
+ .map((tableName) => [
111
+ normalizeScalar(tableName),
112
+ [...responses[tableName]].sort(compareItemsByPKSK).map(normalizeObject),
113
+ ]));
114
+ const unprocessed = (_c = (_b = value.UnprocessedKeys) !== null && _b !== void 0 ? _b : value.UnprocessedItems) !== null && _c !== void 0 ? _c : {};
115
+ const normalizedUnprocessed = Object.fromEntries(Object.keys(unprocessed)
116
+ .sort()
117
+ .map((tableName) => [normalizeScalar(tableName), normalizeObject(unprocessed[tableName])]));
118
+ return { Responses: normalizedResponses, Unprocessed: normalizedUnprocessed };
119
+ }
120
+ if (method === "delete") {
121
+ const normalized = (_d = normalizeObject(value)) !== null && _d !== void 0 ? _d : {};
122
+ if (!normalized || typeof normalized !== "object")
123
+ return normalized;
124
+ const { ConsumedCapacity: _ignored } = normalized, rest = tslib_1.__rest(normalized, ["ConsumedCapacity"]);
125
+ return rest;
126
+ }
127
+ if (method === "scan") {
128
+ return Object.assign(Object.assign({}, normalizeObject(value)), { Items: [...((_e = value.Items) !== null && _e !== void 0 ? _e : [])].sort(compareItemsByPKSK).map(normalizeObject) });
129
+ }
130
+ return normalizeObject(value);
131
+ };
132
+ const compareItemsByPKSK = (left, right) => {
133
+ var _a, _b, _c, _d;
134
+ const leftPK = String((_a = left === null || left === void 0 ? void 0 : left.PK) !== null && _a !== void 0 ? _a : "");
135
+ const rightPK = String((_b = right === null || right === void 0 ? void 0 : right.PK) !== null && _b !== void 0 ? _b : "");
136
+ if (leftPK !== rightPK)
137
+ return leftPK < rightPK ? -1 : 1;
138
+ const leftSK = String((_c = left === null || left === void 0 ? void 0 : left.SK) !== null && _c !== void 0 ? _c : "");
139
+ const rightSK = String((_d = right === null || right === void 0 ? void 0 : right.SK) !== null && _d !== void 0 ? _d : "");
140
+ if (leftSK !== rightSK)
141
+ return leftSK < rightSK ? -1 : 1;
142
+ return 0;
143
+ };
144
+ const runVector = (engine, vector) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
145
+ return withEngine(engine, (ctx) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
146
+ if (vector.setup) {
147
+ yield vector.setup(ctx);
148
+ }
149
+ try {
150
+ const raw = yield vector.execute(ctx);
151
+ const snapshot = normalizeSnapshot(yield ctx.sandbox.snapshot());
152
+ return {
153
+ ok: true,
154
+ value: vector.normalizeResult
155
+ ? vector.normalizeResult(raw)
156
+ : normalizeResult(vector.method, raw),
157
+ snapshot,
158
+ };
159
+ }
160
+ catch (error) {
161
+ const snapshot = normalizeSnapshot(yield ctx.sandbox.snapshot());
162
+ return {
163
+ ok: false,
164
+ error: normalizeError(error),
165
+ snapshot,
166
+ };
167
+ }
168
+ }));
169
+ });
170
+ const createSeed = (ctx) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
171
+ yield ctx.client.documentClient
172
+ .batchWrite({
173
+ RequestItems: {
174
+ [ctx.tableName]: [
175
+ {
176
+ PutRequest: {
177
+ Item: {
178
+ PK: "USER#1",
179
+ SK: "PROFILE#001",
180
+ GSI2PK: "EMAIL#ada@example.com",
181
+ GSI2SK: "USER#1",
182
+ name: "Ada",
183
+ age: 30,
184
+ status: "active",
185
+ score: 10,
186
+ tags: ["math", "history"],
187
+ },
188
+ },
189
+ },
190
+ {
191
+ PutRequest: {
192
+ Item: {
193
+ PK: "USER#1",
194
+ SK: "ORDER#001",
195
+ GSI2PK: "ORDER#OPEN",
196
+ GSI2SK: "2021-01-01T00:00:00.000Z",
197
+ total: 120,
198
+ currency: "USD",
199
+ status: "open",
200
+ },
201
+ },
202
+ },
203
+ {
204
+ PutRequest: {
205
+ Item: {
206
+ PK: "USER#1",
207
+ SK: "ORDER#002",
208
+ GSI2PK: "ORDER#CLOSED",
209
+ GSI2SK: "2021-01-02T00:00:00.000Z",
210
+ total: 99,
211
+ currency: "USD",
212
+ status: "closed",
213
+ },
214
+ },
215
+ },
216
+ {
217
+ PutRequest: {
218
+ Item: {
219
+ PK: "USER#2",
220
+ SK: "PROFILE#001",
221
+ GSI2PK: "EMAIL#grace@example.com",
222
+ GSI2SK: "USER#2",
223
+ name: "Grace",
224
+ age: 35,
225
+ status: "pending",
226
+ score: 20,
227
+ },
228
+ },
229
+ },
230
+ {
231
+ PutRequest: {
232
+ Item: {
233
+ PK: "USER#3",
234
+ SK: "PROFILE#001",
235
+ GSI2PK: "EMAIL#alan@example.com",
236
+ GSI2SK: "USER#3",
237
+ name: "Alan",
238
+ age: 28,
239
+ status: "active",
240
+ score: 15,
241
+ },
242
+ },
243
+ },
244
+ ],
245
+ },
246
+ })
247
+ .promise();
248
+ });
249
+ const createAuxTableIfNeeded = (ctx, tableName) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
250
+ if (ctx.engine !== "local")
251
+ return;
252
+ yield LOCAL_DDB.createTable({
253
+ TableName: tableName,
254
+ AttributeDefinitions: [
255
+ { AttributeName: "PK", AttributeType: "S" },
256
+ { AttributeName: "SK", AttributeType: "S" },
257
+ ],
258
+ KeySchema: [
259
+ { AttributeName: "PK", KeyType: "HASH" },
260
+ { AttributeName: "SK", KeyType: "RANGE" },
261
+ ],
262
+ BillingMode: "PAY_PER_REQUEST",
263
+ })
264
+ .promise()
265
+ .catch((error) => {
266
+ if ((error === null || error === void 0 ? void 0 : error.code) === "ResourceInUseException")
267
+ return;
268
+ throw error;
269
+ });
270
+ yield LOCAL_DDB.waitFor("tableExists", { TableName: tableName }).promise();
271
+ });
272
+ const destroyAuxTableIfNeeded = (ctx, tableName) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
273
+ if (ctx.engine !== "local")
274
+ return;
275
+ yield LOCAL_DDB.deleteTable({ TableName: tableName })
276
+ .promise()
277
+ .catch((error) => {
278
+ if ((error === null || error === void 0 ? void 0 : error.code) === "ResourceNotFoundException")
279
+ return;
280
+ throw error;
281
+ });
282
+ yield LOCAL_DDB.waitFor("tableNotExists", { TableName: tableName })
283
+ .promise()
284
+ .catch((error) => {
285
+ if ((error === null || error === void 0 ? void 0 : error.code) === "ResourceNotFoundException")
286
+ return;
287
+ throw error;
288
+ });
289
+ });
290
+ const baseVectorsByMethod = {
291
+ get: [
292
+ {
293
+ id: "get.existing",
294
+ method: "get",
295
+ setup: createSeed,
296
+ execute: ({ client, tableName }) => client.documentClient
297
+ .get({ TableName: tableName, Key: { PK: "USER#1", SK: "PROFILE#001" } })
298
+ .promise(),
299
+ },
300
+ {
301
+ id: "get.missing",
302
+ method: "get",
303
+ setup: createSeed,
304
+ execute: ({ client, tableName }) => client.documentClient
305
+ .get({ TableName: tableName, Key: { PK: "USER#404", SK: "PROFILE#001" } })
306
+ .promise(),
307
+ },
308
+ {
309
+ id: "get.consistent-read",
310
+ method: "get",
311
+ setup: createSeed,
312
+ execute: ({ client, tableName }) => client.documentClient
313
+ .get({
314
+ TableName: tableName,
315
+ Key: { PK: "USER#2", SK: "PROFILE#001" },
316
+ ConsistentRead: true,
317
+ })
318
+ .promise(),
319
+ },
320
+ {
321
+ id: "get.bad-key",
322
+ method: "get",
323
+ execute: ({ client, tableName }) => client.documentClient
324
+ .get({ TableName: tableName, Key: { PK: 123, SK: "A" } })
325
+ .promise(),
326
+ },
327
+ ],
328
+ put: [
329
+ {
330
+ id: "put.insert",
331
+ method: "put",
332
+ execute: ({ client, tableName }) => client.documentClient
333
+ .put({
334
+ TableName: tableName,
335
+ Item: {
336
+ PK: "USER#10",
337
+ SK: "PROFILE#001",
338
+ GSI2PK: "EMAIL#new@example.com",
339
+ GSI2SK: "USER#10",
340
+ name: "New",
341
+ score: 1,
342
+ },
343
+ })
344
+ .promise(),
345
+ },
346
+ {
347
+ id: "put.overwrite",
348
+ method: "put",
349
+ setup: createSeed,
350
+ execute: ({ client, tableName }) => client.documentClient
351
+ .put({
352
+ TableName: tableName,
353
+ Item: {
354
+ PK: "USER#1",
355
+ SK: "PROFILE#001",
356
+ GSI2PK: "EMAIL#ada@example.com",
357
+ GSI2SK: "USER#1",
358
+ name: "Ada Lovelace",
359
+ age: 31,
360
+ },
361
+ })
362
+ .promise(),
363
+ },
364
+ {
365
+ id: "put.conditional-fail",
366
+ method: "put",
367
+ setup: createSeed,
368
+ execute: ({ client, tableName }) => client.documentClient
369
+ .put({
370
+ TableName: tableName,
371
+ Item: {
372
+ PK: "USER#1",
373
+ SK: "PROFILE#001",
374
+ name: "Nope",
375
+ },
376
+ ConditionExpression: "attribute_not_exists(PK)",
377
+ })
378
+ .promise(),
379
+ },
380
+ {
381
+ id: "put.conditional-pass-with-placeholders",
382
+ method: "put",
383
+ setup: createSeed,
384
+ execute: ({ client, tableName }) => client.documentClient
385
+ .put({
386
+ TableName: tableName,
387
+ Item: {
388
+ PK: "USER#11",
389
+ SK: "PROFILE#001",
390
+ name: "Placeholder",
391
+ status: "active",
392
+ },
393
+ ConditionExpression: "attribute_not_exists(#pk) and :status = :status",
394
+ ExpressionAttributeNames: { "#pk": "PK" },
395
+ ExpressionAttributeValues: { ":status": "active" },
396
+ })
397
+ .promise(),
398
+ },
399
+ {
400
+ id: "put.bad-condition-expression",
401
+ method: "put",
402
+ execute: ({ client, tableName }) => client.documentClient
403
+ .put({
404
+ TableName: tableName,
405
+ Item: { PK: "A", SK: "A" },
406
+ ConditionExpression: "unknown_fn(PK)",
407
+ })
408
+ .promise(),
409
+ },
410
+ ],
411
+ update: [
412
+ {
413
+ id: "update.set-and-return-all-new",
414
+ method: "update",
415
+ setup: createSeed,
416
+ execute: ({ client, tableName }) => client.documentClient
417
+ .update({
418
+ TableName: tableName,
419
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
420
+ UpdateExpression: "SET #name = :name, #score = :score",
421
+ ExpressionAttributeNames: { "#name": "name", "#score": "score" },
422
+ ExpressionAttributeValues: { ":name": "Ada Updated", ":score": 11 },
423
+ ReturnValues: "ALL_NEW",
424
+ })
425
+ .promise(),
426
+ },
427
+ {
428
+ id: "update.remove-gsi",
429
+ method: "update",
430
+ setup: createSeed,
431
+ execute: ({ client, tableName }) => client.documentClient
432
+ .update({
433
+ TableName: tableName,
434
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
435
+ UpdateExpression: "REMOVE GSI2PK, GSI2SK",
436
+ ReturnValues: "ALL_NEW",
437
+ })
438
+ .promise(),
439
+ },
440
+ {
441
+ id: "update.upsert",
442
+ method: "update",
443
+ execute: ({ client, tableName }) => client.documentClient
444
+ .update({
445
+ TableName: tableName,
446
+ Key: { PK: "USER#99", SK: "PROFILE#001" },
447
+ UpdateExpression: "SET #name = :name",
448
+ ExpressionAttributeNames: { "#name": "name" },
449
+ ExpressionAttributeValues: { ":name": "Created" },
450
+ ReturnValues: "ALL_NEW",
451
+ })
452
+ .promise(),
453
+ },
454
+ {
455
+ id: "update.conditional-fail",
456
+ method: "update",
457
+ setup: createSeed,
458
+ execute: ({ client, tableName }) => client.documentClient
459
+ .update({
460
+ TableName: tableName,
461
+ Key: { PK: "USER#404", SK: "PROFILE#001" },
462
+ ConditionExpression: "attribute_exists(PK)",
463
+ UpdateExpression: "SET #name = :name",
464
+ ExpressionAttributeNames: { "#name": "name" },
465
+ ExpressionAttributeValues: { ":name": "Nope" },
466
+ })
467
+ .promise(),
468
+ },
469
+ {
470
+ id: "update.bad-update-expression",
471
+ method: "update",
472
+ setup: createSeed,
473
+ execute: ({ client, tableName }) => client.documentClient
474
+ .update({
475
+ TableName: tableName,
476
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
477
+ UpdateExpression: "SET",
478
+ })
479
+ .promise(),
480
+ },
481
+ {
482
+ id: "update.missing-placeholder",
483
+ method: "update",
484
+ setup: createSeed,
485
+ execute: ({ client, tableName }) => client.documentClient
486
+ .update({
487
+ TableName: tableName,
488
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
489
+ UpdateExpression: "SET #name = :missing",
490
+ ExpressionAttributeNames: { "#name": "name" },
491
+ })
492
+ .promise(),
493
+ },
494
+ {
495
+ id: "update.key-mutation-error",
496
+ method: "update",
497
+ setup: createSeed,
498
+ execute: ({ client, tableName }) => client.documentClient
499
+ .update({
500
+ TableName: tableName,
501
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
502
+ UpdateExpression: "SET PK = :pk",
503
+ ExpressionAttributeValues: { ":pk": "USER#X" },
504
+ })
505
+ .promise(),
506
+ },
507
+ ],
508
+ delete: [
509
+ {
510
+ id: "delete.existing",
511
+ method: "delete",
512
+ setup: createSeed,
513
+ execute: ({ client, tableName }) => client.documentClient
514
+ .delete({ TableName: tableName, Key: { PK: "USER#3", SK: "PROFILE#001" } })
515
+ .promise(),
516
+ },
517
+ {
518
+ id: "delete.missing",
519
+ method: "delete",
520
+ setup: createSeed,
521
+ execute: ({ client, tableName }) => client.documentClient
522
+ .delete({ TableName: tableName, Key: { PK: "USER#404", SK: "PROFILE#001" } })
523
+ .promise(),
524
+ },
525
+ {
526
+ id: "delete.conditional-fail",
527
+ method: "delete",
528
+ setup: createSeed,
529
+ execute: ({ client, tableName }) => client.documentClient
530
+ .delete({
531
+ TableName: tableName,
532
+ Key: { PK: "USER#2", SK: "PROFILE#001" },
533
+ ConditionExpression: "#status = :status",
534
+ ExpressionAttributeNames: { "#status": "status" },
535
+ ExpressionAttributeValues: { ":status": "active" },
536
+ })
537
+ .promise(),
538
+ },
539
+ {
540
+ id: "delete.conditional-pass",
541
+ method: "delete",
542
+ setup: createSeed,
543
+ execute: ({ client, tableName }) => client.documentClient
544
+ .delete({
545
+ TableName: tableName,
546
+ Key: { PK: "USER#2", SK: "PROFILE#001" },
547
+ ConditionExpression: "#status = :status",
548
+ ExpressionAttributeNames: { "#status": "status" },
549
+ ExpressionAttributeValues: { ":status": "pending" },
550
+ })
551
+ .promise(),
552
+ },
553
+ ],
554
+ query: [
555
+ {
556
+ id: "query.hash-only",
557
+ method: "query",
558
+ setup: createSeed,
559
+ execute: ({ client, tableName }) => client.documentClient
560
+ .query({
561
+ TableName: tableName,
562
+ KeyConditionExpression: "PK = :pk",
563
+ ExpressionAttributeValues: { ":pk": "USER#1" },
564
+ })
565
+ .promise(),
566
+ },
567
+ {
568
+ id: "query.begins-with",
569
+ method: "query",
570
+ setup: createSeed,
571
+ execute: ({ client, tableName }) => client.documentClient
572
+ .query({
573
+ TableName: tableName,
574
+ KeyConditionExpression: "PK = :pk and begins_with(SK, :prefix)",
575
+ ExpressionAttributeValues: {
576
+ ":pk": "USER#1",
577
+ ":prefix": "ORDER#",
578
+ },
579
+ })
580
+ .promise(),
581
+ },
582
+ {
583
+ id: "query.range-between",
584
+ method: "query",
585
+ setup: createSeed,
586
+ execute: ({ client, tableName }) => client.documentClient
587
+ .query({
588
+ TableName: tableName,
589
+ KeyConditionExpression: "PK = :pk and SK between :from and :to",
590
+ ExpressionAttributeValues: {
591
+ ":pk": "USER#1",
592
+ ":from": "ORDER#001",
593
+ ":to": "ORDER#010",
594
+ },
595
+ })
596
+ .promise(),
597
+ },
598
+ {
599
+ id: "query.range-operator-and-backward",
600
+ method: "query",
601
+ setup: createSeed,
602
+ execute: ({ client, tableName }) => client.documentClient
603
+ .query({
604
+ TableName: tableName,
605
+ KeyConditionExpression: "PK = :pk and SK >= :from",
606
+ ExpressionAttributeValues: {
607
+ ":pk": "USER#1",
608
+ ":from": "ORDER#001",
609
+ },
610
+ ScanIndexForward: false,
611
+ })
612
+ .promise(),
613
+ },
614
+ {
615
+ id: "query.filter-limit-scanned-count",
616
+ method: "query",
617
+ setup: createSeed,
618
+ execute: ({ client, tableName }) => client.documentClient
619
+ .query({
620
+ TableName: tableName,
621
+ KeyConditionExpression: "PK = :pk",
622
+ FilterExpression: "#status = :status",
623
+ ExpressionAttributeNames: { "#status": "status" },
624
+ ExpressionAttributeValues: {
625
+ ":pk": "USER#1",
626
+ ":status": "open",
627
+ },
628
+ Limit: 1,
629
+ })
630
+ .promise(),
631
+ },
632
+ {
633
+ id: "query.pagination-exclusive-start",
634
+ method: "query",
635
+ setup: (ctx) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
636
+ yield createSeed(ctx);
637
+ }),
638
+ execute: ({ client, tableName }) => client.documentClient
639
+ .query({
640
+ TableName: tableName,
641
+ KeyConditionExpression: "PK = :pk",
642
+ ExpressionAttributeValues: { ":pk": "USER#1" },
643
+ Limit: 1,
644
+ })
645
+ .promise(),
646
+ },
647
+ {
648
+ id: "query.gsi",
649
+ method: "query",
650
+ setup: createSeed,
651
+ execute: ({ client, tableName }) => client.documentClient
652
+ .query({
653
+ TableName: tableName,
654
+ IndexName: "GSI2",
655
+ KeyConditionExpression: "GSI2PK = :pk",
656
+ ExpressionAttributeValues: { ":pk": "ORDER#OPEN" },
657
+ })
658
+ .promise(),
659
+ },
660
+ {
661
+ id: "query.gsi-consistent-read-error",
662
+ method: "query",
663
+ setup: createSeed,
664
+ execute: ({ client, tableName }) => client.documentClient
665
+ .query({
666
+ TableName: tableName,
667
+ IndexName: "GSI2",
668
+ KeyConditionExpression: "GSI2PK = :pk",
669
+ ExpressionAttributeValues: { ":pk": "ORDER#OPEN" },
670
+ ConsistentRead: true,
671
+ })
672
+ .promise(),
673
+ },
674
+ {
675
+ id: "query.bad-key-condition",
676
+ method: "query",
677
+ setup: createSeed,
678
+ execute: ({ client, tableName }) => client.documentClient
679
+ .query({
680
+ TableName: tableName,
681
+ KeyConditionExpression: "PK = :pk and invalid(SK, :x)",
682
+ ExpressionAttributeValues: {
683
+ ":pk": "USER#1",
684
+ ":x": "A",
685
+ },
686
+ })
687
+ .promise(),
688
+ },
689
+ ],
690
+ scan: [
691
+ {
692
+ id: "scan.all",
693
+ method: "scan",
694
+ setup: createSeed,
695
+ execute: ({ client, tableName }) => client.documentClient.scan({ TableName: tableName }).promise(),
696
+ },
697
+ {
698
+ id: "scan.filter-limit",
699
+ method: "scan",
700
+ setup: createSeed,
701
+ execute: ({ client, tableName }) => client.documentClient
702
+ .scan({
703
+ TableName: tableName,
704
+ FilterExpression: "attribute_exists(GSI2PK) and #status = :status",
705
+ ExpressionAttributeNames: { "#status": "status" },
706
+ ExpressionAttributeValues: { ":status": "active" },
707
+ })
708
+ .promise(),
709
+ },
710
+ {
711
+ id: "scan.bad-limit",
712
+ method: "scan",
713
+ setup: createSeed,
714
+ execute: ({ client, tableName }) => client.documentClient
715
+ .scan({ TableName: tableName, Limit: 0 })
716
+ .promise(),
717
+ },
718
+ ],
719
+ batchGet: [
720
+ {
721
+ id: "batch-get.basic",
722
+ method: "batchGet",
723
+ setup: createSeed,
724
+ execute: ({ client, tableName }) => client.documentClient
725
+ .batchGet({
726
+ RequestItems: {
727
+ [tableName]: {
728
+ Keys: [
729
+ { PK: "USER#1", SK: "PROFILE#001" },
730
+ { PK: "USER#2", SK: "PROFILE#001" },
731
+ ],
732
+ },
733
+ },
734
+ })
735
+ .promise(),
736
+ },
737
+ {
738
+ id: "batch-get.missing-items",
739
+ method: "batchGet",
740
+ setup: createSeed,
741
+ execute: ({ client, tableName }) => client.documentClient
742
+ .batchGet({
743
+ RequestItems: {
744
+ [tableName]: {
745
+ Keys: [
746
+ { PK: "USER#1", SK: "PROFILE#001" },
747
+ { PK: "USER#404", SK: "PROFILE#001" },
748
+ ],
749
+ },
750
+ },
751
+ })
752
+ .promise(),
753
+ },
754
+ {
755
+ id: "batch-get.duplicate-keys-error",
756
+ method: "batchGet",
757
+ setup: createSeed,
758
+ execute: ({ client, tableName }) => client.documentClient
759
+ .batchGet({
760
+ RequestItems: {
761
+ [tableName]: {
762
+ Keys: [
763
+ { PK: "USER#1", SK: "PROFILE#001" },
764
+ { PK: "USER#1", SK: "PROFILE#001" },
765
+ ],
766
+ },
767
+ },
768
+ })
769
+ .promise(),
770
+ },
771
+ {
772
+ id: "batch-get.too-many-keys-error",
773
+ method: "batchGet",
774
+ execute: ({ client, tableName }) => client.documentClient
775
+ .batchGet({
776
+ RequestItems: {
777
+ [tableName]: {
778
+ Keys: Array.from({ length: 101 }).map((_, i) => ({
779
+ PK: `USER#${i}`,
780
+ SK: "PROFILE#001",
781
+ })),
782
+ },
783
+ },
784
+ })
785
+ .promise(),
786
+ },
787
+ ],
788
+ batchWrite: [
789
+ {
790
+ id: "batch-write.put-and-delete",
791
+ method: "batchWrite",
792
+ setup: createSeed,
793
+ execute: ({ client, tableName }) => client.documentClient
794
+ .batchWrite({
795
+ RequestItems: {
796
+ [tableName]: [
797
+ {
798
+ PutRequest: {
799
+ Item: {
800
+ PK: "USER#20",
801
+ SK: "PROFILE#001",
802
+ name: "BatchPut",
803
+ },
804
+ },
805
+ },
806
+ {
807
+ DeleteRequest: {
808
+ Key: { PK: "USER#3", SK: "PROFILE#001" },
809
+ },
810
+ },
811
+ ],
812
+ },
813
+ })
814
+ .promise(),
815
+ },
816
+ {
817
+ id: "batch-write.too-many-items-error",
818
+ method: "batchWrite",
819
+ execute: ({ client, tableName }) => client.documentClient
820
+ .batchWrite({
821
+ RequestItems: {
822
+ [tableName]: Array.from({ length: 26 }).map((_, i) => ({
823
+ PutRequest: {
824
+ Item: { PK: `U#${i}`, SK: "S#1" },
825
+ },
826
+ })),
827
+ },
828
+ })
829
+ .promise(),
830
+ },
831
+ {
832
+ id: "batch-write.invalid-entry-error",
833
+ method: "batchWrite",
834
+ execute: ({ client, tableName }) => client.documentClient
835
+ .batchWrite({
836
+ RequestItems: {
837
+ [tableName]: [{ Nope: true }],
838
+ },
839
+ })
840
+ .promise(),
841
+ },
842
+ ],
843
+ transactWrite: [
844
+ {
845
+ id: "transact-write.success",
846
+ method: "transactWrite",
847
+ setup: createSeed,
848
+ execute: ({ client, tableName }) => client.documentClient
849
+ .transactWrite({
850
+ TransactItems: [
851
+ {
852
+ ConditionCheck: {
853
+ TableName: tableName,
854
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
855
+ ConditionExpression: "attribute_exists(PK)",
856
+ },
857
+ },
858
+ {
859
+ Update: {
860
+ TableName: tableName,
861
+ Key: { PK: "USER#2", SK: "PROFILE#001" },
862
+ UpdateExpression: "SET #score = :score",
863
+ ExpressionAttributeNames: { "#score": "score" },
864
+ ExpressionAttributeValues: { ":score": 25 },
865
+ },
866
+ },
867
+ {
868
+ Put: {
869
+ TableName: tableName,
870
+ Item: {
871
+ PK: "USER#30",
872
+ SK: "PROFILE#001",
873
+ name: "FromTx",
874
+ },
875
+ ConditionExpression: "attribute_not_exists(PK)",
876
+ },
877
+ },
878
+ {
879
+ Delete: {
880
+ TableName: tableName,
881
+ Key: { PK: "USER#3", SK: "PROFILE#001" },
882
+ },
883
+ },
884
+ ],
885
+ })
886
+ .promise(),
887
+ },
888
+ {
889
+ id: "transact-write.conditional-fail-and-rollback",
890
+ method: "transactWrite",
891
+ setup: createSeed,
892
+ execute: ({ client, tableName }) => client.documentClient
893
+ .transactWrite({
894
+ TransactItems: [
895
+ {
896
+ Update: {
897
+ TableName: tableName,
898
+ Key: { PK: "USER#2", SK: "PROFILE#001" },
899
+ UpdateExpression: "SET #score = :score",
900
+ ExpressionAttributeNames: { "#score": "score" },
901
+ ExpressionAttributeValues: { ":score": 100 },
902
+ },
903
+ },
904
+ {
905
+ ConditionCheck: {
906
+ TableName: tableName,
907
+ Key: { PK: "USER#404", SK: "PROFILE#001" },
908
+ ConditionExpression: "attribute_exists(PK)",
909
+ },
910
+ },
911
+ ],
912
+ })
913
+ .promise(),
914
+ },
915
+ {
916
+ id: "transact-write.duplicate-target-error",
917
+ method: "transactWrite",
918
+ setup: createSeed,
919
+ execute: ({ client, tableName }) => client.documentClient
920
+ .transactWrite({
921
+ TransactItems: [
922
+ {
923
+ Update: {
924
+ TableName: tableName,
925
+ Key: { PK: "USER#2", SK: "PROFILE#001" },
926
+ UpdateExpression: "SET #score = :score",
927
+ ExpressionAttributeNames: { "#score": "score" },
928
+ ExpressionAttributeValues: { ":score": 100 },
929
+ },
930
+ },
931
+ {
932
+ Delete: {
933
+ TableName: tableName,
934
+ Key: { PK: "USER#2", SK: "PROFILE#001" },
935
+ },
936
+ },
937
+ ],
938
+ })
939
+ .promise(),
940
+ },
941
+ {
942
+ id: "transact-write.too-many-items-error",
943
+ method: "transactWrite",
944
+ execute: ({ client, tableName }) => client.documentClient
945
+ .transactWrite({
946
+ TransactItems: Array.from({ length: 101 }).map((_, i) => ({
947
+ Put: {
948
+ TableName: tableName,
949
+ Item: { PK: `TX#${i}`, SK: "S#1" },
950
+ },
951
+ })),
952
+ })
953
+ .promise(),
954
+ },
955
+ {
956
+ id: "transact-write.bad-update-expression-error",
957
+ method: "transactWrite",
958
+ setup: createSeed,
959
+ execute: ({ client, tableName }) => client.documentClient
960
+ .transactWrite({
961
+ TransactItems: [
962
+ {
963
+ Update: {
964
+ TableName: tableName,
965
+ Key: { PK: "USER#2", SK: "PROFILE#001" },
966
+ UpdateExpression: "SET",
967
+ },
968
+ },
969
+ ],
970
+ })
971
+ .promise(),
972
+ },
973
+ ],
974
+ };
975
+ const generatedVectors = Object.keys(spec_1.IN_MEMORY_SPEC.methods).flatMap((method) => {
976
+ const typedMethod = method;
977
+ return baseVectorsByMethod[typedMethod];
978
+ });
979
+ const additionalDifferentialVectors = [
980
+ {
981
+ id: "query.pagination-continuity",
982
+ method: "query",
983
+ setup: createSeed,
984
+ execute: ({ client, tableName }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
985
+ const p1 = yield client.documentClient
986
+ .query({
987
+ TableName: tableName,
988
+ KeyConditionExpression: "PK = :pk",
989
+ ExpressionAttributeValues: { ":pk": "USER#1" },
990
+ Limit: 1,
991
+ })
992
+ .promise();
993
+ const p2 = yield client.documentClient
994
+ .query({
995
+ TableName: tableName,
996
+ KeyConditionExpression: "PK = :pk",
997
+ ExpressionAttributeValues: { ":pk": "USER#1" },
998
+ Limit: 1,
999
+ ExclusiveStartKey: p1.LastEvaluatedKey,
1000
+ })
1001
+ .promise();
1002
+ const p3 = yield client.documentClient
1003
+ .query({
1004
+ TableName: tableName,
1005
+ KeyConditionExpression: "PK = :pk",
1006
+ ExpressionAttributeValues: { ":pk": "USER#1" },
1007
+ Limit: 10,
1008
+ ExclusiveStartKey: p2.LastEvaluatedKey,
1009
+ })
1010
+ .promise();
1011
+ return { p1, p2, p3 };
1012
+ }),
1013
+ },
1014
+ {
1015
+ id: "scan.pagination-continuity",
1016
+ method: "scan",
1017
+ setup: createSeed,
1018
+ execute: ({ client, tableName }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
1019
+ var _a;
1020
+ const pages = [];
1021
+ let startKey = undefined;
1022
+ do {
1023
+ const page = yield client.documentClient
1024
+ .scan({
1025
+ TableName: tableName,
1026
+ Limit: 2,
1027
+ ExclusiveStartKey: startKey,
1028
+ })
1029
+ .promise();
1030
+ pages.push(page);
1031
+ startKey = page.LastEvaluatedKey;
1032
+ } while (startKey);
1033
+ const full = yield client.documentClient
1034
+ .scan({
1035
+ TableName: tableName,
1036
+ })
1037
+ .promise();
1038
+ return {
1039
+ pagedItems: pages.flatMap((page) => { var _a; return (_a = page.Items) !== null && _a !== void 0 ? _a : []; }),
1040
+ fullItems: (_a = full.Items) !== null && _a !== void 0 ? _a : [],
1041
+ pageCount: pages.length,
1042
+ };
1043
+ }),
1044
+ normalizeResult: (value) => {
1045
+ var _a, _b, _c, _d;
1046
+ return (Object.assign(Object.assign({}, normalizeObject(value)), { pagedItems: [...((_a = value.pagedItems) !== null && _a !== void 0 ? _a : [])]
1047
+ .sort(compareItemsByPKSK)
1048
+ .map(normalizeObject), fullItems: [...((_b = value.fullItems) !== null && _b !== void 0 ? _b : [])]
1049
+ .sort(compareItemsByPKSK)
1050
+ .map(normalizeObject), pageCount: value.pageCount, pagedMatchesFull: JSON.stringify([...((_c = value.pagedItems) !== null && _c !== void 0 ? _c : [])].sort(compareItemsByPKSK).map(normalizeObject)) ===
1051
+ JSON.stringify([...((_d = value.fullItems) !== null && _d !== void 0 ? _d : [])].sort(compareItemsByPKSK).map(normalizeObject)) }));
1052
+ },
1053
+ },
1054
+ {
1055
+ id: "query.bad-exclusive-start-key",
1056
+ method: "query",
1057
+ setup: createSeed,
1058
+ execute: ({ client, tableName }) => client.documentClient
1059
+ .query({
1060
+ TableName: tableName,
1061
+ IndexName: "GSI2",
1062
+ KeyConditionExpression: "GSI2PK = :pk",
1063
+ ExpressionAttributeValues: { ":pk": "ORDER#OPEN" },
1064
+ ExclusiveStartKey: { PK: "USER#1", SK: "ORDER#001" },
1065
+ })
1066
+ .promise(),
1067
+ },
1068
+ {
1069
+ id: "query.missing-expression-attribute-name",
1070
+ method: "query",
1071
+ setup: createSeed,
1072
+ execute: ({ client, tableName }) => client.documentClient
1073
+ .query({
1074
+ TableName: tableName,
1075
+ KeyConditionExpression: "#pk = :pk",
1076
+ ExpressionAttributeValues: { ":pk": "USER#1" },
1077
+ })
1078
+ .promise(),
1079
+ },
1080
+ {
1081
+ id: "query.limit-non-integer",
1082
+ method: "query",
1083
+ setup: createSeed,
1084
+ execute: ({ client, tableName }) => client.documentClient
1085
+ .query({
1086
+ TableName: tableName,
1087
+ KeyConditionExpression: "PK = :pk",
1088
+ ExpressionAttributeValues: { ":pk": "USER#1" },
1089
+ Limit: 1.5,
1090
+ })
1091
+ .promise(),
1092
+ },
1093
+ {
1094
+ id: "update.if-not-exists-existing-plus",
1095
+ method: "update",
1096
+ setup: createSeed,
1097
+ execute: ({ client, tableName }) => client.documentClient
1098
+ .update({
1099
+ TableName: tableName,
1100
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
1101
+ UpdateExpression: "SET #score = if_not_exists(#score, :zero) + :inc",
1102
+ ExpressionAttributeNames: { "#score": "score" },
1103
+ ExpressionAttributeValues: { ":zero": 0, ":inc": 2 },
1104
+ ReturnValues: "ALL_NEW",
1105
+ })
1106
+ .promise(),
1107
+ },
1108
+ {
1109
+ id: "update.if-not-exists-missing-plus",
1110
+ method: "update",
1111
+ setup: createSeed,
1112
+ execute: ({ client, tableName }) => client.documentClient
1113
+ .update({
1114
+ TableName: tableName,
1115
+ Key: { PK: "USER#2", SK: "PROFILE#001" },
1116
+ UpdateExpression: "SET #visits = if_not_exists(#visits, :zero) + :inc",
1117
+ ExpressionAttributeNames: { "#visits": "visits" },
1118
+ ExpressionAttributeValues: { ":zero": 0, ":inc": 1 },
1119
+ ReturnValues: "ALL_NEW",
1120
+ })
1121
+ .promise(),
1122
+ },
1123
+ {
1124
+ id: "update.list-append-with-if-not-exists",
1125
+ method: "update",
1126
+ setup: createSeed,
1127
+ execute: ({ client, tableName }) => client.documentClient
1128
+ .update({
1129
+ TableName: tableName,
1130
+ Key: { PK: "USER#2", SK: "PROFILE#001" },
1131
+ UpdateExpression: "SET #tags = list_append(if_not_exists(#tags, :empty), :more)",
1132
+ ExpressionAttributeNames: { "#tags": "tags" },
1133
+ ExpressionAttributeValues: { ":empty": [], ":more": ["new", "vip"] },
1134
+ ReturnValues: "ALL_NEW",
1135
+ })
1136
+ .promise(),
1137
+ },
1138
+ {
1139
+ id: "scan.filter.contains",
1140
+ method: "scan",
1141
+ setup: createSeed,
1142
+ execute: ({ client, tableName }) => client.documentClient
1143
+ .scan({
1144
+ TableName: tableName,
1145
+ FilterExpression: "contains(#tags, :tag)",
1146
+ ExpressionAttributeNames: { "#tags": "tags" },
1147
+ ExpressionAttributeValues: { ":tag": "math" },
1148
+ })
1149
+ .promise(),
1150
+ },
1151
+ {
1152
+ id: "scan.filter.attribute-type-and-size",
1153
+ method: "scan",
1154
+ setup: createSeed,
1155
+ execute: ({ client, tableName }) => client.documentClient
1156
+ .scan({
1157
+ TableName: tableName,
1158
+ FilterExpression: "attribute_type(#name, :t) and size(#name) > :min",
1159
+ ExpressionAttributeNames: { "#name": "name" },
1160
+ ExpressionAttributeValues: { ":t": "S", ":min": 2 },
1161
+ })
1162
+ .promise(),
1163
+ },
1164
+ {
1165
+ id: "scan.missing-expression-attribute-value",
1166
+ method: "scan",
1167
+ setup: createSeed,
1168
+ execute: ({ client, tableName }) => client.documentClient
1169
+ .scan({
1170
+ TableName: tableName,
1171
+ FilterExpression: "#status = :missing",
1172
+ ExpressionAttributeNames: { "#status": "status" },
1173
+ })
1174
+ .promise(),
1175
+ },
1176
+ {
1177
+ id: "batch-get.multi-table",
1178
+ method: "batchGet",
1179
+ setup: createSeed,
1180
+ execute: (ctx) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
1181
+ const auxTable = `${ctx.tableName}-aux-batch-get`;
1182
+ yield createAuxTableIfNeeded(ctx, auxTable);
1183
+ try {
1184
+ yield ctx.client.documentClient
1185
+ .batchWrite({
1186
+ RequestItems: {
1187
+ [auxTable]: [
1188
+ {
1189
+ PutRequest: {
1190
+ Item: { PK: "AUX#1", SK: "ITEM#1", flag: true },
1191
+ },
1192
+ },
1193
+ ],
1194
+ },
1195
+ })
1196
+ .promise();
1197
+ return yield ctx.client.documentClient
1198
+ .batchGet({
1199
+ RequestItems: {
1200
+ [ctx.tableName]: {
1201
+ Keys: [{ PK: "USER#1", SK: "PROFILE#001" }],
1202
+ },
1203
+ [auxTable]: {
1204
+ Keys: [{ PK: "AUX#1", SK: "ITEM#1" }],
1205
+ },
1206
+ },
1207
+ })
1208
+ .promise();
1209
+ }
1210
+ finally {
1211
+ yield destroyAuxTableIfNeeded(ctx, auxTable);
1212
+ }
1213
+ }),
1214
+ },
1215
+ {
1216
+ id: "batch-write.multi-table",
1217
+ method: "batchWrite",
1218
+ setup: createSeed,
1219
+ normalizeResult: () => ({ UnprocessedItems: {} }),
1220
+ execute: (ctx) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
1221
+ const auxTable = `${ctx.tableName}-aux-batch-write`;
1222
+ yield createAuxTableIfNeeded(ctx, auxTable);
1223
+ try {
1224
+ return yield ctx.client.documentClient
1225
+ .batchWrite({
1226
+ RequestItems: {
1227
+ [ctx.tableName]: [
1228
+ {
1229
+ PutRequest: { Item: { PK: "USER#70", SK: "PROFILE#001", ok: true } },
1230
+ },
1231
+ ],
1232
+ [auxTable]: [
1233
+ {
1234
+ PutRequest: { Item: { PK: "AUX#2", SK: "ITEM#1", ok: true } },
1235
+ },
1236
+ ],
1237
+ },
1238
+ })
1239
+ .promise();
1240
+ }
1241
+ finally {
1242
+ yield destroyAuxTableIfNeeded(ctx, auxTable);
1243
+ }
1244
+ }),
1245
+ },
1246
+ {
1247
+ id: "transact-write.rollback-on-parser-error-mid-transaction",
1248
+ method: "transactWrite",
1249
+ setup: createSeed,
1250
+ execute: ({ client, tableName }) => client.documentClient
1251
+ .transactWrite({
1252
+ TransactItems: [
1253
+ {
1254
+ Update: {
1255
+ TableName: tableName,
1256
+ Key: { PK: "USER#2", SK: "PROFILE#001" },
1257
+ UpdateExpression: "SET #score = :score",
1258
+ ExpressionAttributeNames: { "#score": "score" },
1259
+ ExpressionAttributeValues: { ":score": 999 },
1260
+ },
1261
+ },
1262
+ {
1263
+ Update: {
1264
+ TableName: tableName,
1265
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
1266
+ UpdateExpression: "SET",
1267
+ },
1268
+ },
1269
+ ],
1270
+ })
1271
+ .promise(),
1272
+ },
1273
+ {
1274
+ id: "transact-write.key-mutation-error",
1275
+ method: "transactWrite",
1276
+ setup: createSeed,
1277
+ execute: ({ client, tableName }) => client.documentClient
1278
+ .transactWrite({
1279
+ TransactItems: [
1280
+ {
1281
+ Update: {
1282
+ TableName: tableName,
1283
+ Key: { PK: "USER#2", SK: "PROFILE#001" },
1284
+ UpdateExpression: "SET PK = :pk",
1285
+ ExpressionAttributeValues: { ":pk": "USER#X" },
1286
+ },
1287
+ },
1288
+ ],
1289
+ })
1290
+ .promise(),
1291
+ },
1292
+ ];
1293
+ const supportedParamCoverageVectors = [
1294
+ {
1295
+ id: "coverage.get.supported",
1296
+ method: "get",
1297
+ setup: createSeed,
1298
+ coverage: { supported: ["TableName", "Key", "ConsistentRead"] },
1299
+ execute: ({ client, tableName }) => client.documentClient
1300
+ .get({
1301
+ TableName: tableName,
1302
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
1303
+ ConsistentRead: true,
1304
+ })
1305
+ .promise(),
1306
+ },
1307
+ {
1308
+ id: "coverage.put.supported",
1309
+ method: "put",
1310
+ setup: createSeed,
1311
+ coverage: {
1312
+ supported: [
1313
+ "TableName",
1314
+ "Item",
1315
+ "ConditionExpression",
1316
+ "ExpressionAttributeNames",
1317
+ "ExpressionAttributeValues",
1318
+ ],
1319
+ },
1320
+ execute: ({ client, tableName }) => client.documentClient
1321
+ .put({
1322
+ TableName: tableName,
1323
+ Item: { PK: "COVER#PUT", SK: "1", status: "ok" },
1324
+ ConditionExpression: "attribute_not_exists(#pk) and :v = :v",
1325
+ ExpressionAttributeNames: { "#pk": "PK" },
1326
+ ExpressionAttributeValues: { ":v": "ok" },
1327
+ })
1328
+ .promise(),
1329
+ },
1330
+ {
1331
+ id: "coverage.update.supported",
1332
+ method: "update",
1333
+ setup: createSeed,
1334
+ coverage: {
1335
+ supported: [
1336
+ "TableName",
1337
+ "Key",
1338
+ "ConditionExpression",
1339
+ "UpdateExpression",
1340
+ "ExpressionAttributeNames",
1341
+ "ExpressionAttributeValues",
1342
+ "ReturnValues",
1343
+ ],
1344
+ },
1345
+ execute: ({ client, tableName }) => client.documentClient
1346
+ .update({
1347
+ TableName: tableName,
1348
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
1349
+ ConditionExpression: "attribute_exists(PK)",
1350
+ UpdateExpression: "SET #score = :score",
1351
+ ExpressionAttributeNames: { "#score": "score" },
1352
+ ExpressionAttributeValues: { ":score": 12 },
1353
+ ReturnValues: "ALL_NEW",
1354
+ })
1355
+ .promise(),
1356
+ },
1357
+ {
1358
+ id: "coverage.delete.supported",
1359
+ method: "delete",
1360
+ setup: createSeed,
1361
+ coverage: {
1362
+ supported: [
1363
+ "TableName",
1364
+ "Key",
1365
+ "ConditionExpression",
1366
+ "ExpressionAttributeNames",
1367
+ "ExpressionAttributeValues",
1368
+ ],
1369
+ },
1370
+ execute: ({ client, tableName }) => client.documentClient
1371
+ .delete({
1372
+ TableName: tableName,
1373
+ Key: { PK: "USER#3", SK: "PROFILE#001" },
1374
+ ConditionExpression: "#status = :status",
1375
+ ExpressionAttributeNames: { "#status": "status" },
1376
+ ExpressionAttributeValues: { ":status": "active" },
1377
+ })
1378
+ .promise(),
1379
+ },
1380
+ {
1381
+ id: "coverage.query.supported",
1382
+ method: "query",
1383
+ setup: createSeed,
1384
+ coverage: {
1385
+ supported: [
1386
+ "TableName",
1387
+ "IndexName",
1388
+ "KeyConditionExpression",
1389
+ "FilterExpression",
1390
+ "ExpressionAttributeNames",
1391
+ "ExpressionAttributeValues",
1392
+ "Limit",
1393
+ "ExclusiveStartKey",
1394
+ "ScanIndexForward",
1395
+ "ConsistentRead",
1396
+ ],
1397
+ },
1398
+ execute: ({ client, tableName }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
1399
+ const firstPrimary = yield client.documentClient
1400
+ .query({
1401
+ TableName: tableName,
1402
+ KeyConditionExpression: "PK = :pk",
1403
+ FilterExpression: "attribute_exists(#status)",
1404
+ ExpressionAttributeNames: { "#status": "status" },
1405
+ ExpressionAttributeValues: { ":pk": "USER#1" },
1406
+ ScanIndexForward: true,
1407
+ Limit: 1,
1408
+ })
1409
+ .promise();
1410
+ const secondPrimary = yield client.documentClient
1411
+ .query({
1412
+ TableName: tableName,
1413
+ KeyConditionExpression: "PK = :pk",
1414
+ FilterExpression: "attribute_exists(#status)",
1415
+ ExpressionAttributeNames: { "#status": "status" },
1416
+ ExpressionAttributeValues: { ":pk": "USER#1" },
1417
+ ScanIndexForward: true,
1418
+ Limit: 2,
1419
+ ExclusiveStartKey: firstPrimary.LastEvaluatedKey,
1420
+ })
1421
+ .promise();
1422
+ const gsi = yield client.documentClient
1423
+ .query({
1424
+ TableName: tableName,
1425
+ IndexName: "GSI2",
1426
+ KeyConditionExpression: "GSI2PK = :pk",
1427
+ ExpressionAttributeValues: { ":pk": "ORDER#OPEN" },
1428
+ ConsistentRead: false,
1429
+ Limit: 1,
1430
+ })
1431
+ .promise();
1432
+ return { secondPrimary, gsi };
1433
+ }),
1434
+ },
1435
+ {
1436
+ id: "coverage.scan.supported",
1437
+ method: "scan",
1438
+ setup: createSeed,
1439
+ coverage: {
1440
+ supported: [
1441
+ "TableName",
1442
+ "FilterExpression",
1443
+ "ExpressionAttributeNames",
1444
+ "ExpressionAttributeValues",
1445
+ "Limit",
1446
+ "ExclusiveStartKey",
1447
+ ],
1448
+ },
1449
+ execute: ({ client, tableName }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
1450
+ const first = yield client.documentClient
1451
+ .scan({
1452
+ TableName: tableName,
1453
+ FilterExpression: "#status = :status",
1454
+ ExpressionAttributeNames: { "#status": "status" },
1455
+ ExpressionAttributeValues: { ":status": "active" },
1456
+ Limit: 1,
1457
+ })
1458
+ .promise();
1459
+ yield client.documentClient
1460
+ .scan({
1461
+ TableName: tableName,
1462
+ FilterExpression: "#status = :status",
1463
+ ExpressionAttributeNames: { "#status": "status" },
1464
+ ExpressionAttributeValues: { ":status": "active" },
1465
+ Limit: 2,
1466
+ ExclusiveStartKey: first.LastEvaluatedKey,
1467
+ })
1468
+ .promise();
1469
+ return client.documentClient
1470
+ .scan({
1471
+ TableName: tableName,
1472
+ FilterExpression: "#status = :status",
1473
+ ExpressionAttributeNames: { "#status": "status" },
1474
+ ExpressionAttributeValues: { ":status": "active" },
1475
+ })
1476
+ .promise();
1477
+ }),
1478
+ },
1479
+ {
1480
+ id: "coverage.batchGet.supported",
1481
+ method: "batchGet",
1482
+ setup: createSeed,
1483
+ coverage: { supported: ["RequestItems"] },
1484
+ execute: ({ client, tableName }) => client.documentClient
1485
+ .batchGet({
1486
+ RequestItems: { [tableName]: { Keys: [{ PK: "USER#1", SK: "PROFILE#001" }] } },
1487
+ })
1488
+ .promise(),
1489
+ },
1490
+ {
1491
+ id: "coverage.batchWrite.supported",
1492
+ method: "batchWrite",
1493
+ setup: createSeed,
1494
+ coverage: { supported: ["RequestItems"] },
1495
+ execute: ({ client, tableName }) => client.documentClient
1496
+ .batchWrite({
1497
+ RequestItems: {
1498
+ [tableName]: [{ PutRequest: { Item: { PK: "COVER#BW", SK: "1" } } }],
1499
+ },
1500
+ })
1501
+ .promise(),
1502
+ },
1503
+ {
1504
+ id: "coverage.transactWrite.supported",
1505
+ method: "transactWrite",
1506
+ setup: createSeed,
1507
+ coverage: { supported: ["TransactItems"] },
1508
+ execute: ({ client, tableName }) => client.documentClient
1509
+ .transactWrite({
1510
+ TransactItems: [
1511
+ {
1512
+ ConditionCheck: {
1513
+ TableName: tableName,
1514
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
1515
+ ConditionExpression: "attribute_exists(PK)",
1516
+ },
1517
+ },
1518
+ ],
1519
+ })
1520
+ .promise(),
1521
+ },
1522
+ ];
1523
+ const unsupportedParamVectors = [
1524
+ ...Object.entries(spec_1.IN_MEMORY_SPEC.methods).flatMap(([method, spec]) => {
1525
+ var _a;
1526
+ return ((_a = spec.unsupportedParams) !== null && _a !== void 0 ? _a : []).map((param) => ({
1527
+ id: `unsupported.${method}.${param}`,
1528
+ method: method,
1529
+ coverage: { unsupported: [param] },
1530
+ setup: method === "get" ||
1531
+ method === "put" ||
1532
+ method === "update" ||
1533
+ method === "delete" ||
1534
+ method === "query" ||
1535
+ method === "scan" ||
1536
+ method === "batchGet" ||
1537
+ method === "batchWrite" ||
1538
+ method === "transactWrite"
1539
+ ? createSeed
1540
+ : undefined,
1541
+ execute: (ctx) => {
1542
+ const baseByMethod = {
1543
+ get: {
1544
+ TableName: ctx.tableName,
1545
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
1546
+ },
1547
+ put: {
1548
+ TableName: ctx.tableName,
1549
+ Item: { PK: "UNSUPPORTED#PUT", SK: "1" },
1550
+ },
1551
+ update: {
1552
+ TableName: ctx.tableName,
1553
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
1554
+ UpdateExpression: "SET #name = :name",
1555
+ ExpressionAttributeNames: { "#name": "name" },
1556
+ ExpressionAttributeValues: { ":name": "x" },
1557
+ },
1558
+ delete: {
1559
+ TableName: ctx.tableName,
1560
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
1561
+ },
1562
+ query: {
1563
+ TableName: ctx.tableName,
1564
+ KeyConditionExpression: "PK = :pk",
1565
+ ExpressionAttributeValues: { ":pk": "USER#1" },
1566
+ },
1567
+ scan: {
1568
+ TableName: ctx.tableName,
1569
+ },
1570
+ batchGet: {
1571
+ RequestItems: {
1572
+ [ctx.tableName]: {
1573
+ Keys: [{ PK: "USER#1", SK: "PROFILE#001" }],
1574
+ },
1575
+ },
1576
+ },
1577
+ batchWrite: {
1578
+ RequestItems: {
1579
+ [ctx.tableName]: [{ PutRequest: { Item: { PK: "UNSUPPORTED#BW", SK: "1" } } }],
1580
+ },
1581
+ },
1582
+ transactWrite: {
1583
+ TransactItems: [
1584
+ {
1585
+ ConditionCheck: {
1586
+ TableName: ctx.tableName,
1587
+ Key: { PK: "USER#1", SK: "PROFILE#001" },
1588
+ ConditionExpression: "attribute_exists(PK)",
1589
+ },
1590
+ },
1591
+ ],
1592
+ },
1593
+ };
1594
+ const valueByParam = {
1595
+ AttributesToGet: ["PK"],
1596
+ ProjectionExpression: "PK",
1597
+ ExpressionAttributeNames: { "#pk": "PK" },
1598
+ Expected: {},
1599
+ ReturnValues: "ALL_OLD",
1600
+ ReturnConsumedCapacity: "TOTAL",
1601
+ ReturnItemCollectionMetrics: "SIZE",
1602
+ AttributeUpdates: {},
1603
+ Select: "ALL_ATTRIBUTES",
1604
+ KeyConditions: {},
1605
+ QueryFilter: {},
1606
+ ConditionalOperator: "AND",
1607
+ Segment: 1,
1608
+ TotalSegments: 2,
1609
+ ScanFilter: {},
1610
+ ClientRequestToken: "token-1",
1611
+ };
1612
+ const params = Object.assign(Object.assign({}, baseByMethod[method]), { [param]: valueByParam[param] });
1613
+ return ctx.client.documentClient[method](params).promise();
1614
+ },
1615
+ }));
1616
+ }),
1617
+ ];
1618
+ const seededFuzzVectors = [11, 42, 99].map((seed) => ({
1619
+ id: `fuzz.seed-${seed}`,
1620
+ method: "transactWrite",
1621
+ execute: ({ client, tableName }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
1622
+ var _b, _c;
1623
+ const state = {
1624
+ seed,
1625
+ next: seed,
1626
+ };
1627
+ const random = () => {
1628
+ state.next = (state.next * 48271) % 0x7fffffff;
1629
+ return state.next / 0x7fffffff;
1630
+ };
1631
+ const results = [];
1632
+ for (let i = 0; i < 80; i += 1) {
1633
+ const dice = random();
1634
+ const user = `F#${Math.floor(random() * 8)}`;
1635
+ const key = { PK: user, SK: `S#${Math.floor(random() * 5)}` };
1636
+ if (dice < 0.25) {
1637
+ try {
1638
+ yield client.documentClient
1639
+ .put({
1640
+ TableName: tableName,
1641
+ Item: Object.assign(Object.assign({}, key), { GSI2PK: `GX#${key.PK}`, GSI2SK: key.SK, score: Math.floor(random() * 100), status: random() > 0.5 ? "active" : "pending" }),
1642
+ })
1643
+ .promise();
1644
+ results.push({ op: "put", key, ok: true });
1645
+ }
1646
+ catch (error) {
1647
+ results.push({ op: "put", key, ok: false, error: normalizeError(error) });
1648
+ }
1649
+ continue;
1650
+ }
1651
+ if (dice < 0.5) {
1652
+ try {
1653
+ const mutateGsi = random() > 0.6;
1654
+ const response = yield client.documentClient
1655
+ .update({
1656
+ TableName: tableName,
1657
+ Key: key,
1658
+ UpdateExpression: mutateGsi
1659
+ ? random() > 0.5
1660
+ ? "SET #score = :score, GSI2PK = :gpk, GSI2SK = :gsk"
1661
+ : "SET #score = :score REMOVE GSI2PK, GSI2SK"
1662
+ : "SET #score = :score",
1663
+ ExpressionAttributeNames: { "#score": "score" },
1664
+ ExpressionAttributeValues: mutateGsi
1665
+ ? {
1666
+ ":score": Math.floor(random() * 100),
1667
+ ":gpk": `GX#${key.PK}`,
1668
+ ":gsk": key.SK,
1669
+ }
1670
+ : { ":score": Math.floor(random() * 100) },
1671
+ ReturnValues: "ALL_NEW",
1672
+ })
1673
+ .promise();
1674
+ results.push({
1675
+ op: "update",
1676
+ key,
1677
+ ok: true,
1678
+ attrs: normalizeObject((_b = response.Attributes) !== null && _b !== void 0 ? _b : {}),
1679
+ });
1680
+ }
1681
+ catch (error) {
1682
+ results.push({ op: "update", key, ok: false, error: normalizeError(error) });
1683
+ }
1684
+ continue;
1685
+ }
1686
+ if (dice < 0.7) {
1687
+ try {
1688
+ yield client.documentClient
1689
+ .delete({
1690
+ TableName: tableName,
1691
+ Key: key,
1692
+ ConditionExpression: "attribute_not_exists(blocked)",
1693
+ })
1694
+ .promise();
1695
+ results.push({ op: "delete", key, ok: true });
1696
+ }
1697
+ catch (error) {
1698
+ results.push({ op: "delete", key, ok: false, error: normalizeError(error) });
1699
+ }
1700
+ continue;
1701
+ }
1702
+ if (dice < 0.85) {
1703
+ try {
1704
+ const useGsi = random() > 0.5;
1705
+ const response = useGsi
1706
+ ? yield client.documentClient
1707
+ .query({
1708
+ TableName: tableName,
1709
+ IndexName: "GSI2",
1710
+ KeyConditionExpression: "GSI2PK = :pk",
1711
+ ExpressionAttributeValues: { ":pk": `GX#${user}` },
1712
+ Limit: 3,
1713
+ })
1714
+ .promise()
1715
+ : yield client.documentClient
1716
+ .query({
1717
+ TableName: tableName,
1718
+ KeyConditionExpression: "PK = :pk",
1719
+ ExpressionAttributeValues: { ":pk": user },
1720
+ Limit: 3,
1721
+ })
1722
+ .promise();
1723
+ results.push({
1724
+ op: useGsi ? "query-gsi" : "query",
1725
+ key,
1726
+ ok: true,
1727
+ count: response.Count,
1728
+ scannedCount: response.ScannedCount,
1729
+ items: normalizeObject((_c = response.Items) !== null && _c !== void 0 ? _c : []),
1730
+ });
1731
+ }
1732
+ catch (error) {
1733
+ results.push({ op: "query", key, ok: false, error: normalizeError(error) });
1734
+ }
1735
+ continue;
1736
+ }
1737
+ try {
1738
+ yield client.documentClient
1739
+ .transactWrite({
1740
+ TransactItems: [
1741
+ {
1742
+ Put: {
1743
+ TableName: tableName,
1744
+ Item: {
1745
+ PK: `${user}#tx`,
1746
+ SK: key.SK,
1747
+ score: Math.floor(random() * 100),
1748
+ },
1749
+ },
1750
+ },
1751
+ {
1752
+ ConditionCheck: {
1753
+ TableName: tableName,
1754
+ Key: key,
1755
+ ConditionExpression: random() > 0.5 ? "attribute_exists(PK)" : "attribute_not_exists(PK)",
1756
+ },
1757
+ },
1758
+ ],
1759
+ })
1760
+ .promise();
1761
+ results.push({ op: "transactWrite", key, ok: true });
1762
+ }
1763
+ catch (error) {
1764
+ results.push({
1765
+ op: "transactWrite",
1766
+ key,
1767
+ ok: false,
1768
+ error: normalizeError(error),
1769
+ });
1770
+ }
1771
+ }
1772
+ return results;
1773
+ }),
1774
+ }));
1775
+ describe("dynamodb conformance (local vs in-memory)", () => {
1776
+ const differentialVectors = [
1777
+ ...generatedVectors,
1778
+ ...additionalDifferentialVectors,
1779
+ ...supportedParamCoverageVectors,
1780
+ ...seededFuzzVectors,
1781
+ ];
1782
+ test("every supported method in the manifest has differential vector coverage", () => {
1783
+ const coveredMethods = new Set(differentialVectors.map((vector) => vector.method));
1784
+ const expectedMethods = new Set(Object.keys(spec_1.IN_MEMORY_SPEC.methods));
1785
+ expect(coveredMethods).toEqual(expectedMethods);
1786
+ });
1787
+ test("supported and unsupported parameter coverage matches the spec", () => {
1788
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
1789
+ const supportedCoverage = new Map();
1790
+ const unsupportedCoverage = new Map();
1791
+ for (const vector of [...differentialVectors, ...unsupportedParamVectors]) {
1792
+ if (!((_a = vector.coverage) === null || _a === void 0 ? void 0 : _a.supported) && !((_b = vector.coverage) === null || _b === void 0 ? void 0 : _b.unsupported))
1793
+ continue;
1794
+ const method = vector.method;
1795
+ if (!supportedCoverage.has(method))
1796
+ supportedCoverage.set(method, new Set());
1797
+ if (!unsupportedCoverage.has(method))
1798
+ unsupportedCoverage.set(method, new Set());
1799
+ for (const param of (_d = (_c = vector.coverage) === null || _c === void 0 ? void 0 : _c.supported) !== null && _d !== void 0 ? _d : []) {
1800
+ supportedCoverage.get(method).add(param);
1801
+ }
1802
+ for (const param of (_f = (_e = vector.coverage) === null || _e === void 0 ? void 0 : _e.unsupported) !== null && _f !== void 0 ? _f : []) {
1803
+ unsupportedCoverage.get(method).add(param);
1804
+ }
1805
+ }
1806
+ for (const [method, spec] of Object.entries(spec_1.IN_MEMORY_SPEC.methods)) {
1807
+ expect((_g = supportedCoverage.get(method)) !== null && _g !== void 0 ? _g : new Set()).toEqual(new Set(spec.supportedParams));
1808
+ expect((_h = unsupportedCoverage.get(method)) !== null && _h !== void 0 ? _h : new Set()).toEqual(new Set((_j = spec.unsupportedParams) !== null && _j !== void 0 ? _j : []));
1809
+ }
1810
+ });
1811
+ test.each(differentialVectors)("vector $id", (vector) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
1812
+ const [local, memory] = yield Promise.all([
1813
+ runVector("local", vector),
1814
+ runVector("memory", vector),
1815
+ ]);
1816
+ expect(memory).toEqual(local);
1817
+ }));
1818
+ test.each(unsupportedParamVectors)("unsupported vector $id throws deterministic NotSupportedError in memory", (vector) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
1819
+ const result = yield runVector("memory", vector);
1820
+ expect(result.ok).toBe(false);
1821
+ if (result.ok)
1822
+ return;
1823
+ const [methodName, param] = vector.id
1824
+ .replace("unsupported.", "")
1825
+ .split(".");
1826
+ expect(result.error).toEqual({
1827
+ code: "NotSupportedError",
1828
+ message: `${param} is not supported in in-memory mode`,
1829
+ method: methodName,
1830
+ featurePath: `${methodName}.${param}`,
1831
+ reason: `${param} is not supported in in-memory mode.`,
1832
+ });
1833
+ }));
1834
+ });
1835
+ //# sourceMappingURL=conformance.test.js.map