UNPKG

@aws-amplify/appsync-modelgen-plugin

Version:
906 lines 42.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AppSyncModelVisitor = exports.CodeGenPrimaryKeyType = exports.CodeGenGenerateEnum = void 0; const visitor_plugin_common_1 = require("@graphql-codegen/visitor-plugin-common"); const change_case_1 = require("change-case"); const pluralize_1 = require("pluralize"); const crypto_1 = __importDefault(require("crypto")); const graphql_1 = require("graphql"); const fieldUtils_1 = require("../utils/fieldUtils"); const get_type_info_1 = require("../utils/get-type-info"); const process_connections_1 = require("../utils/process-connections"); const sort_1 = require("../utils/sort"); const warn_1 = require("../utils/warn"); const process_auth_1 = require("../utils/process-auth"); const process_connections_v2_1 = require("../utils/process-connections-v2"); const graphql_transformer_common_1 = require("graphql-transformer-common"); const process_primary_key_1 = require("../utils/process-primary-key"); const process_index_1 = require("../utils/process-index"); const constants_1 = require("../utils/constants"); const process_has_many_1 = require("../utils/process-has-many"); var CodeGenGenerateEnum; (function (CodeGenGenerateEnum) { CodeGenGenerateEnum["metadata"] = "metadata"; CodeGenGenerateEnum["code"] = "code"; CodeGenGenerateEnum["loader"] = "loader"; })(CodeGenGenerateEnum = exports.CodeGenGenerateEnum || (exports.CodeGenGenerateEnum = {})); var CodeGenPrimaryKeyType; (function (CodeGenPrimaryKeyType) { CodeGenPrimaryKeyType["ManagedId"] = "ManagedId"; CodeGenPrimaryKeyType["OptionallyManagedId"] = "OptionallyManagedId"; CodeGenPrimaryKeyType["CustomId"] = "CustomId"; })(CodeGenPrimaryKeyType = exports.CodeGenPrimaryKeyType || (exports.CodeGenPrimaryKeyType = {})); class AppSyncModelVisitor extends visitor_plugin_common_1.BaseVisitor { constructor(_schema, rawConfig, additionalConfig, defaultScalars = visitor_plugin_common_1.DEFAULT_SCALARS) { super(rawConfig, { ...additionalConfig, scalars: (0, visitor_plugin_common_1.buildScalars)(_schema, rawConfig.scalars || '', defaultScalars), target: rawConfig.target, isDataStoreEnabled: rawConfig.isDataStoreEnabled, isTimestampFieldsAdded: rawConfig.isTimestampFieldsAdded, handleListNullabilityTransparently: rawConfig.handleListNullabilityTransparently, usePipelinedTransformer: rawConfig.usePipelinedTransformer, transformerVersion: rawConfig.transformerVersion, respectPrimaryKeyAttributesOnConnectionField: rawConfig.respectPrimaryKeyAttributesOnConnectionField, improvePluralization: rawConfig.improvePluralization, generateModelsForLazyLoadAndCustomSelectionSet: rawConfig.generateModelsForLazyLoadAndCustomSelectionSet, codegenVersion: rawConfig.codegenVersion, }); this._schema = _schema; this.READ_ONLY_FIELDS = ['id']; this.SCALAR_TYPE_MAP = {}; this.modelMap = {}; this.nonModelMap = {}; this.enumMap = {}; this.queryMap = {}; this.mutationMap = {}; this.subscriptionMap = {}; this.inputObjectMap = {}; this.unionMap = {}; this.interfaceMap = {}; this.typesToSkip = ['AMPLIFY']; const typesUsedInDirectives = []; if (rawConfig.directives) { const directiveSchema = (0, graphql_1.parse)(rawConfig.directives); directiveSchema.definitions.forEach((definition) => { if (definition.kind === graphql_1.Kind.ENUM_TYPE_DEFINITION || definition.kind === graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION) { typesUsedInDirectives.push(definition.name.value); } }); } this.typesToSkip.push(...typesUsedInDirectives); } ObjectTypeDefinition(node, index, parent) { var _a, _b, _c; if (this.typesToSkip.includes(node.name.value)) { return; } const directives = this.getDirectives(node.directives); const fields = node.fields; const modelDirective = directives.find(directive => directive.name === 'model'); if (modelDirective) { const model = { name: node.name.value, type: 'model', directives, fields, }; if (this.config.respectPrimaryKeyAttributesOnConnectionField || this.config.target === 'introspection') { this.ensurePrimaryKeyField(model, directives); } else { this.ensureIdField(model); } this.addTimestampFields(model, modelDirective); this.sortFields(model); this.modelMap[node.name.value] = model; } else if (node.name.value === ((_a = this._schema.getQueryType()) === null || _a === void 0 ? void 0 : _a.name)) { fields.forEach(field => { this.queryMap[field.name] = { ...field, operationType: 'query', }; }); } else if (node.name.value === ((_b = this._schema.getMutationType()) === null || _b === void 0 ? void 0 : _b.name)) { fields.forEach(field => { this.mutationMap[field.name] = { ...field, operationType: 'mutation', }; }); } else if (node.name.value === ((_c = this._schema.getSubscriptionType()) === null || _c === void 0 ? void 0 : _c.name)) { fields.forEach(field => { this.subscriptionMap[field.name] = { ...field, operationType: 'subscription', }; }); } else { const nonModel = { name: node.name.value, type: 'model', directives, fields, }; this.nonModelMap[node.name.value] = nonModel; } } FieldDefinition(node) { var _a; const directive = this.getDirectives(node.directives); const parameters = (_a = node.arguments) !== null && _a !== void 0 ? _a : []; return { name: node.name.value, directives: directive, ...(0, get_type_info_1.getTypeInfo)(node.type, this._schema), parameters, }; } InputObjectTypeDefinition(node) { if (this.typesToSkip.includes(node.name.value)) { return; } const inputValues = node.fields; const inputObject = { name: node.name.value, type: 'input', inputValues, }; this.inputObjectMap[node.name.value] = inputObject; } InputValueDefinition(node) { const directives = this.getDirectives(node.directives); return { name: node.name.value, directives, ...(0, get_type_info_1.getTypeInfo)(node.type, this._schema), }; } EnumTypeDefinition(node) { if (this.typesToSkip.includes(node.name.value)) { return; } const enumName = this.getEnumName(node.name.value); const values = node.values ? node.values.reduce((acc, val) => { acc[this.getEnumValue(val.name.value)] = val.name.value; return acc; }, {}) : {}; this.enumMap[node.name.value] = { name: enumName, type: 'enum', values, }; } UnionTypeDefinition(node) { var _a, _b; if (this.typesToSkip.includes(node.name.value)) { return; } const unionObject = { name: node.name.value, type: 'union', typeNames: (_b = (_a = node.types) === null || _a === void 0 ? void 0 : _a.map(type => type.name.value)) !== null && _b !== void 0 ? _b : [], }; this.unionMap[node.name.value] = unionObject; } InterfaceTypeDefinition(node) { if (this.typesToSkip.includes(node.name.value)) { return; } const fields = node.fields; const interfaceEntry = { name: node.name.value, type: 'interface', fields, }; this.interfaceMap[node.name.value] = interfaceEntry; } processDirectives(shouldUseModelNameFieldInHasManyAndBelongsTo, shouldImputeKeyForUniDirectionalHasMany, shouldUseFieldsInAssociatedWithInHasOne = false) { if (this.config.usePipelinedTransformer || this.config.transformerVersion === 2) { this.processV2KeyDirectives(); this.processConnectionDirectivesV2(shouldUseModelNameFieldInHasManyAndBelongsTo, shouldImputeKeyForUniDirectionalHasMany, shouldUseFieldsInAssociatedWithInHasOne); } else { this.processConnectionDirective(); } this.processAuthDirectives(); } generate() { const shouldUseModelNameFieldInHasManyAndBelongsTo = false; const shouldImputeKeyForUniDirectionalHasMany = false; this.processDirectives(shouldUseModelNameFieldInHasManyAndBelongsTo, shouldImputeKeyForUniDirectionalHasMany); return ''; } getDirectives(directives) { if (directives) { return directives.map(d => ({ name: d.name.value, arguments: this.getDirectiveArguments(d), })); } return []; } getDirectiveArguments(directive) { const directiveArguments = {}; if (directive.arguments) { directive.arguments.reduce((acc, arg) => { directiveArguments[arg.name.value] = (0, graphql_1.valueFromASTUntyped)(arg.value); if ((directive.name.value === 'hasOne' || directive.name.value === 'belongsTo' || directive.name.value === 'hasMany') && directiveArguments.references && !Array.isArray(directiveArguments.references)) { directiveArguments.references = [directiveArguments.references]; } return directiveArguments; }, directiveArguments); } return directiveArguments; } getSelectedModels() { if (this._parsedConfig.selectedType) { const selectedModel = this.modelMap[this._parsedConfig.selectedType]; return selectedModel ? { [this._parsedConfig.selectedType]: selectedModel } : {}; } return this.modelMap; } getSelectedNonModels() { if (this._parsedConfig.selectedType) { const selectedModel = this.nonModelMap[this._parsedConfig.selectedType]; return selectedModel ? { [this._parsedConfig.selectedType]: selectedModel } : {}; } return this.nonModelMap; } getSelectedEnums() { if (this._parsedConfig.selectedType) { const selectedModel = this.enumMap[this._parsedConfig.selectedType]; return selectedModel ? { [this._parsedConfig.selectedType]: selectedModel } : {}; } return this.enumMap; } selectedTypeIsEnum() { if (this._parsedConfig && this._parsedConfig.selectedType) { if (this._parsedConfig.selectedType in this.enumMap) { return true; } } return false; } selectedTypeIsNonModel() { if (this._parsedConfig && this._parsedConfig.selectedType) { if (this._parsedConfig.selectedType in this.nonModelMap) { return true; } } return false; } getNativeType(field, options) { const typeName = field.type; let typeNameStr = ''; if (typeName in this.scalars) { typeNameStr = this.scalars[typeName]; } else if (this.isModelType(field)) { typeNameStr = this.getModelName(this.modelMap[typeName]); } else if (this.isEnumType(field)) { typeNameStr = this.getEnumName(this.enumMap[typeName]); } else if (this.isNonModelType(field)) { typeNameStr = this.getNonModelName(this.nonModelMap[typeName]); } else { throw new Error(`Unknown type ${typeName} for field ${field.name}. Did you forget to add the @model directive`); } return field.isList ? this.getListType(typeNameStr, field) : typeNameStr; } getListType(typeStr, field) { return `List<${typeStr}>`; } getFieldName(field) { return field.name; } getEnumName(enumField) { if (typeof enumField === 'string') { return enumField; } return enumField.name; } getModelName(model) { return model.name; } getNonModelName(model) { return model.name; } getEnumValue(value) { return (0, change_case_1.constantCase)(value); } getModelPrimaryKeyField(model) { return model.fields.find(field => field.primaryKeyInfo); } isEnumType(field) { const typeName = field.type; return typeName in this.enumMap; } isModelType(field) { const typeName = field.type; return typeName in this.modelMap; } isNonModelType(field) { const typeName = field.type; return typeName in this.nonModelMap; } computeVersion() { const typeArr = []; Object.values({ ...this.modelMap, ...this.nonModelMap }).forEach((obj) => { const directives = this.config.usePipelinedTransformer || this.config.transformerVersion === 2 ? obj.directives.filter(dir => dir.name === 'primaryKey' || dir.name === 'index') : obj.directives.filter(dir => dir.name === 'key'); const fields = obj.fields .map((field) => { const fieldDirectives = this.config.usePipelinedTransformer ? field.directives.filter(field => field.name === 'hasOne' || field.name === 'belongsTo' || field.name === 'hasMany' || field.name === 'manyToMany') : field.directives.filter(field => field.name === 'connection'); return { name: field.name, directives: fieldDirectives, type: field.type, isNullable: field.isNullable, isList: field.isList, isListNullable: field.isListNullable, }; }) .sort((a, b) => (0, sort_1.sortFields)(a, b)); typeArr.push({ name: obj.name, directives, fields, }); }); typeArr.sort(sort_1.sortFields); return crypto_1.default .createHash('MD5') .update(JSON.stringify(typeArr)) .digest() .toString('hex'); } sortFields(model) { model.fields = model.fields.reduce((acc, field) => { if (field.name === 'id') { acc.unshift(field); } else { acc.push(field); } return acc; }, []); } ensurePrimaryKeyField(model, directives) { if (this.config.usePipelinedTransformer || this.config.transformerVersion === 2) { this.ensurePrimaryKeyFieldV2(model, directives); } else { this.ensurePrimaryKeyFieldV1(model, directives); } } ensurePrimaryKeyFieldV2(model, directives) { var _a; let primaryKeyFieldName; let primaryKeyField; const fieldWithPrimaryKeyDirective = model.fields.find(f => f.directives.find(dir => dir.name === 'primaryKey')); if (!fieldWithPrimaryKeyDirective) { primaryKeyFieldName = constants_1.DEFAULT_HASH_KEY_FIELD; this.ensureIdField(model); primaryKeyField = this.getPrimaryKeyFieldByName(model, primaryKeyFieldName); primaryKeyField.primaryKeyInfo = { primaryKeyType: CodeGenPrimaryKeyType.ManagedId, sortKeyFields: [], }; } else { primaryKeyFieldName = fieldWithPrimaryKeyDirective.name; primaryKeyField = this.getPrimaryKeyFieldByName(model, primaryKeyFieldName); const sortKeyFieldNames = (_a = (0, process_connections_1.flattenFieldDirectives)(model).find(d => d.name === 'primaryKey')) === null || _a === void 0 ? void 0 : _a.arguments.sortKeyFields; const sortKeyFields = (sortKeyFieldNames === null || sortKeyFieldNames === void 0 ? void 0 : sortKeyFieldNames.length) > 0 ? sortKeyFieldNames.map(fieldName => model.fields.find(f => f.name === fieldName)) : []; primaryKeyField.primaryKeyInfo = { primaryKeyType: primaryKeyFieldName === constants_1.DEFAULT_HASH_KEY_FIELD && sortKeyFields.length === 0 ? CodeGenPrimaryKeyType.OptionallyManagedId : CodeGenPrimaryKeyType.CustomId, sortKeyFields, }; } } ensurePrimaryKeyFieldV1(model, directives) { let primaryKeyFieldName; let primaryKeyField; const keyDirective = directives.find(d => d.name === 'key' && !d.arguments.name); if (keyDirective) { primaryKeyFieldName = keyDirective.arguments.fields[0]; primaryKeyField = this.getPrimaryKeyFieldByName(model, primaryKeyFieldName); const sortKeyFieldNames = keyDirective.arguments.fields.slice(1); const sortKeyFields = (sortKeyFieldNames === null || sortKeyFieldNames === void 0 ? void 0 : sortKeyFieldNames.length) > 0 ? sortKeyFieldNames.map(fieldName => model.fields.find(f => f.name === fieldName)) : []; primaryKeyField.primaryKeyInfo = { primaryKeyType: primaryKeyFieldName === constants_1.DEFAULT_HASH_KEY_FIELD && sortKeyFields.length === 0 ? CodeGenPrimaryKeyType.OptionallyManagedId : CodeGenPrimaryKeyType.CustomId, sortKeyFields, }; } else { primaryKeyFieldName = constants_1.DEFAULT_HASH_KEY_FIELD; this.ensureIdField(model); primaryKeyField = this.getPrimaryKeyFieldByName(model, primaryKeyFieldName); primaryKeyField.primaryKeyInfo = { primaryKeyType: CodeGenPrimaryKeyType.ManagedId, sortKeyFields: [], }; } } getPrimaryKeyFieldByName(model, primaryKeyFieldName) { const primaryKeyField = model.fields.find(f => f.name === primaryKeyFieldName); if (!primaryKeyField) { throw new Error(`Cannot find primary key field in type ${model.name}`); } if (primaryKeyField.isNullable) { throw new Error(`The primary key on type '${model.name}' must reference non-null fields.`); } return primaryKeyField; } ensureIdField(model) { const idField = model.fields.find(field => field.name === constants_1.DEFAULT_HASH_KEY_FIELD); if (idField) { idField.isNullable = false; } else { model.fields.splice(0, 0, { name: 'id', type: 'ID', isNullable: false, isList: false, directives: [], }); } } processConnectionDirective() { Object.values(this.modelMap).forEach(model => { model.fields.forEach(field => { var _a, _b; const connectionInfo = (0, process_connections_1.processConnections)(field, model, this.modelMap, !!this.config.isDataStoreEnabled); if (connectionInfo) { if (connectionInfo.kind === process_connections_1.CodeGenConnectionType.HAS_MANY || connectionInfo.kind === process_connections_1.CodeGenConnectionType.HAS_ONE) { (0, fieldUtils_1.addFieldToModel)(connectionInfo.connectedModel, connectionInfo.associatedWith); } else if (connectionInfo.targetName && ((_b = connectionInfo.targetName !== ((_a = this.getModelPrimaryKeyField(model)) === null || _a === void 0 ? void 0 : _a.name)) !== null && _b !== void 0 ? _b : 'id')) { (0, fieldUtils_1.removeFieldFromModel)(model, connectionInfo.targetName); } field.connectionInfo = connectionInfo; } }); const modelTypes = Object.values(this.modelMap).map(model => model.name); model.fields = model.fields.filter(field => { const fieldType = field.type; const connectionInfo = field.connectionInfo; if (modelTypes.includes(fieldType) && connectionInfo === undefined) { (0, warn_1.printWarning)(`Model ${model.name} has field ${field.name} of type ${field.type} but its not connected. Add a @connection directive if want to connect them.`); return false; } return true; }); }); } generateIntermediateModel(firstModel, secondModel, relationName) { const firstModelKeyFieldName = this.generateIntermediateModelPrimaryKeyFieldName(firstModel); const firstModelSortKeyFields = this.getSortKeyFields(firstModel); const secondModelKeyFieldName = this.generateIntermediateModelPrimaryKeyFieldName(secondModel); const secondModelSortKeyFields = this.getSortKeyFields(secondModel); let intermediateModel = { name: relationName, type: 'model', directives: [{ name: 'model', arguments: {} }], fields: [ { type: 'ID', isNullable: false, isList: false, name: 'id', directives: [], }, { type: 'ID', isNullable: true, isList: false, name: firstModelKeyFieldName, directives: [ { name: 'index', arguments: { name: 'by' + firstModel.name, sortKeyFields: firstModelSortKeyFields.map(f => this.generateIntermediateModelSortKeyFieldName(firstModel, f)), }, }, ], }, ...firstModelSortKeyFields.map(field => { return { type: field.type, isNullable: true, isList: field.isList, name: this.generateIntermediateModelSortKeyFieldName(firstModel, field), directives: [], }; }), { type: 'ID', isNullable: true, isList: false, name: secondModelKeyFieldName, directives: [ { name: 'index', arguments: { name: 'by' + secondModel.name, sortKeyFields: secondModelSortKeyFields.map(f => this.generateIntermediateModelSortKeyFieldName(secondModel, f)), }, }, ], }, ...secondModelSortKeyFields.map(field => { return { type: field.type, isNullable: true, isList: field.isList, name: this.generateIntermediateModelSortKeyFieldName(secondModel, field), directives: [], }; }), { type: firstModel.name, isNullable: false, isList: false, name: (0, change_case_1.camelCase)(firstModel.name), directives: [ { name: 'belongsTo', arguments: { fields: [ firstModelKeyFieldName, ...firstModelSortKeyFields.map(f => this.generateIntermediateModelSortKeyFieldName(firstModel, f)), ], }, }, ], }, { type: secondModel.name, isNullable: false, isList: false, name: (0, change_case_1.camelCase)(secondModel.name), directives: [ { name: 'belongsTo', arguments: { fields: [ secondModelKeyFieldName, ...secondModelSortKeyFields.map(f => this.generateIntermediateModelSortKeyFieldName(secondModel, f)), ], }, }, ], }, ], }; return intermediateModel; } generateIntermediateModelPrimaryKeyFieldName(model) { if (this.isCustomPKEnabled()) { const primaryKeyField = model.fields.find(f => f.primaryKeyInfo); return (0, fieldUtils_1.toCamelCase)([model.name, primaryKeyField.name]); } return `${(0, change_case_1.camelCase)(model.name)}ID`; } generateIntermediateModelSortKeyFieldName(model, sortKeyField) { const modelName = model.name.charAt(0).toLocaleLowerCase() + model.name.slice(1); return `${modelName}${sortKeyField.name}`; } getSortKeyFields(model) { const keyDirective = model.directives.find(d => d.name === 'key' && !d.arguments.name); return keyDirective ? keyDirective.arguments.fields.slice(1).map(fieldName => model.fields.find(f => f.name === fieldName)) : []; } determinePrimaryKeyFieldname(model) { let primaryKeyFieldName = 'id'; model.fields.forEach(field => { field.directives.forEach(dir => { if (dir.name === 'primaryKey') { primaryKeyFieldName = field.name; } }); }); return primaryKeyFieldName; } convertManyToManyDirectives(contexts) { contexts.forEach(context => { let directiveIndex = context.field.directives.indexOf(context.directive, 0); if (directiveIndex > -1) { context.field.directives.splice(directiveIndex, 1); context.field.type = (0, graphql_transformer_common_1.graphqlName)((0, graphql_transformer_common_1.toUpper)(context.directive.arguments.relationName)); context.field.directives.push({ name: 'hasMany', arguments: { indexName: `by${context.model.name}`, fields: [ this.determinePrimaryKeyFieldname(context.model), ...this.getSortKeyFields(context.model).map(f => this.getFieldName(f)), ], }, }); } else { throw new Error('manyToMany directive not found on manyToMany field...'); } }); } processManyToManyDirectives() { let manyDirectiveMap = new Map(); Object.values(this.modelMap).forEach(model => { model.fields.forEach(field => { field.directives.forEach(dir => { if (dir.name === 'manyToMany') { let relationName = (0, graphql_transformer_common_1.graphqlName)((0, graphql_transformer_common_1.toUpper)(dir.arguments.relationName)); let existingRelation = manyDirectiveMap.get(relationName); if (existingRelation) { existingRelation.push({ model: model, field: field, directive: dir }); } else { manyDirectiveMap.set(relationName, [{ model: model, field: field, directive: dir }]); } } }); }); }); manyDirectiveMap.forEach((value, key) => { if (value.length != 2) { throw new Error(`Error for relation: '${value[0].directive.arguments.relationName}', there should be two matching manyToMany directives and found: ${value.length}`); } let intermediateModel = this.generateIntermediateModel(value[0].model, value[1].model, (0, graphql_transformer_common_1.graphqlName)((0, graphql_transformer_common_1.toUpper)(value[0].directive.arguments.relationName))); const extractedAuthDirectives = [...value[0].model.directives, ...value[1].model.directives] .filter(directive => directive.name === 'auth'); const serializedDirectives = extractedAuthDirectives.map(directive => JSON.stringify(directive)); const uniqueSerializedDirectives = serializedDirectives.filter((serializedDirective, index, array) => array.indexOf(serializedDirective) === index); const authDirectives = uniqueSerializedDirectives.map(serializedDirective => JSON.parse(serializedDirective)); intermediateModel.directives = [...intermediateModel.directives, ...authDirectives]; const modelDirective = intermediateModel.directives.find(directive => directive.name === 'model'); if (modelDirective) { (0, process_primary_key_1.processPrimaryKey)(intermediateModel); (0, process_index_1.processIndex)(intermediateModel); this.ensurePrimaryKeyField(intermediateModel, intermediateModel.directives); this.addTimestampFields(intermediateModel, modelDirective); this.sortFields(intermediateModel); } this.modelMap[intermediateModel.name] = intermediateModel; this.convertManyToManyDirectives(value); }); } processConnectionDirectivesV2(shouldUseModelNameFieldInHasManyAndBelongsTo, shouldImputeKeyForUniDirectionalHasMany, shouldUseFieldsInAssociatedWithInHasOne) { var _a; this.processManyToManyDirectives(); const isCustomPKEnabled = this.isCustomPKEnabled(); Object.values(this.modelMap).forEach(model => { model.fields.forEach(field => { const connectionInfo = (0, process_connections_v2_1.processConnectionsV2)(field, model, this.modelMap, shouldUseModelNameFieldInHasManyAndBelongsTo, isCustomPKEnabled, shouldUseFieldsInAssociatedWithInHasOne); if (connectionInfo) { if (connectionInfo.kind === process_connections_1.CodeGenConnectionType.HAS_MANY) { if (isCustomPKEnabled) { connectionInfo.associatedWithFields.forEach(associateField => (0, fieldUtils_1.addFieldToModel)(connectionInfo.connectedModel, associateField)); } else { (0, fieldUtils_1.addFieldToModel)(connectionInfo.connectedModel, connectionInfo.associatedWith); } if (shouldImputeKeyForUniDirectionalHasMany && (0, process_has_many_1.hasManyHasImplicitKey)(field, model, connectionInfo)) { (0, process_has_many_1.addHasManyKey)(field, model, connectionInfo); } } else if (connectionInfo.kind === process_connections_1.CodeGenConnectionType.HAS_ONE) { if (isCustomPKEnabled) { const connectedModelFields = (0, fieldUtils_1.getModelPrimaryKeyComponentFields)(connectionInfo.connectedModel); if ((connectedModelFields === null || connectedModelFields === void 0 ? void 0 : connectedModelFields.length) > 0 && connectionInfo.targetNames) { connectionInfo.targetNames.forEach((target, index) => { (0, fieldUtils_1.addFieldToModel)(model, { name: target, directives: [], type: connectedModelFields[index].type, isList: false, isNullable: field.isNullable, }); }); } } else if (connectionInfo.targetName) { (0, fieldUtils_1.addFieldToModel)(model, { name: connectionInfo.targetName, directives: [], type: 'ID', isList: false, isNullable: field.isNullable, }); } } else if (connectionInfo.kind === process_connections_1.CodeGenConnectionType.BELONGS_TO) { if (isCustomPKEnabled) { const connectedModelFields = (0, fieldUtils_1.getModelPrimaryKeyComponentFields)(connectionInfo.connectedModel); if ((connectedModelFields === null || connectedModelFields === void 0 ? void 0 : connectedModelFields.length) > 0) { connectionInfo.targetNames.forEach((target, index) => { (0, fieldUtils_1.addFieldToModel)(model, { name: target, directives: [], type: connectedModelFields[index].type, isList: false, isNullable: field.isNullable, }); }); } } else { (0, fieldUtils_1.addFieldToModel)(model, { name: connectionInfo.targetName, directives: [], type: 'ID', isList: false, isNullable: field.isNullable, }); } } field.connectionInfo = connectionInfo; } }); const modelTypes = Object.values(this.modelMap).map(model => model.name); model.fields = model.fields.filter(field => { const fieldType = field.type; const connectionInfo = field.connectionInfo; if (modelTypes.includes(fieldType) && connectionInfo === undefined) { (0, warn_1.printWarning)(`Model ${model.name} has field ${field.name} of type ${field.type} but its not connected. Add the appropriate ${field.isList ? '@hasMany' : '@hasOne'}/@belongsTo directive if you want to connect them.`); return false; } return true; }); }); if (isCustomPKEnabled) { if (['java', 'swift', 'dart'].includes((_a = this.config.target) !== null && _a !== void 0 ? _a : '')) { Object.values(this.modelMap).forEach(model => { model.fields.forEach(field => { const connectionInfo = field.connectionInfo; if (connectionInfo && connectionInfo.kind !== process_connections_1.CodeGenConnectionType.HAS_MANY && connectionInfo.kind !== process_connections_1.CodeGenConnectionType.HAS_ONE && connectionInfo.targetNames && connectionInfo.targetName !== 'id') { const primaryKeyFieldNames = (0, fieldUtils_1.getModelPrimaryKeyComponentFields)(model).map(field => field.name); connectionInfo.targetNames .filter(targetName => !primaryKeyFieldNames.includes(targetName)) .forEach(targetName => (0, fieldUtils_1.removeFieldFromModel)(model, targetName)); } }); }); } } else { Object.values(this.modelMap).forEach(model => { const primaryKeyFields = (0, fieldUtils_1.getModelPrimaryKeyComponentFields)(model); const primaryKeyName = ((primaryKeyFields === null || primaryKeyFields === void 0 ? void 0 : primaryKeyFields.length) > 0) ? this.getFieldName(primaryKeyFields[0]) : undefined; model.fields.forEach(field => { const connectionInfo = field.connectionInfo; if (connectionInfo && connectionInfo.kind !== process_connections_1.CodeGenConnectionType.HAS_MANY && connectionInfo.kind !== process_connections_1.CodeGenConnectionType.HAS_ONE && connectionInfo.targetName && connectionInfo.targetName !== 'id' && !connectionInfo.isUsingReferences && !(this.config.target === 'introspection' && primaryKeyName && primaryKeyName === connectionInfo.targetName)) { (0, fieldUtils_1.removeFieldFromModel)(model, connectionInfo.targetName); } }); }); } } processV2KeyDirectives() { Object.values(this.modelMap).forEach(model => { (0, process_primary_key_1.processPrimaryKey)(model); (0, process_index_1.processIndex)(model); }); } processAuthDirectives() { Object.values(this.modelMap).forEach(model => { const filteredDirectives = model.directives.filter(d => d.name !== 'auth'); const authDirectives = (0, process_auth_1.processAuthDirective)(model.directives); model.directives = [...filteredDirectives, ...authDirectives]; model.fields.forEach(field => { const nonAuthDirectives = field.directives.filter(d => d.name != 'auth'); const authDirectives = (0, process_auth_1.processAuthDirective)(field.directives); field.directives = [...nonAuthDirectives, ...authDirectives]; }); }); } pluralizeModelName(model) { return (0, pluralize_1.plural)(model.name); } addTimestampFields(model, directive) { if (!this.config.isTimestampFieldsAdded) { return; } if (directive.name !== 'model') { return; } if (directive.arguments && directive.arguments.hasOwnProperty('timestamps') && directive.arguments.timestamps === null) { return; } const timestamps = directive.arguments.timestamps; const createdAtField = { name: (timestamps === null || timestamps === void 0 ? void 0 : timestamps.createdAt) || constants_1.DEFAULT_CREATED_TIME, directives: [], type: 'AWSDateTime', isList: false, isNullable: true, isReadOnly: true, }; const updatedAtField = { name: (timestamps === null || timestamps === void 0 ? void 0 : timestamps.updatedAt) || constants_1.DEFAULT_UPDATED_TIME, directives: [], type: 'AWSDateTime', isList: false, isNullable: true, isReadOnly: true, }; (0, fieldUtils_1.addFieldToModel)(model, createdAtField); (0, fieldUtils_1.addFieldToModel)(model, updatedAtField); } isRequiredField(field) { return !(this.config.handleListNullabilityTransparently ? (field.isList ? field.isListNullable : field.isNullable) : field.isNullable); } isCustomPKEnabled() { var _a; return ((this.config.usePipelinedTransformer || this.config.transformerVersion === 2) && ((_a = this.config.respectPrimaryKeyAttributesOnConnectionField) !== null && _a !== void 0 ? _a : false)); } isGenerateModelsForLazyLoadAndCustomSelectionSet() { var _a; return (_a = this.config.generateModelsForLazyLoadAndCustomSelectionSet) !== null && _a !== void 0 ? _a : false; } get models() { return this.modelMap; } get enums() { return this.enumMap; } get nonModels() { return this.nonModelMap; } get queries() { return this.queryMap; } get mutations() { return this.mutationMap; } get subscriptions() { return this.subscriptionMap; } get inputs() { return this.inputObjectMap; } get unions() { return this.unionMap; } get interfaces() { return this.interfaceMap; } } exports.AppSyncModelVisitor = AppSyncModelVisitor; //# sourceMappingURL=appsync-visitor.js.map