@webda/aws 4.0.0-beta.2 → 4.0.0-beta.4

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 (169) hide show
  1. package/README.md +64 -7
  2. package/lib/deployers/awsdeployer.d.ts +340 -0
  3. package/lib/deployers/awsdeployer.d.ts.map +1 -0
  4. package/lib/deployers/awsdeployer.js +673 -0
  5. package/lib/deployers/awsdeployer.js.map +1 -0
  6. package/lib/deployers/cloudformation.service.d.ts +438 -0
  7. package/lib/deployers/cloudformation.service.d.ts.map +1 -0
  8. package/lib/deployers/cloudformation.service.js +889 -0
  9. package/lib/deployers/cloudformation.service.js.map +1 -0
  10. package/lib/deployers/index.d.ts +4 -254
  11. package/lib/deployers/index.d.ts.map +1 -1
  12. package/lib/deployers/index.js +4 -542
  13. package/lib/deployers/index.js.map +1 -1
  14. package/lib/deployers/lambda-entrypoint.d.ts +33 -1
  15. package/lib/deployers/lambda-entrypoint.d.ts.map +1 -1
  16. package/lib/deployers/lambda-entrypoint.js +44 -10
  17. package/lib/deployers/lambda-entrypoint.js.map +1 -1
  18. package/lib/deployers/lambdapackager.service.d.ts +123 -0
  19. package/lib/deployers/lambdapackager.service.d.ts.map +1 -0
  20. package/lib/deployers/lambdapackager.service.js +149 -0
  21. package/lib/deployers/lambdapackager.service.js.map +1 -0
  22. package/lib/deployers/zip.d.ts +42 -0
  23. package/lib/deployers/zip.d.ts.map +1 -0
  24. package/lib/deployers/zip.js +129 -0
  25. package/lib/deployers/zip.js.map +1 -0
  26. package/lib/index.d.ts +1 -0
  27. package/lib/index.d.ts.map +1 -1
  28. package/lib/index.js +1 -0
  29. package/lib/index.js.map +1 -1
  30. package/lib/services/aws-parameters.d.ts +33 -0
  31. package/lib/services/aws-parameters.d.ts.map +1 -0
  32. package/lib/services/aws-parameters.js +18 -0
  33. package/lib/services/aws-parameters.js.map +1 -0
  34. package/lib/services/awscommands.service.d.ts +39 -0
  35. package/lib/services/awscommands.service.d.ts.map +1 -0
  36. package/lib/services/awscommands.service.js +127 -0
  37. package/lib/services/awscommands.service.js.map +1 -0
  38. package/lib/services/cloudwatchlogger.service.d.ts +131 -0
  39. package/lib/services/cloudwatchlogger.service.d.ts.map +1 -0
  40. package/lib/services/{cloudwatchlogger.js → cloudwatchlogger.service.js} +60 -28
  41. package/lib/services/cloudwatchlogger.service.js.map +1 -0
  42. package/lib/services/contributors.d.ts +36 -0
  43. package/lib/services/contributors.d.ts.map +1 -0
  44. package/lib/services/contributors.js +2 -0
  45. package/lib/services/contributors.js.map +1 -0
  46. package/lib/services/dynamodb.service.d.ts +298 -0
  47. package/lib/services/dynamodb.service.d.ts.map +1 -0
  48. package/lib/services/dynamodb.service.js +986 -0
  49. package/lib/services/dynamodb.service.js.map +1 -0
  50. package/lib/services/index.d.ts +11 -31
  51. package/lib/services/index.d.ts.map +1 -1
  52. package/lib/services/index.js +11 -8
  53. package/lib/services/index.js.map +1 -1
  54. package/lib/services/lambdacaller.service.d.ts +81 -0
  55. package/lib/services/lambdacaller.service.d.ts.map +1 -0
  56. package/lib/services/lambdacaller.service.js +75 -0
  57. package/lib/services/lambdacaller.service.js.map +1 -0
  58. package/lib/services/lambdaserver.service.d.ts +127 -0
  59. package/lib/services/lambdaserver.service.d.ts.map +1 -0
  60. package/lib/services/lambdaserver.service.js +294 -0
  61. package/lib/services/lambdaserver.service.js.map +1 -0
  62. package/lib/services/{route53.d.ts → route53.service.d.ts} +21 -12
  63. package/lib/services/route53.service.d.ts.map +1 -0
  64. package/lib/services/{route53.js → route53.service.js} +25 -28
  65. package/lib/services/route53.service.js.map +1 -0
  66. package/lib/services/s3binary.service.d.ts +215 -0
  67. package/lib/services/s3binary.service.d.ts.map +1 -0
  68. package/lib/services/{s3binary.js → s3binary.service.js} +93 -55
  69. package/lib/services/s3binary.service.js.map +1 -0
  70. package/lib/services/secretsmanager.service.d.ts +102 -0
  71. package/lib/services/secretsmanager.service.d.ts.map +1 -0
  72. package/lib/services/{secretsmanager.js → secretsmanager.service.js} +40 -22
  73. package/lib/services/secretsmanager.service.js.map +1 -0
  74. package/lib/services/{sqsqueue.d.ts → sqsqueue.service.d.ts} +60 -35
  75. package/lib/services/sqsqueue.service.d.ts.map +1 -0
  76. package/lib/services/{sqsqueue.js → sqsqueue.service.js} +53 -28
  77. package/lib/services/sqsqueue.service.js.map +1 -0
  78. package/package.json +56 -64
  79. package/webda.module.json +1425 -264
  80. package/lib/deployers/cloudformation.d.ts +0 -317
  81. package/lib/deployers/cloudformation.d.ts.map +0 -1
  82. package/lib/deployers/cloudformation.js +0 -837
  83. package/lib/deployers/cloudformation.js.map +0 -1
  84. package/lib/deployers/cloudformation.spec.d.ts +0 -2
  85. package/lib/deployers/cloudformation.spec.d.ts.map +0 -1
  86. package/lib/deployers/cloudformation.spec.js +0 -530
  87. package/lib/deployers/cloudformation.spec.js.map +0 -1
  88. package/lib/deployers/index.spec.d.ts +0 -9
  89. package/lib/deployers/index.spec.d.ts.map +0 -1
  90. package/lib/deployers/index.spec.js +0 -595
  91. package/lib/deployers/index.spec.js.map +0 -1
  92. package/lib/deployers/lambdapackager.d.ts +0 -28
  93. package/lib/deployers/lambdapackager.d.ts.map +0 -1
  94. package/lib/deployers/lambdapackager.js +0 -26
  95. package/lib/deployers/lambdapackager.js.map +0 -1
  96. package/lib/deployers/lambdapackager.spec.d.ts +0 -2
  97. package/lib/deployers/lambdapackager.spec.d.ts.map +0 -1
  98. package/lib/deployers/lambdapackager.spec.js +0 -44
  99. package/lib/deployers/lambdapackager.spec.js.map +0 -1
  100. package/lib/index.spec.d.ts +0 -11
  101. package/lib/index.spec.d.ts.map +0 -1
  102. package/lib/index.spec.js +0 -42
  103. package/lib/index.spec.js.map +0 -1
  104. package/lib/services/aws-mixin.d.ts +0 -25
  105. package/lib/services/aws-mixin.d.ts.map +0 -1
  106. package/lib/services/aws-mixin.js +0 -18
  107. package/lib/services/aws-mixin.js.map +0 -1
  108. package/lib/services/cloudwatchlogger.d.ts +0 -82
  109. package/lib/services/cloudwatchlogger.d.ts.map +0 -1
  110. package/lib/services/cloudwatchlogger.js.map +0 -1
  111. package/lib/services/cloudwatchlogger.spec.d.ts +0 -2
  112. package/lib/services/cloudwatchlogger.spec.d.ts.map +0 -1
  113. package/lib/services/cloudwatchlogger.spec.js +0 -104
  114. package/lib/services/cloudwatchlogger.spec.js.map +0 -1
  115. package/lib/services/dynamodb.d.ts +0 -174
  116. package/lib/services/dynamodb.d.ts.map +0 -1
  117. package/lib/services/dynamodb.js +0 -711
  118. package/lib/services/dynamodb.js.map +0 -1
  119. package/lib/services/dynamodb.spec.d.ts +0 -24
  120. package/lib/services/dynamodb.spec.d.ts.map +0 -1
  121. package/lib/services/dynamodb.spec.js +0 -344
  122. package/lib/services/dynamodb.spec.js.map +0 -1
  123. package/lib/services/lambdacaller.d.ts +0 -69
  124. package/lib/services/lambdacaller.d.ts.map +0 -1
  125. package/lib/services/lambdacaller.js +0 -63
  126. package/lib/services/lambdacaller.js.map +0 -1
  127. package/lib/services/lambdacaller.spec.d.ts +0 -2
  128. package/lib/services/lambdacaller.spec.d.ts.map +0 -1
  129. package/lib/services/lambdacaller.spec.js +0 -70
  130. package/lib/services/lambdacaller.spec.js.map +0 -1
  131. package/lib/services/lambdaserver.d.ts +0 -87
  132. package/lib/services/lambdaserver.d.ts.map +0 -1
  133. package/lib/services/lambdaserver.js +0 -263
  134. package/lib/services/lambdaserver.js.map +0 -1
  135. package/lib/services/lambdaserver.spec.d.ts +0 -2
  136. package/lib/services/lambdaserver.spec.d.ts.map +0 -1
  137. package/lib/services/lambdaserver.spec.js +0 -417
  138. package/lib/services/lambdaserver.spec.js.map +0 -1
  139. package/lib/services/route53.d.ts.map +0 -1
  140. package/lib/services/route53.js.map +0 -1
  141. package/lib/services/route53.spec.d.ts +0 -2
  142. package/lib/services/route53.spec.d.ts.map +0 -1
  143. package/lib/services/route53.spec.js +0 -102
  144. package/lib/services/route53.spec.js.map +0 -1
  145. package/lib/services/s3binary.d.ts +0 -163
  146. package/lib/services/s3binary.d.ts.map +0 -1
  147. package/lib/services/s3binary.js.map +0 -1
  148. package/lib/services/s3binary.spec.d.ts +0 -2
  149. package/lib/services/s3binary.spec.d.ts.map +0 -1
  150. package/lib/services/s3binary.spec.js +0 -284
  151. package/lib/services/s3binary.spec.js.map +0 -1
  152. package/lib/services/secretsmanager.d.ts +0 -81
  153. package/lib/services/secretsmanager.d.ts.map +0 -1
  154. package/lib/services/secretsmanager.js.map +0 -1
  155. package/lib/services/secretsmanager.spec.d.ts +0 -2
  156. package/lib/services/secretsmanager.spec.d.ts.map +0 -1
  157. package/lib/services/secretsmanager.spec.js +0 -66
  158. package/lib/services/secretsmanager.spec.js.map +0 -1
  159. package/lib/services/sqsqueue.d.ts.map +0 -1
  160. package/lib/services/sqsqueue.js.map +0 -1
  161. package/lib/services/sqsqueue.spec.d.ts +0 -2
  162. package/lib/services/sqsqueue.spec.d.ts.map +0 -1
  163. package/lib/services/sqsqueue.spec.js +0 -157
  164. package/lib/services/sqsqueue.spec.js.map +0 -1
  165. package/lib/shell.d.ts +0 -13
  166. package/lib/shell.d.ts.map +0 -1
  167. package/lib/shell.js +0 -42
  168. package/lib/shell.js.map +0 -1
  169. package/webda.shell.json +0 -11
