@aws-amplify/graphql-model-transformer 2.3.0-rds-4.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/lib/graphql-model-transformer.d.ts +2 -1
  3. package/lib/graphql-model-transformer.d.ts.map +1 -1
  4. package/lib/graphql-model-transformer.js +60 -49
  5. package/lib/graphql-model-transformer.js.map +1 -1
  6. package/lib/rds-lambda.zip +0 -0
  7. package/lib/rds-notification-lambda.zip +0 -0
  8. package/lib/rds-patching-lambda.zip +0 -0
  9. package/lib/resolvers/rds/mutation.d.ts.map +1 -1
  10. package/lib/resolvers/rds/mutation.js +3 -0
  11. package/lib/resolvers/rds/mutation.js.map +1 -1
  12. package/lib/resolvers/rds/query.d.ts.map +1 -1
  13. package/lib/resolvers/rds/query.js +1 -0
  14. package/lib/resolvers/rds/query.js.map +1 -1
  15. package/lib/resolvers/rds/resolver.d.ts +4 -2
  16. package/lib/resolvers/rds/resolver.d.ts.map +1 -1
  17. package/lib/resolvers/rds/resolver.js +68 -45
  18. package/lib/resolvers/rds/resolver.js.map +1 -1
  19. package/lib/resources/amplify-dynamodb-table/amplify-dynamo-model-resource-generator.d.ts +13 -0
  20. package/lib/resources/amplify-dynamodb-table/amplify-dynamo-model-resource-generator.d.ts.map +1 -0
  21. package/lib/resources/amplify-dynamodb-table/amplify-dynamo-model-resource-generator.js +172 -0
  22. package/lib/resources/amplify-dynamodb-table/amplify-dynamo-model-resource-generator.js.map +1 -0
  23. package/lib/resources/amplify-dynamodb-table/amplify-dynamodb-table-construct/index.d.ts +42 -0
  24. package/lib/resources/amplify-dynamodb-table/amplify-dynamodb-table-construct/index.d.ts.map +1 -0
  25. package/lib/resources/amplify-dynamodb-table/amplify-dynamodb-table-construct/index.js +244 -0
  26. package/lib/resources/amplify-dynamodb-table/amplify-dynamodb-table-construct/index.js.map +1 -0
  27. package/lib/resources/amplify-dynamodb-table/amplify-table-manager-lambda/amplify-table-manager-handler.d.ts +12 -0
  28. package/lib/resources/amplify-dynamodb-table/amplify-table-manager-lambda/amplify-table-manager-handler.d.ts.map +1 -0
  29. package/lib/resources/amplify-dynamodb-table/amplify-table-manager-lambda/amplify-table-manager-handler.js +703 -0
  30. package/lib/resources/amplify-dynamodb-table/amplify-table-manager-lambda/amplify-table-manager-handler.js.map +1 -0
  31. package/lib/resources/dynamo-model-resource-generator.d.ts +5 -2
  32. package/lib/resources/dynamo-model-resource-generator.d.ts.map +1 -1
  33. package/lib/resources/dynamo-model-resource-generator.js +47 -60
  34. package/lib/resources/dynamo-model-resource-generator.js.map +1 -1
  35. package/lib/resources/rds-model-resource-generator.d.ts +1 -1
  36. package/lib/resources/rds-model-resource-generator.d.ts.map +1 -1
  37. package/lib/resources/rds-model-resource-generator.js +19 -16
  38. package/lib/resources/rds-model-resource-generator.js.map +1 -1
  39. package/package.json +12 -10
