@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.
- package/CHANGELOG.md +12 -1
- package/lib/graphql-model-transformer.d.ts +2 -1
- package/lib/graphql-model-transformer.d.ts.map +1 -1
- package/lib/graphql-model-transformer.js +60 -49
- 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/resolvers/rds/mutation.d.ts.map +1 -1
- package/lib/resolvers/rds/mutation.js +3 -0
- package/lib/resolvers/rds/mutation.js.map +1 -1
- package/lib/resolvers/rds/query.d.ts.map +1 -1
- package/lib/resolvers/rds/query.js +1 -0
- package/lib/resolvers/rds/query.js.map +1 -1
- package/lib/resolvers/rds/resolver.d.ts +4 -2
- package/lib/resolvers/rds/resolver.d.ts.map +1 -1
- package/lib/resolvers/rds/resolver.js +68 -45
- package/lib/resolvers/rds/resolver.js.map +1 -1
- 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 +172 -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 +42 -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 +244 -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 +12 -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 +703 -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 +47 -60
- package/lib/resources/dynamo-model-resource-generator.js.map +1 -1
- package/lib/resources/rds-model-resource-generator.d.ts +1 -1
- package/lib/resources/rds-model-resource-generator.d.ts.map +1 -1
- package/lib/resources/rds-model-resource-generator.js +19 -16
- package/lib/resources/rds-model-resource-generator.js.map +1 -1
- 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
|