@@ -0,0 +1,986 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
35
+ import { ConditionalCheckFailedException, DynamoDB, DynamoDBClient } from "@aws-sdk/client-dynamodb";
36
+ import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb";
37
+ import { EventRepository, InstanceCache, MemoryRepository, Store, StoreNotFoundError, StoreParameters, UpdateConditionFailError, useModel, useModelMetadata, WebdaError } from "@webda/core";
38
+ import * as WebdaQL from "@webda/ql";
39
+ import { loadAWSParameters } from "./aws-parameters.js";
40
+ /**
41
+ * Name of the DynamoDB hash key attribute
42
+ */
43
+ const KEY_ATTRIBUTE = "uuid";
44
+ /**
45
+ * Attribute storing the model identifier, used to rebuild subclasses
46
+ */
47
+ const TYPE_ATTRIBUTE = "__type";
48
+ /**
49
+ * Define DynamoDB parameters
50
+ */
51
+ export class DynamoStoreParameters extends StoreParameters {
52
+ /**
53
+ * @override
54
+ * @param params - raw parameters
55
+ * @returns this
56
+ */
57
+ load(params = {}) {
58
+ super.load(params);
59
+ loadAWSParameters(this);
60
+ if (this.table === undefined) {
61
+ throw new WebdaError.CodeError("DYNAMODB_TABLE_PARAMETER_REQUIRED", "Need to define a table at least");
62
+ }
63
+ this.globalIndexes ?? (this.globalIndexes = {});
64
+ this.tables ?? (this.tables = {});
65
+ return this;
66
+ }
67
+ }
68
+ /**
69
+ * Serialize a date for DynamoDB
70
+ * @param date - the date to serialize
71
+ * @returns ISO string
72
+ */
73
+ function serializeDate(date) {
74
+ return date.toISOString();
75
+ }
76
+ /**
77
+ * Clean an object to store in DynamoDB
78
+ *
79
+ * Dates are converted to ISO strings, empty strings and undefined values are removed
80
+ *
81
+ * @param object - the value to clean
82
+ * @returns the cleaned value
83
+ */
84
+ export function cleanObject(object) {
85
+ if (object === null || typeof object !== "object")
86
+ return object;
87
+ if (object instanceof Date) {
88
+ return serializeDate(object);
89
+ }
90
+ if (typeof object.toJSON === "function" && !Array.isArray(object)) {
91
+ const json = object.toJSON();
92
+ if (json !== object) {
93
+ return cleanObject(json);
94
+ }
95
+ }
96
+ const res = Array.isArray(object) ? [] : {};
97
+ for (const i in object) {
98
+ if (object[i] === "" || object[i] === undefined || typeof object[i] === "function") {
99
+ continue;
100
+ }
101
+ res[i] = cleanObject(object[i]);
102
+ }
103
+ return res;
104
+ }
105
+ /**
106
+ * DynamoDB-backed repository for a single model class
107
+ *
108
+ * Every object is stored as one item, keyed by the string primary key in the
109
+ * `uuid` hash key attribute.
110
+ */
111
+ export class DynamoRepository extends MemoryRepository {
112
+ /**
113
+ * Create a new DynamoRepository
114
+ * @param model - the model class
115
+ * @param pks - primary key field names
116
+ * @param client - the DynamoDB document client
117
+ * @param table - the table name
118
+ * @param globalIndexes - global secondary indexes usable by queries
119
+ * @param scanPage - scan page size used by __clean
120
+ * @param storeName - store name used in errors
121
+ * @param separator - primary key separator
122
+ */
123
+ constructor(model, pks, client, table, globalIndexes = {}, scanPage, storeName = table, separator) {
124
+ // Pass an empty Map — we do NOT use in-memory storage
125
+ super(model, pks, separator, new Map());
126
+ this.client = client;
127
+ this.table = table;
128
+ this.globalIndexes = globalIndexes;
129
+ this.scanPage = scanPage;
130
+ this.storeName = storeName;
131
+ }
132
+ /**
133
+ * The backing table name
134
+ * @returns the table name
135
+ */
136
+ getTable() {
137
+ return this.table;
138
+ }
139
+ /**
140
+ * Return the DynamoDB key of an object or primary key
141
+ * @param primaryKey - the object or primary key
142
+ * @returns the string key
143
+ */
144
+ getKey(primaryKey) {
145
+ return this.getPrimaryKey(primaryKey).toString();
146
+ }
147
+ /**
148
+ * Convert a model or plain object to a DynamoDB item
149
+ * @param data - the object to convert
150
+ * @returns the item
151
+ */
152
+ toItem(data) {
153
+ const item = cleanObject(data);
154
+ item[KEY_ATTRIBUTE] = this.getKey(data);
155
+ item[TYPE_ATTRIBUTE] = data?.constructor?.Metadata?.Identifier ?? this.model.Metadata?.Identifier;
156
+ if (item[TYPE_ATTRIBUTE] === undefined) {
157
+ delete item[TYPE_ATTRIBUTE];
158
+ }
159
+ return item;
160
+ }
161
+ /**
162
+ * Convert a DynamoDB item to a model instance
163
+ *
164
+ * The `__type` attribute is used to instantiate the right subclass
165
+ * @param item - the DynamoDB item
166
+ * @returns the model instance
167
+ */
168
+ fromItem(item) {
169
+ const data = { ...item };
170
+ let model = this.model;
171
+ const type = data[TYPE_ATTRIBUTE];
172
+ delete data[TYPE_ATTRIBUTE];
173
+ if (type && type !== this.model.Metadata?.Identifier) {
174
+ try {
175
+ model = useModel(type) ?? this.model;
176
+ }
177
+ catch {
178
+ model = this.model;
179
+ }
180
+ }
181
+ if (!this.pks.includes(KEY_ATTRIBUTE)) {
182
+ delete data[KEY_ATTRIBUTE];
183
+ }
184
+ const instance = new model({});
185
+ if (typeof instance.load === "function") {
186
+ instance.load(data);
187
+ }
188
+ else {
189
+ Object.assign(instance, data);
190
+ }
191
+ if (type) {
192
+ Object.defineProperty(instance, TYPE_ATTRIBUTE, {
193
+ value: type,
194
+ enumerable: false,
195
+ configurable: true,
196
+ writable: true
197
+ });
198
+ }
199
+ return instance;
200
+ }
201
+ /**
202
+ * Add a write condition to the DynamoDB parameters
203
+ * @param params - the DynamoDB parameters
204
+ * @param writeCondition - the expected value
205
+ * @param field - the field to check
206
+ */
207
+ setWriteCondition(params, writeCondition, field) {
208
+ params.ExpressionAttributeNames ?? (params.ExpressionAttributeNames = {});
209
+ params.ExpressionAttributeValues ?? (params.ExpressionAttributeValues = {});
210
+ params.ExpressionAttributeNames["#cf"] = field;
211
+ if (writeCondition instanceof Date) {
212
+ writeCondition = serializeDate(writeCondition);
213
+ }
214
+ params.ExpressionAttributeValues[":cf"] = writeCondition;
215
+ params.ConditionExpression = params.ConditionExpression
216
+ ? `${params.ConditionExpression} AND #cf = :cf`
217
+ : "#cf = :cf";
218
+ }
219
+ /**
220
+ * Build a document path expression for an attribute like `team.id`
221
+ * @param attribute - the attribute path
222
+ * @param names - expression attribute names to fill
223
+ * @param prefix - placeholder prefix
224
+ * @returns the path expression
225
+ */
226
+ attributePath(attribute, names, prefix) {
227
+ return attribute
228
+ .split(".")
229
+ .map((part, i) => {
230
+ names[`#${prefix}${i}`] = part;
231
+ return `#${prefix}${i}`;
232
+ })
233
+ .join(".");
234
+ }
235
+ /** @override */
236
+ async get(primaryKey) {
237
+ const key = this.getKey(primaryKey);
238
+ const item = (await this.client.get({
239
+ TableName: this.table,
240
+ Key: { [KEY_ATTRIBUTE]: key }
241
+ })).Item;
242
+ if (!item) {
243
+ throw new StoreNotFoundError(key, this.storeName);
244
+ }
245
+ return this.fromItem(item);
246
+ }
247
+ /** @override */
248
+ async exists(primaryKey) {
249
+ const item = (await this.client.get({
250
+ TableName: this.table,
251
+ Key: { [KEY_ATTRIBUTE]: this.getKey(primaryKey) },
252
+ ProjectionExpression: "#k",
253
+ ExpressionAttributeNames: { "#k": KEY_ATTRIBUTE }
254
+ })).Item;
255
+ return item !== undefined;
256
+ }
257
+ /** @override */
258
+ async create(data, save = true) {
259
+ // Build once so a generated primary key is kept (and not reset by an undefined one in data)
260
+ const item = this.buildItem(data);
261
+ if (save === false) {
262
+ return item;
263
+ }
264
+ const key = this.getKey(item);
265
+ try {
266
+ await this.client.put({
267
+ TableName: this.table,
268
+ Item: this.toItem(item),
269
+ ConditionExpression: "attribute_not_exists(#k)",
270
+ ExpressionAttributeNames: { "#k": KEY_ATTRIBUTE }
271
+ });
272
+ }
273
+ catch (err) {
274
+ if (err instanceof ConditionalCheckFailedException) {
275
+ throw new Error(`Already exists: ${key}`);
276
+ }
277
+ throw err;
278
+ }
279
+ return item;
280
+ }
281
+ /** @override */
282
+ async update(data, conditionField, condition) {
283
+ const key = this.getKey(data);
284
+ const params = {
285
+ TableName: this.table,
286
+ Item: this.toItem(data),
287
+ ConditionExpression: "attribute_exists(#k)",
288
+ ExpressionAttributeNames: { "#k": KEY_ATTRIBUTE }
289
+ };
290
+ if (conditionField) {
291
+ this.setWriteCondition(params, condition, conditionField);
292
+ }
293
+ try {
294
+ await this.client.put(params);
295
+ }
296
+ catch (err) {
297
+ if (err instanceof ConditionalCheckFailedException) {
298
+ if (!conditionField) {
299
+ throw new StoreNotFoundError(key, this.storeName);
300
+ }
301
+ throw new UpdateConditionFailError(key, conditionField, condition);
302
+ }
303
+ throw err;
304
+ }
305
+ }
306
+ /** @override */
307
+ async patch(primaryKey, data, conditionField, condition) {
308
+ const key = this.getKey(primaryKey);
309
+ const object = cleanObject(data);
310
+ const sets = [];
311
+ const ExpressionAttributeValues = {};
312
+ const ExpressionAttributeNames = { "#k": KEY_ATTRIBUTE };
313
+ let i = 1;
314
+ for (const attr in object) {
315
+ if (attr === KEY_ATTRIBUTE || this.pks.includes(attr) || object[attr] === undefined) {
316
+ continue;
317
+ }
318
+ sets.push(`#a${i} = :v${i}`);
319
+ ExpressionAttributeValues[`:v${i}`] = object[attr];
320
+ ExpressionAttributeNames[`#a${i}`] = attr;
321
+ i++;
322
+ }
323
+ if (!sets.length) {
324
+ return;
325
+ }
326
+ const params = {
327
+ TableName: this.table,
328
+ Key: { [KEY_ATTRIBUTE]: key },
329
+ UpdateExpression: "SET " + sets.join(", "),
330
+ ConditionExpression: "attribute_exists(#k)",
331
+ ExpressionAttributeValues,
332
+ ExpressionAttributeNames
333
+ };
334
+ // The Write Condition checks the value before writing
335
+ if (conditionField) {
336
+ this.setWriteCondition(params, condition, conditionField);
337
+ }
338
+ try {
339
+ await this.client.update(params);
340
+ }
341
+ catch (err) {
342
+ if (err instanceof ConditionalCheckFailedException) {
343
+ if (!conditionField) {
344
+ throw new StoreNotFoundError(key, this.storeName);
345
+ }
346
+ throw new UpdateConditionFailError(key, conditionField, condition);
347
+ }
348
+ throw err;
349
+ }
350
+ }
351
+ /** @override */
352
+ async delete(primaryKey, conditionField, condition) {
353
+ const key = this.getKey(primaryKey);
354
+ const params = {
355
+ TableName: this.table,
356
+ Key: { [KEY_ATTRIBUTE]: key }
357
+ };
358
+ if (conditionField) {
359
+ this.setWriteCondition(params, condition, conditionField);
360
+ }
361
+ try {
362
+ await this.client.delete(params);
363
+ }
364
+ catch (err) {
365
+ if (err instanceof ConditionalCheckFailedException) {
366
+ throw new UpdateConditionFailError(key, conditionField, condition);
367
+ }
368
+ throw err;
369
+ }
370
+ }
371
+ /** @override */
372
+ async removeAttribute(primaryKey, attribute, conditionField, condition) {
373
+ const key = this.getKey(primaryKey);
374
+ const ExpressionAttributeNames = { "#k": KEY_ATTRIBUTE };
375
+ const params = {
376
+ TableName: this.table,
377
+ Key: { [KEY_ATTRIBUTE]: key },
378
+ UpdateExpression: `REMOVE ${this.attributePath(String(attribute), ExpressionAttributeNames, "r")}`,
379
+ ConditionExpression: "attribute_exists(#k)",
380
+ ExpressionAttributeNames
381
+ };
382
+ if (conditionField) {
383
+ this.setWriteCondition(params, condition, conditionField);
384
+ }
385
+ try {
386
+ await this.client.update(params);
387
+ }
388
+ catch (err) {
389
+ if (err instanceof ConditionalCheckFailedException) {
390
+ if (!conditionField) {
391
+ throw new StoreNotFoundError(key, this.storeName);
392
+ }
393
+ throw new UpdateConditionFailError(key, conditionField, condition);
394
+ }
395
+ throw err;
396
+ }
397
+ }
398
+ /** @override */
399
+ async incrementAttributes(primaryKey, info, conditionField, condition) {
400
+ const key = this.getKey(primaryKey);
401
+ const entries = Array.isArray(info)
402
+ ? info.map((e) => typeof e === "string" ? { property: e, value: 1 } : { property: e.property, value: e.value ?? 1 })
403
+ : Object.entries(info).map(([property, value]) => ({ property: String(property), value: value }));
404
+ if (!entries.length) {
405
+ return;
406
+ }
407
+ const ExpressionAttributeNames = { "#k": KEY_ATTRIBUTE };
408
+ const ExpressionAttributeValues = {};
409
+ const adds = entries.map((p, i) => {
410
+ ExpressionAttributeValues[`:v${i}`] = p.value;
411
+ return `${this.attributePath(p.property, ExpressionAttributeNames, `a${i}_`)} :v${i}`;
412
+ });
413
+ const params = {
414
+ TableName: this.table,
415
+ Key: { [KEY_ATTRIBUTE]: key },
416
+ UpdateExpression: "ADD " + adds.join(", "),
417
+ ConditionExpression: "attribute_exists(#k)",
418
+ ExpressionAttributeValues,
419
+ ExpressionAttributeNames
420
+ };
421
+ if (conditionField) {
422
+ this.setWriteCondition(params, condition, conditionField);
423
+ }
424
+ try {
425
+ await this.client.update(params);
426
+ }
427
+ catch (err) {
428
+ if (err instanceof ConditionalCheckFailedException) {
429
+ if (!conditionField) {
430
+ throw new StoreNotFoundError(key, this.storeName);
431
+ }
432
+ throw new UpdateConditionFailError(key, conditionField, condition);
433
+ }
434
+ throw err;
435
+ }
436
+ }
437
+ /** @override */
438
+ async upsertItemToCollection(primaryKey, collection, item, index, itemWriteConditionField, itemWriteCondition) {
439
+ const key = this.getKey(primaryKey);
440
+ const prop = String(collection);
441
+ const ExpressionAttributeNames = { "#k": KEY_ATTRIBUTE, "#col": prop };
442
+ const ExpressionAttributeValues = {};
443
+ const params = {
444
+ TableName: this.table,
445
+ Key: { [KEY_ATTRIBUTE]: key },
446
+ ConditionExpression: "attribute_exists(#k)",
447
+ ExpressionAttributeNames,
448
+ ExpressionAttributeValues
449
+ };
450
+ if (index === undefined) {
451
+ params.UpdateExpression = "SET #col = list_append(if_not_exists(#col, :empty_list), :item)";
452
+ ExpressionAttributeValues[":item"] = [cleanObject(item)];
453
+ ExpressionAttributeValues[":empty_list"] = [];
454
+ }
455
+ else {
456
+ params.UpdateExpression = `SET #col[${index}] = :item`;
457
+ ExpressionAttributeValues[":item"] = cleanObject(item);
458
+ if (itemWriteCondition !== undefined) {
459
+ ExpressionAttributeValues[":condValue"] = itemWriteCondition;
460
+ ExpressionAttributeNames["#field"] = itemWriteConditionField;
461
+ params.ConditionExpression += ` AND #col[${index}].#field = :condValue`;
462
+ }
463
+ }
464
+ try {
465
+ await this.client.update(params);
466
+ }
467
+ catch (err) {
468
+ if (err instanceof ConditionalCheckFailedException) {
469
+ if (itemWriteCondition === undefined) {
470
+ throw new StoreNotFoundError(key, this.storeName);
471
+ }
472
+ throw new UpdateConditionFailError(key, itemWriteConditionField, itemWriteCondition);
473
+ }
474
+ else if (err.name === "ValidationException") {
475
+ throw new StoreNotFoundError(key, this.storeName);
476
+ }
477
+ throw err;
478
+ }
479
+ }
480
+ /** @override */
481
+ async deleteItemFromCollection(primaryKey, collection, index, itemWriteConditionField, itemWriteCondition) {
482
+ const key = this.getKey(primaryKey);
483
+ const ExpressionAttributeNames = { "#k": KEY_ATTRIBUTE, "#col": String(collection) };
484
+ const params = {
485
+ TableName: this.table,
486
+ Key: { [KEY_ATTRIBUTE]: key },
487
+ UpdateExpression: `REMOVE #col[${index}]`,
488
+ ConditionExpression: "attribute_exists(#k)",
489
+ ExpressionAttributeNames
490
+ };
491
+ if (itemWriteCondition !== undefined) {
492
+ params.ExpressionAttributeValues = { ":condValue": itemWriteCondition };
493
+ ExpressionAttributeNames["#field"] = itemWriteConditionField;
494
+ params.ConditionExpression += ` AND #col[${index}].#field = :condValue`;
495
+ }
496
+ try {
497
+ await this.client.update(params);
498
+ }
499
+ catch (err) {
500
+ if (err instanceof ConditionalCheckFailedException) {
501
+ if (itemWriteCondition === undefined) {
502
+ throw new StoreNotFoundError(key, this.storeName);
503
+ }
504
+ throw new UpdateConditionFailError(key, itemWriteConditionField, itemWriteCondition);
505
+ }
506
+ else if (err.name === "ValidationException") {
507
+ throw new StoreNotFoundError(key, this.storeName);
508
+ }
509
+ throw err;
510
+ }
511
+ }
512
+ /**
513
+ * Translate a WebdaQL query into a DynamoDB scan or query
514
+ *
515
+ * A query on the hash key or on a global index hash key with `=` uses a DynamoDB Query,
516
+ * anything else is a Scan. The part of the expression DynamoDB cannot evaluate is
517
+ * returned in `filter` and must be applied on the results.
518
+ *
519
+ * @see https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html
520
+ * @see https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html
521
+ * @param query - the parsed query
522
+ * @returns the items and the residual filter
523
+ */
524
+ async find(query) {
525
+ let scan = true;
526
+ let IndexName = undefined;
527
+ let result;
528
+ const limit = query.limit ?? 1000;
529
+ const primaryKeys = { [KEY_ATTRIBUTE]: null };
530
+ Object.keys(this.globalIndexes).forEach(name => {
531
+ primaryKeys[this.globalIndexes[name].key] = name;
532
+ });
533
+ // We could use PartQL but localstack is not compatible
534
+ const filter = new WebdaQL.AndExpression([]);
535
+ let KeyConditionExpression = "";
536
+ let ExpressionAttributeValues = {};
537
+ const FilterExpression = [];
538
+ let ExpressionAttributeNames = {};
539
+ let indexNode;
540
+ let sortOrder = "ASC";
541
+ let processingExpression;
542
+ if (!(query.filter instanceof WebdaQL.AndExpression)) {
543
+ processingExpression = new WebdaQL.AndExpression([query.filter]);
544
+ }
545
+ else {
546
+ processingExpression = query.filter;
547
+ }
548
+ // A FALSE conjunct matches nothing: do not hit DynamoDB (never fail open)
549
+ if (processingExpression.children.some(c => c instanceof WebdaQL.BooleanExpression && !c.value)) {
550
+ return { results: [], filter, continuationToken: undefined };
551
+ }
552
+ // A TRUE conjunct is neutral
553
+ processingExpression = new WebdaQL.AndExpression(processingExpression.children.filter(c => !(c instanceof WebdaQL.BooleanExpression)));
554
+ // Search for the index
555
+ processingExpression.children.some(child => {
556
+ if (child instanceof WebdaQL.ComparisonExpression) {
557
+ // Primary key requires equal operator
558
+ if (child.operator === "=" && child.attribute.length === 1 && primaryKeys[child.attribute[0]] !== undefined) {
559
+ // Query not scan
560
+ scan = false;
561
+ IndexName = primaryKeys[child.attribute[0]] ?? undefined;
562
+ indexNode = child;
563
+ KeyConditionExpression = `#${child.attribute[0]} = :${child.attribute[0]}`;
564
+ ExpressionAttributeNames[`#${child.attribute[0]}`] = child.attribute[0];
565
+ ExpressionAttributeValues[`:${child.attribute[0]}`] = child.value;
566
+ if (IndexName && query.orderBy && this.globalIndexes[IndexName].sort) {
567
+ const sortKey = this.globalIndexes[IndexName].sort;
568
+ // Might update sort order
569
+ query.orderBy.forEach(order => {
570
+ if (order.field === sortKey) {
571
+ sortOrder = order.direction;
572
+ }
573
+ });
574
+ }
575
+ return true;
576
+ }
577
+ }
578
+ return false;
579
+ });
580
+ let count = 1;
581
+ // Build the Query/Filter
582
+ processingExpression.children.forEach(child => {
583
+ if (child === indexNode) {
584
+ return;
585
+ }
586
+ // Only work on Comparison Node for now
587
+ if (child instanceof WebdaQL.ComparisonExpression) {
588
+ let operator = child.operator;
589
+ // DynamoDB does not manage LIKE
590
+ if (child.operator === "LIKE") {
591
+ filter.children.push(child);
592
+ return;
593
+ }
594
+ // != is <> in Dynamo
595
+ if (operator === "!=") {
596
+ operator = "<>";
597
+ }
598
+ // DynamoDB does not allow more than 100 items in IN
599
+ if (child.operator === "IN" && child.value.length > 100) {
600
+ filter.children.push(child);
601
+ return;
602
+ }
603
+ const isSortKey = IndexName && this.globalIndexes[IndexName].sort === child.attribute[0];
604
+ // A sort key cannot be used in a filter expression and IN is not allowed in a key condition
605
+ if (isSortKey && child.operator === "IN") {
606
+ filter.children.push(child);
607
+ return;
608
+ }
609
+ // Function conditions (IS NULL / IS NOT NULL) are not allowed on a sort key either
610
+ if (isSortKey && (child.operator === "IS NULL" || child.operator === "IS NOT NULL")) {
611
+ filter.children.push(child);
612
+ return;
613
+ }
614
+ // Subfields like team.id needs to be #a1.#a2
615
+ const attr = `a${count++}`;
616
+ let fullAttr = `#${attr}`;
617
+ child.attribute.slice(1).forEach(v => {
618
+ const subAttr = `#a${count++}`;
619
+ fullAttr += `.${subAttr}`;
620
+ ExpressionAttributeNames[subAttr] = v;
621
+ });
622
+ ExpressionAttributeNames[`#${attr}`] = child.attribute[0];
623
+ // IS NULL matches a missing attribute or one stored with the NULL type (JS null).
624
+ // Empty strings are not stored (see cleanObject), so they also match IS NULL here.
625
+ if (child.operator === "IS NULL" || child.operator === "IS NOT NULL") {
626
+ ExpressionAttributeValues[`:${attr}`] = "NULL";
627
+ FilterExpression.push(child.operator === "IS NULL"
628
+ ? `(attribute_not_exists(${fullAttr}) OR attribute_type(${fullAttr}, :${attr}))`
629
+ : `(attribute_exists(${fullAttr}) AND NOT attribute_type(${fullAttr}, :${attr}))`);
630
+ return;
631
+ }
632
+ let valueExpression = `:${attr}`;
633
+ if (child.operator === "IN") {
634
+ // Need to follow `a IN (b, c, d)
635
+ valueExpression = "(" + valueExpression;
636
+ ExpressionAttributeValues[`:${attr}`] = child.value[0];
637
+ child.value.slice(1).forEach(v => {
638
+ const subAttr = `:a${count++}`;
639
+ valueExpression += `, ${subAttr}`;
640
+ ExpressionAttributeValues[subAttr] = v;
641
+ });
642
+ valueExpression += ")";
643
+ }
644
+ else {
645
+ // For all other just give the value
646
+ ExpressionAttributeValues[`:${attr}`] = child.value;
647
+ }
648
+ // Manage CONTAINS
649
+ if (child.operator === "CONTAINS") {
650
+ FilterExpression.push(`contains(${fullAttr}, :${attr})`);
651
+ return;
652
+ }
653
+ // If this is a sort key
654
+ if (isSortKey) {
655
+ // Sort key
656
+ KeyConditionExpression += ` AND ${fullAttr} ${operator} ${valueExpression}`;
657
+ return;
658
+ }
659
+ // Otherwise fallback to normal Filter
660
+ FilterExpression.push(`${fullAttr} ${operator} ${valueExpression}`);
661
+ }
662
+ else {
663
+ filter.children.push(child);
664
+ }
665
+ });
666
+ if (!Object.keys(ExpressionAttributeNames).length) {
667
+ ExpressionAttributeNames = undefined;
668
+ }
669
+ if (!Object.keys(ExpressionAttributeValues).length) {
670
+ ExpressionAttributeValues = undefined;
671
+ }
672
+ let ExclusiveStartKey = query.continuationToken
673
+ ? JSON.parse(Buffer.from(query.continuationToken, "base64").toString())
674
+ : undefined;
675
+ // Scan if not primary key was provided
676
+ if (scan) {
677
+ const Items = [];
678
+ do {
679
+ result = await this.client.scan({
680
+ TableName: this.table,
681
+ FilterExpression: FilterExpression.length ? FilterExpression.join(" AND ") : undefined,
682
+ ExclusiveStartKey,
683
+ ExpressionAttributeNames,
684
+ ExpressionAttributeValues,
685
+ Limit: limit - Items.length
686
+ });
687
+ Items.push(...result.Items);
688
+ result.Items = Items;
689
+ ExclusiveStartKey = result.LastEvaluatedKey;
690
+ } while (Items.length < limit && result.LastEvaluatedKey);
691
+ }
692
+ else {
693
+ result = await this.client.query({
694
+ TableName: this.table,
695
+ IndexName,
696
+ ExclusiveStartKey,
697
+ KeyConditionExpression,
698
+ FilterExpression: FilterExpression.length ? FilterExpression.join(" AND ") : undefined,
699
+ ExpressionAttributeNames,
700
+ ExpressionAttributeValues,
701
+ Limit: limit,
702
+ ScanIndexForward: sortOrder === "ASC"
703
+ });
704
+ }
705
+ return {
706
+ results: result.Items.map(c => this.fromItem(c)),
707
+ filter,
708
+ continuationToken: result.LastEvaluatedKey
709
+ ? Buffer.from(JSON.stringify(result.LastEvaluatedKey)).toString("base64")
710
+ : undefined
711
+ };
712
+ }
713
+ /**
714
+ * Query the table
715
+ *
716
+ * Pages are retrieved until the limit is reached, applying the part of the
717
+ * filter that DynamoDB cannot evaluate and restricting to the model hierarchy
718
+ * @override
719
+ * @param query - the WebdaQL query
720
+ * @returns the results and the continuation token
721
+ */
722
+ async query(query) {
723
+ const parsed = typeof query === "string" ? WebdaQL.parse(query) : query;
724
+ const limit = parsed.limit ?? 1000;
725
+ const ids = this.buildClassFilterIdentifiers();
726
+ const results = [];
727
+ let continuationToken = parsed.continuationToken;
728
+ do {
729
+ const page = await this.find({
730
+ ...parsed,
731
+ filter: parsed.filter,
732
+ limit: limit - results.length,
733
+ continuationToken
734
+ });
735
+ results.push(...page.results.filter(item => {
736
+ const type = item[TYPE_ATTRIBUTE];
737
+ if (ids && type && !ids.includes(type)) {
738
+ return false;
739
+ }
740
+ return page.filter.eval(item);
741
+ }));
742
+ continuationToken = page.continuationToken;
743
+ } while (results.length < limit && continuationToken);
744
+ return {
745
+ results,
746
+ continuationToken: results.length >= limit ? continuationToken : undefined
747
+ };
748
+ }
749
+ /**
750
+ * Iterate over the query results
751
+ * @override
752
+ * @param query - the WebdaQL query
753
+ */
754
+ async *iterate(query) {
755
+ const parsed = WebdaQL.parse(query);
756
+ if (!parsed.limit) {
757
+ parsed.limit = 100;
758
+ }
759
+ do {
760
+ const res = await this.query(parsed);
761
+ for (const item of res.results) {
762
+ yield item;
763
+ }
764
+ parsed.continuationToken = res.continuationToken;
765
+ } while (parsed.continuationToken);
766
+ }
767
+ /**
768
+ * Delete all items from the table (used in tests)
769
+ */
770
+ async __clean() {
771
+ let ExclusiveStartKey;
772
+ do {
773
+ const result = await this.client.scan({
774
+ TableName: this.table,
775
+ Limit: this.scanPage,
776
+ ExclusiveStartKey
777
+ });
778
+ await Promise.all((result.Items ?? []).map(item => this.client.delete({ TableName: this.table, Key: { [KEY_ATTRIBUTE]: item[KEY_ATTRIBUTE] } })));
779
+ ExclusiveStartKey = result.LastEvaluatedKey;
780
+ } while (ExclusiveStartKey);
781
+ }
782
+ }
783
+ /**
784
+ * DynamoStore handles the DynamoDB
785
+ *
786
+ * Parameters:
787
+ * accessKeyId: '' // try WEBDA_AWS_KEY env variable if not found
788
+ * secretAccessKey: '' // try WEBDA_AWS_SECRET env variable if not found
789
+ * table: ''
790
+ * region: ''
791
+ *
792
+ * The table must have a `uuid` string hash key
793
+ *
794
+ * @WebdaModda
795
+ */
796
+ let DynamoStore = (() => {
797
+ var _a;
798
+ let _classSuper = Store;
799
+ let _instanceExtraInitializers = [];
800
+ let _getRepository_decorators;
801
+ return _a = class DynamoStore extends _classSuper {
802
+ constructor() {
803
+ super(...arguments);
804
+ this._client = __runInitializers(this, _instanceExtraInitializers);
805
+ }
806
+ /**
807
+ * Create the AWS client
808
+ * @returns this
809
+ */
810
+ resolve() {
811
+ super.resolve();
812
+ this._client = DynamoDBDocument.from(new DynamoDBClient(this.parameters), {
813
+ marshallOptions: {
814
+ removeUndefinedValues: true,
815
+ convertClassInstanceToMap: true
816
+ }
817
+ });
818
+ return this;
819
+ }
820
+ /**
821
+ * Copy one DynamoDB table to another
822
+ *
823
+ * @param output - worker output to report progress
824
+ * @param source - source table
825
+ * @param target - target table
826
+ */
827
+ static async copyTable(output, source, target) {
828
+ const db = new DynamoDB({});
829
+ let ExclusiveStartKey;
830
+ const props = await db.describeTable({
831
+ TableName: source
832
+ });
833
+ output.startProgress("copyTable", props.Table.ItemCount, `Copying ${source} to ${target}`);
834
+ do {
835
+ const info = await db.scan({
836
+ TableName: source,
837
+ ExclusiveStartKey
838
+ });
839
+ do {
840
+ const items = [];
841
+ while (info.Items.length && items.length < 25) {
842
+ items.push(info.Items.shift());
843
+ }
844
+ if (!items.length) {
845
+ break;
846
+ }
847
+ await db.batchWriteItem({
848
+ RequestItems: {
849
+ [target]: items.map(Item => ({
850
+ PutRequest: { Item }
851
+ }))
852
+ }
853
+ });
854
+ output.incrementProgress(items.length, "copyTable");
855
+ } while (true);
856
+ ExclusiveStartKey = info.LastEvaluatedKey;
857
+ } while (ExclusiveStartKey);
858
+ }
859
+ /**
860
+ * Resolve the table name for a given model class
861
+ *
862
+ * `tables[identifier]` overrides the default `table`
863
+ * @param model - the model class
864
+ * @returns the table name
865
+ */
866
+ resolveTable(model) {
867
+ const meta = useModelMetadata(model);
868
+ return (meta && this.parameters.tables?.[meta.Identifier]) || this.parameters.table;
869
+ }
870
+ /**
871
+ * Build the DynamoRepository for a model
872
+ *
873
+ * The result is cached per model class
874
+ * @param model - the model class
875
+ * @returns a repository backed by this store's DynamoDB table
876
+ */
877
+ getRepository(model) {
878
+ const meta = useModelMetadata(model);
879
+ const inner = new DynamoRepository(model, meta.PrimaryKey, this._client, this.resolveTable(model), this.parameters.globalIndexes, this.parameters.scanPage, this.getName(), meta.PrimaryKeySeparator);
880
+ // Wrap in EventRepository so typed CRUD events fire; consumers reach them
881
+ // via useRepository(model).on(...).
882
+ return new EventRepository(model, meta.PrimaryKey, inner, meta.PrimaryKeySeparator);
883
+ }
884
+ /**
885
+ * Return the underlying DynamoRepository for each model this store manages
886
+ * @returns the repositories
887
+ */
888
+ getRepositories() {
889
+ const repos = [];
890
+ for (const modelId of Object.keys(this._modelsHierarchy ?? {})) {
891
+ let model;
892
+ try {
893
+ model = useModel(modelId);
894
+ }
895
+ catch {
896
+ continue;
897
+ }
898
+ if (!model) {
899
+ continue;
900
+ }
901
+ const repo = this.getRepository(model);
902
+ repos.push((repo.repository ?? repo));
903
+ }
904
+ return repos;
905
+ }
906
+ /**
907
+ * IAM policy required by the store
908
+ * @param accountId - AWS account id
909
+ * @returns the policy statement
910
+ */
911
+ getARNPolicy(accountId) {
912
+ const region = this.parameters.region || "us-east-1";
913
+ const tables = new Set([this.parameters.table, ...Object.values(this.parameters.tables ?? {})]);
914
+ return {
915
+ Sid: this.constructor.name + this.getName(),
916
+ Effect: "Allow",
917
+ Action: [
918
+ "dynamodb:BatchGetItem",
919
+ "dynamodb:BatchWriteItem",
920
+ "dynamodb:DeleteItem",
921
+ "dynamodb:GetItem",
922
+ "dynamodb:GetRecords",
923
+ "dynamodb:GetShardIterator",
924
+ "dynamodb:PutItem",
925
+ "dynamodb:Query",
926
+ "dynamodb:Scan",
927
+ "dynamodb:UpdateItem"
928
+ ],
929
+ Resource: [...tables].map(table => "arn:aws:dynamodb:" + region + ":" + accountId + ":table/" + table)
930
+ };
931
+ }
932
+ /**
933
+ * Delete all items from the managed tables (used in tests)
934
+ */
935
+ async __clean() {
936
+ const done = new Set();
937
+ for (const repo of this.getRepositories()) {
938
+ if (done.has(repo.getTable())) {
939
+ continue;
940
+ }
941
+ done.add(repo.getTable());
942
+ await repo.__clean();
943
+ }
944
+ }
945
+ /**
946
+ * CloudFormation resources for the table
947
+ * @param deployer - the deployer requesting the resources
948
+ * @returns the resources
949
+ */
950
+ getCloudFormation(deployer) {
951
+ if (this.parameters.CloudFormationSkip) {
952
+ return {};
953
+ }
954
+ const resources = {};
955
+ this.parameters.CloudFormation = this.parameters.CloudFormation || {};
956
+ this.parameters.CloudFormation.Table = this.parameters.CloudFormation.Table || {};
957
+ const KeySchema = this.parameters.CloudFormation.KeySchema || [{ KeyType: "HASH", AttributeName: KEY_ATTRIBUTE }];
958
+ const AttributeDefinitions = this.parameters.CloudFormation.AttributeDefinitions || [];
959
+ this.parameters.CloudFormation.Table.BillingMode =
960
+ this.parameters.CloudFormation.Table.BillingMode || "PAY_PER_REQUEST";
961
+ AttributeDefinitions.push({ AttributeName: KEY_ATTRIBUTE, AttributeType: "S" });
962
+ resources[this.getName() + "DynamoTable"] = {
963
+ Type: "AWS::DynamoDB::Table",
964
+ Properties: {
965
+ ...this.parameters.CloudFormation.Table,
966
+ TableName: this.parameters.table,
967
+ KeySchema,
968
+ AttributeDefinitions,
969
+ Tags: deployer.getDefaultTags(this.parameters.CloudFormation.Table.Tags)
970
+ }
971
+ };
972
+ // Add any Other resources with prefix of the service
973
+ return resources;
974
+ }
975
+ },
976
+ (() => {
977
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
978
+ _getRepository_decorators = [InstanceCache()];
979
+ __esDecorate(_a, null, _getRepository_decorators, { kind: "method", name: "getRepository", static: false, private: false, access: { has: obj => "getRepository" in obj, get: obj => obj.getRepository }, metadata: _metadata }, null, _instanceExtraInitializers);
980
+ if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
981
+ })(),
982
+ _a;
983
+ })();
984
+ export { DynamoStore };
985
+ export default DynamoStore;
986
+ //# sourceMappingURL=dynamodb.service.js.map