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