UNPKG

@aws-amplify/graphql-schema-generator

Version:
255 lines 16 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.findMatchingField = exports.checkDestructiveNullabilityChange = exports.getParentNode = exports.applyFieldNameOverrides = exports.applyModelAuthOverrides = exports.applyModelNameOverrides = exports.applyJSONFieldTypeOverrides = exports.applyModelOverrides = exports.applyFieldOverrides = exports.applySchemaOverrides = void 0; const graphql_1 = require("graphql"); const graphql_transformer_common_1 = require("graphql-transformer-common"); const graphql_transformer_core_1 = require("@aws-amplify/graphql-transformer-core"); const MODEL_DIRECTIVE_NAME = 'model'; const REFERS_TO_DIRECTIVE_NAME = 'refersTo'; const RELATIONAL_DIRECTIVES = ['hasOne', 'hasMany', 'belongsTo']; const AUTH_DIRECTIVE_NAME = 'auth'; const applySchemaOverrides = (document, existingDocument) => { if (!existingDocument) { return document; } let updatedDocument = preserveRelationalDirectives(document, existingDocument); const schemaVisitor = { FieldDefinition: { leave: (node, key, parent, path, ancestors) => { const parentObjectType = (0, exports.getParentNode)(ancestors); if (!parentObjectType || !(parentObjectType === null || parentObjectType === void 0 ? void 0 : parentObjectType.name)) { return; } const columnName = getMappedName(node); const tableName = getMappedName(parentObjectType); checkDuplicateFieldMapping(columnName, tableName, existingDocument); const correspondingField = (0, exports.findMatchingField)(columnName, tableName, existingDocument); if (!correspondingField) return; return (0, exports.applyFieldOverrides)(node, correspondingField); }, }, ObjectTypeDefinition: { leave: (node, key, parent, path, ancestors) => { const tableName = getMappedName(node); checkDuplicateModelMapping(tableName, existingDocument); const correspondingModel = findMatchingModel(tableName, existingDocument); if (!correspondingModel) return; return (0, exports.applyModelOverrides)(node, correspondingModel); }, }, }; updatedDocument = (0, graphql_1.visit)(updatedDocument, schemaVisitor); updatedDocument['definitions'] = [ ...updatedDocument['definitions'], ...(0, graphql_transformer_common_1.getNonModelTypes)(existingDocument), ...getCustomEnumTypes(document, existingDocument), ]; return updatedDocument; }; exports.applySchemaOverrides = applySchemaOverrides; const preserveRelationalDirectives = (document, existingDocument) => { const documentWrapper = document; existingDocument.definitions .filter((def) => def.kind === 'ObjectTypeDefinition' && def.directives.find((dir) => dir.name.value === MODEL_DIRECTIVE_NAME)) .forEach((existingObject) => { const existingTableName = getMappedName(existingObject); const newObject = findMatchingModel(existingTableName, document); if (!newObject) { return; } const relationalFields = existingObject.fields.filter((field) => field.directives.find((dir) => RELATIONAL_DIRECTIVES.includes(dir.name.value))); const newObjectWrapper = new graphql_transformer_core_1.ObjectDefinitionWrapper(newObject); relationalFields.forEach((relationalField) => { newObjectWrapper.fields.push(new graphql_transformer_core_1.FieldWrapper(relationalField)); }); if (relationalFields.length > 0) { const excludedDefinitions = documentWrapper.definitions.filter((def) => getMappedName(def) !== existingTableName); documentWrapper.definitions = [...excludedDefinitions, newObjectWrapper.serialize()]; } }); return documentWrapper; }; const applyFieldOverrides = (field, existingField) => { return { ...field, ...(0, exports.applyJSONFieldTypeOverrides)(field, existingField), ...(0, exports.applyFieldNameOverrides)(field, existingField), }; }; exports.applyFieldOverrides = applyFieldOverrides; const applyModelOverrides = (obj, existingObj) => { let updatedModel = { ...obj }; updatedModel = (0, exports.applyModelNameOverrides)(obj, existingObj); updatedModel = (0, exports.applyModelAuthOverrides)(updatedModel, existingObj); return updatedModel; }; exports.applyModelOverrides = applyModelOverrides; const applyJSONFieldTypeOverrides = (field, existingField) => { const isJSONType = (0, graphql_transformer_common_1.isOfType)(field === null || field === void 0 ? void 0 : field.type, 'AWSJSON'); if (!isJSONType) { return field; } const isExistingFieldArrayOrObject = (0, graphql_transformer_common_1.isArrayOrObject)(existingField === null || existingField === void 0 ? void 0 : existingField.type, []); if (!isExistingFieldArrayOrObject) { return field; } (0, exports.checkDestructiveNullabilityChange)(field, existingField); return { type: existingField === null || existingField === void 0 ? void 0 : existingField.type, }; }; exports.applyJSONFieldTypeOverrides = applyJSONFieldTypeOverrides; const applyModelNameOverrides = (obj, existingObj) => { var _a, _b, _c, _d; const tableName = getMappedName(obj); const existingTableName = getMappedName(existingObj); const existingTypeName = (_a = existingObj === null || existingObj === void 0 ? void 0 : existingObj.name) === null || _a === void 0 ? void 0 : _a.value; if (tableName !== existingTableName && tableName !== existingTypeName) { return obj; } if (tableName === existingTypeName) { return { ...obj, ...{ name: existingObj === null || existingObj === void 0 ? void 0 : existingObj.name }, ...{ directives: (_b = obj === null || obj === void 0 ? void 0 : obj.directives) === null || _b === void 0 ? void 0 : _b.filter((dir) => dir.name.value !== REFERS_TO_DIRECTIVE_NAME) }, }; } return { ...obj, ...{ name: existingObj === null || existingObj === void 0 ? void 0 : existingObj.name }, ...{ directives: [ ...(_c = existingObj === null || existingObj === void 0 ? void 0 : existingObj.directives) === null || _c === void 0 ? void 0 : _c.filter((dir) => dir.name.value === REFERS_TO_DIRECTIVE_NAME), ...(_d = obj === null || obj === void 0 ? void 0 : obj.directives) === null || _d === void 0 ? void 0 : _d.filter((dir) => dir.name.value !== REFERS_TO_DIRECTIVE_NAME), ], }, }; }; exports.applyModelNameOverrides = applyModelNameOverrides; const applyModelAuthOverrides = (obj, existingObj) => { var _a, _b, _c; const authDirectiveExists = (_a = existingObj === null || existingObj === void 0 ? void 0 : existingObj.directives) === null || _a === void 0 ? void 0 : _a.find((dir) => { var _a; return ((_a = dir === null || dir === void 0 ? void 0 : dir.name) === null || _a === void 0 ? void 0 : _a.value) === AUTH_DIRECTIVE_NAME; }); if (!authDirectiveExists) { return obj; } return { ...obj, ...{ directives: [ ...(_b = obj === null || obj === void 0 ? void 0 : obj.directives) === null || _b === void 0 ? void 0 : _b.filter((dir) => dir.name.value !== AUTH_DIRECTIVE_NAME), ...(_c = existingObj === null || existingObj === void 0 ? void 0 : existingObj.directives) === null || _c === void 0 ? void 0 : _c.filter((dir) => dir.name.value === AUTH_DIRECTIVE_NAME), ], }, }; }; exports.applyModelAuthOverrides = applyModelAuthOverrides; const applyFieldNameOverrides = (field, existingField) => { var _a, _b, _c, _d, _e, _f; const columnName = getMappedName(field); const existingColumnName = getMappedName(existingField); const existingFieldName = (_a = existingField === null || existingField === void 0 ? void 0 : existingField.name) === null || _a === void 0 ? void 0 : _a.value; if (columnName !== existingColumnName && columnName !== existingFieldName) { return field; } const existingFieldIsRelational = (_b = existingField === null || existingField === void 0 ? void 0 : existingField.directives) === null || _b === void 0 ? void 0 : _b.find((dir) => { var _a; return RELATIONAL_DIRECTIVES.includes((_a = dir === null || dir === void 0 ? void 0 : dir.name) === null || _a === void 0 ? void 0 : _a.value); }); const existingFieldHasRefersTo = (_c = existingField === null || existingField === void 0 ? void 0 : existingField.directives) === null || _c === void 0 ? void 0 : _c.find((dir) => { var _a; return ((_a = dir === null || dir === void 0 ? void 0 : dir.name) === null || _a === void 0 ? void 0 : _a.value) === REFERS_TO_DIRECTIVE_NAME; }); if (existingFieldIsRelational && existingFieldHasRefersTo) { throw new Error(`Field "${existingFieldName}" cannot be renamed because it is a relational field.`); } if (columnName === existingFieldName) { return { ...{ name: existingField === null || existingField === void 0 ? void 0 : existingField.name }, ...{ directives: (_d = field === null || field === void 0 ? void 0 : field.directives) === null || _d === void 0 ? void 0 : _d.filter((dir) => dir.name.value !== REFERS_TO_DIRECTIVE_NAME) }, }; } return { ...{ name: existingField === null || existingField === void 0 ? void 0 : existingField.name }, ...{ directives: [ ...(_e = existingField === null || existingField === void 0 ? void 0 : existingField.directives) === null || _e === void 0 ? void 0 : _e.filter((dir) => dir.name.value === REFERS_TO_DIRECTIVE_NAME), ...(_f = field === null || field === void 0 ? void 0 : field.directives) === null || _f === void 0 ? void 0 : _f.filter((dir) => dir.name.value !== REFERS_TO_DIRECTIVE_NAME), ], }, }; }; exports.applyFieldNameOverrides = applyFieldNameOverrides; const getParentNode = (ancestors) => { if (ancestors && (ancestors === null || ancestors === void 0 ? void 0 : ancestors.length) > 0) { return ancestors[ancestors.length - 1]; } }; exports.getParentNode = getParentNode; const checkDestructiveNullabilityChange = (field, existingField) => { var _a; const isFieldRequired = (0, graphql_transformer_common_1.isNonNullType)(field === null || field === void 0 ? void 0 : field.type); const isExistingFieldRequired = (0, graphql_transformer_common_1.isNonNullType)(existingField === null || existingField === void 0 ? void 0 : existingField.type); if (isFieldRequired && !isExistingFieldRequired) { console.warn(`The field ${(_a = field === null || field === void 0 ? void 0 : field.name) === null || _a === void 0 ? void 0 : _a.value} has been changed to an optional type while it is required in the database. This may result in SQL errors in the mutations.`); } }; exports.checkDestructiveNullabilityChange = checkDestructiveNullabilityChange; const getMappedName = (node) => { var _a, _b, _c; const nodeName = (_a = node === null || node === void 0 ? void 0 : node.name) === null || _a === void 0 ? void 0 : _a.value; const refersToDirective = node.directives.find((dir) => dir.name.value === REFERS_TO_DIRECTIVE_NAME); if (!refersToDirective) { return nodeName; } const mappedName = (_b = refersToDirective === null || refersToDirective === void 0 ? void 0 : refersToDirective.arguments) === null || _b === void 0 ? void 0 : _b.find((arg) => { var _a; return ((_a = arg === null || arg === void 0 ? void 0 : arg.name) === null || _a === void 0 ? void 0 : _a.value) === 'name'; }); if (!mappedName) { return nodeName; } return (_c = mappedName === null || mappedName === void 0 ? void 0 : mappedName.value) === null || _c === void 0 ? void 0 : _c.value; }; const findMatchingModel = (tableName, existingDocument) => { const matchedModel = existingDocument.definitions.find((def) => { var _a, _b; return (def === null || def === void 0 ? void 0 : def.kind) === 'ObjectTypeDefinition' && ((_a = def === null || def === void 0 ? void 0 : def.directives) === null || _a === void 0 ? void 0 : _a.find((dir) => { var _a; return ((_a = dir === null || dir === void 0 ? void 0 : dir.name) === null || _a === void 0 ? void 0 : _a.value) === MODEL_DIRECTIVE_NAME; })) && (((_b = def === null || def === void 0 ? void 0 : def.name) === null || _b === void 0 ? void 0 : _b.value) === tableName || getMappedName(def) === tableName); }); if (matchedModel) { return matchedModel; } }; const findMatchingField = (columnName, taleName, document) => { var _a; const matchingObject = findMatchingModel(taleName, document); if (!matchingObject) { return; } return (_a = matchingObject === null || matchingObject === void 0 ? void 0 : matchingObject.fields) === null || _a === void 0 ? void 0 : _a.find((field) => { var _a; return ((_a = field === null || field === void 0 ? void 0 : field.name) === null || _a === void 0 ? void 0 : _a.value) === columnName || getMappedName(field) === columnName; }); }; exports.findMatchingField = findMatchingField; const checkDuplicateModelMapping = (tableName, document) => { const matchedTypes = document.definitions.filter((def) => { var _a; return (def === null || def === void 0 ? void 0 : def.kind) === 'ObjectTypeDefinition' && (((_a = def === null || def === void 0 ? void 0 : def.name) === null || _a === void 0 ? void 0 : _a.value) === tableName || getMappedName(def) === tableName); }); if ((matchedTypes === null || matchedTypes === void 0 ? void 0 : matchedTypes.length) > 1) { throw new Error(`Types ${matchedTypes .map((type) => { var _a; return (_a = type === null || type === void 0 ? void 0 : type.name) === null || _a === void 0 ? void 0 : _a.value; }) .join(', ')} are mapped to the same table ${tableName}. Remove the duplicate mapping.`); } }; const checkDuplicateFieldMapping = (columnName, tableName, document) => { var _a; const matchingObject = findMatchingModel(tableName, document); if (!matchingObject) { return; } const matchedFields = (_a = matchingObject === null || matchingObject === void 0 ? void 0 : matchingObject.fields) === null || _a === void 0 ? void 0 : _a.filter((def) => { var _a; return ((_a = def === null || def === void 0 ? void 0 : def.name) === null || _a === void 0 ? void 0 : _a.value) === columnName || getMappedName(def) === columnName; }); if ((matchedFields === null || matchedFields === void 0 ? void 0 : matchedFields.length) > 1) { throw new Error(`Fields ${matchedFields .map((field) => { var _a; return (_a = field === null || field === void 0 ? void 0 : field.name) === null || _a === void 0 ? void 0 : _a.value; }) .join(', ')} are mapped to the same column ${columnName}. Remove the duplicate mapping.`); } }; const getCustomEnumTypes = (document, existingDocument) => { const existingEnumTypes = getEnumTypes(existingDocument); const newEnumTypes = getEnumTypes(document); return existingEnumTypes.filter((existingEnum) => !newEnumTypes.find((newEnum) => { var _a, _b; return ((_a = newEnum === null || newEnum === void 0 ? void 0 : newEnum.name) === null || _a === void 0 ? void 0 : _a.value) === ((_b = existingEnum === null || existingEnum === void 0 ? void 0 : existingEnum.name) === null || _b === void 0 ? void 0 : _b.value); })); }; const getEnumTypes = (document) => { return document.definitions.filter((def) => def.kind === 'EnumTypeDefinition').map((def) => def); }; //# sourceMappingURL=schema-overrides.js.map