UNPKG

@aws-amplify/graphql-transformer-core

Version:

A framework to transform from GraphQL SDL to AWS CloudFormation.

278 lines 15.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DefaultTransformHost = void 0; const aws_appsync_1 = require("aws-cdk-lib/aws-appsync"); const aws_lambda_1 = require("aws-cdk-lib/aws-lambda"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const graphql_transformer_common_1 = require("graphql-transformer-common"); const object_hash_1 = __importDefault(require("object-hash")); const appsync_function_1 = require("./appsync-function"); const searchable_datasource_1 = require("./cdk-compat/searchable-datasource"); const template_asset_1 = require("./cdk-compat/template-asset"); const utils_1 = require("./utils"); const function_runtime_1 = require("./utils/function-runtime"); const types_1 = require("./types"); class DefaultTransformHost { constructor(options) { this.dataSources = new Map(); this.resolvers = new Map(); this.appsyncFunctions = new Map(); this.getDataSource = (name) => { return this.hasDataSource(name) ? this.dataSources.get(name) : undefined; }; this.hasResolver = (typeName, fieldName) => this.resolvers.has(`${typeName}:${fieldName}`); this.getResolver = (typeName, fieldName) => { const resolverRef = `${typeName}:${fieldName}`; return this.resolvers.has(resolverRef) ? this.resolvers.get(resolverRef) : undefined; }; this.addHttpDataSource = (name, endpoint, options, scope) => { if (this.dataSources.has(name)) { throw new Error(`DataSource ${name} already exists in the API`); } const dataSource = this.doAddHttpDataSource(name, endpoint, options, scope); this.dataSources.set(name, dataSource); return dataSource; }; this.addDynamoDbDataSource = (name, table, options, scope) => { if (this.dataSources.has(name)) { throw new Error(`DataSource ${name} already exists in the API`); } const dataSource = this.doAddDynamoDbDataSource(name, table, options, scope); this.dataSources.set((options === null || options === void 0 ? void 0 : options.name) || name, dataSource); return dataSource; }; this.addNoneDataSource = (name, options, scope) => { if (this.dataSources.has(name)) { throw new Error(`DataSource ${name} already exists in the API`); } const dataSource = this.doAddNoneDataSource(name, options, scope); this.dataSources.set(name, dataSource); return dataSource; }; this.addLambdaDataSource = (name, lambdaFunction, options, scope) => { if (!aws_cdk_lib_1.Token.isUnresolved(name) && this.dataSources.has(name)) { throw new Error(`DataSource ${name} already exists in the API`); } const dataSource = this.doAddLambdaDataSource(name, lambdaFunction, options, scope); this.dataSources.set(name, dataSource); return dataSource; }; this.addAppSyncJsRuntimeFunction = (name, codeMappingTemplate, dataSourceName, scope) => { return this.addAppSyncFunction(name, { codeMappingTemplate }, dataSourceName, scope, types_1.APPSYNC_JS_RUNTIME); }; this.addAppSyncVtlRuntimeFunction = (name, requestMappingTemplate, responseMappingTemplate, dataSourceName, scope) => { return this.addAppSyncFunction(name, { requestMappingTemplate, responseMappingTemplate }, dataSourceName, scope, types_1.VTL_RUNTIME); }; this.addAppSyncFunction = (name, mappingTemplate, dataSourceName, scope, runtime) => { if (dataSourceName && !aws_cdk_lib_1.Token.isUnresolved(dataSourceName) && !this.dataSources.has(dataSourceName)) { throw new Error(`DataSource ${dataSourceName} is missing in the API`); } const dataSource = this.dataSources.get(dataSourceName); const hashes = this.getMappingTemplateHash(mappingTemplate); const obj = { dataSource: dataSourceName, ...hashes, }; const slotHash = (0, object_hash_1.default)(obj); if (!this.api.disableResolverDeduping && this.appsyncFunctions.has(slotHash)) { const appsyncFunction = this.appsyncFunctions.get(slotHash); this.bindMappingTemplate(mappingTemplate, appsyncFunction, this.api.assetProvider, runtime); return appsyncFunction; } const fn = new appsync_function_1.AppSyncFunctionConfiguration(scope || this.api, name, { api: this.api, dataSource: dataSource || dataSourceName, mappingTemplate, runtime, }); this.appsyncFunctions.set(slotHash, fn); return fn; }; this.addJsRuntimeResolver = (typeName, fieldName, codeMappingTemplate, resolverLogicalId, dataSourceName, pipelineConfig, scope) => { return this.addResolver(typeName, fieldName, { codeMappingTemplate }, resolverLogicalId, dataSourceName, pipelineConfig, scope, types_1.APPSYNC_JS_RUNTIME); }; this.addVtlRuntimeResolver = (typeName, fieldName, requestMappingTemplate, responseMappingTemplate, resolverLogicalId, dataSourceName, pipelineConfig, scope) => { return this.addResolver(typeName, fieldName, { requestMappingTemplate, responseMappingTemplate }, resolverLogicalId, dataSourceName, pipelineConfig, scope, types_1.VTL_RUNTIME); }; this.addResolver = (typeName, fieldName, mappingTemplate, resolverLogicalId, dataSourceName, pipelineConfig, scope, runtime) => { if (dataSourceName && !aws_cdk_lib_1.Token.isUnresolved(dataSourceName) && !this.dataSources.has(dataSourceName)) { throw new Error(`DataSource ${dataSourceName} is missing in the API`); } const resolverName = (0, graphql_transformer_common_1.toCamelCase)([(0, graphql_transformer_common_1.resourceName)(typeName), (0, graphql_transformer_common_1.resourceName)(fieldName), 'Resolver']); const resourceId = resolverLogicalId !== null && resolverLogicalId !== void 0 ? resolverLogicalId : graphql_transformer_common_1.ResolverResourceIDs.ResolverResourceID(typeName, fieldName); const runtimeSpecificProps = (0, function_runtime_1.getRuntimeSpecificFunctionProps)(this.api, { mappingTemplate, runtime, api: this.api, }); if (dataSourceName) { const dataSource = this.dataSources.get(dataSourceName); const resolver = new aws_appsync_1.CfnResolver(scope || this.api, resolverName, { apiId: this.api.apiId, fieldName, typeName, kind: 'UNIT', dataSourceName: (dataSource === null || dataSource === void 0 ? void 0 : dataSource.ds.attrName) || dataSourceName, ...runtimeSpecificProps, }); resolver.overrideLogicalId(resourceId); (0, utils_1.setResourceName)(resolver, { name: `${typeName}.${fieldName}` }); this.api.addSchemaDependency(resolver); return resolver; } if (pipelineConfig) { const resolver = new aws_appsync_1.CfnResolver(scope || this.api, resolverName, { apiId: this.api.apiId, fieldName, typeName, kind: 'PIPELINE', pipelineConfig: { functions: pipelineConfig, }, ...runtimeSpecificProps, }); resolver.overrideLogicalId(resourceId); (0, utils_1.setResourceName)(resolver, { name: `${typeName}.${fieldName}` }); this.api.addSchemaDependency(resolver); this.resolvers.set(`${typeName}:${fieldName}`, resolver); return resolver; } throw new Error('Resolver needs either dataSourceName or pipelineConfig to be passed'); }; this.addLambdaFunction = (functionName, functionKey, handlerName, filePath, runtime, layers, role, environment, timeout, scope, vpc, description) => { const dummyCode = 'if __name__ == "__main__":'; const fn = new aws_lambda_1.Function(scope || this.api, functionName, { code: aws_lambda_1.Code.fromInline(dummyCode), handler: handlerName, runtime, role, layers, environment, timeout, description, }); fn.addLayers(); const cfnFn = fn.node.defaultChild; (0, utils_1.setResourceName)(fn, { name: functionName, setOnDefaultChild: true }); const functionCode = new template_asset_1.S3MappingFunctionCode(functionKey, filePath).bind(fn, this.api.assetProvider); cfnFn.code = { s3Key: functionCode.s3ObjectKey, s3Bucket: functionCode.s3BucketName, }; const subnetIds = vpc === null || vpc === void 0 ? void 0 : vpc.subnetAvailabilityZoneConfig.map((sn) => sn.subnetId); if (vpc === null || vpc === void 0 ? void 0 : vpc.vpcId) { cfnFn.vpcConfig = { subnetIds: subnetIds, securityGroupIds: vpc === null || vpc === void 0 ? void 0 : vpc.securityGroupIds, }; } return fn; }; this.api = options.api; } setAPI(api) { this.api = api; } hasDataSource(name) { return this.dataSources.has(name); } addSearchableDataSource(name, awsRegion, endpoint, options, scope) { if (this.dataSources.has(name)) { throw new Error(`DataSource ${name} already exists in the API`); } const data = this.doAddSearchableDataSource(name, endpoint, awsRegion, options, scope); this.dataSources.set((options === null || options === void 0 ? void 0 : options.name) || name, data); return data; } doAddNoneDataSource(id, options, scope) { var _a; const noneDataSource = new aws_appsync_1.NoneDataSource(scope !== null && scope !== void 0 ? scope : this.api, id, { api: this.api, name: options === null || options === void 0 ? void 0 : options.name, description: options === null || options === void 0 ? void 0 : options.description, }); (0, utils_1.setResourceName)(noneDataSource, { name: (_a = options === null || options === void 0 ? void 0 : options.name) !== null && _a !== void 0 ? _a : id, setOnDefaultChild: true }); return noneDataSource; } doAddDynamoDbDataSource(id, table, options, scope) { var _a; const ds = new aws_appsync_1.DynamoDbDataSource(scope !== null && scope !== void 0 ? scope : this.api, id, { api: this.api, table, name: options === null || options === void 0 ? void 0 : options.name, description: options === null || options === void 0 ? void 0 : options.description, serviceRole: options === null || options === void 0 ? void 0 : options.serviceRole, }); const cfnDataSource = ds.node.defaultChild; cfnDataSource.overrideLogicalId(id); (0, utils_1.setResourceName)(ds, { name: (_a = options === null || options === void 0 ? void 0 : options.name) !== null && _a !== void 0 ? _a : id, setOnDefaultChild: true }); return ds; } doAddHttpDataSource(id, endpoint, options, scope) { var _a; const ds = new aws_appsync_1.HttpDataSource(scope !== null && scope !== void 0 ? scope : this.api, id, { api: this.api, endpoint, name: options === null || options === void 0 ? void 0 : options.name, description: options === null || options === void 0 ? void 0 : options.description, authorizationConfig: options === null || options === void 0 ? void 0 : options.authorizationConfig, }); const cfnDataSource = ds.node.defaultChild; cfnDataSource.overrideLogicalId(id); (0, utils_1.setResourceName)(ds, { name: (_a = options === null || options === void 0 ? void 0 : options.name) !== null && _a !== void 0 ? _a : id, setOnDefaultChild: true }); return ds; } doAddSearchableDataSource(id, endpoint, region, options, scope) { var _a; const searchableDataSource = new searchable_datasource_1.SearchableDataSource(scope !== null && scope !== void 0 ? scope : this.api, id, { api: this.api, name: options === null || options === void 0 ? void 0 : options.name, endpoint, region, serviceRole: options === null || options === void 0 ? void 0 : options.serviceRole, }); (0, utils_1.setResourceName)(searchableDataSource, { name: (_a = options === null || options === void 0 ? void 0 : options.name) !== null && _a !== void 0 ? _a : id, setOnDefaultChild: true }); return searchableDataSource; } doAddLambdaDataSource(id, lambdaFunction, options, scope) { var _a; const ds = new aws_appsync_1.LambdaDataSource(scope || this.api, id, { api: this.api, lambdaFunction, name: options === null || options === void 0 ? void 0 : options.name, description: options === null || options === void 0 ? void 0 : options.description, }); const cfnDataSource = ds.node.defaultChild; cfnDataSource.overrideLogicalId(id); (0, utils_1.setResourceName)(ds, { name: (_a = options === null || options === void 0 ? void 0 : options.name) !== null && _a !== void 0 ? _a : id, setOnDefaultChild: true }); return ds; } getMappingTemplateHash(mappingTemplate) { var _a, _b; const isJsRuntimeTemplate = (mappingTemplate) => { return mappingTemplate.codeMappingTemplate !== undefined; }; return isJsRuntimeTemplate(mappingTemplate) ? { codeMappingTemplate: mappingTemplate.codeMappingTemplate.getTemplateHash() } : { requestMappingTemplate: (_a = mappingTemplate.requestMappingTemplate) === null || _a === void 0 ? void 0 : _a.getTemplateHash(), responseMappingTemplate: (_b = mappingTemplate.responseMappingTemplate) === null || _b === void 0 ? void 0 : _b.getTemplateHash(), }; } bindMappingTemplate(mappingTemplate, functionConfiguration, assetProvider, runtime) { if ((0, function_runtime_1.isJsResolverFnRuntime)(runtime)) { const { codeMappingTemplate } = mappingTemplate; codeMappingTemplate.bind(functionConfiguration, assetProvider); } else { const { requestMappingTemplate, responseMappingTemplate } = mappingTemplate; requestMappingTemplate && requestMappingTemplate.bind(functionConfiguration, assetProvider); responseMappingTemplate && responseMappingTemplate.bind(functionConfiguration, assetProvider); } } } exports.DefaultTransformHost = DefaultTransformHost; //# sourceMappingURL=transform-host.js.map