@aws-amplify/amplify-category-storage
Version:
amplify-cli storage plugin
614 lines • 30.9 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getIAMPolicies = exports.migrate = exports.updateWalkthrough = exports.addWalkthrough = void 0;
const amplify_cli_core_1 = require("@aws-amplify/amplify-cli-core");
const amplify_prompts_1 = require("@aws-amplify/amplify-prompts");
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const uuid_1 = require("uuid");
const ddb_stack_transform_1 = require("../cdk-stack-builder/ddb-stack-transform");
const dynamoDB_input_state_1 = require("./dynamoDB-input-state");
async function addWalkthrough(context, defaultValuesFilename) {
amplify_prompts_1.printer.blankLine();
amplify_prompts_1.printer.info('Welcome to the NoSQL DynamoDB database wizard');
amplify_prompts_1.printer.info('This wizard asks you a series of questions to help determine how to set up your NoSQL database table.');
amplify_prompts_1.printer.blankLine();
const defaultValuesSrc = path.join(__dirname, '..', 'default-values', defaultValuesFilename);
const { getAllDefaults } = await (_a = defaultValuesSrc, Promise.resolve().then(() => __importStar(require(_a))));
const { amplify } = context;
const defaultValues = getAllDefaults(amplify.getProjectDetails());
const resourceName = await askResourceNameQuestion(defaultValues);
const tableName = await askTableNameQuestion(defaultValues, resourceName);
const { attributeAnswers, indexableAttributeList } = await askAttributeListQuestion();
const partitionKey = await askPrimaryKeyQuestion(indexableAttributeList, attributeAnswers);
const cliInputs = {
resourceName,
tableName,
partitionKey,
};
cliInputs.sortKey = await askSortKeyQuestion(indexableAttributeList, attributeAnswers, cliInputs.partitionKey.fieldName);
cliInputs.gsi = await askGSIQuestion(indexableAttributeList, attributeAnswers);
cliInputs.triggerFunctions = await askTriggersQuestion(context, cliInputs.resourceName);
const cliInputsState = new dynamoDB_input_state_1.DynamoDBInputState(context, cliInputs.resourceName);
await cliInputsState.saveCliInputPayload(cliInputs);
const stackGenerator = new ddb_stack_transform_1.DDBStackTransform(context, cliInputs.resourceName);
await stackGenerator.transform();
return cliInputs.resourceName;
}
exports.addWalkthrough = addWalkthrough;
async function updateWalkthrough(context) {
var _a, _b, _c;
const amplifyMeta = amplify_cli_core_1.stateManager.getMeta();
const dynamoDbResources = {};
Object.keys(amplifyMeta[amplify_cli_core_1.AmplifyCategories.STORAGE]).forEach((resourceName) => {
if (amplifyMeta[amplify_cli_core_1.AmplifyCategories.STORAGE][resourceName].service === amplify_cli_core_1.AmplifySupportedService.DYNAMODB &&
amplifyMeta[amplify_cli_core_1.AmplifyCategories.STORAGE][resourceName].mobileHubMigrated !== true &&
amplifyMeta[amplify_cli_core_1.AmplifyCategories.STORAGE][resourceName].serviceType !== 'imported') {
dynamoDbResources[resourceName] = amplifyMeta[amplify_cli_core_1.AmplifyCategories.STORAGE][resourceName];
}
});
if (!amplifyMeta[amplify_cli_core_1.AmplifyCategories.STORAGE] || Object.keys(dynamoDbResources).length === 0) {
const errMessage = 'No resources to update. You need to add a resource.';
amplify_prompts_1.printer.error(errMessage);
void context.usageData.emitError(new amplify_cli_core_1.ResourceDoesNotExistError(errMessage));
(0, amplify_cli_core_1.exitOnNextTick)(0);
return undefined;
}
const resources = Object.keys(dynamoDbResources);
const resourceName = await amplify_prompts_1.prompter.pick('Specify the resource that you would want to update', resources);
const cliInputsState = new dynamoDB_input_state_1.DynamoDBInputState(context, resourceName);
const headlessMigrate = ((_a = context.input.options) === null || _a === void 0 ? void 0 : _a.yes) || ((_b = context.input.options) === null || _b === void 0 ? void 0 : _b.forcePush) || ((_c = context.input.options) === null || _c === void 0 ? void 0 : _c.headless);
if (!cliInputsState.cliInputFileExists()) {
if (headlessMigrate || (await amplify_prompts_1.prompter.yesOrNo((0, amplify_cli_core_1.getMigrateResourceMessageForOverride)(amplify_cli_core_1.AmplifyCategories.STORAGE, resourceName), true))) {
await cliInputsState.migrate();
const stackGenerator = new ddb_stack_transform_1.DDBStackTransform(context, resourceName);
await stackGenerator.transform();
}
else {
return undefined;
}
}
const cliInputs = cliInputsState.getCliInputPayload();
const existingAttributeDefinitions = [];
if (cliInputs.partitionKey) {
existingAttributeDefinitions.push(cliInputs.partitionKey);
}
if (cliInputs.sortKey) {
existingAttributeDefinitions.push(cliInputs.sortKey);
}
if (cliInputs.gsi && cliInputs.gsi.length > 0) {
cliInputs.gsi.forEach((gsi) => {
if (gsi.partitionKey) {
existingAttributeDefinitions.push(gsi.partitionKey);
}
if (gsi.sortKey) {
existingAttributeDefinitions.push(gsi.sortKey);
}
});
}
if (!cliInputs.resourceName) {
throw new Error('resourceName not found in cli-inputs');
}
const { attributeAnswers, indexableAttributeList } = await askAttributeListQuestion(existingAttributeDefinitions);
cliInputs.gsi = await askGSIQuestion(indexableAttributeList, attributeAnswers, cliInputs.gsi);
cliInputs.triggerFunctions = await askTriggersQuestion(context, cliInputs.resourceName, cliInputs.triggerFunctions);
await cliInputsState.saveCliInputPayload(cliInputs);
const stackGenerator = new ddb_stack_transform_1.DDBStackTransform(context, cliInputs.resourceName);
await stackGenerator.transform();
return cliInputs;
}
exports.updateWalkthrough = updateWalkthrough;
async function askTriggersQuestion(context, resourceName, existingTriggerFunctions) {
const triggerFunctions = existingTriggerFunctions || [];
if (!existingTriggerFunctions || existingTriggerFunctions.length === 0) {
if (await amplify_prompts_1.prompter.confirmContinue('Do you want to add a Lambda Trigger for your Table?')) {
let triggerName;
try {
triggerName = await addTrigger(context, resourceName);
return [triggerName];
}
catch (e) {
amplify_prompts_1.printer.error(e.message);
}
}
}
else {
let triggerName;
let continueWithTriggerOperationQuestion = true;
while (continueWithTriggerOperationQuestion) {
const triggerOperationAnswer = await amplify_prompts_1.prompter.pick('Select from the following options', [
'Add a Trigger',
'Remove a trigger',
`I'm done`,
]);
switch (triggerOperationAnswer) {
case 'Add a Trigger': {
try {
triggerName = await addTrigger(context, resourceName, triggerFunctions);
triggerFunctions.push(triggerName);
continueWithTriggerOperationQuestion = false;
}
catch (e) {
amplify_prompts_1.printer.error(e.message);
continueWithTriggerOperationQuestion = true;
}
break;
}
case 'Remove a trigger': {
try {
if (triggerFunctions.length === 0) {
throw new Error('No triggers found associated with this table');
}
else {
triggerName = await removeTrigger(context, resourceName, triggerFunctions);
const index = triggerFunctions.indexOf(triggerName);
if (index >= 0) {
triggerFunctions.splice(index, 1);
continueWithTriggerOperationQuestion = false;
}
else {
throw new Error('Could not find trigger function');
}
}
}
catch (e) {
amplify_prompts_1.printer.error(e.message);
continueWithTriggerOperationQuestion = true;
}
break;
}
case `I'm done`: {
continueWithTriggerOperationQuestion = false;
break;
}
default:
amplify_prompts_1.printer.error(`${triggerOperationAnswer} not supported`);
}
}
}
return triggerFunctions;
}
async function askGSIQuestion(indexableAttributeList, attributeDefinitions, existingGSIList) {
amplify_prompts_1.printer.blankLine();
amplify_prompts_1.printer.info('You can optionally add global secondary indexes for this table. These are useful when you run queries defined in a different column than the primary key.');
amplify_prompts_1.printer.info('To learn more about indexes, see:');
amplify_prompts_1.printer.info('https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.SecondaryIndexes');
amplify_prompts_1.printer.blankLine();
let gsiList = [];
if (existingGSIList &&
!!existingGSIList.length &&
(await amplify_prompts_1.prompter.yesOrNo('Do you want to keep existing global secondary indexes created on your table?', true))) {
gsiList = existingGSIList;
}
if (await amplify_prompts_1.prompter.yesOrNo('Do you want to add global secondary indexes to your table?', true)) {
let continueWithGSIQuestions = true;
while (continueWithGSIQuestions) {
if (indexableAttributeList.length > 0) {
const gsiNameValidator = (message) => (input) => /^[a-zA-Z0-9_-]+$/.test(input) ? true : message;
const gsiName = await amplify_prompts_1.prompter.input('Provide the GSI name', {
validate: gsiNameValidator('You can use the following characters: a-z A-Z 0-9 - _'),
});
const gsiPartitionKeyName = await amplify_prompts_1.prompter.pick('Choose partition key for the GSI', [...new Set(indexableAttributeList)]);
const gsiPrimaryKeyIndex = attributeDefinitions.findIndex((attr) => attr.AttributeName === gsiPartitionKeyName);
const gsiItem = {
name: gsiName,
partitionKey: {
fieldName: gsiPartitionKeyName,
fieldType: attributeDefinitions[gsiPrimaryKeyIndex].AttributeType,
},
};
const sortKeyOptions = indexableAttributeList.filter((att) => att !== gsiPartitionKeyName);
if (sortKeyOptions.length > 0) {
if (await amplify_prompts_1.prompter.yesOrNo('Do you want to add a sort key to your global secondary index?', true)) {
const gsiSortKeyName = await amplify_prompts_1.prompter.pick('Choose sort key for the GSI', [...new Set(sortKeyOptions)]);
const gsiSortKeyIndex = attributeDefinitions.findIndex((attr) => attr.AttributeName === gsiSortKeyName);
gsiItem.sortKey = {
fieldName: gsiSortKeyName,
fieldType: attributeDefinitions[gsiSortKeyIndex].AttributeType,
};
}
}
gsiList.push(gsiItem);
continueWithGSIQuestions = await amplify_prompts_1.prompter.yesOrNo('Do you want to add more global secondary indexes to your table?', true);
}
else {
amplify_prompts_1.printer.error('You do not have any other attributes remaining to configure');
break;
}
}
}
return gsiList;
}
async function askSortKeyQuestion(indexableAttributeList, attributeDefinitions, partitionKeyFieldName) {
if (await amplify_prompts_1.prompter.yesOrNo('Do you want to add a sort key to your table?', true)) {
if (attributeDefinitions.length > 1) {
const sortKeyName = await amplify_prompts_1.prompter.pick('Choose sort key for the table', indexableAttributeList.filter((att) => att !== partitionKeyFieldName));
const sortKeyAttrTypeIndex = attributeDefinitions.findIndex((attr) => attr.AttributeName === sortKeyName);
return {
fieldName: sortKeyName,
fieldType: attributeDefinitions[sortKeyAttrTypeIndex].AttributeType,
};
}
else {
amplify_prompts_1.printer.error('You must add additional keys in order to select a sort key.');
}
}
return undefined;
}
async function askPrimaryKeyQuestion(indexableAttributeList, attributeDefinitions) {
amplify_prompts_1.printer.blankLine();
amplify_prompts_1.printer.info('Before you create the database, you must specify how items in your table are uniquely organized. You do this by specifying a primary key. The primary key uniquely identifies each item in the table so that no two items can have the same key. This can be an individual column, or a combination that includes a primary key and a sort key.');
amplify_prompts_1.printer.blankLine();
amplify_prompts_1.printer.info('To learn more about primary keys, see:');
amplify_prompts_1.printer.info('https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.PrimaryKey');
amplify_prompts_1.printer.blankLine();
const partitionKeyName = await amplify_prompts_1.prompter.pick('Choose partition key for the table', indexableAttributeList);
const primaryAttrTypeIndex = attributeDefinitions.findIndex((attr) => attr.AttributeName === partitionKeyName);
return {
fieldName: partitionKeyName,
fieldType: attributeDefinitions[primaryAttrTypeIndex].AttributeType,
};
}
async function askAttributeListQuestion(existingAttributeDefinitions) {
const attributeTypes = {
string: { code: 'string', indexable: true },
number: { code: 'number', indexable: true },
binary: { code: 'binary', indexable: true },
boolean: { code: 'boolean', indexable: false },
list: { code: 'list', indexable: false },
map: { code: 'map', indexable: false },
null: { code: 'null', indexable: false },
'string-set': { code: 'string-set', indexable: false },
'number-set': { code: 'number-set', indexable: false },
'binary-set': { code: 'binary-set', indexable: false },
};
amplify_prompts_1.printer.blankLine();
amplify_prompts_1.printer.info('You can now add columns to the table.');
amplify_prompts_1.printer.blankLine();
let continueAttributeQuestion = true;
let attributeAnswers = [];
let indexableAttributeList = [];
let existingAttributes = [];
if (existingAttributeDefinitions) {
existingAttributes = existingAttributeDefinitions.map((attr) => {
return {
AttributeName: attr.fieldName,
AttributeType: attr.fieldType,
};
});
}
if (existingAttributes.length > 0) {
attributeAnswers = existingAttributes;
indexableAttributeList = attributeAnswers.map((attr) => attr.AttributeName);
continueAttributeQuestion = await amplify_prompts_1.prompter.yesOrNo('Would you like to add another column?', true);
}
while (continueAttributeQuestion) {
const attributeNameValidator = (message) => (input) => /^[a-zA-Z0-9_-]+$/.test(input) ? true : message;
const attributeName = await amplify_prompts_1.prompter.input('What would you like to name this column', {
validate: attributeNameValidator('You can use the following characters: a-z A-Z 0-9 - _'),
});
const attributeType = await amplify_prompts_1.prompter.pick('Choose the data type', Object.keys(attributeTypes));
if (attributeAnswers.findIndex((attribute) => attribute.AttributeName === attributeName) !== -1) {
continueAttributeQuestion = await amplify_prompts_1.prompter.confirmContinue('This attribute was already added. Do you want to add another attribute?');
continue;
}
attributeAnswers.push({
AttributeName: attributeName,
AttributeType: attributeTypes[attributeType].code,
});
if (attributeTypes[attributeType].indexable) {
indexableAttributeList.push(attributeName);
}
continueAttributeQuestion = await amplify_prompts_1.prompter.yesOrNo('Would you like to add another column?', true);
}
return { attributeAnswers, indexableAttributeList };
}
async function askTableNameQuestion(defaultValues, resourceName) {
const tableNameValidator = (message) => (input) => /^[a-zA-Z0-9._-]+$/.test(input) ? true : message;
const tableName = await amplify_prompts_1.prompter.input('Provide table name', {
validate: tableNameValidator('You can use the following characters: a-z A-Z 0-9 . - _'),
initial: resourceName || defaultValues['tableName'],
});
return tableName;
}
async function askResourceNameQuestion(defaultValues) {
const resourceName = await amplify_prompts_1.prompter.input('Provide a friendly name', {
validate: (0, amplify_prompts_1.alphanumeric)(),
initial: defaultValues['resourceName'],
});
return resourceName;
}
async function removeTrigger(context, resourceName, triggerList) {
const functionName = await amplify_prompts_1.prompter.pick('Select from the function you would like to remove', triggerList);
const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath();
const functionCFNFilePath = path.join(projectBackendDirPath, 'function', functionName, `${functionName}-cloudformation-template.json`);
if (fs.existsSync(functionCFNFilePath)) {
const functionCFNFile = context.amplify.readJsonFile(functionCFNFilePath);
delete functionCFNFile.Resources[`${resourceName}TriggerPolicy`];
delete functionCFNFile.Resources[`${resourceName}Trigger`];
const functionCFNString = JSON.stringify(functionCFNFile, null, 4);
fs.writeFileSync(functionCFNFilePath, functionCFNString, 'utf8');
}
return functionName;
}
async function addTrigger(context, resourceName, triggerList) {
const triggerTypeAnswer = await amplify_prompts_1.prompter.pick('Select from the following options', [
'Choose an existing function from the project',
'Create a new function',
]);
let functionName;
if (triggerTypeAnswer === 'Choose an existing function from the project') {
let lambdaResources = await getLambdaFunctions(context);
if (triggerList) {
const filteredLambdaResources = [];
lambdaResources.forEach((lambdaResource) => {
if (triggerList.indexOf(lambdaResource) === -1) {
filteredLambdaResources.push(lambdaResource);
}
});
lambdaResources = filteredLambdaResources;
}
if (lambdaResources.length === 0) {
throw new Error("No functions were found in the project. Use 'amplify add function' to add a new function.");
}
functionName = await amplify_prompts_1.prompter.pick('Select from the following options', lambdaResources);
}
else {
const targetDir = context.amplify.pathManager.getBackendDirPath();
const [shortId] = (0, uuid_1.v4)().split('-');
functionName = `${resourceName}Trigger${shortId}`;
const pluginDir = __dirname;
const defaults = {
functionName: `${functionName}`,
roleName: `${resourceName}LambdaRole${shortId}`,
};
const copyJobs = [
{
dir: pluginDir,
template: path.join('..', '..', '..', '..', 'resources', 'triggers', 'dynamoDB', 'lambda-cloudformation-template.json.ejs'),
target: path.join(targetDir, 'function', functionName, `${functionName}-cloudformation-template.json`),
},
{
dir: pluginDir,
template: path.join('..', '..', '..', '..', 'resources', 'triggers', 'dynamoDB', 'event.json'),
target: path.join(targetDir, 'function', functionName, 'src', 'event.json'),
},
{
dir: pluginDir,
template: path.join('..', '..', '..', '..', 'resources', 'triggers', 'dynamoDB', 'index.js'),
target: path.join(targetDir, 'function', functionName, 'src', 'index.js'),
},
{
dir: pluginDir,
template: path.join('..', '..', '..', '..', 'resources', 'triggers', 'dynamoDB', 'package.json.ejs'),
target: path.join(targetDir, 'function', functionName, 'src', 'package.json'),
},
];
await context.amplify.copyBatch(context, copyJobs, defaults);
const backendConfigs = {
service: amplify_cli_core_1.AmplifySupportedService.LAMBDA,
providerPlugin: 'awscloudformation',
build: true,
};
context.amplify.updateamplifyMetaAfterResourceAdd('function', functionName, backendConfigs);
amplify_prompts_1.printer.success(`Successfully added resource ${functionName} locally`);
}
const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath();
const functionCFNFilePath = path.join(projectBackendDirPath, 'function', functionName, `${functionName}-cloudformation-template.json`);
if (fs.existsSync(functionCFNFilePath)) {
const functionCFNFile = context.amplify.readJsonFile(functionCFNFilePath);
functionCFNFile.Parameters[`storage${resourceName}Name`] = {
Type: 'String',
Default: `storage${resourceName}Name`,
};
functionCFNFile.Parameters[`storage${resourceName}Arn`] = {
Type: 'String',
Default: `storage${resourceName}Arn`,
};
functionCFNFile.Parameters[`storage${resourceName}StreamArn`] = {
Type: 'String',
Default: `storage${resourceName}Arn`,
};
functionCFNFile.Resources[`${resourceName}TriggerPolicy`] = {
DependsOn: ['LambdaExecutionRole'],
Type: 'AWS::IAM::Policy',
Properties: {
PolicyName: `lambda-trigger-policy-${resourceName}`,
Roles: [
{
Ref: 'LambdaExecutionRole',
},
],
PolicyDocument: {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: ['dynamodb:DescribeStream', 'dynamodb:GetRecords', 'dynamodb:GetShardIterator', 'dynamodb:ListStreams'],
Resource: [
{
Ref: `storage${resourceName}StreamArn`,
},
],
},
],
},
},
};
functionCFNFile.Resources[`${resourceName}Trigger`] = {
Type: 'AWS::Lambda::EventSourceMapping',
DependsOn: [`${resourceName}TriggerPolicy`],
Properties: {
BatchSize: 100,
Enabled: true,
EventSourceArn: {
Ref: `storage${resourceName}StreamArn`,
},
FunctionName: {
'Fn::GetAtt': ['LambdaFunction', 'Arn'],
},
StartingPosition: 'LATEST',
},
};
const amplifyMetaFilePath = amplify_cli_core_1.pathManager.getAmplifyMetaFilePath();
const amplifyMeta = context.amplify.readJsonFile(amplifyMetaFilePath);
const resourceDependsOn = amplifyMeta.function[functionName].dependsOn || [];
let resourceExists = false;
resourceDependsOn.forEach((resource) => {
if (resource.resourceName === resourceName) {
resourceExists = true;
resourceDependsOn.attributes = ['Name', 'Arn', 'StreamArn'];
}
});
if (!resourceExists) {
resourceDependsOn.push({
category: amplify_cli_core_1.AmplifyCategories.STORAGE,
resourceName,
attributes: ['Name', 'Arn', 'StreamArn'],
});
}
const functionCFNString = JSON.stringify(functionCFNFile, null, 4);
fs.writeFileSync(functionCFNFilePath, functionCFNString, 'utf8');
context.amplify.updateamplifyMetaAfterResourceUpdate('function', functionName, 'dependsOn', resourceDependsOn);
amplify_prompts_1.printer.success(`Successfully updated resource ${functionName} locally`);
if (await amplify_prompts_1.prompter.confirmContinue(`Do you want to edit the local ${functionName} lambda function now?`)) {
await context.amplify.openEditor(context, `${projectBackendDirPath}/function/${functionName}/src/index.js`);
}
}
else {
throw new Error(`Function ${functionName} does not exist`);
}
return functionName;
}
async function getLambdaFunctions(context) {
const { allResources } = await context.amplify.getResourceStatus();
const lambdaResources = allResources
.filter((resource) => resource.service === amplify_cli_core_1.AmplifySupportedService.LAMBDA)
.map((resource) => resource.resourceName);
return lambdaResources;
}
function migrate(context, projectPath, resourceName) {
const resourceDirPath = path.join(projectPath, 'amplify', 'backend', amplify_cli_core_1.AmplifyCategories.STORAGE, resourceName);
const cfnFilePath = path.join(resourceDirPath, `${resourceName}-cloudformation-template.json`);
const removeDanglingCommas = (value) => {
const regex = /,(?!\s*?[{["'\w])/g;
return value.replace(regex, '');
};
let oldCfnString = fs.readFileSync(cfnFilePath, 'utf8');
oldCfnString = removeDanglingCommas(oldCfnString);
const oldCfn = JSON.parse(oldCfnString);
const newCfn = {};
Object.assign(newCfn, oldCfn);
if (!newCfn.Parameters) {
newCfn.Parameters = {};
}
newCfn.Parameters.env = {
Type: 'String',
};
if (!newCfn.Conditions) {
newCfn.Conditions = {};
}
newCfn.Conditions.ShouldNotCreateEnvResources = {
'Fn::Equals': [
{
Ref: 'env',
},
'NONE',
],
};
newCfn.Resources.DynamoDBTable.Properties.TableName = {
'Fn::If': [
'ShouldNotCreateEnvResources',
{
Ref: 'tableName',
},
{
'Fn::Join': [
'',
[
{
Ref: 'tableName',
},
'-',
{
Ref: 'env',
},
],
],
},
],
};
const jsonString = JSON.stringify(newCfn, null, '\t');
fs.writeFileSync(cfnFilePath, jsonString, 'utf8');
}
exports.migrate = migrate;
function getIAMPolicies(resourceName, crudOptions) {
let policy = {};
const actions = [];
crudOptions.forEach((crudOption) => {
switch (crudOption) {
case 'create':
actions.push('dynamodb:Put*', 'dynamodb:Create*', 'dynamodb:BatchWriteItem', 'dynamodb:PartiQLInsert');
break;
case 'update':
actions.push('dynamodb:Update*', 'dynamodb:RestoreTable*', 'dynamodb:PartiQLUpdate');
break;
case 'read':
actions.push('dynamodb:Get*', 'dynamodb:BatchGetItem', 'dynamodb:List*', 'dynamodb:Describe*', 'dynamodb:Scan', 'dynamodb:Query', 'dynamodb:PartiQLSelect');
break;
case 'delete':
actions.push('dynamodb:Delete*', 'dynamodb:PartiQLDelete');
break;
default:
console.log(`${crudOption} not supported`);
}
});
policy = {
Effect: 'Allow',
Action: actions,
Resource: crudOptions.customPolicyResource
? crudOptions.customPolicyResource
: [
{ Ref: `${amplify_cli_core_1.AmplifyCategories.STORAGE}${resourceName}Arn` },
{
'Fn::Join': [
'/',
[
{
Ref: `${amplify_cli_core_1.AmplifyCategories.STORAGE}${resourceName}Arn`,
},
'index/*',
],
],
},
],
};
const attributes = ['Name', 'Arn', 'StreamArn'];
return { policy, attributes };
}
exports.getIAMPolicies = getIAMPolicies;
//# sourceMappingURL=dynamoDb-walkthrough.js.map