diff --git a/forward_engineering/alterScript/alterScriptFromDeltaHelper.js b/forward_engineering/alterScript/alterScriptFromDeltaHelper.js index 8207516..4eb9a01 100644 --- a/forward_engineering/alterScript/alterScriptFromDeltaHelper.js +++ b/forward_engineering/alterScript/alterScriptFromDeltaHelper.js @@ -1,9 +1,9 @@ +/** + * @typedef {import('../../shared/types').App} App + * @typedef {import('./types/AlterScriptDto').AlterScriptDto} AlterScriptDto + */ const { getContainersScripts } = require('./alterScriptHelpers/alterContainerHelper'); -const { - getModifyCollectionScriptDtos, - getModifyCollectionKeysScriptDtos, - getModifyColumnScriptDtos, -} = require('./alterScriptHelpers/alterEntityHelper'); +const { getEntitiesScripts } = require('./alterScriptHelpers/alterEntityHelper'); const { getDeleteForeignKeyScriptDtos, getAddForeignKeyScriptDtos, @@ -11,15 +11,18 @@ const { } = require('./alterScriptHelpers/alterForeignKeyHelper'); const { getModifyViewScriptDtos } = require('./alterScriptHelpers/alterViewHelper'); +/** + * @param {T} data + * @return {Array} + */ const getItems = data => [data?.items].flat().filter(Boolean); /** - * @param dto {{ + * @param {{ * collection: Object, * app: App - * }} - * @return {AlterScriptDto[]} - * */ + * }} param + */ const getAlterContainersScriptDtos = ({ collection, app }) => { const { added, deleted, modified } = collection.properties?.containers?.properties || {}; const addedContainers = getItems(added); @@ -29,41 +32,86 @@ const getAlterContainersScriptDtos = ({ collection, app }) => { const { getAddContainerScriptDto, getDeleteContainerScriptDto, getModifyContainerScriptDto } = getContainersScripts(app); - const addContainersScriptDtos = addedContainers + const addedContainersScriptDtos = addedContainers .map(container => Object.values(container.properties)[0]) .flatMap(getAddContainerScriptDto); - const deleteContainersScriptDtos = deletedContainers + const deletedContainersScriptDtos = deletedContainers .map(container => Object.values(container.properties)[0]) .flatMap(getDeleteContainerScriptDto); - const modifyContainersScriptDtos = modifiedContainers + const modifiedContainersScriptDtos = modifiedContainers .map(containerWrapper => Object.values(containerWrapper.properties)[0]) .flatMap(getModifyContainerScriptDto); - return [...addContainersScriptDtos, ...deleteContainersScriptDtos, ...modifyContainersScriptDtos].filter(Boolean); + // Schemas can only be dropped after all contained tables are removed, + // so container cleanup must happen last. + return { + deletedContainersScriptDtos, + upsertedContainersScriptDtos: [...addedContainersScriptDtos, ...modifiedContainersScriptDtos], + }; }; +/** + * @param {{collection: Object, app: App, modelDefinitions: Object, internalDefinitions: Object, externalDefinitions: Object, inlineDeltaRelationships?: any[]}} param + * @return {Array} + */ const getAlterCollectionScriptDtos = ({ collection, app, modelDefinitions, internalDefinitions, externalDefinitions, + inlineDeltaRelationships = [], }) => { - const modifyScriptsData = getItems(collection.properties?.entities?.properties?.modified).map( - item => Object.values(item.properties)[0], - ); + const { added, deleted, modified } = collection.properties?.entities?.properties || {}; + const addedCollections = getItems(added).map(item => Object.values(item.properties)[0]); + const deletedCollections = getItems(deleted).map(item => Object.values(item.properties)[0]); + const modifyScriptsData = getItems(modified).map(item => Object.values(item.properties)[0]); + + const { + getAddCollectionScriptDto, + getDeleteCollectionScriptDto, + getModifyCollectionScriptDtos, + getModifyCollectionKeysScriptDtos, + getModifyColumnScriptDtos, + getAddColumnScriptDtos, + getDeleteColumnScriptDtos, + } = getEntitiesScripts(app, inlineDeltaRelationships); + + const addedCollectionScriptDtos = addedCollections + .filter(collection => collection.role.compMod.created) + .map(getAddCollectionScriptDto); + + const addedColumnScriptDtos = addedCollections.flatMap(getAddColumnScriptDtos); + + const deletedCollectionScriptDtos = deletedCollections + .filter(collection => collection.role.compMod.deleted) + .map(getDeleteCollectionScriptDto); + + const deletedColumnScriptDtos = deletedCollections + .filter(collection => !collection.role.compMod.deleted) + .flatMap(getDeleteColumnScriptDtos); const modifyCollectionScriptDtos = modifyScriptsData.flatMap(getModifyCollectionScriptDtos); const modifyCollectionKeysScriptDtos = modifyScriptsData.flatMap(getModifyCollectionKeysScriptDtos); const modifyColumnScriptDtos = modifyScriptsData.flatMap(getModifyColumnScriptDtos); - return [...modifyCollectionScriptDtos, ...modifyColumnScriptDtos, ...modifyCollectionKeysScriptDtos].filter( - Boolean, - ); + return [ + ...deletedCollectionScriptDtos, + ...addedCollectionScriptDtos, + ...modifyCollectionScriptDtos, + ...deletedColumnScriptDtos, + ...addedColumnScriptDtos, + ...modifyColumnScriptDtos, + ...modifyCollectionKeysScriptDtos, + ].filter(Boolean); }; +/** + * @param {Object} collection + * @return {Array} + */ const getAlterViewScriptDtos = collection => { const modifyViewScriptDtos = getItems(collection.properties?.views?.properties?.modified) .map(viewWrapper => Object.values(viewWrapper.properties)[0]) @@ -73,6 +121,10 @@ const getAlterViewScriptDtos = collection => { return [...modifyViewScriptDtos].filter(Boolean); }; +/** + * @param {{collection: Object, app: App, ignoreRelationshipIDs?: string[]}} param + * @return {Array} + */ const getAlterRelationshipsScriptDtos = ({ collection, app, ignoreRelationshipIDs = [] }) => { const addedRelationships = getItems(collection.properties?.relationships?.properties?.added) .filter(Boolean) @@ -105,6 +157,10 @@ const getAlterRelationshipsScriptDtos = ({ collection, app, ignoreRelationshipID return [...deleteFkScriptDtos, ...addFkScriptDtos, ...modifiedFkScriptDtos].filter(Boolean); }; +/** + * @param {{collection: Object, options: Object}} param + * @return {Array} + */ const getInlineRelationships = ({ collection, options }) => { if (options?.scriptGenerationOptions?.feActiveOptions?.foreignKeys !== 'inline') { return []; @@ -121,13 +177,17 @@ const getInlineRelationships = ({ collection, options }) => { return addedRelationships; }; +/** + * @param {AlterScriptDto} dto + * @return {AlterScriptDto | undefined} + */ const prettifyAlterScriptDto = dto => { if (!dto) { return undefined; } /** * @type {Array} - * */ + */ const nonEmptyScriptModificationDtos = dto.scripts .map(scriptDto => ({ ...scriptDto, @@ -143,6 +203,11 @@ const prettifyAlterScriptDto = dto => { }; }; +/** + * @param {Object} data + * @param {App} app + * @return {Array} + */ const getAlterScriptDtos = (data, app) => { const collection = JSON.parse(data.jsonSchema); @@ -159,7 +224,10 @@ const getAlterScriptDtos = (data, app) => { const inlineDeltaRelationships = getInlineRelationships({ collection, options: data.options }); const ignoreRelationshipIDs = inlineDeltaRelationships.map(relationship => relationship.role.id); - const containersScriptDtos = getAlterContainersScriptDtos({ collection, app }); + const { deletedContainersScriptDtos, upsertedContainersScriptDtos } = getAlterContainersScriptDtos({ + collection, + app, + }); const collectionsScriptDtos = getAlterCollectionScriptDtos({ collection, @@ -167,6 +235,7 @@ const getAlterScriptDtos = (data, app) => { modelDefinitions, internalDefinitions, externalDefinitions, + inlineDeltaRelationships, }); const viewScriptDtos = getAlterViewScriptDtos(collection); @@ -177,7 +246,13 @@ const getAlterScriptDtos = (data, app) => { ignoreRelationshipIDs, }); - return [...containersScriptDtos, ...collectionsScriptDtos, ...viewScriptDtos, ...relationshipScriptDtos] + return [ + ...upsertedContainersScriptDtos, + ...collectionsScriptDtos, + ...viewScriptDtos, + ...relationshipScriptDtos, + ...deletedContainersScriptDtos, + ] .filter(Boolean) .map(dto => dto && prettifyAlterScriptDto(dto)) .filter(Boolean); diff --git a/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js b/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js index ddf91b4..68a6a4a 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js @@ -1,35 +1,204 @@ +/** + * @typedef {import('../../../shared/types').App} App + */ +const { omit, toPairs } = require('lodash'); +const { AlterScriptDto } = require('../types/AlterScriptDto'); const { getModifiedCommentOnColumnScriptDtos } = require('./columnHelpers/commentsHelper'); const { getModifyNonNullColumnsScriptDtos } = require('./columnHelpers/nonNullConstraintHelper'); +const { getUpdateTypesScriptDtos } = require('./columnHelpers/alterTypeHelper'); const { getModifyCheckConstraintScriptDtos } = require('./entityHelpers/checkConstraintHelper'); +const { getRenameColumnScriptDtos } = require('./columnHelpers/alterColumnNameHelper'); const { getModifyEntityCommentsScriptDtos } = require('./entityHelpers/commentsHelper'); const { getModifyPkConstraintsScriptDtos } = require('./entityHelpers/primaryKeyHelper'); const { getModifyUkConstraintsScriptDtos } = require('./entityHelpers/uniqueKeyHelper'); const { getModifiedDefaultColumnValueScriptDtos } = require('./columnHelpers/defaultValueHelper'); +const { + getEntityName, + getSchemaNameFromCollection, + getSchemaOfAlterCollection, + getFullCollectionName, + wrapInQuotes, +} = require('../../utils/general'); +const { getRelationshipName } = require('./alterForeignKeyHelper'); +const { createColumnDefinitionBySchema } = require('./createColumnDefinition'); +/** + * @param {Object} ddlProvider + * @param {Array} inlineDeltaRelationships + * @returns {(collection: Object) => AlterScriptDto} + */ +const getAddCollectionScriptDto = (ddlProvider, inlineDeltaRelationships) => collection => { + const jsonSchema = { ...collection, ...(omit(collection?.role, 'properties') || {}) }; + const schemaName = getSchemaNameFromCollection({ collection }); + const schemaData = { schemaName }; + + const columnDefinitions = toPairs(jsonSchema.properties).map(([name, column]) => + createColumnDefinitionBySchema({ + name, + jsonSchema: column, + parentJsonSchema: jsonSchema, + ddlProvider, + schemaData, + }), + ); + + const checkConstraints = (jsonSchema.chkConstr || []).map(check => + ddlProvider.createCheckConstraint(ddlProvider.hydrateCheckConstraint(check)), + ); + + const foreignKeyConstraints = inlineDeltaRelationships + .filter(relationship => relationship.role.childCollection === collection.role.id) + .map(relationship => { + const compMod = relationship.role.compMod; + const relationshipName = compMod.code?.new || compMod.name?.new || getRelationshipName(relationship) || ''; + return ddlProvider.createForeignKeyConstraint( + { + name: relationshipName, + foreignKey: compMod.child.collection.fkFields, + primaryTable: compMod.parent.collection.name, + primaryKey: compMod.parent.collection.fkFields, + primaryTableActivated: compMod.parent.collection.isActivated, + foreignTableActivated: compMod.child.collection.isActivated, + primarySchemaName: compMod.parent.bucket.name, + customProperties: compMod.customProperties?.new, + }, + {}, + schemaData, + ); + }); + + const tableData = { + name: getEntityName(jsonSchema), + columns: columnDefinitions.map(def => ddlProvider.convertColumnDefinition(def)), + checkConstraints, + foreignKeyConstraints, + schemaData, + columnDefinitions, + }; + + const hydratedTable = ddlProvider.hydrateTable({ tableData, entityData: [jsonSchema], jsonSchema }); + const script = ddlProvider.createTable(hydratedTable, jsonSchema.isActivated); + + return AlterScriptDto.getInstance([script], true, false); +}; + +/** + * @param {Object} ddlProvider + * @returns {(collection: Object) => AlterScriptDto} + */ +const getDeleteCollectionScriptDto = ddlProvider => collection => { + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(collectionSchema); + const script = ddlProvider.dropTable({ tableName: fullTableName }); + + return AlterScriptDto.getInstance([script], true, true); +}; + +/** + * @param {Object} collection + * @returns {Array} + */ const getModifyCollectionScriptDtos = collection => { const modifyCheckConstraintScriptDtos = getModifyCheckConstraintScriptDtos(collection); const modifyCommentScriptDtos = getModifyEntityCommentsScriptDtos(collection); return [...modifyCheckConstraintScriptDtos, ...modifyCommentScriptDtos].filter(Boolean); }; +/** + * @param {Object} collection + * @returns {Array} + */ const getModifyCollectionKeysScriptDtos = collection => { const modifyPkConstraintDtos = getModifyPkConstraintsScriptDtos(collection); const modifyUkConstraintDtos = getModifyUkConstraintsScriptDtos(collection); return [...modifyPkConstraintDtos, ...modifyUkConstraintDtos].filter(Boolean); }; -const getModifyColumnScriptDtos = collection => { +/** + * @param {Object} ddlProvider + * @returns {(collection: Object) => Array} + */ +const getAddColumnScriptDtos = ddlProvider => collection => { + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(collectionSchema); + const schemaName = getSchemaNameFromCollection({ collection }); + const schemaData = { schemaName }; + + return toPairs(collection.properties) + .filter(([name, jsonSchema]) => !jsonSchema.compMod) + .map(([name, jsonSchema]) => { + const columnDefinition = createColumnDefinitionBySchema({ + name, + jsonSchema, + parentJsonSchema: collectionSchema, + ddlProvider, + schemaData, + }); + const script = ddlProvider.addColumn({ + tableName: fullTableName, + columnDefinition: ddlProvider.convertColumnDefinition(columnDefinition), + }); + return AlterScriptDto.getInstance([script], true, false); + }) + .filter(Boolean); +}; + +/** + * @param {Object} ddlProvider + * @returns {(collection: Object) => Array} + */ +const getDeleteColumnScriptDtos = ddlProvider => collection => { + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(collectionSchema); + + return toPairs(collection.properties) + .filter(([name, jsonSchema]) => !jsonSchema.compMod) + .map(([name]) => { + const columnName = wrapInQuotes(name); + const script = ddlProvider.dropColumn({ tableName: fullTableName, columnName }); + return AlterScriptDto.getInstance([script], true, true); + }) + .filter(Boolean); +}; + +/** + * @param {Object} ddlProvider + * @returns {(collection: Object) => Array} + */ +const getModifyColumnScriptDtos = ddlProvider => collection => { + const renamedColumnsScriptDtos = getRenameColumnScriptDtos(collection); + const updateTypeScriptDtos = getUpdateTypesScriptDtos(ddlProvider)(collection); const modifyNotNullScriptDtos = getModifyNonNullColumnsScriptDtos(collection); const modifyCommentScriptDtos = getModifiedCommentOnColumnScriptDtos(collection); const modifyDefaultColumnValueScriptDtos = getModifiedDefaultColumnValueScriptDtos({ collection }); - return [...modifyNotNullScriptDtos, ...modifyDefaultColumnValueScriptDtos, ...modifyCommentScriptDtos].filter( - Boolean, - ); + return [ + ...renamedColumnsScriptDtos, + ...updateTypeScriptDtos, + ...modifyNotNullScriptDtos, + ...modifyDefaultColumnValueScriptDtos, + ...modifyCommentScriptDtos, + ].filter(Boolean); +}; + +/** + * @param {App} app + * @param {Array} inlineDeltaRelationships + */ +const getEntitiesScripts = (app, inlineDeltaRelationships) => { + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + + return { + getAddCollectionScriptDto: getAddCollectionScriptDto(ddlProvider, inlineDeltaRelationships), + getDeleteCollectionScriptDto: getDeleteCollectionScriptDto(ddlProvider), + getModifyCollectionScriptDtos, + getModifyColumnScriptDtos: getModifyColumnScriptDtos(ddlProvider), + getModifyCollectionKeysScriptDtos, + getAddColumnScriptDtos: getAddColumnScriptDtos(ddlProvider), + getDeleteColumnScriptDtos: getDeleteColumnScriptDtos(ddlProvider), + }; }; module.exports = { - getModifyCollectionScriptDtos, - getModifyColumnScriptDtos, - getModifyCollectionKeysScriptDtos, + getEntitiesScripts, }; diff --git a/forward_engineering/alterScript/alterScriptHelpers/alterForeignKeyHelper.js b/forward_engineering/alterScript/alterScriptHelpers/alterForeignKeyHelper.js index e78894d..532b489 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/alterForeignKeyHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/alterForeignKeyHelper.js @@ -7,8 +7,7 @@ const { assignTemplates } = require('../../utils/assignTemplates'); const getRelationshipName = relationship => { const compMod = relationship.role.compMod; - const name = compMod.code?.new || compMod.name?.new || relationship.role.code || relationship.role.name; - return name; + return compMod.code?.new || compMod.name?.new || relationship.role.code || relationship.role.name; }; const getFullChildTableName = relationship => { @@ -24,7 +23,6 @@ const getAddSingleForeignKeyStatementDto = relationship => { const relationshipName = getRelationshipName(relationship); const ddlProvider = require('../../ddlProvider/ddlProvider')(); - const schemaData = { schemaName: compMod.child.bucket.name, }; @@ -41,7 +39,6 @@ const getAddSingleForeignKeyStatementDto = relationship => { primaryTable: compMod.parent.collection.name, primarySchemaName: compMod.parent.bucket.name, primaryTableActivated: compMod.parent.collection.isActivated, - isActivated: Boolean(relationship.role?.compMod?.isActivated?.new), }, {}, schemaData, @@ -76,16 +73,14 @@ const getAddForeignKeyScriptDtos = addedRelationships => { const getDeleteSingleForeignKeyStatementDto = relationship => { const compMod = relationship.role.compMod; - const tableName = getFullChildTableName(relationship); - const relationshipName = getRelationshipName(relationship); - const fkConstraintName = wrapInQuotes(relationshipName); + const constraintName = wrapInQuotes(relationshipName); const statement = assignTemplates({ template: templates.dropForeignKey, templateData: { tableName, - fkConstraintName, + constraintName, }, }); @@ -102,7 +97,11 @@ const canRelationshipBeDeleted = relationship => { if (!compMod) { return false; } - return [compMod.code?.old || compMod.name?.old, compMod.child?.bucket, compMod.child?.collection].every(Boolean); + return [ + compMod.code?.old || compMod.name?.old || getRelationshipName(relationship), + compMod.child?.bucket, + compMod.child?.collection, + ].every(Boolean); }; const getDeleteForeignKeyScriptDtos = deletedRelationships => { diff --git a/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/alterColumnNameHelper.js b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/alterColumnNameHelper.js new file mode 100644 index 0000000..00b20e9 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/alterColumnNameHelper.js @@ -0,0 +1,60 @@ +const { toPairs } = require('lodash'); +const { + getSchemaOfAlterCollection, + getFullCollectionName, + isParentContainerActivated, + isObjectInDeltaModelActivated, + wrapInQuotes, +} = require('../../../utils/general'); +const templates = require('../../../ddlProvider/templates'); +const { AlterScriptDto } = require('../../types/AlterScriptDto'); +const { assignTemplates } = require('../../../utils/assignTemplates'); + +/** + * @param {string} tableName + * @param {string} oldColumnName + * @param {string} newColumnName + * @return string + */ +const alterColumnName = (tableName, oldColumnName, newColumnName) => { + return assignTemplates({ + template: templates.renameColumn, + templateData: { + tableName, + oldColumnName: wrapInQuotes(oldColumnName), + newColumnName: wrapInQuotes(newColumnName), + }, + }); +}; + +/** + * @param {Object} collection + * @return {Array} + */ +const getRenameColumnScriptDtos = collection => { + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(collectionSchema); + const isContainerActivated = isParentContainerActivated(collection); + const isCollectionActivated = isObjectInDeltaModelActivated(collection); + + return toPairs(collection.properties).map(([_, jsonSchema]) => { + if (!jsonSchema.compMod) { + return undefined; + } + const compMod = jsonSchema.compMod || {}; + const { newField = {}, oldField = {} } = compMod; + + if (newField.name && oldField.name && newField.name !== oldField.name) { + const isActivated = isContainerActivated && isCollectionActivated && jsonSchema.isActivated; + const script = alterColumnName(fullTableName, oldField.name, newField.name); + + return AlterScriptDto.getInstance([script], isActivated, false); + } + + return undefined; + }); +}; + +module.exports = { + getRenameColumnScriptDtos, +}; diff --git a/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/alterTypeHelper.js b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/alterTypeHelper.js new file mode 100644 index 0000000..cea2a67 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/alterTypeHelper.js @@ -0,0 +1,106 @@ +const { toPairs } = require('lodash'); +const { AlterScriptDto } = require('../../types/AlterScriptDto'); +const { + checkFieldPropertiesChanged, + getFullCollectionName, + wrapInQuotes, + isObjectInDeltaModelActivated, + isParentContainerActivated, + getSchemaOfAlterCollection, + getSchemaNameFromCollection, +} = require('../../../utils/general'); +const { assignTemplates } = require('../../../utils/assignTemplates'); +const templates = require('../../../ddlProvider/templates'); +const { createColumnDefinitionBySchema } = require('../createColumnDefinition'); +const { getColumnType } = require('../../../ddlProvider/ddlHelpers/columnDefinition/getColumnType'); + +/** + * @param {string} tableName + * @param {string} columnName + * @param {string} dataType + * @return string + */ +const alterColumnType = (tableName, columnName, dataType) => { + return assignTemplates({ + template: templates.updateColumnType, + templateData: { + tableName, + columnName, + dataType, + }, + }); +}; + +/** + * @return {boolean} + */ +const hasLengthChanged = (collection, oldFieldName, currentJsonSchema) => { + const oldProperty = collection.role.properties[oldFieldName]; + + const previousLength = oldProperty?.length; + const newLength = currentJsonSchema?.length; + return previousLength !== newLength; +}; + +/** + * @return {boolean} + */ +const hasPrecisionOrScaleChanged = (collection, oldFieldName, currentJsonSchema) => { + const oldProperty = collection.role.properties[oldFieldName]; + + const previousPrecision = oldProperty?.precision; + const newPrecision = currentJsonSchema?.precision; + const previousScale = oldProperty?.scale; + const newScale = currentJsonSchema?.scale; + + return previousPrecision !== newPrecision || previousScale !== newScale; +}; + +/** + * @param {Object} ddlProvider + * @return {(collection: Object) => Array} + */ +const getUpdateTypesScriptDtos = ddlProvider => collection => { + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(collectionSchema); + const isContainerActivated = isParentContainerActivated(collection); + const isCollectionActivated = isObjectInDeltaModelActivated(collection); + const schemaName = getSchemaNameFromCollection({ collection }); + const schemaData = { schemaName }; + + return toPairs(collection.properties) + .filter(([_, jsonSchema]) => { + if (!jsonSchema.compMod) { + return false; + } + const hasTypeChanged = checkFieldPropertiesChanged(jsonSchema.compMod, ['type', 'mode']); + if (!hasTypeChanged) { + const oldName = jsonSchema.compMod.oldField.name; + const isNewLength = hasLengthChanged(collection, oldName, jsonSchema); + const isNewPrecisionOrScale = hasPrecisionOrScaleChanged(collection, oldName, jsonSchema); + return isNewLength || isNewPrecisionOrScale; + } + return true; + }) + .map(([columnName, jsonSchema]) => { + const columnDefinition = createColumnDefinitionBySchema({ + name: columnName, + jsonSchema, + parentJsonSchema: collectionSchema, + ddlProvider, + schemaData, + }); + + const dataType = getColumnType(columnDefinition).trim(); + + const columnNameQuoted = wrapInQuotes(columnName); + const script = alterColumnType(fullTableName, columnNameQuoted, dataType); + const isActivated = isContainerActivated && isCollectionActivated && jsonSchema.isActivated; + + return AlterScriptDto.getInstance([script], isActivated, false); + }); +}; + +module.exports = { + getUpdateTypesScriptDtos, +}; diff --git a/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/defaultValueHelper.js b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/defaultValueHelper.js index cca83e2..ee02612 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/defaultValueHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/defaultValueHelper.js @@ -16,7 +16,7 @@ const templates = require('../../../ddlProvider/templates'); * @param {string} props.columnName * @param {string} props.defaultValue * @return string - * */ + */ const updateColumnDefaultValue = ({ tableName, columnName, defaultValue }) => { const templateConfig = { tableName, @@ -30,7 +30,7 @@ const updateColumnDefaultValue = ({ tableName, columnName, defaultValue }) => { * @param {Object} props * @param {Object} props.collection * @returns { Array } - * */ + */ const getUpdatedDefaultColumnValueScriptDtos = ({ collection }) => { const isContainerActivated = isParentContainerActivated(collection); const isCollectionActivated = isObjectInDeltaModelActivated(collection); @@ -62,7 +62,7 @@ const getUpdatedDefaultColumnValueScriptDtos = ({ collection }) => { * @param {string} props.tableName * @param {string} props.columnName * @return string - * */ + */ const dropColumnDefaultValue = ({ tableName, columnName }) => { const templateConfig = { tableName, @@ -75,7 +75,7 @@ const dropColumnDefaultValue = ({ tableName, columnName }) => { * @param {Object} props * @param {Object} props.collection * @returns { Array } - * */ + */ const getDeletedDefaultColumnValueScriptDtos = ({ collection }) => { const isContainerActivated = isParentContainerActivated(collection); const isCollectionActivated = isObjectInDeltaModelActivated(collection); @@ -106,7 +106,7 @@ const getDeletedDefaultColumnValueScriptDtos = ({ collection }) => { * @param {Object} props * @param {Object} props.collection * @returns { Array } - * */ + */ const getModifiedDefaultColumnValueScriptDtos = ({ collection }) => { const updatedDefaultValuesScriptDtos = getUpdatedDefaultColumnValueScriptDtos({ collection }); const dropDefaultValuesScriptDtos = getDeletedDefaultColumnValueScriptDtos({ collection }); diff --git a/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js index 6d38d13..7f901e8 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js @@ -14,7 +14,7 @@ const templates = require('../../../ddlProvider/templates'); * @param tableName {string} * @param columnName {string} * @return string - * */ + */ const setNotNullConstraint = (tableName, columnName) => { return assignTemplates({ template: templates.alterNotNull, @@ -29,7 +29,7 @@ const setNotNullConstraint = (tableName, columnName) => { * @param tableName {string} * @param columnName {string} * @return string - * */ + */ const dropNotNullConstraint = (tableName, columnName) => { return assignTemplates({ template: templates.dropNotNull, @@ -43,7 +43,7 @@ const dropNotNullConstraint = (tableName, columnName) => { /** * @param {Object} collection * @return {AlterScriptDto[]} - * */ + */ const getModifyNonNullColumnsScriptDtos = collection => { const collectionSchema = getSchemaOfAlterCollection(collection); const fullTableName = getFullCollectionName(collectionSchema); diff --git a/forward_engineering/alterScript/alterScriptHelpers/createColumnDefinition.js b/forward_engineering/alterScript/alterScriptHelpers/createColumnDefinition.js new file mode 100644 index 0000000..c7a5752 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/createColumnDefinition.js @@ -0,0 +1,105 @@ +const { isBoolean, isNumber } = require('lodash'); + +const createColumnDefinition = data => ({ + name: '', + type: '', + nullable: true, + primaryKey: false, + default: '', + length: '', + scale: '', + precision: '', + hasMaxLength: false, + expression: '', + ...data, +}); + +const isNullable = (parentSchema, propertyName) => { + if (!Array.isArray(parentSchema.required)) { + return true; + } + + return !parentSchema.required.includes(propertyName); +}; + +const getDefault = jsonSchema => { + const defaultValue = jsonSchema.default; + + if (isBoolean(defaultValue)) { + return defaultValue; + } else if (jsonSchema.default === null) { + return 'NULL'; + } + + return defaultValue; +}; + +const getLength = jsonSchema => { + if (isNumber(jsonSchema.length)) { + return jsonSchema.length; + } else if (isNumber(jsonSchema.maxLength)) { + return jsonSchema.maxLength; + } + + return ''; +}; + +const getScale = jsonSchema => { + if (isNumber(jsonSchema.scale)) { + return jsonSchema.scale; + } + + return ''; +}; + +const getPrecision = jsonSchema => { + if (isNumber(jsonSchema.precision)) { + return jsonSchema.precision; + } else if (isNumber(jsonSchema.fractSecPrecision)) { + return jsonSchema.fractSecPrecision; + } + + return ''; +}; + +const hasMaxLength = jsonSchema => { + if (jsonSchema.hasMaxLength) { + return jsonSchema.hasMaxLength; + } + + return ''; +}; + +const getType = jsonSchema => { + if (jsonSchema.$ref) { + return jsonSchema.$ref.split('/').pop(); + } + + return jsonSchema.mode || jsonSchema.childType || jsonSchema.type; +}; + +const createColumnDefinitionBySchema = ({ name, jsonSchema, parentJsonSchema, ddlProvider, schemaData }) => { + const columnDefinition = createColumnDefinition({ + name, + type: getType(jsonSchema), + nullable: isNullable(parentJsonSchema, name), + default: getDefault(jsonSchema), + primaryKey: jsonSchema.primaryKey, + length: getLength(jsonSchema), + scale: getScale(jsonSchema), + precision: getPrecision(jsonSchema), + hasMaxLength: hasMaxLength(jsonSchema), + isActivated: jsonSchema.isActivated, + expression: jsonSchema.expression, + }); + + return ddlProvider.hydrateColumn({ + columnDefinition, + jsonSchema, + schemaData: {}, + }); +}; + +module.exports = { + createColumnDefinitionBySchema, +}; diff --git a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/primaryKeyHelper.js b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/primaryKeyHelper.js index d760d9c..20e9b0e 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/primaryKeyHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/primaryKeyHelper.js @@ -77,11 +77,11 @@ const wasCompositePkChangedInTransitionFromCompositeToRegular = collection => { const wasCompositePkChangedInTransitionFromRegularToComposite = collection => { /** * @type {AlterCollectionRoleCompModPrimaryKey} - * */ + */ const pkDto = collection?.role?.compMod?.primaryKey || {}; /** * @type {AlterCollectionRoleCompModPKDto[]} - * */ + */ const newPrimaryKeys = pkDto.new || []; const idsOfColumns = newPrimaryKeys.flatMap(pk => pk.compositePrimaryKey?.map(dto => dto.keyId) || []); if (idsOfColumns.length !== amountOfColumnsInRegularPk) { @@ -142,7 +142,7 @@ const getCreateCompositePKDDLProviderConfig = (primaryKey, entityName, entity) = const getAddCompositePkScriptDtos = collection => { /** * @type {AlterCollectionRoleCompModPrimaryKey} - * */ + */ const pkDto = collection?.role?.compMod?.primaryKey || {}; const newPrimaryKeys = pkDto.new || []; const oldPrimaryKeys = pkDto.old || []; diff --git a/forward_engineering/alterScript/types/AlterKeyDto.js b/forward_engineering/alterScript/types/AlterKeyDto.js index 56e0421..5c21323 100644 --- a/forward_engineering/alterScript/types/AlterKeyDto.js +++ b/forward_engineering/alterScript/types/AlterKeyDto.js @@ -1,12 +1,12 @@ class KeyTransitionDto { /** * @type {boolean} - * */ + */ didTransitionHappen; /** * @return {KeyTransitionDto} - * */ + */ static noTransition() { return { didTransitionHappen: false, @@ -15,7 +15,7 @@ class KeyTransitionDto { /** * @return {KeyTransitionDto} - * */ + */ static transition() { return { didTransitionHappen: true, @@ -26,13 +26,13 @@ class KeyTransitionDto { class PrimaryKeyTransitionDto extends KeyTransitionDto { /** * @type {boolean | undefined} - * */ + */ wasPkChangedInTransition; /** * @param {boolean} wasPkChangedInTransition * @return {PrimaryKeyTransitionDto} - * */ + */ static transition(wasPkChangedInTransition) { return { didTransitionHappen: true, @@ -44,13 +44,13 @@ class PrimaryKeyTransitionDto extends KeyTransitionDto { class UniqueKeyTransitionDto extends KeyTransitionDto { /** * @type {boolean | undefined} - * */ + */ wasUniqueKeyChangedInTransition; /** * @param {boolean} wasUniqueKeyChangedInTransition * @return {UniqueKeyTransitionDto} - * */ + */ static transition(wasUniqueKeyChangedInTransition) { return { didTransitionHappen: true, @@ -62,22 +62,22 @@ class UniqueKeyTransitionDto extends KeyTransitionDto { class KeyScriptModificationDto { /** * @type {string} - * */ + */ script; /** * @type {boolean} - * */ + */ isDropScript; /** * @type {string} - * */ + */ fullTableName; /** * @type {boolean} - * */ + */ isActivated; /** @@ -85,7 +85,7 @@ class KeyScriptModificationDto { * @param {string} script * @param {boolean} isDropScript * @param {boolean} isActivated - * */ + */ constructor(script, fullTableName, isDropScript, isActivated) { this.script = script; this.isDropScript = isDropScript; diff --git a/forward_engineering/alterScript/types/AlterScriptDto.js b/forward_engineering/alterScript/types/AlterScriptDto.js index 599c33f..eca0f18 100644 --- a/forward_engineering/alterScript/types/AlterScriptDto.js +++ b/forward_engineering/alterScript/types/AlterScriptDto.js @@ -1,24 +1,24 @@ class ModificationScript { /** * @type string - * */ + */ script; /** * @type boolean - * */ + */ isDropScript; } class AlterScriptDto { /** * @type {boolean | undefined} - * */ + */ isActivated; /** * @type {Array} - * */ + */ scripts; /** @@ -26,7 +26,7 @@ class AlterScriptDto { * @param isActivated {boolean} * @param isDropScripts {boolean} * @return {Array} - * */ + */ static getInstances(scripts, isActivated, isDropScripts) { return (scripts || []).filter(Boolean).map(script => ({ isActivated, @@ -44,7 +44,7 @@ class AlterScriptDto { * @param isActivated {boolean} * @param isDropScripts {boolean} * @return {AlterScriptDto | undefined} - * */ + */ static getInstance(scripts, isActivated, isDropScripts) { if (!scripts?.filter(Boolean)?.length) { return undefined; @@ -63,11 +63,11 @@ class AlterScriptDto { * @param createScript {string | undefined} * @param isActivated {boolean} * @return {AlterScriptDto | undefined} - * */ + */ static getDropAndRecreateInstance(dropScript, createScript, isActivated) { /** * @type {ModificationScript[]} - * */ + */ const scriptModificationDtos = []; if (dropScript) { scriptModificationDtos.push({ diff --git a/forward_engineering/ddlProvider/ddlHelpers/key/constraintsHelper.js b/forward_engineering/ddlProvider/ddlHelpers/key/constraintsHelper.js index fcb1fc8..ebf1134 100644 --- a/forward_engineering/ddlProvider/ddlHelpers/key/constraintsHelper.js +++ b/forward_engineering/ddlProvider/ddlHelpers/key/constraintsHelper.js @@ -70,7 +70,7 @@ const alterUkConstraint = (tableName, isParentActivated, keyData) => { /** * @param tableName {string} * @param constraintName {string} - * */ + */ const dropUkConstraint = (tableName, constraintName) => { const templateData = { tableName, diff --git a/forward_engineering/ddlProvider/ddlProvider.js b/forward_engineering/ddlProvider/ddlProvider.js index 3f5287c..6933aed 100644 --- a/forward_engineering/ddlProvider/ddlProvider.js +++ b/forward_engineering/ddlProvider/ddlProvider.js @@ -407,6 +407,18 @@ module.exports = (baseProvider, options, app) => { }); }, + dropTable({ tableName }) { + return assignTemplates({ template: templates.dropTable, templateData: { tableName } }); + }, + + addColumn({ tableName, columnDefinition }) { + return assignTemplates({ template: templates.addColumn, templateData: { tableName, columnDefinition } }); + }, + + dropColumn({ tableName, columnName }) { + return assignTemplates({ template: templates.dropColumn, templateData: { tableName, columnName } }); + }, + hydrateIndex(indexData, tableData, schemaData) { return { ...indexData, schemaName: schemaData.schemaName }; }, diff --git a/forward_engineering/ddlProvider/templates.js b/forward_engineering/ddlProvider/templates.js index f4ab282..1d73c01 100644 --- a/forward_engineering/ddlProvider/templates.js +++ b/forward_engineering/ddlProvider/templates.js @@ -1,12 +1,18 @@ module.exports = { createSchema: 'CREATE SCHEMA ${schemaName}${authorization}${dataCapture};', - dropSchema: 'DROP SCHEMA ${schemaName} RESTRICT', + dropSchema: 'DROP SCHEMA ${schemaName} RESTRICT;', alterSchema: 'ALTER SCHEMA ${schemaName}${dataCapture};', createTable: 'CREATE${tableType} TABLE${ifNotExists} ${name}${tableProps}${tableOptions};', + dropTable: 'DROP TABLE ${tableName};', + + addColumn: 'ALTER TABLE ${tableName} ADD COLUMN ${columnDefinition};', + + dropColumn: 'ALTER TABLE ${tableName} DROP COLUMN ${columnName};', + createAuxiliaryTable: 'CREATE${tableType} TABLE ${name}${tableOptions};', comment: '\nCOMMENT ON ${objectType} ${objectName} IS ${comment};\n', @@ -18,7 +24,7 @@ module.exports = { createForeignKey: 'ALTER TABLE ${foreignTable} ADD CONSTRAINT ${name} FOREIGN KEY (${foreignKey}) REFERENCES ${primaryTable} (${primaryKey})${onDelete};', - dropForeignKey: 'ALTER TABLE {$tableName} DROP FOREIGN KEY ${constraintName};', + dropForeignKey: 'ALTER TABLE ${tableName} DROP FOREIGN KEY ${constraintName};', createForeignKeyConstraint: '${name} FOREIGN KEY (${foreignKey}) REFERENCES ${primaryTable} (${primaryKey})${onDelete}', @@ -49,7 +55,11 @@ module.exports = { dropCheckConstraint: 'ALTER TABLE ${tableName} DROP CHECK ${constraintName};', + updateColumnType: 'ALTER TABLE ${tableName} ALTER COLUMN ${columnName} SET DATA TYPE ${dataType};', + updateColumnDefaultValue: 'ALTER TABLE ${tableName} ALTER COLUMN ${columnName} SET DEFAULT ${defaultValue};', dropColumnDefaultValue: 'ALTER TABLE ${tableName} ALTER COLUMN ${columnName} DROP DEFAULT;', + + renameColumn: 'ALTER TABLE ${tableName} RENAME COLUMN ${oldColumnName} TO ${newColumnName};', }; diff --git a/forward_engineering/utils/general.js b/forward_engineering/utils/general.js index 76a365a..37aa491 100644 --- a/forward_engineering/utils/general.js +++ b/forward_engineering/utils/general.js @@ -146,6 +146,10 @@ const isParentContainerActivated = collection => { ); }; +const checkFieldPropertiesChanged = (compMod, propertiesToCheck) => { + return propertiesToCheck.some(prop => compMod?.oldField[prop] !== compMod?.newField[prop]); +}; + /** * * @template {object} T @@ -193,4 +197,5 @@ module.exports = { isParentContainerActivated, getSchemaNameFromCollection, getUpdatedProperties, + checkFieldPropertiesChanged, }; diff --git a/forward_engineering/utils/joinActivatedAndDeactivatedStatements.js b/forward_engineering/utils/joinActivatedAndDeactivatedStatements.js index ff95b9a..98f1e03 100644 --- a/forward_engineering/utils/joinActivatedAndDeactivatedStatements.js +++ b/forward_engineering/utils/joinActivatedAndDeactivatedStatements.js @@ -8,7 +8,7 @@ const { INLINE_COMMENT } = require('../../constants/constants'); * delimiter: string; * }} * @return {string} - * */ + */ const getDelimiter = ({ index, numberOfStatements, lastIndexOfActivatedStatement, delimiter }) => { const isLastStatement = index === numberOfStatements - 1; const isLastActivatedStatement = index === lastIndexOfActivatedStatement; @@ -31,7 +31,7 @@ const getDelimiter = ({ index, numberOfStatements, lastIndexOfActivatedStatement * indent?: string; * }} * @return {string} - * */ + */ const joinActivatedAndDeactivatedStatements = ({ statements, delimiter = ',', indent = '\n' }) => { const lastIndexOfActivatedStatement = statements.findLastIndex(statement => !statement.startsWith(INLINE_COMMENT)); const numberOfStatements = statements.length;