1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | exports.ResourceFactory = void 0;
|
7 | const table_1 = require("cloudform-types/types/dynamoDb/table");
|
8 | const resolver_1 = __importDefault(require("cloudform-types/types/appSync/resolver"));
|
9 | const cloudform_types_1 = require("cloudform-types");
|
10 | const graphql_mapping_template_1 = require("graphql-mapping-template");
|
11 | const graphql_transformer_common_1 = require("graphql-transformer-common");
|
12 | const graphql_transformer_core_1 = require("graphql-transformer-core");
|
13 | class 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 | }
|
252 | exports.ResourceFactory = ResourceFactory;
|
253 |
|
\ | No newline at end of file |