1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.ModelConnectionTransformer = void 0;
|
4 | const graphql_transformer_core_1 = require("graphql-transformer-core");
|
5 | const graphql_1 = require("graphql");
|
6 | const resources_1 = require("./resources");
|
7 | const graphql_dynamodb_transformer_1 = require("graphql-dynamodb-transformer");
|
8 | const graphql_transformer_common_1 = require("graphql-transformer-common");
|
9 | const graphql_transformer_common_2 = require("graphql-transformer-common");
|
10 | const definitions_1 = require("./definitions");
|
11 | const CONNECTION_STACK_NAME = 'ConnectionStack';
|
12 | function makeConnectionAttributeName(type, field) {
|
13 | return field ? graphql_transformer_common_1.toCamelCase([type, field, 'id']) : graphql_transformer_common_1.toCamelCase([type, 'id']);
|
14 | }
|
15 | function validateKeyField(field) {
|
16 | if (!field) {
|
17 | return;
|
18 | }
|
19 | const baseType = graphql_transformer_common_1.getBaseType(field.type);
|
20 | const isAList = graphql_transformer_common_1.isListType(field.type);
|
21 | if ((baseType === 'ID' || baseType === 'String') && !isAList) {
|
22 | return;
|
23 | }
|
24 | throw new graphql_transformer_core_1.InvalidDirectiveError(`If you define a field and specify it as a 'keyField', it must be of type 'ID' or 'String'.`);
|
25 | }
|
26 | function validateKeyFieldConnectionWithKey(field, ctx) {
|
27 | const isNonNull = graphql_transformer_common_1.isNonNullType(field.type);
|
28 | const isAList = graphql_transformer_common_1.isListType(field.type);
|
29 | const isAScalarOrEnum = graphql_transformer_common_1.isScalarOrEnum(field.type, ctx.getTypeDefinitionsOfKind(graphql_1.Kind.ENUM_TYPE_DEFINITION));
|
30 | if (!isAList && isNonNull && isAScalarOrEnum) {
|
31 | return;
|
32 | }
|
33 | throw new graphql_transformer_core_1.InvalidDirectiveError(`All fields provided to an @connection must be non-null scalar or enum fields.`);
|
34 | }
|
35 | function getFieldType(fields, fieldName) {
|
36 | return fields.find(f => f.name.value === fieldName).type;
|
37 | }
|
38 | function checkFieldsAgainstIndex(parentFields, relatedTypeFields, inputFieldNames, keySchema, field) {
|
39 | const hashAttributeName = keySchema[0].AttributeName;
|
40 | const tablePKType = getFieldType(relatedTypeFields, String(hashAttributeName));
|
41 | const queryPKType = getFieldType(parentFields, inputFieldNames[0]);
|
42 | const numFields = inputFieldNames.length;
|
43 | if (graphql_transformer_common_1.getBaseType(tablePKType) !== graphql_transformer_common_1.getBaseType(queryPKType)) {
|
44 | throw new graphql_transformer_core_1.InvalidDirectiveError(`${inputFieldNames[0]} field is not of type ${graphql_transformer_common_1.getBaseType(tablePKType)}`);
|
45 | }
|
46 | if (numFields > keySchema.length && keySchema.length !== 2) {
|
47 | throw new graphql_transformer_core_1.InvalidDirectiveError('Too many fields passed in to @connection directive.');
|
48 | }
|
49 | if (numFields > 1) {
|
50 | const querySortFields = inputFieldNames.slice(1);
|
51 | const tableSortFields = String(keySchema[1].AttributeName).split(graphql_transformer_common_2.ModelResourceIDs.ModelCompositeKeySeparator());
|
52 | if (querySortFields.length !== tableSortFields.length) {
|
53 | throw new graphql_transformer_core_1.InvalidDirectiveError(`Invalid @connection directive ${field.name.value}. fields does not accept partial sort key`);
|
54 | }
|
55 | }
|
56 | if (numFields === 2) {
|
57 | const sortAttributeName = String(keySchema[1].AttributeName).split(graphql_transformer_common_2.ModelResourceIDs.ModelCompositeKeySeparator())[0];
|
58 | const tableSKType = getFieldType(relatedTypeFields, String(sortAttributeName));
|
59 | const querySKType = getFieldType(parentFields, inputFieldNames[1]);
|
60 | if (graphql_transformer_common_1.getBaseType(tableSKType) !== graphql_transformer_common_1.getBaseType(querySKType)) {
|
61 | throw new graphql_transformer_core_1.InvalidDirectiveError(`${inputFieldNames[1]} field is not of type ${graphql_transformer_common_1.getBaseType(tableSKType)}`);
|
62 | }
|
63 | }
|
64 | else if (numFields > 2) {
|
65 | const tableSortFields = String(keySchema[1].AttributeName).split(graphql_transformer_common_2.ModelResourceIDs.ModelCompositeKeySeparator());
|
66 | const tableSortKeyTypes = tableSortFields.map(name => getFieldType(relatedTypeFields, name));
|
67 | const querySortFields = inputFieldNames.slice(1);
|
68 | const querySortKeyTypes = querySortFields.map(name => getFieldType(parentFields, name));
|
69 | querySortKeyTypes.forEach((fieldType, index) => {
|
70 | if (graphql_transformer_common_1.getBaseType(fieldType) !== graphql_transformer_common_1.getBaseType(tableSortKeyTypes[index])) {
|
71 | throw new graphql_transformer_core_1.InvalidDirectiveError(`${querySortFields[index]} field is not of type ${graphql_transformer_common_1.getBaseType(tableSortKeyTypes[index])} arguments`);
|
72 | }
|
73 | });
|
74 | }
|
75 | }
|
76 | class ModelConnectionTransformer extends graphql_transformer_core_1.Transformer {
|
77 | constructor() {
|
78 | super('ModelConnectionTransformer', graphql_transformer_core_1.gql `
|
79 | directive @connection(
|
80 | name: String
|
81 | keyField: String
|
82 | sortField: String
|
83 | keyName: String
|
84 | limit: Int
|
85 | fields: [String!]
|
86 | ) on FIELD_DEFINITION
|
87 | `);
|
88 | this.before = (ctx) => {
|
89 | const template = this.resources.initTemplate();
|
90 | ctx.mergeResources(template.Resources);
|
91 | ctx.mergeParameters(template.Parameters);
|
92 | ctx.mergeOutputs(template.Outputs);
|
93 | };
|
94 | this.field = (parent, field, directive, ctx) => {
|
95 | const parentTypeName = parent.name.value;
|
96 | const fieldName = field.name.value;
|
97 | ctx.mapResourceToStack(CONNECTION_STACK_NAME, graphql_transformer_common_2.ResolverResourceIDs.ResolverResourceID(parentTypeName, fieldName));
|
98 | const parentModelDirective = parent.directives.find((dir) => dir.name.value === 'model');
|
99 | if (!parentModelDirective) {
|
100 | throw new graphql_transformer_core_1.InvalidDirectiveError(`@connection must be on an @model object type field.`);
|
101 | }
|
102 | const relatedTypeName = graphql_transformer_common_1.getBaseType(field.type);
|
103 | const relatedType = ctx.inputDocument.definitions.find(d => d.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION && d.name.value === relatedTypeName);
|
104 | if (!relatedType) {
|
105 | throw new graphql_transformer_core_1.InvalidDirectiveError(`Could not find an object type named ${relatedTypeName}.`);
|
106 | }
|
107 | const modelDirective = relatedType.directives.find((dir) => dir.name.value === 'model');
|
108 | if (!modelDirective) {
|
109 | throw new graphql_transformer_core_1.InvalidDirectiveError(`Object type ${relatedTypeName} must be annotated with @model.`);
|
110 | }
|
111 | if (graphql_transformer_common_1.getDirectiveArgument(directive, 'fields')) {
|
112 | this.connectionWithKey(parent, field, directive, ctx);
|
113 | return;
|
114 | }
|
115 | let connectionName = graphql_transformer_common_1.getDirectiveArgument(directive, 'name');
|
116 | let associatedSortFieldName = null;
|
117 | let sortType = null;
|
118 | const associatedConnectionField = relatedType.fields.find((f) => {
|
119 | if (f === field) {
|
120 | return false;
|
121 | }
|
122 | const relatedDirective = f.directives.find((dir) => dir.name.value === 'connection');
|
123 | if (relatedDirective) {
|
124 | const relatedDirectiveName = graphql_transformer_common_1.getDirectiveArgument(relatedDirective, 'name');
|
125 | if (connectionName && relatedDirectiveName && relatedDirectiveName === connectionName) {
|
126 | associatedSortFieldName = graphql_transformer_common_1.getDirectiveArgument(relatedDirective, 'sortField');
|
127 | return true;
|
128 | }
|
129 | }
|
130 | return false;
|
131 | });
|
132 | if (connectionName && !associatedConnectionField) {
|
133 | throw new graphql_transformer_core_1.InvalidDirectiveError(`Found one half of connection "${connectionName}" at ${parentTypeName}.${fieldName} but no related field on type ${relatedTypeName}`);
|
134 | }
|
135 | connectionName = connectionName || `${parentTypeName}.${fieldName}`;
|
136 | const leftConnectionIsList = graphql_transformer_common_1.isListType(field.type);
|
137 | const leftConnectionIsNonNull = graphql_transformer_common_1.isNonNullType(field.type);
|
138 | const rightConnectionIsList = associatedConnectionField ? graphql_transformer_common_1.isListType(associatedConnectionField.type) : undefined;
|
139 | const rightConnectionIsNonNull = associatedConnectionField ? graphql_transformer_common_1.isNonNullType(associatedConnectionField.type) : undefined;
|
140 | const limit = graphql_transformer_common_1.getDirectiveArgument(directive, 'limit');
|
141 | let connectionAttributeName = graphql_transformer_common_1.getDirectiveArgument(directive, 'keyField');
|
142 | const associatedSortField = associatedSortFieldName && parent.fields.find((f) => f.name.value === associatedSortFieldName);
|
143 | if (associatedSortField) {
|
144 | if (graphql_transformer_common_1.isListType(associatedSortField.type)) {
|
145 | throw new graphql_transformer_core_1.InvalidDirectiveError(`sortField "${associatedSortFieldName}" is a list. It should be a scalar.`);
|
146 | }
|
147 | sortType = graphql_transformer_common_1.getBaseType(associatedSortField.type);
|
148 | if (!graphql_transformer_common_1.isScalar(associatedSortField.type) || sortType === graphql_transformer_common_1.STANDARD_SCALARS.Boolean) {
|
149 | throw new graphql_transformer_core_1.InvalidDirectiveError(`sortField "${associatedSortFieldName}" is of type "${sortType}". ` +
|
150 | `It should be a scalar that maps to a DynamoDB "String", "Number", or "Binary"`);
|
151 | }
|
152 | }
|
153 | const foreignAssociatedSortField = associatedSortFieldName && relatedType.fields.find((f) => f.name.value === associatedSortFieldName);
|
154 | const sortKeyInfo = foreignAssociatedSortField
|
155 | ? {
|
156 | fieldName: foreignAssociatedSortField.name.value,
|
157 | attributeType: graphql_transformer_common_1.attributeTypeFromScalar(foreignAssociatedSortField.type),
|
158 | typeName: graphql_transformer_common_1.getBaseType(foreignAssociatedSortField.type),
|
159 | }
|
160 | : undefined;
|
161 | if (leftConnectionIsList && rightConnectionIsList) {
|
162 | throw new graphql_transformer_core_1.InvalidDirectiveError(`Invalid Connection (${connectionName}): Many to Many connections are not yet supported.`);
|
163 | }
|
164 | else if (leftConnectionIsList && rightConnectionIsList === false) {
|
165 | const primaryKeyField = this.getPrimaryKeyField(ctx, parent);
|
166 | const idFieldName = primaryKeyField ? primaryKeyField.name.value : 'id';
|
167 | if (!connectionAttributeName) {
|
168 | connectionAttributeName = makeConnectionAttributeName(relatedTypeName, associatedConnectionField.name.value);
|
169 | }
|
170 | const existingKeyField = relatedType.fields.find(f => f.name.value === connectionAttributeName);
|
171 | validateKeyField(existingKeyField);
|
172 | const queryResolver = this.resources.makeQueryConnectionResolver(parentTypeName, fieldName, relatedTypeName, connectionAttributeName, connectionName, idFieldName, sortKeyInfo, limit);
|
173 | ctx.setResource(graphql_transformer_common_2.ResolverResourceIDs.ResolverResourceID(parentTypeName, fieldName), queryResolver);
|
174 | this.extendTypeWithConnection(ctx, parent, field, relatedType, sortKeyInfo);
|
175 | }
|
176 | else if (!leftConnectionIsList && rightConnectionIsList) {
|
177 | if (associatedSortFieldName && !associatedSortField) {
|
178 | throw new graphql_transformer_core_1.InvalidDirectiveError(`sortField "${associatedSortFieldName}" not found on type "${parent.name.value}", other half of connection "${connectionName}".`);
|
179 | }
|
180 | const primaryKeyField = this.getPrimaryKeyField(ctx, relatedType);
|
181 | const idFieldName = primaryKeyField ? primaryKeyField.name.value : 'id';
|
182 | if (!connectionAttributeName) {
|
183 | connectionAttributeName = makeConnectionAttributeName(parentTypeName, fieldName);
|
184 | }
|
185 | const existingKeyField = parent.fields.find(f => f.name.value === connectionAttributeName);
|
186 | validateKeyField(existingKeyField);
|
187 | const tableLogicalId = graphql_transformer_common_2.ModelResourceIDs.ModelTableResourceID(parentTypeName);
|
188 | const table = ctx.getResource(tableLogicalId);
|
189 | const sortField = associatedSortField ? { name: associatedSortFieldName, type: sortType } : null;
|
190 | const updated = this.resources.updateTableForConnection(table, connectionName, connectionAttributeName, sortField);
|
191 | ctx.setResource(tableLogicalId, updated);
|
192 | const getResolver = this.resources.makeGetItemConnectionResolver(parentTypeName, fieldName, relatedTypeName, connectionAttributeName, idFieldName);
|
193 | ctx.setResource(graphql_transformer_common_2.ResolverResourceIDs.ResolverResourceID(parentTypeName, fieldName), getResolver);
|
194 | const createInputName = graphql_transformer_common_2.ModelResourceIDs.ModelCreateInputObjectName(parentTypeName);
|
195 | const createInput = ctx.getType(createInputName);
|
196 | if (createInput) {
|
197 | const updated = definitions_1.updateCreateInputWithConnectionField(createInput, connectionAttributeName, leftConnectionIsNonNull);
|
198 | ctx.putType(updated);
|
199 | }
|
200 | const updateInputName = graphql_transformer_common_2.ModelResourceIDs.ModelUpdateInputObjectName(parentTypeName);
|
201 | const updateInput = ctx.getType(updateInputName);
|
202 | if (updateInput) {
|
203 | const updated = definitions_1.updateUpdateInputWithConnectionField(updateInput, connectionAttributeName);
|
204 | ctx.putType(updated);
|
205 | }
|
206 | }
|
207 | else if (leftConnectionIsList) {
|
208 | const primaryKeyField = this.getPrimaryKeyField(ctx, parent);
|
209 | const idFieldName = primaryKeyField ? primaryKeyField.name.value : 'id';
|
210 | if (!connectionAttributeName) {
|
211 | connectionAttributeName = makeConnectionAttributeName(parentTypeName, fieldName);
|
212 | }
|
213 | const existingKeyField = relatedType.fields.find(f => f.name.value === connectionAttributeName);
|
214 | validateKeyField(existingKeyField);
|
215 | const tableLogicalId = graphql_transformer_common_2.ModelResourceIDs.ModelTableResourceID(relatedTypeName);
|
216 | const table = ctx.getResource(tableLogicalId);
|
217 | const updated = this.resources.updateTableForConnection(table, connectionName, connectionAttributeName);
|
218 | ctx.setResource(tableLogicalId, updated);
|
219 | const queryResolver = this.resources.makeQueryConnectionResolver(parentTypeName, fieldName, relatedTypeName, connectionAttributeName, connectionName, idFieldName, sortKeyInfo, limit);
|
220 | ctx.setResource(graphql_transformer_common_2.ResolverResourceIDs.ResolverResourceID(parentTypeName, fieldName), queryResolver);
|
221 | this.extendTypeWithConnection(ctx, parent, field, relatedType, sortKeyInfo);
|
222 | const createInputName = graphql_transformer_common_2.ModelResourceIDs.ModelCreateInputObjectName(relatedTypeName);
|
223 | const createInput = ctx.getType(createInputName);
|
224 | if (createInput) {
|
225 | const updated = definitions_1.updateCreateInputWithConnectionField(createInput, connectionAttributeName);
|
226 | ctx.putType(updated);
|
227 | }
|
228 | const updateInputName = graphql_transformer_common_2.ModelResourceIDs.ModelUpdateInputObjectName(relatedTypeName);
|
229 | const updateInput = ctx.getType(updateInputName);
|
230 | if (updateInput) {
|
231 | const updated = definitions_1.updateUpdateInputWithConnectionField(updateInput, connectionAttributeName);
|
232 | ctx.putType(updated);
|
233 | }
|
234 | }
|
235 | else {
|
236 | const primaryKeyField = this.getPrimaryKeyField(ctx, relatedType);
|
237 | const idFieldName = primaryKeyField ? primaryKeyField.name.value : 'id';
|
238 | if (!connectionAttributeName) {
|
239 | connectionAttributeName = makeConnectionAttributeName(parentTypeName, fieldName);
|
240 | }
|
241 | let sortFieldInfo;
|
242 | const sortFieldName = graphql_transformer_common_1.getDirectiveArgument(directive, 'sortField');
|
243 | if (sortFieldName) {
|
244 | const relatedSortField = this.getSortField(relatedType);
|
245 | if (!relatedSortField) {
|
246 | throw new graphql_transformer_core_1.InvalidDirectiveError(`sortField "${sortFieldName}" requires a primary @key on type "${relatedTypeName}" with a sort key that was not found.`);
|
247 | }
|
248 | const sortField = parent.fields.find(f => f.name.value === sortFieldName);
|
249 | if (!sortField) {
|
250 | throw new graphql_transformer_core_1.InvalidDirectiveError(`sortField with name "${sortFieldName} cannot be found on type: ${parent.name.value}`);
|
251 | }
|
252 | const relatedSortFieldType = graphql_transformer_common_1.getBaseType(relatedSortField.type);
|
253 | const sortFieldType = graphql_transformer_common_1.getBaseType(sortField.type);
|
254 | if (relatedSortFieldType !== sortFieldType) {
|
255 | throw new graphql_transformer_core_1.InvalidDirectiveError(`sortField "${relatedSortField.name.value}" on type "${relatedTypeName}" is not matching the ` +
|
256 | `type of field "${sortFieldName}" on type "${parentTypeName}"`);
|
257 | }
|
258 | let sortFieldIsStringLike = true;
|
259 | if (sortFieldType === graphql_transformer_common_1.STANDARD_SCALARS.Int ||
|
260 | sortFieldType === graphql_transformer_common_1.STANDARD_SCALARS.Float ||
|
261 | sortFieldType === graphql_transformer_common_1.STANDARD_SCALARS.Bolean) {
|
262 | sortFieldIsStringLike = false;
|
263 | }
|
264 | sortFieldInfo = {
|
265 | primarySortFieldName: relatedSortField.name.value,
|
266 | sortFieldName,
|
267 | sortFieldIsStringLike,
|
268 | };
|
269 | }
|
270 | const existingKeyField = parent.fields.find(f => f.name.value === connectionAttributeName);
|
271 | validateKeyField(existingKeyField);
|
272 | const getResolver = this.resources.makeGetItemConnectionResolver(parentTypeName, fieldName, relatedTypeName, connectionAttributeName, idFieldName, sortFieldInfo);
|
273 | ctx.setResource(graphql_transformer_common_2.ResolverResourceIDs.ResolverResourceID(parentTypeName, fieldName), getResolver);
|
274 | const createInputName = graphql_transformer_common_2.ModelResourceIDs.ModelCreateInputObjectName(parentTypeName);
|
275 | const createInput = ctx.getType(createInputName);
|
276 | if (createInput) {
|
277 | const updated = definitions_1.updateCreateInputWithConnectionField(createInput, connectionAttributeName, leftConnectionIsNonNull);
|
278 | ctx.putType(updated);
|
279 | }
|
280 | const updateInputName = graphql_transformer_common_2.ModelResourceIDs.ModelUpdateInputObjectName(parentTypeName);
|
281 | const updateInput = ctx.getType(updateInputName);
|
282 | if (updateInput) {
|
283 | const updated = definitions_1.updateUpdateInputWithConnectionField(updateInput, connectionAttributeName);
|
284 | ctx.putType(updated);
|
285 | }
|
286 | }
|
287 | };
|
288 | this.connectionWithKey = (parent, field, directive, ctx) => {
|
289 | const parentTypeName = parent.name.value;
|
290 | const fieldName = field.name.value;
|
291 | const args = graphql_transformer_core_1.getDirectiveArguments(directive);
|
292 | if (args.fields.length === 0) {
|
293 | throw new graphql_transformer_core_1.InvalidDirectiveError('No fields passed in to @connection directive.');
|
294 | }
|
295 | const relatedTypeName = graphql_transformer_common_1.getBaseType(field.type);
|
296 | const relatedType = ctx.inputDocument.definitions.find(d => d.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION && d.name.value === relatedTypeName);
|
297 | const tableLogicalID = graphql_transformer_common_2.ModelResourceIDs.ModelTableResourceID(relatedType.name.value);
|
298 | const tableResource = ctx.getResource(tableLogicalID);
|
299 | let inputFields = [];
|
300 | args.fields.forEach(item => {
|
301 | const fieldsArrayLength = inputFields.length;
|
302 | inputFields.push(parent.fields.find(f => f.name.value === item));
|
303 | if (!inputFields[fieldsArrayLength]) {
|
304 | throw new graphql_transformer_core_1.InvalidDirectiveError(`${item} is not a field in ${parentTypeName}`);
|
305 | }
|
306 | validateKeyFieldConnectionWithKey(inputFields[fieldsArrayLength], ctx);
|
307 | });
|
308 | let index = undefined;
|
309 | if (!args.keyName) {
|
310 | checkFieldsAgainstIndex(parent.fields, relatedType.fields, args.fields, tableResource.Properties.KeySchema, field);
|
311 | }
|
312 | else {
|
313 | index =
|
314 | (tableResource.Properties.GlobalSecondaryIndexes
|
315 | ? tableResource.Properties.GlobalSecondaryIndexes.find(GSI => GSI.IndexName === args.keyName)
|
316 | : null) ||
|
317 | (tableResource.Properties.LocalSecondaryIndexes
|
318 | ? tableResource.Properties.LocalSecondaryIndexes.find(LSI => LSI.IndexName === args.keyName)
|
319 | : null);
|
320 | if (!index) {
|
321 | throw new graphql_transformer_core_1.InvalidDirectiveError(`Key ${args.keyName} does not exist for model ${relatedTypeName}`);
|
322 | }
|
323 | checkFieldsAgainstIndex(parent.fields, relatedType.fields, args.fields, index.KeySchema, field);
|
324 | }
|
325 | if (!graphql_transformer_common_1.isListType(field.type)) {
|
326 | if (args.keyName) {
|
327 | throw new graphql_transformer_core_1.InvalidDirectiveError(`Connection is to a single object but the keyName ${args.keyName} was provided which does not reference the default table.`);
|
328 | }
|
329 | const getResolver = this.resources.makeGetItemConnectionWithKeyResolver(parentTypeName, fieldName, relatedTypeName, args.fields, tableResource.Properties.KeySchema);
|
330 | ctx.setResource(graphql_transformer_common_2.ResolverResourceIDs.ResolverResourceID(parentTypeName, fieldName), getResolver);
|
331 | }
|
332 | else {
|
333 | const keySchema = index ? index.KeySchema : tableResource.Properties.KeySchema;
|
334 | const queryResolver = this.resources.makeQueryConnectionWithKeyResolver(parentTypeName, fieldName, relatedType, args.fields, keySchema, index ? String(index.IndexName) : undefined, args.limit);
|
335 | ctx.setResource(graphql_transformer_common_2.ResolverResourceIDs.ResolverResourceID(parentTypeName, fieldName), queryResolver);
|
336 | let sortKeyInfo = undefined;
|
337 | if (args.fields.length > 1) {
|
338 | sortKeyInfo = undefined;
|
339 | }
|
340 | else {
|
341 | const compositeSortKeyType = 'Composite';
|
342 | const compositeSortKeyName = keySchema[1] ? this.resources.makeCompositeSortKeyName(String(keySchema[1].AttributeName)) : undefined;
|
343 | const sortKeyField = keySchema[1] ? relatedType.fields.find(f => f.name.value === keySchema[1].AttributeName) : undefined;
|
344 | if (sortKeyField) {
|
345 | sortKeyInfo = keySchema[1]
|
346 | ? {
|
347 | fieldName: String(keySchema[1].AttributeName),
|
348 | typeName: graphql_transformer_common_1.getBaseType(sortKeyField.type),
|
349 | model: relatedTypeName,
|
350 | keyName: index ? String(index.IndexName) : 'Primary',
|
351 | }
|
352 | : undefined;
|
353 | }
|
354 | else {
|
355 | sortKeyInfo = keySchema[1]
|
356 | ? {
|
357 | fieldName: compositeSortKeyName,
|
358 | typeName: compositeSortKeyType,
|
359 | model: relatedTypeName,
|
360 | keyName: index ? String(index.IndexName) : 'Primary',
|
361 | }
|
362 | : undefined;
|
363 | }
|
364 | }
|
365 | this.extendTypeWithConnection(ctx, parent, field, relatedType, sortKeyInfo);
|
366 | }
|
367 | };
|
368 | this.resources = new resources_1.ResourceFactory();
|
369 | }
|
370 | typeExist(type, ctx) {
|
371 | return Boolean(type in ctx.nodeMap);
|
372 | }
|
373 | generateModelXConnectionType(ctx, typeDef) {
|
374 | const tableXConnectionName = graphql_transformer_common_2.ModelResourceIDs.ModelConnectionTypeName(typeDef.name.value);
|
375 | if (this.typeExist(tableXConnectionName, ctx)) {
|
376 | return;
|
377 | }
|
378 | const connectionType = graphql_transformer_common_1.blankObject(tableXConnectionName);
|
379 | ctx.addObject(connectionType);
|
380 | ctx.addObjectExtension(graphql_dynamodb_transformer_1.makeModelConnectionType(typeDef.name.value));
|
381 | }
|
382 | generateFilterAndKeyConditionInputs(ctx, field, sortKeyInfo) {
|
383 | const scalarFilters = graphql_dynamodb_transformer_1.makeScalarFilterInputs(this.supportsConditions(ctx));
|
384 | for (const filter of scalarFilters) {
|
385 | if (!this.typeExist(filter.name.value, ctx)) {
|
386 | ctx.addInput(filter);
|
387 | }
|
388 | }
|
389 | const enumFilters = graphql_dynamodb_transformer_1.makeEnumFilterInputObjects(field, ctx, this.supportsConditions(ctx));
|
390 | for (const filter of enumFilters) {
|
391 | if (!this.typeExist(filter.name.value, ctx)) {
|
392 | ctx.addInput(filter);
|
393 | }
|
394 | }
|
395 | const tableXQueryFilterInput = graphql_dynamodb_transformer_1.makeModelXFilterInputObject(field, ctx, this.supportsConditions(ctx));
|
396 | if (!this.typeExist(tableXQueryFilterInput.name.value, ctx)) {
|
397 | ctx.addInput(tableXQueryFilterInput);
|
398 | }
|
399 | if (this.supportsConditions(ctx)) {
|
400 | const attributeTypeEnum = graphql_dynamodb_transformer_1.makeAttributeTypeEnum();
|
401 | if (!this.typeExist(attributeTypeEnum.name.value, ctx)) {
|
402 | ctx.addType(attributeTypeEnum);
|
403 | }
|
404 | }
|
405 | if (sortKeyInfo && sortKeyInfo.typeName !== 'Composite') {
|
406 | const sortKeyConditionInput = graphql_transformer_common_1.makeScalarKeyConditionForType(graphql_transformer_common_1.makeNamedType(sortKeyInfo.typeName));
|
407 | if (!this.typeExist(sortKeyConditionInput.name.value, ctx)) {
|
408 | ctx.addInput(sortKeyConditionInput);
|
409 | }
|
410 | }
|
411 | }
|
412 | supportsConditions(context) {
|
413 | return context.getTransformerVersion() >= graphql_dynamodb_transformer_1.CONDITIONS_MINIMUM_VERSION;
|
414 | }
|
415 | extendTypeWithConnection(ctx, parent, field, returnType, sortKeyInfo) {
|
416 | this.generateModelXConnectionType(ctx, returnType);
|
417 | const type = ctx.getType(parent.name.value);
|
418 | if (type && (type.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION || type.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION)) {
|
419 | const newFields = type.fields.map((f) => {
|
420 | if (f.name.value === field.name.value) {
|
421 | const updated = graphql_dynamodb_transformer_1.makeModelConnectionField(field.name.value, returnType.name.value, sortKeyInfo, [...f.directives]);
|
422 | return updated;
|
423 | }
|
424 | return f;
|
425 | });
|
426 | const updatedType = {
|
427 | ...type,
|
428 | fields: newFields,
|
429 | };
|
430 | ctx.putType(updatedType);
|
431 | if (!this.typeExist('ModelSortDirection', ctx)) {
|
432 | const modelSortDirection = graphql_dynamodb_transformer_1.makeModelSortDirectionEnumObject();
|
433 | ctx.addEnum(modelSortDirection);
|
434 | }
|
435 | this.generateFilterAndKeyConditionInputs(ctx, returnType, sortKeyInfo);
|
436 | }
|
437 | else {
|
438 | throw new graphql_transformer_core_1.InvalidDirectiveError(`Could not find a object or interface type named ${parent.name.value}.`);
|
439 | }
|
440 | }
|
441 | getPrimaryKeyField(ctx, type) {
|
442 | let field;
|
443 | for (const keyDirective of type.directives.filter(d => d.name.value === 'key')) {
|
444 | if (graphql_transformer_common_1.getDirectiveArgument(keyDirective, 'name') === undefined) {
|
445 | const fieldsArg = graphql_transformer_common_1.getDirectiveArgument(keyDirective, 'fields');
|
446 | if (fieldsArg && fieldsArg.length && fieldsArg.length >= 1 && fieldsArg.length <= 2) {
|
447 | field = type.fields.find(f => f.name.value === fieldsArg[0]);
|
448 | }
|
449 | break;
|
450 | }
|
451 | }
|
452 | return field;
|
453 | }
|
454 | getSortField(type) {
|
455 | let field;
|
456 | for (const keyDirective of type.directives.filter(d => d.name.value === 'key')) {
|
457 | if (graphql_transformer_common_1.getDirectiveArgument(keyDirective, 'name') === undefined) {
|
458 | const fieldsArg = graphql_transformer_common_1.getDirectiveArgument(keyDirective, 'fields');
|
459 | if (fieldsArg && fieldsArg.length && fieldsArg.length === 2) {
|
460 | field = type.fields.find(f => f.name.value === fieldsArg[1]);
|
461 | }
|
462 | break;
|
463 | }
|
464 | }
|
465 | return field;
|
466 | }
|
467 | }
|
468 | exports.ModelConnectionTransformer = ModelConnectionTransformer;
|
469 |
|
\ | No newline at end of file |