@@ -0,0 +1,703 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toCreateTableInput = exports.extractTableInputFromEvent = exports.getPointInTimeRecoveryUpdate = exports.getTtlUpdate = exports.getDeletionProtectionUpdate = exports.getSseUpdate = exports.getStreamUpdate = exports.getNextAtomicUpdate = exports.isComplete = exports.onEvent = void 0;
4
+ const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
5
+ const ddbClient = new client_dynamodb_1.DynamoDB();
6
+ const finished = {
7
+ IsComplete: true,
8
+ };
9
+ const notFinished = {
10
+ IsComplete: false,
11
+ };
12
+ const log = (msg, ...other) => {
13
+ console.log(msg, other.map((o) => (typeof o === 'object' ? JSON.stringify(o, undefined, 2) : o)));
14
+ };
15
+ const onEvent = async (event) => {
16
+ var _a;
17
+ console.log({ ...event, ResponseURL: '[redacted]' });
18
+ const tableDef = (0, exports.extractTableInputFromEvent)(event);
19
+ console.log('Input table state: ', tableDef);
20
+ let result;
21
+ switch (event.RequestType) {
22
+ case 'Create':
23
+ console.log('Initiating CREATE event');
24
+ const createTableInput = (0, exports.toCreateTableInput)(tableDef);
25
+ console.log('Create Table Params: ', createTableInput);
26
+ const response = await createNewTable(createTableInput);
27
+ result = {
28
+ PhysicalResourceId: response.tableName,
29
+ Data: {
30
+ TableArn: response.tableArn,
31
+ TableStreamArn: response.streamArn,
32
+ TableName: response.tableName,
33
+ },
34
+ };
35
+ console.log('Returning result: ', result);
36
+ return result;
37
+ case 'Update':
38
+ if (!event.PhysicalResourceId) {
39
+ throw new Error(`Could not find the physical ID for the updated resource`);
40
+ }
41
+ console.log('Fetching current table state');
42
+ const describeTableResult = await ddbClient.describeTable({ TableName: event.PhysicalResourceId });
43
+ if (!describeTableResult.Table) {
44
+ throw new Error(`Could not find ${event.PhysicalResourceId} to update`);
45
+ }
46
+ log('Current table state: ', describeTableResult);
47
+ if (isKeySchemaModified(describeTableResult.Table.KeySchema, tableDef.keySchema)) {
48
+ console.log('Detected table key schema change. Update requires replacement');
49
+ if (tableDef.allowDestructiveGraphqlSchemaUpdates) {
50
+ return replaceTable(describeTableResult.Table, tableDef);
51
+ }
52
+ else {
53
+ throw new Error("Editing key schema of table requires replacement which will cause ALL EXISITING DATA TO BE LOST. If this is intended, set the 'allowDestructiveGraphqlSchemaUpdates' to true and deploy again.");
54
+ }
55
+ }
56
+ if (tableDef.replaceTableUponGsiUpdate && tableDef.allowDestructiveGraphqlSchemaUpdates) {
57
+ const nextUpdate = getNextGSIUpdate(describeTableResult.Table, tableDef);
58
+ if (nextUpdate !== undefined) {
59
+ console.log('Detected global secondary index changes in sandbox mode with destructive updates allowed. Update requires replacement');
60
+ return replaceTable(describeTableResult.Table, tableDef);
61
+ }
62
+ }
63
+ const describePointInTimeRecoveryResult = await ddbClient.describeContinuousBackups({ TableName: event.PhysicalResourceId });
64
+ console.log('Current point in time recovery: ', describePointInTimeRecoveryResult);
65
+ const pointInTimeUpdate = (0, exports.getPointInTimeRecoveryUpdate)(describePointInTimeRecoveryResult.ContinuousBackupsDescription, tableDef);
66
+ if (pointInTimeUpdate) {
67
+ log('Computed point in time recovery update', pointInTimeUpdate);
68
+ await ddbClient.updateContinuousBackups(pointInTimeUpdate);
69
+ await retry(async () => await isTableReady(event.PhysicalResourceId), (res) => res === true);
70
+ console.log(`Table '${event.PhysicalResourceId}' is ready after the update of PointInTimeRecovery.`);
71
+ }
72
+ const deletionProtectionUpdate = (0, exports.getDeletionProtectionUpdate)(describeTableResult.Table, tableDef);
73
+ if (deletionProtectionUpdate) {
74
+ log('Computed deletion protection update', deletionProtectionUpdate);
75
+ await ddbClient.updateTable(deletionProtectionUpdate);
76
+ await retry(async () => await isTableReady(event.PhysicalResourceId), (res) => res === true);
77
+ console.log(`Table '${event.PhysicalResourceId}' is ready after the update of deletion protection.`);
78
+ }
79
+ const sseUpdate = (0, exports.getSseUpdate)(describeTableResult.Table, tableDef);
80
+ if (sseUpdate) {
81
+ log('Computed server side encryption update', sseUpdate);
82
+ await ddbClient.updateTable(sseUpdate);
83
+ await retry(async () => await isTableReady(event.PhysicalResourceId), (res) => res === true);
84
+ console.log(`Table '${event.PhysicalResourceId}' is ready after the update of sever side encryption.`);
85
+ }
86
+ const streamUpdate = await (0, exports.getStreamUpdate)(describeTableResult.Table, tableDef);
87
+ if (streamUpdate) {
88
+ log('Computed stream specification update', streamUpdate);
89
+ await ddbClient.updateTable(streamUpdate);
90
+ await retry(async () => await isTableReady(event.PhysicalResourceId), (res) => res === true);
91
+ console.log(`Table '${event.PhysicalResourceId}' is ready after the update of stream specificaion.`);
92
+ }
93
+ const describeTimeToLiveResult = await ddbClient.describeTimeToLive({ TableName: event.PhysicalResourceId });
94
+ console.log('Current TTL: ', describeTimeToLiveResult);
95
+ const ttlUpdate = (0, exports.getTtlUpdate)(describeTimeToLiveResult.TimeToLiveDescription, tableDef);
96
+ if (ttlUpdate) {
97
+ log('Computed time to live update', ttlUpdate);
98
+ console.log('Initiating TTL update');
99
+ await ddbClient.updateTimeToLive(ttlUpdate);
100
+ result = {
101
+ PhysicalResourceId: event.PhysicalResourceId,
102
+ Data: {
103
+ TableArn: describeTableResult.Table.TableArn,
104
+ TableStreamArn: describeTableResult.Table.LatestStreamArn,
105
+ TableName: describeTableResult.Table.TableName,
106
+ },
107
+ };
108
+ return result;
109
+ }
110
+ const nextGsiUpdate = (0, exports.getNextAtomicUpdate)(describeTableResult.Table, tableDef);
111
+ if (nextGsiUpdate) {
112
+ log('Computed next update', nextGsiUpdate);
113
+ console.log('Initiating table GSI update');
114
+ await ddbClient.updateTable(nextGsiUpdate);
115
+ }
116
+ result = {
117
+ PhysicalResourceId: event.PhysicalResourceId,
118
+ Data: {
119
+ TableArn: describeTableResult.Table.TableArn,
120
+ TableStreamArn: describeTableResult.Table.LatestStreamArn,
121
+ TableName: describeTableResult.Table.TableName,
122
+ },
123
+ };
124
+ return result;
125
+ case 'Delete':
126
+ if (!event.PhysicalResourceId) {
127
+ throw new Error(`Could not find the physical ID for the resource`);
128
+ }
129
+ result = {
130
+ PhysicalResourceId: event.PhysicalResourceId,
131
+ };
132
+ try {
133
+ console.log('Fetching current table state');
134
+ const describeTableResultBeforeDeletion = await ddbClient.describeTable({ TableName: event.PhysicalResourceId });
135
+ if ((_a = describeTableResultBeforeDeletion.Table) === null || _a === void 0 ? void 0 : _a.DeletionProtectionEnabled) {
136
+ return result;
137
+ }
138
+ console.log('Initiating table deletion');
139
+ await ddbClient.deleteTable({ TableName: event.PhysicalResourceId });
140
+ return result;
141
+ }
142
+ catch (err) {
143
+ if (err instanceof client_dynamodb_1.ResourceNotFoundException) {
144
+ console.log('Table to be deleted is not found. Deletion complete.');
145
+ return result;
146
+ }
147
+ throw err;
148
+ }
149
+ default:
150
+ throw new Error(`Event type ${event.RequestType} is not supported`);
151
+ }
152
+ };
153
+ exports.onEvent = onEvent;
154
+ const isComplete = async (event) => {
155
+ var _a, _b, _c;
156
+ log('got event', { ...event, ResponseURL: '[redacted]' });
157
+ if (event.RequestType === 'Delete') {
158
+ console.log('Delete is finished');
159
+ return finished;
160
+ }
161
+ if (!event.PhysicalResourceId) {
162
+ throw new Error('PhysicalResourceId not set in call to isComplete');
163
+ }
164
+ console.log('Fetching current table state');
165
+ const describeTableResult = await retry(async () => await ddbClient.describeTable({ TableName: event.PhysicalResourceId }), (result) => !!(result === null || result === void 0 ? void 0 : result.Table));
166
+ if (((_a = describeTableResult.Table) === null || _a === void 0 ? void 0 : _a.TableStatus) !== 'ACTIVE') {
167
+ console.log('Table not active yet');
168
+ return notFinished;
169
+ }
170
+ if ((_b = describeTableResult.Table.GlobalSecondaryIndexes) === null || _b === void 0 ? void 0 : _b.some((gsi) => gsi.IndexStatus !== 'ACTIVE' || gsi.Backfilling)) {
171
+ console.log('Some GSI is not active yet');
172
+ return notFinished;
173
+ }
174
+ const endState = (0, exports.extractTableInputFromEvent)(event);
175
+ if (event.RequestType === 'Create' || ((_c = event.Data) === null || _c === void 0 ? void 0 : _c.IsTableReplaced) === true) {
176
+ const describePointInTimeRecoveryResult = await ddbClient.describeContinuousBackups({ TableName: event.PhysicalResourceId });
177
+ const pointInTimeUpdate = (0, exports.getPointInTimeRecoveryUpdate)(describePointInTimeRecoveryResult.ContinuousBackupsDescription, endState);
178
+ if (pointInTimeUpdate) {
179
+ console.log('Updating table with point in time recovery enabled');
180
+ await ddbClient.updateContinuousBackups(pointInTimeUpdate);
181
+ return notFinished;
182
+ }
183
+ const describeTimeToLiveResult = await ddbClient.describeTimeToLive({ TableName: event.PhysicalResourceId });
184
+ const ttlUpdate = (0, exports.getTtlUpdate)(describeTimeToLiveResult.TimeToLiveDescription, endState);
185
+ if (ttlUpdate) {
186
+ console.log('Updating table with TTL enabled');
187
+ await ddbClient.updateTimeToLive(ttlUpdate);
188
+ return notFinished;
189
+ }
190
+ console.log('Create is finished');
191
+ return finished;
192
+ }
193
+ const nextUpdate = (0, exports.getNextAtomicUpdate)(describeTableResult.Table, endState);
194
+ log('Computed next update', nextUpdate);
195
+ if (!nextUpdate) {
196
+ console.log('No additional updates needed. Update finished');
197
+ return finished;
198
+ }
199
+ console.log('Initiating table update');
200
+ await ddbClient.updateTable(nextUpdate);
201
+ return notFinished;
202
+ };
203
+ exports.isComplete = isComplete;
204
+ const replaceTable = async (currentState, endState) => {
205
+ if (currentState.DeletionProtectionEnabled === true) {
206
+ throw new Error('Table cannot be replaced when the deletion protection is enabled.');
207
+ }
208
+ console.log('Deleting the old table');
209
+ await ddbClient.deleteTable({ TableName: currentState.TableName });
210
+ await retry(async () => await doesTableExist(currentState.TableName), (res) => res === false);
211
+ console.log(`Table '${currentState.TableName}' does not exist. Deletion is finished.`);
212
+ const createTableInput = (0, exports.toCreateTableInput)(endState);
213
+ console.log('Creating the new table');
214
+ const response = await createNewTable(createTableInput);
215
+ const result = {
216
+ PhysicalResourceId: response.tableName,
217
+ Data: {
218
+ TableArn: response.tableArn,
219
+ TableStreamArn: response.streamArn,
220
+ TableName: response.tableName,
221
+ IsTableReplaced: true,
222
+ },
223
+ };
224
+ log('Returning result', result);
225
+ return result;
226
+ };
227
+ const getNextAtomicUpdate = (currentState, endState) => {
228
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
229
+ const currentStateGSIs = currentState.GlobalSecondaryIndexes || [];
230
+ const isTableBillingModeModified = (((_a = currentState.BillingModeSummary) === null || _a === void 0 ? void 0 : _a.BillingMode) !== undefined && ((_b = currentState.BillingModeSummary) === null || _b === void 0 ? void 0 : _b.BillingMode) !== endState.billingMode) ||
231
+ (((_c = currentState.BillingModeSummary) === null || _c === void 0 ? void 0 : _c.BillingMode) == undefined && endState.billingMode === 'PAY_PER_REQUEST');
232
+ const isTableProvisionThroughputModified = (((_d = endState.provisionedThroughput) === null || _d === void 0 ? void 0 : _d.readCapacityUnits) !== undefined &&
233
+ ((_e = currentState.ProvisionedThroughput) === null || _e === void 0 ? void 0 : _e.ReadCapacityUnits) !== ((_f = endState.provisionedThroughput) === null || _f === void 0 ? void 0 : _f.readCapacityUnits)) ||
234
+ (((_g = endState.provisionedThroughput) === null || _g === void 0 ? void 0 : _g.writeCapacityUnits) !== undefined &&
235
+ ((_h = currentState.ProvisionedThroughput) === null || _h === void 0 ? void 0 : _h.WriteCapacityUnits) !== ((_j = endState.provisionedThroughput) === null || _j === void 0 ? void 0 : _j.writeCapacityUnits));
236
+ if (isTableBillingModeModified || isTableProvisionThroughputModified) {
237
+ let updateInput = {
238
+ TableName: currentState.TableName,
239
+ BillingMode: isTableBillingModeModified ? endState.billingMode : undefined,
240
+ ProvisionedThroughput: isTableProvisionThroughputModified && endState.billingMode === 'PROVISIONED'
241
+ ? {
242
+ ReadCapacityUnits: (_k = endState.provisionedThroughput) === null || _k === void 0 ? void 0 : _k.readCapacityUnits,
243
+ WriteCapacityUnits: (_l = endState.provisionedThroughput) === null || _l === void 0 ? void 0 : _l.writeCapacityUnits,
244
+ }
245
+ : undefined,
246
+ };
247
+ if (isTableBillingModeModified && endState.billingMode === 'PROVISIONED') {
248
+ const indexToBeUpdated = currentStateGSIs.map((gsiToUpdate) => {
249
+ var _a, _b;
250
+ return {
251
+ Update: {
252
+ IndexName: gsiToUpdate.IndexName,
253
+ ProvisionedThroughput: {
254
+ ReadCapacityUnits: (_a = endState.provisionedThroughput) === null || _a === void 0 ? void 0 : _a.readCapacityUnits,
255
+ WriteCapacityUnits: (_b = endState.provisionedThroughput) === null || _b === void 0 ? void 0 : _b.writeCapacityUnits,
256
+ },
257
+ },
258
+ };
259
+ });
260
+ updateInput = {
261
+ ...updateInput,
262
+ GlobalSecondaryIndexUpdates: indexToBeUpdated.length > 0 ? indexToBeUpdated : undefined,
263
+ };
264
+ }
265
+ return parsePropertiesToDynamoDBInput(updateInput);
266
+ }
267
+ return getNextGSIUpdate(currentState, endState);
268
+ };
269
+ exports.getNextAtomicUpdate = getNextAtomicUpdate;
270
+ const getNextGSIUpdate = (currentState, endState) => {
271
+ var _a, _b, _c, _d, _e;
272
+ const endStateGSIs = endState.globalSecondaryIndexes || [];
273
+ const endStateGSINames = endStateGSIs.map((gsi) => gsi.indexName);
274
+ const currentStateGSIs = currentState.GlobalSecondaryIndexes || [];
275
+ const currentStateGSINames = currentStateGSIs.map((gsi) => gsi.IndexName);
276
+ const gsiRequiresReplacementPredicate = (currentGSI) => {
277
+ if (!endStateGSINames.includes(currentGSI.IndexName))
278
+ return true;
279
+ const respectiveEndStateGSI = endStateGSIs.find((endStateGSI) => endStateGSI.indexName === currentGSI.IndexName);
280
+ if (isProjectionModified(currentGSI.Projection, respectiveEndStateGSI.projection))
281
+ return true;
282
+ if (isKeySchemaModified(currentGSI.KeySchema, respectiveEndStateGSI.keySchema))
283
+ return true;
284
+ return false;
285
+ };
286
+ const gsiToRemove = currentStateGSIs.find(gsiRequiresReplacementPredicate);
287
+ if (gsiToRemove) {
288
+ return {
289
+ TableName: currentState.TableName,
290
+ GlobalSecondaryIndexUpdates: [
291
+ {
292
+ Delete: {
293
+ IndexName: gsiToRemove.IndexName,
294
+ },
295
+ },
296
+ ],
297
+ };
298
+ }
299
+ const gsiRequiresCreationPredicate = (endStateGSI) => !currentStateGSINames.includes(endStateGSI.indexName);
300
+ const gsiToAdd = endStateGSIs.find(gsiRequiresCreationPredicate);
301
+ if (gsiToAdd) {
302
+ let gsiProvisionThroughput = gsiToAdd.provisionedThroughput;
303
+ if (endState.billingMode === 'PROVISIONED' && gsiToAdd.provisionedThroughput === undefined) {
304
+ gsiProvisionThroughput = {
305
+ readCapacityUnits: (_a = endState.provisionedThroughput) === null || _a === void 0 ? void 0 : _a.readCapacityUnits,
306
+ writeCapacityUnits: (_b = endState.provisionedThroughput) === null || _b === void 0 ? void 0 : _b.writeCapacityUnits,
307
+ };
308
+ }
309
+ const attributeNamesToInclude = gsiToAdd.keySchema.map((schema) => schema.attributeName);
310
+ const gsiToAddAction = {
311
+ IndexName: gsiToAdd.indexName,
312
+ KeySchema: gsiToAdd.keySchema,
313
+ Projection: gsiToAdd.projection,
314
+ ProvisionedThroughput: gsiProvisionThroughput,
315
+ };
316
+ return {
317
+ TableName: currentState.TableName,
318
+ AttributeDefinitions: (_c = endState.attributeDefinitions) === null || _c === void 0 ? void 0 : _c.filter((def) => attributeNamesToInclude.includes(def.attributeName)).map((def) => usePascalCaseForObjectKeys(def)),
319
+ GlobalSecondaryIndexUpdates: [
320
+ {
321
+ Create: parsePropertiesToDynamoDBInput(gsiToAddAction),
322
+ },
323
+ ],
324
+ };
325
+ }
326
+ const gsiRequiresUpdatePredicate = (endStateGSI) => {
327
+ var _a, _b, _c, _d;
328
+ if (endState.provisionedThroughput &&
329
+ endState.provisionedThroughput.readCapacityUnits &&
330
+ endState.provisionedThroughput.writeCapacityUnits &&
331
+ currentStateGSINames.includes(endStateGSI.indexName)) {
332
+ const currentStateGSI = currentStateGSIs.find((gsi) => gsi.IndexName === endStateGSI.indexName);
333
+ if (currentStateGSI) {
334
+ if (((_a = currentStateGSI.ProvisionedThroughput) === null || _a === void 0 ? void 0 : _a.ReadCapacityUnits) !== ((_b = endStateGSI.provisionedThroughput) === null || _b === void 0 ? void 0 : _b.readCapacityUnits) ||
335
+ ((_c = currentStateGSI.ProvisionedThroughput) === null || _c === void 0 ? void 0 : _c.WriteCapacityUnits) !== ((_d = endStateGSI.provisionedThroughput) === null || _d === void 0 ? void 0 : _d.writeCapacityUnits)) {
336
+ return true;
337
+ }
338
+ }
339
+ }
340
+ return false;
341
+ };
342
+ const gsiToUpdate = endStateGSIs.find(gsiRequiresUpdatePredicate);
343
+ if (gsiToUpdate) {
344
+ return {
345
+ TableName: currentState.TableName,
346
+ GlobalSecondaryIndexUpdates: [
347
+ {
348
+ Update: {
349
+ IndexName: gsiToUpdate.indexName,
350
+ ProvisionedThroughput: {
351
+ ReadCapacityUnits: (_d = gsiToUpdate.provisionedThroughput) === null || _d === void 0 ? void 0 : _d.readCapacityUnits,
352
+ WriteCapacityUnits: (_e = gsiToUpdate.provisionedThroughput) === null || _e === void 0 ? void 0 : _e.writeCapacityUnits,
353
+ },
354
+ },
355
+ },
356
+ ],
357
+ };
358
+ }
359
+ return undefined;
360
+ };
361
+ const getStreamUpdate = async (currentState, endState) => {
362
+ var _a, _b, _c, _d, _e, _f;
363
+ let streamUpdate;
364
+ if (((_a = endState.streamSpecification) === null || _a === void 0 ? void 0 : _a.streamViewType) !== undefined &&
365
+ (currentState.StreamSpecification === undefined || currentState.StreamSpecification.StreamEnabled === false)) {
366
+ streamUpdate = { StreamEnabled: true, StreamViewType: endState.streamSpecification.streamViewType };
367
+ }
368
+ else if (((_b = endState.streamSpecification) === null || _b === void 0 ? void 0 : _b.streamViewType) === undefined && ((_c = currentState.StreamSpecification) === null || _c === void 0 ? void 0 : _c.StreamEnabled) === true) {
369
+ streamUpdate = { StreamEnabled: false };
370
+ }
371
+ else if (((_d = currentState.StreamSpecification) === null || _d === void 0 ? void 0 : _d.StreamEnabled) === true &&
372
+ ((_e = endState.streamSpecification) === null || _e === void 0 ? void 0 : _e.streamViewType) !== undefined &&
373
+ currentState.StreamSpecification.StreamViewType !== ((_f = endState.streamSpecification) === null || _f === void 0 ? void 0 : _f.streamViewType)) {
374
+ console.log('Detect stream view type is changed. Disabling stream before the type change.');
375
+ await ddbClient.updateTable({
376
+ TableName: currentState.TableName,
377
+ StreamSpecification: { StreamEnabled: false },
378
+ });
379
+ await retry(async () => await isTableReady(currentState.TableName), (res) => res === true);
380
+ streamUpdate = { StreamEnabled: true, StreamViewType: endState.streamSpecification.streamViewType };
381
+ }
382
+ if (streamUpdate) {
383
+ return {
384
+ TableName: currentState.TableName,
385
+ StreamSpecification: streamUpdate,
386
+ };
387
+ }
388
+ return undefined;
389
+ };
390
+ exports.getStreamUpdate = getStreamUpdate;
391
+ const getSseUpdate = (currentState, endState) => {
392
+ var _a, _b, _c;
393
+ let sseUpdate;
394
+ if (currentState.SSEDescription) {
395
+ if (!((_a = endState.sseSpecification) === null || _a === void 0 ? void 0 : _a.sseEnabled)) {
396
+ sseUpdate = {
397
+ Enabled: false,
398
+ };
399
+ }
400
+ else if (((_b = endState.sseSpecification) === null || _b === void 0 ? void 0 : _b.sseEnabled) === true &&
401
+ endState.sseSpecification.sseType !== undefined &&
402
+ endState.sseSpecification.sseType !== currentState.SSEDescription.SSEType) {
403
+ sseUpdate = {
404
+ Enabled: true,
405
+ SSEType: endState.sseSpecification.sseType,
406
+ KMSMasterKeyId: endState.sseSpecification.kmsMasterKeyId,
407
+ };
408
+ }
409
+ }
410
+ else {
411
+ if ((_c = endState.sseSpecification) === null || _c === void 0 ? void 0 : _c.sseEnabled) {
412
+ sseUpdate = {
413
+ Enabled: true,
414
+ SSEType: endState.sseSpecification.sseType,
415
+ KMSMasterKeyId: endState.sseSpecification.kmsMasterKeyId,
416
+ };
417
+ }
418
+ }
419
+ if (sseUpdate) {
420
+ return parsePropertiesToDynamoDBInput({
421
+ TableName: currentState.TableName,
422
+ SSESpecification: sseUpdate,
423
+ });
424
+ }
425
+ return undefined;
426
+ };
427
+ exports.getSseUpdate = getSseUpdate;
428
+ const getDeletionProtectionUpdate = (currentState, endState) => {
429
+ if (endState.deletionProtectionEnabled !== undefined && currentState.DeletionProtectionEnabled !== endState.deletionProtectionEnabled) {
430
+ return {
431
+ TableName: currentState.TableName,
432
+ DeletionProtectionEnabled: endState.deletionProtectionEnabled,
433
+ };
434
+ }
435
+ else if (endState.deletionProtectionEnabled === undefined && currentState.DeletionProtectionEnabled === true) {
436
+ return {
437
+ TableName: currentState.TableName,
438
+ DeletionProtectionEnabled: false,
439
+ };
440
+ }
441
+ return undefined;
442
+ };
443
+ exports.getDeletionProtectionUpdate = getDeletionProtectionUpdate;
444
+ const getTtlUpdate = (currentTTL, endState) => {
445
+ const endTTL = endState.timeToLiveSpecification;
446
+ if (currentTTL && currentTTL.TimeToLiveStatus) {
447
+ if (currentTTL.TimeToLiveStatus === 'ENABLED' && currentTTL.AttributeName) {
448
+ if (!endTTL || !endTTL.enabled) {
449
+ return {
450
+ TableName: endState.tableName,
451
+ TimeToLiveSpecification: {
452
+ Enabled: false,
453
+ AttributeName: currentTTL.AttributeName,
454
+ },
455
+ };
456
+ }
457
+ else if (currentTTL.AttributeName !== endTTL.attributeName) {
458
+ return {
459
+ TableName: endState.tableName,
460
+ TimeToLiveSpecification: {
461
+ Enabled: true,
462
+ AttributeName: endTTL.attributeName,
463
+ },
464
+ };
465
+ }
466
+ }
467
+ else if (currentTTL.TimeToLiveStatus === 'DISABLED' && endTTL && endTTL.enabled) {
468
+ return {
469
+ TableName: endState.tableName,
470
+ TimeToLiveSpecification: {
471
+ Enabled: true,
472
+ AttributeName: endTTL.attributeName,
473
+ },
474
+ };
475
+ }
476
+ }
477
+ return undefined;
478
+ };
479
+ exports.getTtlUpdate = getTtlUpdate;
480
+ const getPointInTimeRecoveryUpdate = (currentPointInTime, endState) => {
481
+ var _a, _b;
482
+ if (!currentPointInTime) {
483
+ return undefined;
484
+ }
485
+ const currentStatus = (_a = currentPointInTime.PointInTimeRecoveryDescription) === null || _a === void 0 ? void 0 : _a.PointInTimeRecoveryStatus;
486
+ const endStatus = (_b = endState.pointInTimeRecoverySpecification) === null || _b === void 0 ? void 0 : _b.pointInTimeRecoveryEnabled;
487
+ if (endStatus === undefined || endStatus === false) {
488
+ if (currentStatus === 'ENABLED') {
489
+ return {
490
+ TableName: endState.tableName,
491
+ PointInTimeRecoverySpecification: {
492
+ PointInTimeRecoveryEnabled: false,
493
+ },
494
+ };
495
+ }
496
+ }
497
+ else {
498
+ if (currentStatus === 'DISABLED') {
499
+ return {
500
+ TableName: endState.tableName,
501
+ PointInTimeRecoverySpecification: {
502
+ PointInTimeRecoveryEnabled: true,
503
+ },
504
+ };
505
+ }
506
+ }
507
+ return undefined;
508
+ };
509
+ exports.getPointInTimeRecoveryUpdate = getPointInTimeRecoveryUpdate;
510
+ const extractTableInputFromEvent = (event) => {
511
+ const resourceProperties = { ...event.ResourceProperties };
512
+ delete resourceProperties.ServiceToken;
513
+ const tableDef = convertStringToBooleanOrNumber(resourceProperties);
514
+ return tableDef;
515
+ };
516
+ exports.extractTableInputFromEvent = extractTableInputFromEvent;
517
+ const parsePropertiesToDynamoDBInput = (obj) => {
518
+ return usePascalCaseForObjectKeys(removeUndefinedAttributes(obj));
519
+ };
520
+ const usePascalCaseForObjectKeys = (obj) => {
521
+ const result = {};
522
+ for (const key in obj) {
523
+ if (obj.hasOwnProperty(key) && key !== '') {
524
+ const capitalizedKey = key.charAt(0).toUpperCase() + key.slice(1);
525
+ const value = obj[key];
526
+ if (Array.isArray(value)) {
527
+ result[capitalizedKey] = value.map((v) => usePascalCaseForObjectKeys(v));
528
+ }
529
+ else if (typeof value === 'object' && value !== null) {
530
+ result[capitalizedKey] = usePascalCaseForObjectKeys(value);
531
+ }
532
+ else {
533
+ result[capitalizedKey] = value;
534
+ }
535
+ }
536
+ }
537
+ return result;
538
+ };
539
+ const convertStringToBooleanOrNumber = (obj) => {
540
+ const fieldsToBeConvertedToBoolean = [
541
+ 'deletionProtectionEnabled',
542
+ 'enabled',
543
+ 'sseEnabled',
544
+ 'pointInTimeRecoveryEnabled',
545
+ 'allowDestructiveGraphqlSchemaUpdates',
546
+ 'replaceTableUponGsiUpdate',
547
+ ];
548
+ const fieldsToBeConvertedToNumber = ['readCapacityUnits', 'writeCapacityUnits'];
549
+ for (const key in obj) {
550
+ if (Array.isArray(obj[key])) {
551
+ obj[key] = obj[key].map((o) => convertStringToBooleanOrNumber(o));
552
+ }
553
+ else if (typeof obj[key] === 'object') {
554
+ obj[key] = convertStringToBooleanOrNumber(obj[key]);
555
+ }
556
+ else if (typeof obj[key] === 'string') {
557
+ if ((obj[key] === 'true' || obj[key] === 'false') && fieldsToBeConvertedToBoolean.includes(key)) {
558
+ obj[key] = obj[key] === 'true';
559
+ }
560
+ else if (!isNaN(Number(obj[key])) && fieldsToBeConvertedToNumber.includes(key)) {
561
+ obj[key] = Number(obj[key]);
562
+ }
563
+ }
564
+ }
565
+ return obj;
566
+ };
567
+ const removeUndefinedAttributes = (obj) => {
568
+ for (const key in obj) {
569
+ if (Array.isArray(obj[key])) {
570
+ obj[key].map((o) => removeUndefinedAttributes(o));
571
+ }
572
+ else if (typeof obj[key] === 'object') {
573
+ removeUndefinedAttributes(obj[key]);
574
+ }
575
+ else if (obj[key] === undefined) {
576
+ delete obj[key];
577
+ }
578
+ }
579
+ return obj;
580
+ };
581
+ const toCreateTableInput = (props) => {
582
+ const createTableInput = {
583
+ TableName: props.tableName,
584
+ AttributeDefinitions: props.attributeDefinitions,
585
+ KeySchema: props.keySchema,
586
+ GlobalSecondaryIndexes: props.globalSecondaryIndexes,
587
+ BillingMode: props.billingMode,
588
+ StreamSpecification: props.streamSpecification
589
+ ? {
590
+ StreamEnabled: true,
591
+ StreamViewType: props.streamSpecification.streamViewType,
592
+ }
593
+ : undefined,
594
+ ProvisionedThroughput: props.provisionedThroughput,
595
+ SSESpecification: props.sseSpecification ? { Enabled: props.sseSpecification.sseEnabled } : undefined,
596
+ DeletionProtectionEnabled: props.deletionProtectionEnabled,
597
+ };
598
+ return parsePropertiesToDynamoDBInput(createTableInput);
599
+ };
600
+ exports.toCreateTableInput = toCreateTableInput;
601
+ const createNewTable = async (input) => {
602
+ var _a;
603
+ const tableName = input.TableName;
604
+ const createTableInput = input;
605
+ const result = await ddbClient.createTable(createTableInput);
606
+ return { tableName: tableName, tableArn: result.TableDescription.TableArn, streamArn: (_a = result.TableDescription) === null || _a === void 0 ? void 0 : _a.LatestStreamArn };
607
+ };
608
+ const doesTableExist = async (tableName) => {
609
+ try {
610
+ await ddbClient.describeTable({ TableName: tableName });
611
+ return true;
612
+ }
613
+ catch (error) {
614
+ if (error instanceof client_dynamodb_1.ResourceNotFoundException) {
615
+ return false;
616
+ }
617
+ throw error;
618
+ }
619
+ };
620
+ const isTableReady = async (tableName) => {
621
+ var _a, _b;
622
+ const result = await ddbClient.describeTable({ TableName: tableName });
623
+ if (((_a = result.Table) === null || _a === void 0 ? void 0 : _a.TableStatus) !== 'ACTIVE') {
624
+ console.log('Table not active yet');
625
+ return false;
626
+ }
627
+ if ((_b = result.Table.GlobalSecondaryIndexes) === null || _b === void 0 ? void 0 : _b.some((gsi) => gsi.IndexStatus !== 'ACTIVE' || gsi.Backfilling)) {
628
+ console.log('Some GSI is not active yet');
629
+ return false;
630
+ }
631
+ return true;
632
+ };
633
+ const isProjectionModified = (currentProjection, endProjection) => {
634
+ if (currentProjection.ProjectionType !== endProjection.projectionType)
635
+ return true;
636
+ if (currentProjection.ProjectionType === 'ALL')
637
+ return false;
638
+ const currentNonKeyAttributes = currentProjection.NonKeyAttributes || [];
639
+ const endNonKeyAttributes = endProjection.nonKeyAttributes || [];
640
+ if (currentNonKeyAttributes.length !== endNonKeyAttributes.length)
641
+ return true;
642
+ if (currentNonKeyAttributes.some((currentNonKeyAttribute) => !endNonKeyAttributes.includes(currentNonKeyAttribute)))
643
+ return true;
644
+ return false;
645
+ };
646
+ const isKeySchemaModified = (currentSchema, endSchema) => {
647
+ const currentHashKey = currentSchema.find((schema) => schema.KeyType === 'HASH');
648
+ const endHashKey = endSchema.find((schema) => schema.keyType === 'HASH');
649
+ if ((currentHashKey === null || currentHashKey === void 0 ? void 0 : currentHashKey.AttributeName) !== (endHashKey === null || endHashKey === void 0 ? void 0 : endHashKey.attributeName))
650
+ return true;
651
+ const currentSortKey = currentSchema.find((schema) => schema.KeyType === 'RANGE');
652
+ const endSortKey = endSchema.find((schema) => schema.keyType === 'RANGE');
653
+ if (currentSortKey === undefined && endSortKey === undefined)
654
+ return false;
655
+ if ((currentSortKey === undefined && endSortKey !== undefined) || (currentSortKey !== undefined && endSortKey === undefined))
656
+ return true;
657
+ if ((currentSortKey === null || currentSortKey === void 0 ? void 0 : currentSortKey.AttributeName) !== (endSortKey === null || endSortKey === void 0 ? void 0 : endSortKey.attributeName))
658
+ return true;
659
+ return false;
660
+ };
661
+ const defaultSettings = {
662
+ times: Infinity,
663
+ delayMS: 1000 * 15,
664
+ timeoutMS: 1000 * 60 * 14,
665
+ stopOnError: false,
666
+ };
667
+ const retry = async (func, successPredicate, settings, failurePredicate) => {
668
+ const { times, delayMS, timeoutMS, stopOnError } = {
669
+ ...defaultSettings,
670
+ ...settings,
671
+ };
672
+ let count = 0;
673
+ let result;
674
+ let terminate = false;
675
+ const startTime = Date.now();
676
+ do {
677
+ try {
678
+ result = await func();
679
+ if (successPredicate(result)) {
680
+ return result;
681
+ }
682
+ if (typeof failurePredicate === 'function' && failurePredicate(result)) {
683
+ throw new Error('Retry-able function execution result matched failure predicate. Stopping retries.');
684
+ }
685
+ console.warn(`Retry-able function execution did not match success predicate. Result was [${JSON.stringify(result)}]. Retrying...`);
686
+ }
687
+ catch (err) {
688
+ console.warn(`Retry-able function execution failed with [${err.message || err}]`);
689
+ if (stopOnError) {
690
+ console.log('Stopping retries on error.');
691
+ }
692
+ else {
693
+ console.log('Retrying...');
694
+ }
695
+ terminate = stopOnError;
696
+ }
697
+ count++;
698
+ await sleep(delayMS);
699
+ } while (!terminate && count <= times && Date.now() - startTime < timeoutMS);
700
+ throw new Error('Retry-able function did not match predicate within the given retry constraints');
701
+ };
702
+ const sleep = async (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
703
+ //# sourceMappingURL=amplify-table-manager-handler.js.map