UNPKG

17.7 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.ResourceFactory = void 0;
7const table_1 = require("cloudform-types/types/dynamoDb/table");
8const resolver_1 = __importDefault(require("cloudform-types/types/appSync/resolver"));
9const cloudform_types_1 = require("cloudform-types");
10const graphql_mapping_template_1 = require("graphql-mapping-template");
11const graphql_transformer_common_1 = require("graphql-transformer-common");
12const graphql_transformer_core_1 = require("graphql-transformer-core");
13class ResourceFactory {
14 makeParams() {
15 return {};
16 }
17 initTemplate() {
18 return {
19 Parameters: this.makeParams(),
20 Resources: {},
21 Outputs: {},
22 };
23 }
24 updateTableForConnection(table, connectionName, connectionAttributeName, sortField = null) {
25 const gsis = table.Properties.GlobalSecondaryIndexes || [];
26 if (gsis.length >= 20) {
27 throw new graphql_transformer_core_1.InvalidDirectiveError(`Cannot create connection ${connectionName}. Table ${table.Properties.TableName} out of GSI capacity.`);
28 }
29 const connectionGSIName = `gsi-${connectionName}`;
30 const existingGSI = gsis.find(gsi => gsi.IndexName === connectionGSIName);
31 if (!existingGSI) {
32 const keySchema = [new table_1.KeySchema({ AttributeName: connectionAttributeName, KeyType: 'HASH' })];
33 if (sortField) {
34 keySchema.push(new table_1.KeySchema({ AttributeName: sortField.name, KeyType: 'RANGE' }));
35 }
36 gsis.push(new table_1.GlobalSecondaryIndex({
37 IndexName: connectionGSIName,
38 KeySchema: keySchema,
39 Projection: new table_1.Projection({
40 ProjectionType: 'ALL',
41 }),
42 ProvisionedThroughput: cloudform_types_1.Fn.If(graphql_transformer_common_1.ResourceConstants.CONDITIONS.ShouldUsePayPerRequestBilling, cloudform_types_1.Refs.NoValue, {
43 ReadCapacityUnits: cloudform_types_1.Fn.Ref(graphql_transformer_common_1.ResourceConstants.PARAMETERS.DynamoDBModelTableReadIOPS),
44 WriteCapacityUnits: cloudform_types_1.Fn.Ref(graphql_transformer_common_1.ResourceConstants.PARAMETERS.DynamoDBModelTableWriteIOPS),
45 }),
46 }));
47 }
48 const attributeDefinitions = table.Properties.AttributeDefinitions;
49 const existingAttribute = attributeDefinitions.find(attr => attr.AttributeName === connectionAttributeName);
50 if (!existingAttribute) {
51 attributeDefinitions.push(new table_1.AttributeDefinition({
52 AttributeName: connectionAttributeName,
53 AttributeType: 'S',
54 }));
55 }
56 if (sortField) {
57 const existingSortAttribute = attributeDefinitions.find(attr => attr.AttributeName === sortField.name);
58 if (!existingSortAttribute) {
59 const scalarType = graphql_transformer_common_1.DEFAULT_SCALARS[sortField.type];
60 const attributeType = scalarType === 'String' ? 'S' : 'N';
61 attributeDefinitions.push(new table_1.AttributeDefinition({ AttributeName: sortField.name, AttributeType: attributeType }));
62 }
63 }
64 table.Properties.GlobalSecondaryIndexes = gsis;
65 table.Properties.AttributeDefinitions = attributeDefinitions;
66 return table;
67 }
68 makeGetItemConnectionResolver(type, field, relatedType, connectionAttribute, idFieldName, sortFieldInfo) {
69 let keyObj = graphql_mapping_template_1.obj({
70 [`${idFieldName}`]: graphql_mapping_template_1.ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.${connectionAttribute}, "${graphql_transformer_common_1.NONE_VALUE}"))`),
71 });
72 if (sortFieldInfo) {
73 if (sortFieldInfo.sortFieldIsStringLike) {
74 keyObj.attributes.push([
75 sortFieldInfo.primarySortFieldName,
76 graphql_mapping_template_1.ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.${sortFieldInfo.sortFieldName}, "${graphql_transformer_common_1.NONE_VALUE}"))`),
77 ]);
78 }
79 else {
80 keyObj.attributes.push([
81 sortFieldInfo.primarySortFieldName,
82 graphql_mapping_template_1.ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNull($ctx.source.${sortFieldInfo.sortFieldName}, "${graphql_transformer_common_1.NONE_INT_VALUE}"))`),
83 ]);
84 }
85 }
86 return new resolver_1.default({
87 ApiId: cloudform_types_1.Fn.GetAtt(graphql_transformer_common_1.ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'),
88 DataSourceName: cloudform_types_1.Fn.GetAtt(graphql_transformer_common_1.ModelResourceIDs.ModelTableDataSourceID(relatedType), 'Name'),
89 FieldName: field,
90 TypeName: type,
91 RequestMappingTemplate: graphql_mapping_template_1.print(graphql_mapping_template_1.DynamoDBMappingTemplate.getItem({
92 key: keyObj,
93 })),
94 ResponseMappingTemplate: graphql_mapping_template_1.print(graphql_mapping_template_1.ref('util.toJson($context.result)')),
95 }).dependsOn(graphql_transformer_common_1.ResourceConstants.RESOURCES.GraphQLSchemaLogicalID);
96 }
97 makeQueryConnectionResolver(type, field, relatedType, connectionAttribute, connectionName, idFieldName, sortKeyInfo, limit) {
98 const pageLimit = limit || graphql_transformer_common_1.ResourceConstants.DEFAULT_PAGE_LIMIT;
99 const setup = [
100 graphql_mapping_template_1.set(graphql_mapping_template_1.ref('limit'), graphql_mapping_template_1.ref(`util.defaultIfNull($context.args.limit, ${pageLimit})`)),
101 graphql_mapping_template_1.set(graphql_mapping_template_1.ref('query'), graphql_mapping_template_1.obj({
102 expression: graphql_mapping_template_1.str('#connectionAttribute = :connectionAttribute'),
103 expressionNames: graphql_mapping_template_1.obj({
104 '#connectionAttribute': graphql_mapping_template_1.str(connectionAttribute),
105 }),
106 expressionValues: graphql_mapping_template_1.obj({
107 ':connectionAttribute': graphql_mapping_template_1.obj({
108 S: graphql_mapping_template_1.str(`$context.source.${idFieldName}`),
109 }),
110 }),
111 })),
112 ];
113 if (sortKeyInfo) {
114 setup.push(graphql_transformer_common_1.applyKeyConditionExpression(sortKeyInfo.fieldName, sortKeyInfo.attributeType, 'query'));
115 }
116 return new resolver_1.default({
117 ApiId: cloudform_types_1.Fn.GetAtt(graphql_transformer_common_1.ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'),
118 DataSourceName: cloudform_types_1.Fn.GetAtt(graphql_transformer_common_1.ModelResourceIDs.ModelTableDataSourceID(relatedType), 'Name'),
119 FieldName: field,
120 TypeName: type,
121 RequestMappingTemplate: graphql_mapping_template_1.print(graphql_mapping_template_1.compoundExpression([
122 ...setup,
123 graphql_mapping_template_1.DynamoDBMappingTemplate.query({
124 query: graphql_mapping_template_1.raw('$util.toJson($query)'),
125 scanIndexForward: graphql_mapping_template_1.ifElse(graphql_mapping_template_1.ref('context.args.sortDirection'), graphql_mapping_template_1.ifElse(graphql_mapping_template_1.equals(graphql_mapping_template_1.ref('context.args.sortDirection'), graphql_mapping_template_1.str('ASC')), graphql_mapping_template_1.bool(true), graphql_mapping_template_1.bool(false)), graphql_mapping_template_1.bool(true)),
126 filter: graphql_mapping_template_1.ifElse(graphql_mapping_template_1.ref('context.args.filter'), graphql_mapping_template_1.ref('util.transform.toDynamoDBFilterExpression($ctx.args.filter)'), graphql_mapping_template_1.nul()),
127 limit: graphql_mapping_template_1.ref('limit'),
128 nextToken: graphql_mapping_template_1.ifElse(graphql_mapping_template_1.ref('context.args.nextToken'), graphql_mapping_template_1.ref('util.toJson($context.args.nextToken)'), graphql_mapping_template_1.nul()),
129 index: graphql_mapping_template_1.str(`gsi-${connectionName}`),
130 }),
131 ])),
132 ResponseMappingTemplate: graphql_mapping_template_1.print(graphql_mapping_template_1.compoundExpression([graphql_mapping_template_1.iff(graphql_mapping_template_1.raw('!$result'), graphql_mapping_template_1.set(graphql_mapping_template_1.ref('result'), graphql_mapping_template_1.ref('ctx.result'))), graphql_mapping_template_1.raw('$util.toJson($result)')])),
133 }).dependsOn(graphql_transformer_common_1.ResourceConstants.RESOURCES.GraphQLSchemaLogicalID);
134 }
135 makeGetItemConnectionWithKeyResolver(type, field, relatedType, connectionAttributes, keySchema) {
136 const partitionKeyName = keySchema[0].AttributeName;
137 let keyObj = graphql_mapping_template_1.obj({
138 [partitionKeyName]: graphql_mapping_template_1.ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.${connectionAttributes[0]}, "${graphql_transformer_common_1.NONE_VALUE}"))`),
139 });
140 if (connectionAttributes.length > 2) {
141 const rangeKeyFields = connectionAttributes.slice(1);
142 const sortKeyName = keySchema[1].AttributeName;
143 const condensedSortKeyValue = this.condenseRangeKey(rangeKeyFields.map(keyField => `\${ctx.source.${keyField}}`));
144 keyObj.attributes.push([
145 sortKeyName,
146 graphql_mapping_template_1.ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank("${condensedSortKeyValue}", "${graphql_transformer_common_1.NONE_VALUE}"))`),
147 ]);
148 }
149 else if (connectionAttributes[1]) {
150 const sortKeyName = keySchema[1].AttributeName;
151 keyObj.attributes.push([
152 sortKeyName,
153 graphql_mapping_template_1.ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.${connectionAttributes[1]}, "${graphql_transformer_common_1.NONE_VALUE}"))`),
154 ]);
155 }
156 return new resolver_1.default({
157 ApiId: cloudform_types_1.Fn.GetAtt(graphql_transformer_common_1.ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'),
158 DataSourceName: cloudform_types_1.Fn.GetAtt(graphql_transformer_common_1.ModelResourceIDs.ModelTableDataSourceID(relatedType), 'Name'),
159 FieldName: field,
160 TypeName: type,
161 RequestMappingTemplate: graphql_mapping_template_1.print(graphql_mapping_template_1.compoundExpression([
162 graphql_mapping_template_1.DynamoDBMappingTemplate.getItem({
163 key: keyObj,
164 }),
165 ])),
166 ResponseMappingTemplate: graphql_mapping_template_1.print(graphql_mapping_template_1.ref('util.toJson($context.result)')),
167 }).dependsOn(graphql_transformer_common_1.ResourceConstants.RESOURCES.GraphQLSchemaLogicalID);
168 }
169 makeQueryConnectionWithKeyResolver(type, field, relatedType, connectionAttributes, keySchema, indexName, limit) {
170 const pageLimit = limit || graphql_transformer_common_1.ResourceConstants.DEFAULT_PAGE_LIMIT;
171 const setup = [
172 graphql_mapping_template_1.set(graphql_mapping_template_1.ref('limit'), graphql_mapping_template_1.ref(`util.defaultIfNull($context.args.limit, ${pageLimit})`)),
173 graphql_mapping_template_1.set(graphql_mapping_template_1.ref('query'), this.makeExpression(keySchema, connectionAttributes)),
174 ];
175 if (keySchema[1] && !connectionAttributes[1]) {
176 const sortKeyField = relatedType.fields.find(f => f.name.value === keySchema[1].AttributeName);
177 if (sortKeyField) {
178 setup.push(graphql_transformer_common_1.applyKeyConditionExpression(String(keySchema[1].AttributeName), graphql_transformer_common_1.attributeTypeFromScalar(sortKeyField.type), 'query'));
179 }
180 else {
181 setup.push(graphql_transformer_common_1.applyCompositeKeyConditionExpression(this.getSortKeyNames(String(keySchema[1].AttributeName)), 'query', this.makeCompositeSortKeyName(String(keySchema[1].AttributeName)), String(keySchema[1].AttributeName)));
182 }
183 }
184 let queryArguments = {
185 query: graphql_mapping_template_1.raw('$util.toJson($query)'),
186 scanIndexForward: graphql_mapping_template_1.ifElse(graphql_mapping_template_1.ref('context.args.sortDirection'), graphql_mapping_template_1.ifElse(graphql_mapping_template_1.equals(graphql_mapping_template_1.ref('context.args.sortDirection'), graphql_mapping_template_1.str('ASC')), graphql_mapping_template_1.bool(true), graphql_mapping_template_1.bool(false)), graphql_mapping_template_1.bool(true)),
187 filter: graphql_mapping_template_1.ifElse(graphql_mapping_template_1.ref('context.args.filter'), graphql_mapping_template_1.ref('util.transform.toDynamoDBFilterExpression($ctx.args.filter)'), graphql_mapping_template_1.nul()),
188 limit: graphql_mapping_template_1.ref('limit'),
189 nextToken: graphql_mapping_template_1.ifElse(graphql_mapping_template_1.ref('context.args.nextToken'), graphql_mapping_template_1.ref('util.toJson($context.args.nextToken)'), graphql_mapping_template_1.nul()),
190 index: indexName ? graphql_mapping_template_1.str(indexName) : undefined,
191 };
192 if (!indexName) {
193 const indexArg = 'index';
194 delete queryArguments[indexArg];
195 }
196 const queryObj = graphql_mapping_template_1.DynamoDBMappingTemplate.query(queryArguments);
197 return new resolver_1.default({
198 ApiId: cloudform_types_1.Fn.GetAtt(graphql_transformer_common_1.ResourceConstants.RESOURCES.GraphQLAPILogicalID, 'ApiId'),
199 DataSourceName: cloudform_types_1.Fn.GetAtt(graphql_transformer_common_1.ModelResourceIDs.ModelTableDataSourceID(relatedType.name.value), 'Name'),
200 FieldName: field,
201 TypeName: type,
202 RequestMappingTemplate: graphql_mapping_template_1.print(graphql_mapping_template_1.compoundExpression([...setup, queryObj])),
203 ResponseMappingTemplate: graphql_mapping_template_1.print(graphql_mapping_template_1.compoundExpression([graphql_mapping_template_1.iff(graphql_mapping_template_1.raw('!$result'), graphql_mapping_template_1.set(graphql_mapping_template_1.ref('result'), graphql_mapping_template_1.ref('ctx.result'))), graphql_mapping_template_1.raw('$util.toJson($result)')])),
204 }).dependsOn(graphql_transformer_common_1.ResourceConstants.RESOURCES.GraphQLSchemaLogicalID);
205 }
206 makeExpression(keySchema, connectionAttributes) {
207 if (keySchema[1] && connectionAttributes[1]) {
208 let condensedSortKeyValue = undefined;
209 if (connectionAttributes.length > 2) {
210 const rangeKeyFields = connectionAttributes.slice(1);
211 condensedSortKeyValue = this.condenseRangeKey(rangeKeyFields.map(keyField => `\${context.source.${keyField}}`));
212 }
213 return graphql_mapping_template_1.obj({
214 expression: graphql_mapping_template_1.str('#partitionKey = :partitionKey AND #sortKey = :sortKey'),
215 expressionNames: graphql_mapping_template_1.obj({
216 '#partitionKey': graphql_mapping_template_1.str(String(keySchema[0].AttributeName)),
217 '#sortKey': graphql_mapping_template_1.str(String(keySchema[1].AttributeName)),
218 }),
219 expressionValues: graphql_mapping_template_1.obj({
220 ':partitionKey': graphql_mapping_template_1.obj({
221 S: graphql_mapping_template_1.str(`$context.source.${connectionAttributes[0]}`),
222 }),
223 ':sortKey': graphql_mapping_template_1.obj({
224 S: graphql_mapping_template_1.str(condensedSortKeyValue || `$context.source.${connectionAttributes[1]}`),
225 }),
226 }),
227 });
228 }
229 return graphql_mapping_template_1.obj({
230 expression: graphql_mapping_template_1.str('#partitionKey = :partitionKey'),
231 expressionNames: graphql_mapping_template_1.obj({
232 '#partitionKey': graphql_mapping_template_1.str(String(keySchema[0].AttributeName)),
233 }),
234 expressionValues: graphql_mapping_template_1.obj({
235 ':partitionKey': graphql_mapping_template_1.obj({
236 S: graphql_mapping_template_1.str(`$context.source.${connectionAttributes[0]}`),
237 }),
238 }),
239 });
240 }
241 condenseRangeKey(fields) {
242 return fields.join(graphql_transformer_common_1.ModelResourceIDs.ModelCompositeKeySeparator());
243 }
244 makeCompositeSortKeyName(sortKeyName) {
245 const attributeNames = sortKeyName.split(graphql_transformer_common_1.ModelResourceIDs.ModelCompositeKeySeparator());
246 return graphql_transformer_common_1.toCamelCase(attributeNames);
247 }
248 getSortKeyNames(compositeSK) {
249 return compositeSK.split(graphql_transformer_common_1.ModelResourceIDs.ModelCompositeKeySeparator());
250 }
251}
252exports.ResourceFactory = ResourceFactory;
253//# sourceMappingURL=resources.js.map
\No newline at end of file