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