UNPKG

@aws-amplify/graphql-model-transformer

Version:
201 lines • 12.4 kB
"use strict"; 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; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AmplifyDynamoModelResourceGenerator = exports.ITERATIVE_TABLE_STACK_NAME = void 0; const cdk = __importStar(require("aws-cdk-lib")); const graphql_transformer_common_1 = require("graphql-transformer-common"); const graphql_transformer_core_1 = require("@aws-amplify/graphql-transformer-core"); const aws_dynamodb_1 = require("aws-cdk-lib/aws-dynamodb"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const dynamo_model_resource_generator_1 = require("../dynamo-model-resource-generator"); const path = __importStar(require("path")); const amplify_dynamodb_table_construct_1 = require("./amplify-dynamodb-table-construct"); const waiter_state_machine_1 = require("./waiter-state-machine"); const provider_1 = require("./provider"); exports.ITERATIVE_TABLE_STACK_NAME = 'AmplifyTableManager'; class AmplifyDynamoModelResourceGenerator extends dynamo_model_resource_generator_1.DynamoModelResourceGenerator { constructor() { super(...arguments); this.customResourceServiceToken = ''; } generateResources(ctx) { if (!this.isEnabled()) { return; } if (this.isProvisioned()) { const rootStack = cdk.Stack.of(ctx.stackManager.scope); this.createDynamoDBParameters(rootStack, false); const tableManagerStack = ctx.stackManager.getScopeFor('AmplifyTableCustomProvider', exports.ITERATIVE_TABLE_STACK_NAME); this.createCustomProviderResource(tableManagerStack, ctx); } this.models.forEach((model) => { const tableBaseName = ctx.resourceHelper.getModelNameMapping(model.name.value); const tableLogicalName = graphql_transformer_common_1.ModelResourceIDs.ModelTableResourceID(tableBaseName); const scope = ctx.stackManager.getScopeFor(tableLogicalName, tableBaseName); this.createModelTable(scope, model, ctx); }); this.generateResolvers(ctx); } createCustomProviderResource(scope, context) { const lambdaCode = aws_cdk_lib_1.aws_lambda.Code.fromAsset(path.join(__dirname, '..', '..', '..', 'lib', 'resources', 'amplify-dynamodb-table', 'amplify-table-manager-lambda'), { exclude: ['*.ts', '*.json', 'LICENSE', 'README.md'] }); const importedTableNames = Object.values(context.dataSourceStrategies) .filter(graphql_transformer_core_1.isImportedAmplifyDynamoDbModelDataSourceStrategy) .map((strategy) => strategy.tableName); const lambdaPolicyDocument = new aws_cdk_lib_1.aws_iam.PolicyDocument({ statements: [ new aws_cdk_lib_1.aws_iam.PolicyStatement({ actions: [ 'dynamodb:CreateTable', 'dynamodb:UpdateTable', 'dynamodb:DeleteTable', 'dynamodb:DescribeTable', 'dynamodb:DescribeContinuousBackups', 'dynamodb:DescribeTimeToLive', 'dynamodb:UpdateContinuousBackups', 'dynamodb:UpdateTimeToLive', 'dynamodb:TagResource', 'dynamodb:UntagResource', 'dynamodb:ListTagsOfResource', ], resources: [ cdk.Fn.sub('arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/*-${apiId}-${envName}', { apiId: context.api.apiId, envName: context.synthParameters.amplifyEnvironmentName, }), ...importedTableNames.map((tableName) => cdk.Fn.sub('arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tableName}', { tableName, })), ], }), new aws_cdk_lib_1.aws_iam.PolicyStatement({ actions: ['lambda:ListTags'], resources: [ cdk.Fn.sub('arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:*TableManager*', {}), ], }), ], }); const isCompleteRole = new aws_cdk_lib_1.aws_iam.Role(scope, 'AmplifyManagedTableIsCompleteRole', { assumedBy: new aws_cdk_lib_1.aws_iam.ServicePrincipal('lambda.amazonaws.com'), managedPolicies: [aws_cdk_lib_1.aws_iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], inlinePolicies: { CreateUpdateDeleteTablesPolicy: lambdaPolicyDocument, }, }).withoutPolicyUpdates(); const onEventRole = new aws_cdk_lib_1.aws_iam.Role(scope, 'AmplifyManagedTableOnEventRole', { assumedBy: new aws_cdk_lib_1.aws_iam.ServicePrincipal('lambda.amazonaws.com'), managedPolicies: [aws_cdk_lib_1.aws_iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], inlinePolicies: { CreateUpdateDeleteTablesPolicy: lambdaPolicyDocument, }, }); const customResourceProvider = new provider_1.Provider(scope, graphql_transformer_common_1.ResourceConstants.RESOURCES.TableManagerCustomProviderLogicalID, { lambdaCode, onEventHandlerName: 'amplify-table-manager-handler.onEvent', onEventRole, isCompleteHandlerName: 'amplify-table-manager-handler.isComplete', isCompleteRole, }); const { onEventHandler, isCompleteHandler, serviceToken } = customResourceProvider; const queryInterval = aws_cdk_lib_1.Duration.seconds(10); const totalTimeout = aws_cdk_lib_1.Duration.hours(1); const stateMachineProps = { isCompleteHandler, queryInterval, totalTimeout, maxAttempts: totalTimeout.toSeconds() / queryInterval.toSeconds(), backoffRate: 1, }; const waiterStateMachine = new waiter_state_machine_1.WaiterStateMachine(scope, 'AmplifyTableWaiterStateMachine', stateMachineProps); onEventHandler.addEnvironment('WAITER_STATE_MACHINE_ARN', waiterStateMachine.stateMachineArn); waiterStateMachine.grantStartExecution(onEventHandler); this.customResourceServiceToken = serviceToken; } createModelTable(scope, def, context) { var _a; const modelName = def.name.value; const tableLogicalName = graphql_transformer_common_1.ModelResourceIDs.ModelTableResourceID(modelName); const strategy = context.dataSourceStrategies[modelName]; const isTableImported = (0, graphql_transformer_core_1.isImportedAmplifyDynamoDbModelDataSourceStrategy)(strategy); const tableName = isTableImported ? strategy.tableName : context.resourceHelper.generateTableName(modelName); const { readIops, writeIops, billingMode, pointInTimeRecovery } = this.createDynamoDBParameters(scope, true); new cdk.CfnCondition(scope, graphql_transformer_common_1.ResourceConstants.CONDITIONS.HasEnvironmentParameter, { expression: cdk.Fn.conditionNot(cdk.Fn.conditionEquals(context.synthParameters.amplifyEnvironmentName, graphql_transformer_common_1.ResourceConstants.NONE)), }); const usePayPerRequestBilling = new cdk.CfnCondition(scope, graphql_transformer_common_1.ResourceConstants.CONDITIONS.ShouldUsePayPerRequestBilling, { expression: cdk.Fn.conditionEquals(billingMode, 'PAY_PER_REQUEST'), }); const usePointInTimeRecovery = new cdk.CfnCondition(scope, graphql_transformer_common_1.ResourceConstants.CONDITIONS.ShouldUsePointInTimeRecovery, { expression: cdk.Fn.conditionEquals(pointInTimeRecovery, 'true'), }); const removalPolicy = isTableImported || this.options.EnableDeletionProtection ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY; const table = new amplify_dynamodb_table_construct_1.AmplifyDynamoDBTable(scope, `${tableLogicalName}`, { customResourceServiceToken: this.customResourceServiceToken, allowDestructiveGraphqlSchemaUpdates: context.transformParameters.allowDestructiveGraphqlSchemaUpdates, replaceTableUponGsiUpdate: context.transformParameters.replaceTableUponGsiUpdate, tableName, partitionKey: { name: 'id', type: aws_dynamodb_1.AttributeType.STRING, }, stream: aws_dynamodb_1.StreamViewType.NEW_AND_OLD_IMAGES, encryption: aws_dynamodb_1.TableEncryption.DEFAULT, removalPolicy, deletionProtection: isTableImported, ...(context.isProjectUsingDataStore() ? { timeToLiveAttribute: '_ttl' } : undefined), ...(isTableImported ? { isImported: true } : undefined), }); (0, graphql_transformer_core_1.setResourceName)(table, { name: modelName, setOnDefaultChild: false }); const tableRepresentative = table.tableFromAttr; (0, graphql_transformer_core_1.setResourceName)(tableRepresentative, { name: modelName, setOnDefaultChild: false }); const cfnTable = (_a = table.node.defaultChild) === null || _a === void 0 ? void 0 : _a.node.defaultChild; (0, graphql_transformer_core_1.setResourceName)(cfnTable, { name: modelName, setOnDefaultChild: false }); cfnTable.addPropertyOverride('provisionedThroughput', cdk.Fn.conditionIf(usePayPerRequestBilling.logicalId, cdk.Fn.ref('AWS::NoValue'), { ReadCapacityUnits: readIops, WriteCapacityUnits: writeIops, })); cfnTable.addPropertyOverride('pointInTimeRecoverySpecification', cdk.Fn.conditionIf(usePointInTimeRecovery.logicalId, { PointInTimeRecoveryEnabled: true }, cdk.Fn.ref('AWS::NoValue'))); cfnTable.addPropertyOverride('billingMode', cdk.Fn.conditionIf(usePayPerRequestBilling.logicalId, 'PAY_PER_REQUEST', cdk.Fn.ref('AWS::NoValue')).toString()); const streamArnOutputId = `GetAtt${graphql_transformer_common_1.ModelResourceIDs.ModelTableStreamArn(def.name.value)}`; if (table.tableStreamArn) { new cdk.CfnOutput(cdk.Stack.of(scope), streamArnOutputId, { value: table.tableStreamArn, description: 'Your DynamoDB table StreamArn.', exportName: cdk.Fn.join(':', [context.api.apiId, 'GetAtt', tableLogicalName, 'StreamArn']), }); } const tableNameOutputId = `GetAtt${tableLogicalName}Name`; new cdk.CfnOutput(cdk.Stack.of(scope), tableNameOutputId, { value: table.tableName, description: 'Your DynamoDB table name.', exportName: cdk.Fn.join(':', [context.api.apiId, 'GetAtt', tableLogicalName, 'Name']), }); const role = this.createIAMRole(context, def, scope, tableName); const tableDataSourceLogicalName = `${def.name.value}Table`; this.createModelTableDataSource(def, context, tableRepresentative, scope, role, tableDataSourceLogicalName); } } exports.AmplifyDynamoModelResourceGenerator = AmplifyDynamoModelResourceGenerator; //# sourceMappingURL=amplify-dynamo-model-resource-generator.js.map