diff --git a/forward_engineering/alterScript/alterScriptFromDeltaHelper.js b/forward_engineering/alterScript/alterScriptFromDeltaHelper.js index fc1ab92..8207516 100644 --- a/forward_engineering/alterScript/alterScriptFromDeltaHelper.js +++ b/forward_engineering/alterScript/alterScriptFromDeltaHelper.js @@ -1,3 +1,4 @@ +const { getContainersScripts } = require('./alterScriptHelpers/alterContainerHelper'); const { getModifyCollectionScriptDtos, getModifyCollectionKeysScriptDtos, @@ -12,6 +13,37 @@ const { getModifyViewScriptDtos } = require('./alterScriptHelpers/alterViewHelpe const getItems = data => [data?.items].flat().filter(Boolean); +/** + * @param dto {{ + * collection: Object, + * app: App + * }} + * @return {AlterScriptDto[]} + * */ +const getAlterContainersScriptDtos = ({ collection, app }) => { + const { added, deleted, modified } = collection.properties?.containers?.properties || {}; + const addedContainers = getItems(added); + const deletedContainers = getItems(deleted); + const modifiedContainers = getItems(modified); + + const { getAddContainerScriptDto, getDeleteContainerScriptDto, getModifyContainerScriptDto } = + getContainersScripts(app); + + const addContainersScriptDtos = addedContainers + .map(container => Object.values(container.properties)[0]) + .flatMap(getAddContainerScriptDto); + + const deleteContainersScriptDtos = deletedContainers + .map(container => Object.values(container.properties)[0]) + .flatMap(getDeleteContainerScriptDto); + + const modifyContainersScriptDtos = modifiedContainers + .map(containerWrapper => Object.values(containerWrapper.properties)[0]) + .flatMap(getModifyContainerScriptDto); + + return [...addContainersScriptDtos, ...deleteContainersScriptDtos, ...modifyContainersScriptDtos].filter(Boolean); +}; + const getAlterCollectionScriptDtos = ({ collection, app, @@ -127,6 +159,8 @@ 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 collectionsScriptDtos = getAlterCollectionScriptDtos({ collection, app, @@ -143,7 +177,7 @@ const getAlterScriptDtos = (data, app) => { ignoreRelationshipIDs, }); - return [...collectionsScriptDtos, ...viewScriptDtos, ...relationshipScriptDtos] + return [...containersScriptDtos, ...collectionsScriptDtos, ...viewScriptDtos, ...relationshipScriptDtos] .filter(Boolean) .map(dto => dto && prettifyAlterScriptDto(dto)) .filter(Boolean); diff --git a/forward_engineering/alterScript/alterScriptHelpers/alterContainerHelper.js b/forward_engineering/alterScript/alterScriptHelpers/alterContainerHelper.js new file mode 100644 index 0000000..4ae357b --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/alterContainerHelper.js @@ -0,0 +1,67 @@ +const { isEmpty } = require('lodash'); +const ddlProvider = require('../../ddlProvider'); +const { AlterScriptDto } = require('../types/AlterScriptDto'); +const { + getSchemaCommentStatement, + getDeleteCommentStatement, +} = require('../../ddlProvider/ddlHelpers/comment/commentHelper'); +const { wrapInQuotes, getIsChangeProperties, getUpdatedProperties } = require('../../utils/general'); +const { getModifiedCommentOnSchemaScriptDtos } = require('./containerHelpers/commentsHelper'); + +const extractSchemaName = containerData => containerData.role.name; + +const getAddContainerScriptDto = ddlProvider => containerData => { + const schemaData = { + ...containerData.role, + schemaName: extractSchemaName(containerData), + }; + const script = ddlProvider.createSchema(schemaData); + + return AlterScriptDto.getInstance([script], true, false); +}; + +const getDeleteContainerScriptDto = ddlProvider => containerData => { + const script = ddlProvider.dropSchema({ name: extractSchemaName(containerData) }); + + return AlterScriptDto.getInstance([script], true, true); +}; + +const getModifyContainerScriptDto = ddlProvider => containerData => { + const scripts = []; + const compMod = containerData.role?.compMod || {}; + const schemaName = extractSchemaName(containerData); + const wrappedSchemaName = wrapInQuotes(schemaName); + const isActivated = containerData.isActivated !== false; + const updatedProperties = getUpdatedProperties(compMod, ['dataCapture']); + + if (!isEmpty(updatedProperties)) { + const alterDataCaptureScript = ddlProvider.alterSchema(schemaName, updatedProperties); + scripts.push(AlterScriptDto.getInstance([alterDataCaptureScript], isActivated, false)); + } + + const commentScript = getModifiedCommentOnSchemaScriptDtos({ + schemaName: wrappedSchemaName, + compMod, + isActivated, + }); + + if (commentScript) { + scripts.push(commentScript); + } + + return scripts; +}; + +const getContainersScripts = app => { + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + + return { + getAddContainerScriptDto: getAddContainerScriptDto(ddlProvider), + getDeleteContainerScriptDto: getDeleteContainerScriptDto(ddlProvider), + getModifyContainerScriptDto: getModifyContainerScriptDto(ddlProvider), + }; +}; + +module.exports = { + getContainersScripts, +}; diff --git a/forward_engineering/alterScript/alterScriptHelpers/containerHelpers/commentsHelper.js b/forward_engineering/alterScript/alterScriptHelpers/containerHelpers/commentsHelper.js new file mode 100644 index 0000000..479beab --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/containerHelpers/commentsHelper.js @@ -0,0 +1,26 @@ +const { AlterScriptDto } = require('../../types/AlterScriptDto'); +const { + getSchemaCommentStatement, + dropSchemaCommentStatement, +} = require('../../../ddlProvider/ddlHelpers/comment/commentHelper'); +const { wrapInQuotes } = require('../../../utils/general'); + +const getModifiedCommentOnSchemaScriptDtos = ({ schemaName, compMod, isActivated }) => { + const description = compMod.description || {}; + + if (description.new && description.new !== description.old) { + const script = getSchemaCommentStatement({ schemaName, description: description.new }); + return AlterScriptDto.getInstance([script], isActivated, false); + } + + if (description.old && !description.new) { + const script = dropSchemaCommentStatement({ schemaName }); + return AlterScriptDto.getInstance([script], isActivated, true); + } + + return undefined; +}; + +module.exports = { + getModifiedCommentOnSchemaScriptDtos, +}; diff --git a/forward_engineering/ddlProvider/ddlHelpers/comment/commentHelper.js b/forward_engineering/ddlProvider/ddlHelpers/comment/commentHelper.js index d6c8db8..3ca70c6 100644 --- a/forward_engineering/ddlProvider/ddlHelpers/comment/commentHelper.js +++ b/forward_engineering/ddlProvider/ddlHelpers/comment/commentHelper.js @@ -7,11 +7,20 @@ const { wrapInQuotes, commentIfDeactivated, wrapInSingleQuotes } = require('../. * @enum {string} */ const OBJECT_TYPE = { + schema: 'SCHEMA', column: 'COLUMN', table: 'TABLE', index: 'INDEX', }; +/** + * @enum {string} + */ +const COMMENT_MODE = { + set: 'set', + remove: 'remove', +}; + /** * @param {string} description * @returns {string} @@ -19,11 +28,11 @@ const OBJECT_TYPE = { const escapeSpecialCharacters = description => description.replace(/'/g, "''"); /** - * @param {{ objectName: string, objectType: OBJECT_TYPE, description?: string }} + * @param {{ objectName: string, objectType: OBJECT_TYPE, description?: string, mode?: COMMENT_MODE }} * @returns {string} */ -const getCommentStatement = ({ objectName, objectType, description }) => { - if (!description) { +const getCommentStatement = ({ objectName, objectType, description, mode = COMMENT_MODE.set }) => { + if (mode === COMMENT_MODE.set && !description) { return ''; } @@ -32,18 +41,23 @@ const getCommentStatement = ({ objectName, objectType, description }) => { templateData: { objectType, objectName: trim(objectName), - comment: wrapInSingleQuotes({ name: escapeSpecialCharacters(description) }), + comment: wrapInSingleQuotes({ name: escapeSpecialCharacters(description || '') }), }, }); }; /** - * @param {{ tableName, string, columnName: string, description?: string }} + * @param {{ tableName, columnName: string, description?: string }} * @returns {string} */ const getColumnCommentStatement = ({ tableName, columnName, description }) => { const objectName = tableName + '.' + wrapInQuotes(columnName); - return getCommentStatement({ objectName, objectType: OBJECT_TYPE.column, description }); + return getCommentStatement({ + objectName, + objectType: OBJECT_TYPE.column, + description, + mode: COMMENT_MODE.set, + }); }; /** @@ -51,7 +65,12 @@ const getColumnCommentStatement = ({ tableName, columnName, description }) => { * @returns {string} */ const getTableCommentStatement = ({ tableName, description }) => { - return getCommentStatement({ objectName: tableName, objectType: OBJECT_TYPE.table, description }); + return getCommentStatement({ + objectName: tableName, + objectType: OBJECT_TYPE.table, + description, + mode: COMMENT_MODE.set, + }); }; /** @@ -59,7 +78,25 @@ const getTableCommentStatement = ({ tableName, description }) => { * @returns {string} */ const getIndexCommentStatement = ({ indexName, description }) => { - return getCommentStatement({ objectName: indexName, objectType: OBJECT_TYPE.index, description }); + return getCommentStatement({ + objectName: indexName, + objectType: OBJECT_TYPE.index, + description, + mode: COMMENT_MODE.set, + }); +}; + +/** + * @param {{ schemaName: string, description?: string }} + * @returns {string} + */ +const getSchemaCommentStatement = ({ schemaName, description }) => { + return getCommentStatement({ + objectName: schemaName, + objectType: OBJECT_TYPE.schema, + description, + mode: COMMENT_MODE.set, + }); }; /** @@ -81,9 +118,24 @@ const getColumnComments = ({ tableName, columnDefinitions = [] }) => { .join('\n'); }; +/** + * @param {{ schemaName: string }} + * @returns {string} + */ +const dropSchemaCommentStatement = ({ schemaName }) => { + return getCommentStatement({ + objectName: schemaName, + objectType: OBJECT_TYPE.schema, + mode: COMMENT_MODE.remove, + }); +}; + module.exports = { getColumnCommentStatement, + getSchemaCommentStatement, getTableCommentStatement, getColumnComments, getIndexCommentStatement, + + dropSchemaCommentStatement, }; diff --git a/forward_engineering/ddlProvider/ddlProvider.js b/forward_engineering/ddlProvider/ddlProvider.js index dc487af..3f5287c 100644 --- a/forward_engineering/ddlProvider/ddlProvider.js +++ b/forward_engineering/ddlProvider/ddlProvider.js @@ -20,6 +20,7 @@ const { getTableCommentStatement, getColumnComments, getIndexCommentStatement, + getSchemaCommentStatement, } = require('./ddlHelpers/comment/commentHelper.js'); const { getTableProps } = require('./ddlHelpers/table/getTableProps.js'); const { getTableOptions } = require('./ddlHelpers/table/getTableOptions.js'); @@ -65,20 +66,46 @@ module.exports = (baseProvider, options, app) => { authorizationName: containerData.authorizationName, dataCapture: containerData.dataCapture, isActivated: containerData.isActivated, + description: containerData.description, }; }, - createSchema({ schemaName, ifNotExist, authorizationName, dataCapture, isActivated = true }) { + createSchema({ schemaName, ifNotExist, authorizationName, dataCapture, description, isActivated = true }) { + const wrappedSchemaName = wrapInQuotes(schemaName); const schemaStatement = assignTemplates({ template: templates.createSchema, templateData: { - schemaName: wrapInQuotes(schemaName), + schemaName: wrappedSchemaName, authorization: authorizationName ? ' AUTHORIZATION ' + authorizationName : '', dataCapture: dataCapture ? ' DATA CAPTURE ' + dataCapture : '', }, }); - return commentIfDeactivated(schemaStatement, { isActivated }); + const comment = getSchemaCommentStatement({ schemaName: wrappedSchemaName, description }); + const commentStatement = comment ? '\n' + comment + '\n' : '\n'; + + return commentIfDeactivated(schemaStatement + commentStatement, { isActivated }); + }, + + dropSchema({ name, isActivated = true }) { + const dropSchemaStatement = assignTemplates({ + template: templates.dropSchema, + templateData: { + schemaName: wrapInQuotes(name), + }, + }); + + return commentIfDeactivated(dropSchemaStatement, { isActivated }); + }, + + alterSchema(schemaName, { dataCapture }) { + return assignTemplates({ + template: templates.alterSchema, + templateData: { + schemaName: wrapInQuotes(schemaName), + dataCapture: dataCapture ? ' DATA CAPTURE ' + dataCapture : '', + }, + }); }, hydrateColumn({ columnDefinition, jsonSchema, schemaData, definitionJsonSchema = {} }) { diff --git a/forward_engineering/ddlProvider/templates.js b/forward_engineering/ddlProvider/templates.js index fe6725d..f4ab282 100644 --- a/forward_engineering/ddlProvider/templates.js +++ b/forward_engineering/ddlProvider/templates.js @@ -1,6 +1,10 @@ module.exports = { createSchema: 'CREATE SCHEMA ${schemaName}${authorization}${dataCapture};', + dropSchema: 'DROP SCHEMA ${schemaName} RESTRICT', + + alterSchema: 'ALTER SCHEMA ${schemaName}${dataCapture};', + createTable: 'CREATE${tableType} TABLE${ifNotExists} ${name}${tableProps}${tableOptions};', createAuxiliaryTable: 'CREATE${tableType} TABLE ${name}${tableOptions};', diff --git a/forward_engineering/utils/general.js b/forward_engineering/utils/general.js index dab44a8..76a365a 100644 --- a/forward_engineering/utils/general.js +++ b/forward_engineering/utils/general.js @@ -1,4 +1,4 @@ -const { toLower, omit } = require('lodash'); +const { toLower, omit, isEqual } = require('lodash'); const { INLINE_COMMENT } = require('../../constants/constants'); /** @@ -146,6 +146,33 @@ const isParentContainerActivated = collection => { ); }; +/** + * + * @template {object} T + * @param {{ new: T, old: T }} + * @returns {boolean} + */ +const compareProperties = ({ new: newProperty, old: oldProperty }) => { + if (!newProperty && !oldProperty) { + return; + } + return !isEqual(newProperty, oldProperty); +}; + +/** + * @param {object} compMod + * @param {string[]} properties + * @returns {object} Only changed properties with their new values + */ +const getUpdatedProperties = (compMod, properties) => + properties.reduce((acc, property) => { + const propCompMod = compMod[property] || {}; + if (compareProperties(propCompMod) && propCompMod.new !== undefined) { + acc[property] = propCompMod.new; + } + return acc; + }, {}); + module.exports = { setTab, hasType, @@ -165,4 +192,5 @@ module.exports = { isObjectInDeltaModelActivated, isParentContainerActivated, getSchemaNameFromCollection, + getUpdatedProperties, };