@aws-amplify/graphql-model-transformer
Version:
Amplify graphql @model transformer
201 lines • 12.4 kB
JavaScript
"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