@aws-amplify/graphql-transformer-core
Version:
A framework to transform from GraphQL SDL to AWS CloudFormation.
278 lines • 15.7 kB
JavaScript
"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