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