diff --git a/forward_engineering/config.json b/forward_engineering/config.json index 38c467a1..3e7f9184 100644 --- a/forward_engineering/config.json +++ b/forward_engineering/config.json @@ -36,6 +36,419 @@ "isDropInStatements": true } ], + "scriptGenerationOptions": [ + { + "keyword": "primaryKeys", + "label": "FE_SCRIPT_GENERATION_OPTIONS___PRIMARY_KEYS", + "disabled": false, + "value": { + "inline": { + "default": true, + "disabled": false, + "disabledLabel": "" + }, + "separate": { + "default": false, + "disabled": false, + "disabledLabel": "" + }, + "ignore": { + "default": false, + "disabled": false, + "disabledLabel": "" + } + }, + "adapters": [ + { + "dependency": { + "key": "primaryKey", + "valueType": "array" + }, + "defaultValue": { + "primaryKey": [] + } + }, + { + "dependency": { + "key": "primaryKey", + "valueType": "object" + }, + + "defaultValue": { + "primaryKey": {} + } + }, + { + "dependency": { + "type": "or", + "values": [ + { + "key": "primaryKey", + "value": true + }, + { + "key": "compositePrimaryKey", + "value": true + } + ] + }, + "defaultValue": { + "primaryKey": false, + "compositePrimaryKey": false + } + } + ] + }, + { + "keyword": "foreignKeys", + "label": "FE_SCRIPT_GENERATION_OPTIONS___FOREIGN_KEYS", + "disabled": false, + "value": { + "inline": { + "default": true, + "disabled": false, + "disabledLabel": "" + }, + "separate": { + "default": false, + "disabled": false, + "disabledLabel": "" + }, + "ignore": { + "default": false, + "disabled": false, + "disabledLabel": "" + } + } + }, + { + "keyword": "uniqueConstraints", + "label": "FE_SCRIPT_GENERATION_OPTIONS___UNIQUE_KEYS", + "disabled": false, + "value": { + "inline": { + "default": true, + "disabled": false, + "disabledLabel": "" + }, + "separate": { + "default": false, + "disabled": false, + "disabledLabel": "" + }, + "ignore": { + "default": false, + "disabled": false, + "disabledLabel": "" + } + }, + "adapters": [ + { + "dependency": { + "key": "uniqueKey", + "valueType": "array" + }, + "defaultValue": { + "uniqueKey": [] + } + }, + { + "dependency": { + "key": "uniqueKey", + "valueType": "object" + }, + "defaultValue": { + "uniqueKey": {} + } + }, + { + "dependency": { + "type": "or", + "values": [ + { + "key": "unique", + "value": true + }, + { + "key": "compositeUniqueKey", + "value": true + }, + { + "key": "compMode", + "exist": true + } + ] + }, + "defaultValue": { + "unique": false, + "compositeUniqueKey": false + } + } + ] + }, + { + "keyword": "columnNotNullConstraints", + "label": "FE_SCRIPT_GENERATION_OPTIONS___COLUMN_NOT_NULL", + "disabled": false, + "value": { + "inline": { + "default": true, + "disabled": false, + "disabledLabel": "" + }, + "separate": { + "default": false, + "disabled": false, + "disabledLabel": "" + }, + "ignore": { + "default": false, + "disabled": false, + "disabledLabel": "" + } + }, + "adapters": [ + { + "dependency": { + "key": "required", + "value": true + }, + "defaultValue": { + "required": false + } + } + ] + }, + { + "keyword": "checkConstraints", + "label": "FE_SCRIPT_GENERATION_OPTIONS___CHECK_CONSTRAINTS", + "disabled": false, + "value": { + "inline": { + "default": true, + "disabled": false, + "disabledLabel": "" + }, + "separate": { + "default": false, + "disabled": false, + "disabledLabel": "" + }, + "ignore": { + "default": false, + "disabled": false, + "disabledLabel": "" + } + }, + "adapters": [ + { + "dependency": { + "key": "chkConstr", + "valueType": "array" + }, + "defaultValue": { + "chkConstr": [] + } + } + ] + }, + { + "keyword": "columnDefaultValues", + "label": "FE_SCRIPT_GENERATION_OPTIONS___COLUMN_DEFAULT_VALUES", + "disabled": false, + "value": { + "inline": { + "default": true, + "disabled": false, + "disabledLabel": "" + }, + "separate": { + "default": false, + "disabled": false, + "disabledLabel": "" + }, + "ignore": { + "default": false, + "disabled": false, + "disabledLabel": "" + } + }, + "adapters": [ + { + "dependency": { + "key": "default", + "exist": true + }, + "defaultValue": { + "default": "" + } + } + ] + }, + { + "keyword": "schemaComments", + "label": "FE_SCRIPT_GENERATION_OPTIONS___SCHEMA_COMMENTS", + "disabled": false, + "value": { + "inline": { + "default": false, + "disabled": true, + "disabledLabel": "" + }, + "separate": { + "default": true, + "disabled": false, + "disabledLabel": "" + }, + "ignore": { + "default": false, + "disabled": false, + "disabledLabel": "" + } + }, + "adapters": [ + { + "dependency": { + "key": "type", + "value": "bucket" + }, + "defaultValue": { + "description": "" + } + } + ] + }, + { + "keyword": "tableComments", + "label": "FE_SCRIPT_GENERATION_OPTIONS___TABLE_COMMENTS", + "disabled": false, + "value": { + "inline": { + "default": false, + "disabled": true, + "disabledLabel": "" + }, + "separate": { + "default": true, + "disabled": false, + "disabledLabel": "" + }, + "ignore": { + "default": false, + "disabled": false, + "disabledLabel": "" + } + }, + "adapters": [ + { + "dependency": { + "type": "and", + "values": [ + { + "key": "collectionName", + "exist": true + }, + { + "key": "description", + "exist": true + } + ] + }, + "defaultValue": { + "description": "" + } + } + ] + }, + { + "keyword": "viewComments", + "label": "FE_SCRIPT_GENERATION_OPTIONS___VIEW_COMMENTS", + "disabled": false, + "value": { + "inline": { + "default": false, + "disabled": true, + "disabledLabel": "" + }, + "separate": { + "default": true, + "disabled": false, + "disabledLabel": "" + }, + "ignore": { + "default": false, + "disabled": false, + "disabledLabel": "" + } + }, + "adapters": [ + { + "dependency": { + "key": "viewOn", + "exist": true + }, + "defaultValue": { + "description": "" + } + } + ] + }, + { + "keyword": "columnComments", + "label": "FE_SCRIPT_GENERATION_OPTIONS___COLUMN_COMMENTS", + "disabled": false, + "value": { + "inline": { + "default": false, + "disabled": true, + "disabledLabel": "" + }, + "separate": { + "default": true, + "disabled": false, + "disabledLabel": "" + }, + "ignore": { + "default": false, + "disabled": false, + "disabledLabel": "" + } + }, + "adapters": [ + { + "dependency": { + "type": "and", + "values": [ + { + "type": "not", + "values": [ + { + "key": "type", + "value": "bucket" + } + ] + }, + { + "key": "collectionName", + "exist": false + }, + { + "key": "viewOn", + "exist": false + }, + { + "key": "description", + "exist": true + } + ] + }, + "defaultValue": { + "description": "" + } + } + ] + } + ], "feLevelSelector": { "entity": { "separateBucket": true diff --git a/forward_engineering/configs/templates.js b/forward_engineering/configs/templates.js index 4ed7bdc3..8d336af6 100644 --- a/forward_engineering/configs/templates.js +++ b/forward_engineering/configs/templates.js @@ -41,6 +41,7 @@ module.exports = { createKeyConstraint: '${constraintName}${keyType}${clustered}${columns}${options}${partition}', createRegularPrimaryKeyConstraint: '${constraintName} PRIMARY KEY (${columnName})', + createRegularUniqueKeyConstraint: '${constraintName} UNIQUE (${columnName})', createDefaultConstraint: 'ALTER TABLE ${tableName} ADD CONSTRAINT [${constraintName}] DEFAULT (${default}) FOR [${columnName}]${terminator}\n', diff --git a/forward_engineering/ddlProvider.js b/forward_engineering/ddlProvider.js index 8ac143ad..257a8cd2 100644 --- a/forward_engineering/ddlProvider.js +++ b/forward_engineering/ddlProvider.js @@ -35,7 +35,7 @@ module.exports = (baseProvider, options, app) => { } = require('./helpers/general')(app); const keyHelper = require('./helpers/keyHelper')(app); const { getTerminator } = require('./helpers/optionsHelper'); - const { createKeyConstraint, createDefaultConstraint, generateConstraintsString } = + const { createPKConstraint, createUKConstraint, createDefaultConstraint, generateConstraintsString } = require('./helpers/constraintsHelper')(app); const { wrapIfNotExistSchema, wrapIfNotExistDatabase, wrapIfNotExistTable, wrapIfNotExistView } = require('./helpers/ifNotExistStatementHelper')(app); @@ -130,7 +130,7 @@ module.exports = (baseProvider, options, app) => { : ''; const columnComments = getColumnsComments(name, tableTerminator, columnDefinitions); const dividedKeysConstraints = divideIntoActivatedAndDeactivated( - keyConstraints.map(createKeyConstraint(templates, tableTerminator, isActivated)), + keyConstraints.map(createPKConstraint(templates, tableTerminator, isActivated)), key => key.statement, ); const keyConstraintsString = generateConstraintsString(dividedKeysConstraints, isActivated); @@ -199,7 +199,7 @@ module.exports = (baseProvider, options, app) => { : getTableName(columnDefinition.type, columnDefinition.schemaName); const notNull = columnDefinition.nullable ? '' : ' NOT NULL'; const primaryKey = columnDefinition.primaryKey - ? ' ' + createKeyConstraint(templates, terminator, true)(columnDefinition.primaryKeyOptions).statement + ? ' ' + createPKConstraint(templates, terminator, true)(columnDefinition.primaryKeyOptions).statement : ''; const defaultValue = getDefaultValue( columnDefinition.default, @@ -215,7 +215,7 @@ module.exports = (baseProvider, options, app) => { ? getEncryptedWith(columnDefinition.encryption[0]) : ''; const unique = columnDefinition.unique - ? ' ' + createKeyConstraint(templates, terminator, true)(columnDefinition.uniqueKeyOptions).statement + ? ' ' + createUKConstraint(templates, terminator, true)(columnDefinition.uniqueKeyOptions).statement : ''; const temporalTableTime = getTempTableTime( columnDefinition.isTempTableStartTimeColumn, @@ -995,7 +995,7 @@ module.exports = (baseProvider, options, app) => { }, addPKConstraint(tableName, isParentActivated, keyData, isPKWithOptions, isAlterScript) { - const constraintStatementDto = createKeyConstraint( + const constraintStatementDto = createPKConstraint( templates, terminator, isParentActivated, @@ -1029,5 +1029,32 @@ module.exports = (baseProvider, options, app) => { }; return assignTemplates(templates.dropConstraint, templateConfig); }, + + addUniqueConstraint(tableName, isParentActivated, keyData, isUKWithOptions, isAlterScript) { + const constraintStatementDto = createUKConstraint( + templates, + terminator, + isParentActivated, + isUKWithOptions, + isAlterScript, + )(keyData); + + return { + statement: assignTemplates(templates.addConstraint, { + tableName, + constraintStatement: (constraintStatementDto.statement || '').trim(), + terminator, + }), + isActivated: constraintStatementDto.isActivated, + }; + }, + + dropUniqueConstraint(tableName, constraintName) { + return assignTemplates(templates.dropConstraint, { + tableName, + constraintName, + terminator, + }); + }, }; }; diff --git a/forward_engineering/helpers/alterScriptFromDeltaHelper.js b/forward_engineering/helpers/alterScriptFromDeltaHelper.js index 4f54834e..b65da81b 100644 --- a/forward_engineering/helpers/alterScriptFromDeltaHelper.js +++ b/forward_engineering/helpers/alterScriptFromDeltaHelper.js @@ -112,6 +112,14 @@ module.exports = _ => { const { getAddViewScriptDto, getDeleteViewScriptDto, getModifiedViewScriptDto } = require('./alterScriptHelpers/alterViewHelper')(app, options); + const checkIfOnlyDescriptionChanged = view => { + const changedProps = Object.entries(view.role?.compMod).filter(([_, value]) => value.new !== value.old); + + // If the only change is the description, we ignore it + // descriptions are handled in separate methods + return !(changedProps.length === 1 && changedProps[0][0] === 'description'); + }; + const createViewsScriptsDtos = [] .concat(collection.properties?.views?.properties?.added?.items) .filter(Boolean) @@ -134,6 +142,7 @@ module.exports = _ => { .map(item => Object.values(item.properties)[0]) .map(view => ({ ...view, ...(view.role || {}) })) .filter(view => !view.compMod?.created && !view.compMod?.deleted) + .filter(checkIfOnlyDescriptionChanged) .flatMap(getModifiedViewScriptDto); return { deleteViewsScriptsDtos, createViewsScriptsDtos, modifiedViewsScriptsDtos }; diff --git a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js index 3667cf14..c5c6b9c9 100644 --- a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js @@ -18,6 +18,7 @@ module.exports = (app, options) => { const { getModifyCheckConstraintScriptDtos } = require('./entityHelpers/checkConstraintHelper'); const { getModifyPkConstraintsScriptDtos } = require('./entityHelpers/primaryKeyHelper'); const { getModifyNonNullColumnsScriptDtos } = require('./columnHelpers/notNullConstraintsHelper'); + const { getModifyUniqueConstraintsScriptDtos } = require('./entityHelpers/uniqueConstraintHelper'); /** * @param {Collection} collection @@ -96,6 +97,7 @@ module.exports = (app, options) => { const idToNameHashTable = generateIdToNameHashTable(jsonSchema); const idToActivatedHashTable = generateIdToActivatedHashTable(jsonSchema); const modifyCheckConstraintScriptDtos = getModifyCheckConstraintScriptDtos(_, ddlProvider)(collection); + const modifyUniqueConstraintsScriptDtos = getModifyUniqueConstraintsScriptDtos(app, _, ddlProvider)(collection); const modifyPKConstraintDtos = getModifyPkConstraintsScriptDtos(app, _, ddlProvider)(collection); const indexesScriptsDtos = modifyGroupItems({ data: jsonSchema, @@ -118,7 +120,12 @@ module.exports = (app, options) => { AlterScriptDto.getInstance([ddlProvider.dropIndex(tableName, index)], true, true), }).flat(); - return [...modifyCheckConstraintScriptDtos, ...modifyPKConstraintDtos, ...indexesScriptsDtos].filter(Boolean); + return [ + ...modifyCheckConstraintScriptDtos, + ...modifyPKConstraintDtos, + ...modifyUniqueConstraintsScriptDtos, + ...indexesScriptsDtos, + ].filter(Boolean); }; /** @@ -302,7 +309,7 @@ module.exports = (app, options) => { const comment = column.description; const oldComment = tables[tableName].role?.properties[columnNameToSearchComment]?.description; - if (comment || !oldComment) { + if (!comment || oldComment) { return undefined; } diff --git a/forward_engineering/helpers/alterScriptHelpers/entityHelpers/primaryKeyHelper.js b/forward_engineering/helpers/alterScriptHelpers/entityHelpers/primaryKeyHelper.js index 21096367..509751b7 100644 --- a/forward_engineering/helpers/alterScriptHelpers/entityHelpers/primaryKeyHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/entityHelpers/primaryKeyHelper.js @@ -282,7 +282,7 @@ const getAddCompositePkScriptDtos = (app, _, ddlProvider) => collection => { return []; } - const { fullTableName, entityName } = getCollectionNames(_, collection); + const { fullTableName } = getCollectionNames(_, collection); return newPrimaryKeys .map(newPk => { diff --git a/forward_engineering/helpers/alterScriptHelpers/entityHelpers/uniqueConstraintHelper.js b/forward_engineering/helpers/alterScriptHelpers/entityHelpers/uniqueConstraintHelper.js new file mode 100644 index 00000000..f5b5429d --- /dev/null +++ b/forward_engineering/helpers/alterScriptHelpers/entityHelpers/uniqueConstraintHelper.js @@ -0,0 +1,357 @@ +const { AlterScriptDto } = require('../types/AlterScriptDto'); + +class UniqueConstraintScriptModificationDto { + /** + * @type string + * */ + script; + + /** + * @type boolean + * */ + isDropScript; + + /** + * @type {string} + * */ + fullTableName; + + /** + * @type {boolean} + * */ + isActivated; + + /** + * @param script {string} + * @param fullTableName {string} + * @param isDropScript {boolean} + * @param isActivated {boolean} + * */ + constructor(script, fullTableName, isDropScript, isActivated) { + this.script = script; + this.isDropScript = isDropScript; + this.fullTableName = fullTableName; + this.isActivated = isActivated; + } +} + +/** + * @param entityName {string} + * @param constraintName {string} + * @return {string} + * */ +const getDefaultUniqueConstraintName = (entityName, constraintName) => { + return constraintName || `${entityName}_ukey`; +}; + +/** + * @param collection {AlterCollectionDto} + * @return {object} + * */ +const getCollectionNames = (_, collection) => { + const { getFullCollectionName, getSchemaOfAlterCollection, getEntityName } = require('../../../utils/general')(_); + + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(collectionSchema); + const entityName = getEntityName(collectionSchema); + + return { + fullTableName, + entityName, + }; +}; + +/** + * @param newConstraints {Array} + * @param oldConstraints {Array} + * @return {boolean} + * */ +const areUniqueConstraintsEqual = (_, newConstraints, oldConstraints) => { + if (newConstraints.length !== oldConstraints.length) { + return false; + } + return _(oldConstraints).differenceWith(newConstraints, _.isEqual).isEmpty(); +}; + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getAddCompositeUKScriptDtos = (app, _, ddlProvider) => collection => { + const { getCompositeUniqueKeys } = require('../../keyHelper')(app); + + const uniqueDto = collection?.role?.compMod?.uniqueKey || {}; + const newUniqueConstraints = uniqueDto.new || []; + const oldUniqueConstraints = uniqueDto.old || []; + + if (newUniqueConstraints.length === 0 && oldUniqueConstraints.length === 0) { + return []; + } + + if (areUniqueConstraintsEqual(_, newUniqueConstraints, oldUniqueConstraints)) { + return []; + } + + const { fullTableName } = getCollectionNames(_, collection); + + return newUniqueConstraints + .map(newConstraint => { + const keyData = getCompositeUniqueKeys({ ...collection, ...(collection?.role || {}) }, true)[0]; + + if (!keyData) { + return null; + } + + const statementDto = ddlProvider.addUniqueConstraint( + fullTableName, + collection.isActivated, + keyData, + true, + true, + ); + + return new UniqueConstraintScriptModificationDto( + statementDto.statement, + fullTableName, + false, + statementDto.isActivated, + ); + }) + .filter(scriptDto => Boolean(scriptDto?.script)); +}; + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getDropCompositeUKScriptDtos = (app, _, ddlProvider) => collection => { + const { wrapInBrackets } = require('../../../utils/general')(_); + + const uniqueDto = collection?.role?.compMod?.uniqueKey || {}; + const newUniqueConstraints = uniqueDto.new || []; + const oldUniqueConstraints = uniqueDto.old || []; + + if (newUniqueConstraints.length === 0 && oldUniqueConstraints.length === 0) { + return []; + } + + if (areUniqueConstraintsEqual(_, newUniqueConstraints, oldUniqueConstraints)) { + return []; + } + + const { fullTableName, entityName } = getCollectionNames(_, collection); + + return oldUniqueConstraints + .map(oldConstraint => { + const constraintName = getDefaultUniqueConstraintName(entityName, oldConstraint.constraintName); + const ddlConstraintName = wrapInBrackets(constraintName); + const script = ddlProvider.dropUniqueConstraint(fullTableName, ddlConstraintName); + + return new UniqueConstraintScriptModificationDto(script, fullTableName, true, collection.isActivated); + }) + .filter(scriptDto => Boolean(scriptDto.script)); +}; + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getModifyCompositeUKScriptDtos = (app, _, ddlProvider) => collection => { + const dropUniqueConstraintScriptDtos = getDropCompositeUKScriptDtos(app, _, ddlProvider)(collection); + const addUniqueConstraintScriptDtos = getAddCompositeUKScriptDtos(app, _, ddlProvider)(collection); + + return [...dropUniqueConstraintScriptDtos, ...addUniqueConstraintScriptDtos].filter(Boolean); +}; + +/** + * @param constraintDtos {UniqueConstraintScriptModificationDto[]} + * @return {UniqueConstraintScriptModificationDto[]} + * */ +const sortModifyUniqueConstraints = constraintDtos => { + return constraintDtos.sort((c1, c2) => { + if (c1.fullTableName === c2.fullTableName) { + // Number(true) = 1, Number(false) = 0; + // This ensures that DROP script appears before CREATE script + return Number(c2.isDropScript) - Number(c1.isDropScript); + } + // This sorts all statements based on full table name, ASC + return c1.fullTableName < c2.fullTableName; + }); +}; + +/** + * @param entityName {string} + * @param columnName {string} + * @return {string} + * */ +const getDefaultUniqueConstraintNameForRegularUK = (entityName, columnName) => { + return `${entityName}_${columnName}_pkey`; +}; + +/** + * @param columnJsonSchema {AlterCollectionColumnDto} + * @param entityName {string} + * @param columnName {string} + * @return {string} + * */ +const getConstraintNameForRegularUK = (columnJsonSchema, entityName, columnName) => { + if (columnJsonSchema.uniqueKeyOptions?.length > 0) { + const constraintOption = columnJsonSchema.uniqueKeyOptions[0]; + if (constraintOption.constraintName) { + return constraintOption.constraintName; + } + } + return getDefaultUniqueConstraintNameForRegularUK(entityName, columnName); +}; + +/** + * @return {(columnJsonSchema: AlterCollectionColumnDto, collection: AlterCollectionDto) => boolean} + * */ +const wasFieldChangedToBeARegularUK = _ => (columnJsonSchema, collection) => { + const oldName = columnJsonSchema.compMod.oldField.name; + const oldColumnJsonSchema = collection.role.properties[oldName]; + + const isRegularUniqueKey = columnJsonSchema.unique && !columnJsonSchema.compositeUniqueKey; + const wasTheFieldAnyUniqueKey = Boolean(oldColumnJsonSchema?.unique); + + return isRegularUniqueKey && !wasTheFieldAnyUniqueKey; +}; + +/** + * @return {(columnJsonSchema: AlterCollectionColumnDto, collection: AlterCollectionDto) => boolean} + * */ +const isFieldNoLongerARegularUK = _ => (columnJsonSchema, collection) => { + const oldName = columnJsonSchema.compMod.oldField.name; + + const oldJsonSchema = collection.role.properties[oldName]; + const wasTheFieldARegularUniqueKey = oldJsonSchema?.unique && !oldJsonSchema?.compositeUniqueKey; + + const isNotAnyUniqueKey = !columnJsonSchema.unique && !columnJsonSchema.compositeUniqueKey; + return wasTheFieldARegularUniqueKey && isNotAnyUniqueKey; +}; + +/** + * @return {(columnJsonSchema: AlterCollectionColumnDto, collection: AlterCollectionDto) => boolean} + * */ +const wasRegularUKModified = _ => (columnJsonSchema, collection) => { + const oldName = columnJsonSchema.compMod.oldField.name; + const oldJsonSchema = collection.role.properties[oldName] || {}; + + const isRegularUniqueKey = columnJsonSchema.unique && !columnJsonSchema.compositeUniqueKey; + const wasTheFieldARegularUniqueKey = oldJsonSchema?.unique && !oldJsonSchema?.compositeUniqueKey; + + if (!(isRegularUniqueKey && wasTheFieldARegularUniqueKey)) { + return false; + } + + // Compare unique key options to detect if they changed + const currentOptions = columnJsonSchema.uniqueKeyOptions || []; + const oldOptions = oldJsonSchema.uniqueKeyOptions || []; + + const areOptionsEqual = _(oldOptions).differenceWith(currentOptions, _.isEqual).isEmpty(); + return !areOptionsEqual; +}; + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getAddUKScriptDtos = (app, _, ddlProvider) => collection => { + const { getFullCollectionName, getSchemaOfAlterCollection, getEntityName, wrapInBrackets } = + require('../../../utils/general')(_); + const { hydrateUniqueOptions } = require('../../keyHelper')(app); + + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(collectionSchema); + const entityName = getEntityName(collectionSchema); + + return _.toPairs(collection.properties) + .filter(([name, jsonSchema]) => { + if (wasFieldChangedToBeARegularUK(_)(jsonSchema, collection)) { + return true; + } + return wasRegularUKModified(_)(jsonSchema, collection); + }) + .map(([name, jsonSchema]) => { + let keyData = { + constraintName: getDefaultUniqueConstraintNameForRegularUK(entityName, name), + columnName: wrapInBrackets(name), + }; + const isUKWithOptions = Boolean(jsonSchema.uniqueKeyOptions?.length); + + if (jsonSchema.uniqueKeyOptions) { + keyData = hydrateUniqueOptions(jsonSchema.uniqueKeyOptions[0], name, jsonSchema.isActivated); + } + + const statementDto = ddlProvider.addUniqueConstraint( + fullTableName, + collection.isActivated, + keyData, + isUKWithOptions, + true, + ); + return new UniqueConstraintScriptModificationDto( + statementDto.statement, + fullTableName, + false, + statementDto.isActivated, + ); + }) + .filter(scriptDto => Boolean(scriptDto.script)); +}; + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getDropUKScriptDtos = (_, ddlProvider) => collection => { + const { getFullCollectionName, getSchemaOfAlterCollection, getEntityName, wrapInBrackets } = + require('../../../utils/general')(_); + + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(collectionSchema); + const entityName = getEntityName(collectionSchema); + + return _.toPairs(collection.properties) + .filter(([name, jsonSchema]) => { + if (isFieldNoLongerARegularUK(_)(jsonSchema, collection)) { + return true; + } + return wasRegularUKModified(_)(jsonSchema, collection); + }) + .map(([name, jsonSchema]) => { + const oldName = jsonSchema.compMod.oldField.name; + const oldJsonSchema = collection.role.properties[oldName]; + const ddlConstraintName = wrapInBrackets(getConstraintNameForRegularUK(oldJsonSchema, entityName, oldName)); + + const script = ddlProvider.dropUniqueConstraint(fullTableName, ddlConstraintName); + return new UniqueConstraintScriptModificationDto(script, fullTableName, true, collection.isActivated); + }) + .filter(scriptDto => Boolean(scriptDto.script)); +}; + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getModifyUKScriptDtos = (app, _, ddlProvider) => collection => { + const dropUKScriptDtos = getDropUKScriptDtos(_, ddlProvider)(collection); + const addUKScriptDtos = getAddUKScriptDtos(app, _, ddlProvider)(collection); + + return [...dropUKScriptDtos, ...addUKScriptDtos].filter(Boolean); +}; + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getModifyUniqueConstraintsScriptDtos = (app, _, ddlProvider) => collection => { + const modifyCompositeUKScriptDtos = getModifyCompositeUKScriptDtos(app, _, ddlProvider)(collection); + const modifyUKScriptDtos = getModifyUKScriptDtos(app, _, ddlProvider)(collection); + + const allDtos = [...modifyCompositeUKScriptDtos, ...modifyUKScriptDtos]; + const sortedDtos = sortModifyUniqueConstraints(allDtos); + + return sortedDtos + .map(dto => { + return AlterScriptDto.getInstance([dto.script], dto.isActivated, dto.isDropScript); + }) + .filter(Boolean); +}; + +module.exports = { + getModifyUniqueConstraintsScriptDtos, +}; diff --git a/forward_engineering/helpers/constraintsHelper.js b/forward_engineering/helpers/constraintsHelper.js index a021c23f..346a237b 100644 --- a/forward_engineering/helpers/constraintsHelper.js +++ b/forward_engineering/helpers/constraintsHelper.js @@ -8,10 +8,9 @@ module.exports = app => { const { getRelationOptionsIndex } = require('./indexHelper')(app); const { trimBraces } = require('./general')(app); - const createKeyConstraint = + const createPKConstraint = (templates, terminator, isParentActivated, isPKWithOptions, isAlterScript) => keyData => { const isAllColumnsDeactivated = checkAllKeysDeactivated(keyData.columns || []); - const columns = getKeyColumns(isAllColumnsDeactivated, isParentActivated, keyData.columns); if (!isPKWithOptions && isAlterScript) { return { @@ -23,6 +22,42 @@ module.exports = app => { }; } + return createKeyConstraint( + templates, + terminator, + isParentActivated, + isPKWithOptions, + isAlterScript, + )(keyData); + }; + + const createUKConstraint = + (templates, terminator, isParentActivated, isUKWithOptions, isAlterScript) => keyData => { + const isAllColumnsDeactivated = checkAllKeysDeactivated(keyData.columns || []); + + if (!isUKWithOptions && isAlterScript) { + return { + statement: assignTemplates(templates.createRegularUniqueKeyConstraint, { + constraintName: keyData.constraintName, + columnName: keyData.columnName, + }), + isActivated: !isAllColumnsDeactivated, + }; + } + + return createKeyConstraint( + templates, + terminator, + isParentActivated, + isUKWithOptions, + isAlterScript, + )(keyData); + }; + + const createKeyConstraint = + (templates, terminator, isParentActivated, isPKWithOptions, isAlterScript) => keyData => { + const isAllColumnsDeactivated = checkAllKeysDeactivated(keyData.columns || []); + const columns = getKeyColumns(isAllColumnsDeactivated, isParentActivated, keyData.columns); const additionalConstraintStatement = isAlterScript ? '' : 'CONSTRAINT'; if (!keyDataHasOptions(keyData)) { @@ -126,6 +161,8 @@ module.exports = app => { return { createDefaultConstraint, createKeyConstraint, + createPKConstraint, + createUKConstraint, generateConstraintsString, }; }; diff --git a/forward_engineering/helpers/keyHelper.js b/forward_engineering/helpers/keyHelper.js index 9046c222..e6ddccfb 100644 --- a/forward_engineering/helpers/keyHelper.js +++ b/forward_engineering/helpers/keyHelper.js @@ -145,12 +145,14 @@ module.exports = app => { })); }; - const getCompositeUniqueKeys = jsonSchema => { + const getCompositeUniqueKeys = (jsonSchema, isModifiedUK) => { if (!Array.isArray(jsonSchema.uniqueKey)) { return []; } - return jsonSchema.uniqueKey + const uniqueKey = isModifiedUK ? jsonSchema.compMod.uniqueKey.new : jsonSchema.uniqueKey; + + return uniqueKey .filter(uniqueKey => !_.isEmpty(uniqueKey.compositeUniqueKey)) .map(uniqueKey => ({ ...hydrateUniqueOptions(uniqueKey), @@ -250,6 +252,7 @@ module.exports = app => { isInlinePrimaryKey, hydratePrimaryKeyOptions, hydrateUniqueOptions, + getCompositeUniqueKeys, getCompositePrimaryKeys, getCompositeKeyConstraints, getColumnConstraints,