From 9164c0c62dbd67f5b371cf87ef1c7dd04c54677f Mon Sep 17 00:00:00 2001 From: chulanovskyi Date: Tue, 4 Nov 2025 01:17:37 +0200 Subject: [PATCH 01/10] feat: added script generation options --- forward_engineering/config.json | 433 +++++++++++++++++++++++++++++++- 1 file changed, 432 insertions(+), 1 deletion(-) diff --git a/forward_engineering/config.json b/forward_engineering/config.json index bf877b1..3100863 100644 --- a/forward_engineering/config.json +++ b/forward_engineering/config.json @@ -38,5 +38,436 @@ "compMode": { "entity": true, "container": 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": { + "type": "or", + "values": [ + { + "key": "chkConstr", + "valueType": "array" + }, + { + "key": "checkConstraint", + "valueType": "array" + } + ] + }, + "defaultValue": { + "chkConstr": [], + "checkConstraint": [] + } + } + ] + }, + { + "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": true, + "disabled": false, + "disabledLabel": "" + }, + "separate": { + "default": false, + "disabled": false, + "disabledLabel": "" + }, + "ignore": { + "default": false, + "disabled": false, + "disabledLabel": "" + } + }, + "adapters": [ + { + "dependency": { + "type": "and", + "values": [ + { + "key": "type", + "value": "bucket" + }, + { + "key": "description", + "exist": true + } + ] + }, + "defaultValue": { + "description": "" + } + } + ] + }, + { + "keyword": "tableComments", + "label": "FE_SCRIPT_GENERATION_OPTIONS___TABLE_COMMENTS", + "disabled": false, + "value": { + "inline": { + "default": true, + "disabled": false, + "disabledLabel": "" + }, + "separate": { + "default": false, + "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": true, + "disabled": false, + "disabledLabel": "" + }, + "separate": { + "default": false, + "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": true, + "disabled": false, + "disabledLabel": "" + }, + "separate": { + "default": false, + "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": "" + } + } + ] + } + ] } From 808cdb109b6a03373fa3d9bac43f8bbec4aa7c9b Mon Sep 17 00:00:00 2001 From: chulanovskyi Date: Tue, 4 Nov 2025 01:26:17 +0200 Subject: [PATCH 02/10] chore: untangled dependencies, resolved sonar remarks --- forward_engineering/api.js | 3 + forward_engineering/dbtProvider.js | 23 +- forward_engineering/ddlProvider.js | 96 +-- .../helpers/alterScriptFromDeltaHelper.js | 58 +- .../alterContainerHelper.js | 6 +- .../alterScriptHelpers/alterEntityHelper.js | 28 +- .../alterScriptHelpers/alterViewHelper.js | 10 +- .../helpers/alterScriptHelpers/common.js | 2 +- .../createColumnDefinition.js | 27 +- .../helpers/applyToInstanceHelper.js | 8 +- .../helpers/columnDefinitionHelper.js | 8 +- .../helpers/commentIfDeactivated.js | 4 +- .../helpers/constraintsHelper.js | 112 ++-- forward_engineering/helpers/general.js | 452 +++++++------- .../helpers/ifNotExistStatementHelper.js | 73 ++- forward_engineering/helpers/indexHelper.js | 570 +++++++++--------- forward_engineering/helpers/keyHelper.js | 438 +++++++------- forward_engineering/utils/assignTemplates.js | 15 + forward_engineering/utils/general.js | 42 ++ 19 files changed, 1004 insertions(+), 971 deletions(-) create mode 100644 forward_engineering/utils/assignTemplates.js create mode 100644 forward_engineering/utils/general.js diff --git a/forward_engineering/api.js b/forward_engineering/api.js index 2cbe6d6..c5b4c31 100644 --- a/forward_engineering/api.js +++ b/forward_engineering/api.js @@ -39,9 +39,11 @@ module.exports = { callback({ message: error.message, stack: error.stack }); } }, + generateViewScript(data, logger, callback, app) { callback(new Error('Forward-Engineering of delta model on view level is not supported')); }, + generateContainerScript(data, logger, callback, app) { try { data.jsonSchema = data.collections[0]; @@ -56,6 +58,7 @@ module.exports = { callback({ message: error.message, stack: error.stack }); } }, + isDropInStatements(data, logger, callback, app) { try { const cb = (error, script = '') => diff --git a/forward_engineering/dbtProvider.js b/forward_engineering/dbtProvider.js index 461ac9b..9716b13 100644 --- a/forward_engineering/dbtProvider.js +++ b/forward_engineering/dbtProvider.js @@ -8,27 +8,14 @@ const { toLower, toUpper } = require('lodash'); const types = require('./configs/types'); const defaultTypes = require('./configs/defaultTypes'); const { decorateType } = require('./helpers/columnDefinitionHelper'); -const getKeyHelper = require('./helpers/keyHelper'); +const keyHelper = require('./helpers/keyHelper'); class DbtProvider { /** - * @type {AppInstance} - */ - #appInstance; - - /** - * @param {{ appInstance: AppInstance }} - */ - constructor({ appInstance }) { - this.#appInstance = appInstance; - } - - /** - * @param {{ appInstance }} * @returns {DbtProvider} */ - static createDbtProvider({ appInstance }) { - return new DbtProvider({ appInstance }); + static createDbtProvider() { + return new DbtProvider(); } /** @@ -67,8 +54,6 @@ class DbtProvider { * @returns {ConstraintDto[]} */ getCompositeKeyConstraints({ jsonSchema }) { - const keyHelper = getKeyHelper(this.#appInstance); - return keyHelper.getCompositeKeyConstraints({ jsonSchema }); } @@ -77,8 +62,6 @@ class DbtProvider { * @returns {ConstraintDto[]} */ getColumnConstraints({ columnDefinition, jsonSchema }) { - const keyHelper = getKeyHelper(this.#appInstance); - return keyHelper.getColumnConstraints({ columnDefinition }); } } diff --git a/forward_engineering/ddlProvider.js b/forward_engineering/ddlProvider.js index e626463..afe515e 100644 --- a/forward_engineering/ddlProvider.js +++ b/forward_engineering/ddlProvider.js @@ -4,42 +4,46 @@ const types = require('./configs/types'); const templates = require('./configs/templates'); const { commentIfDeactivated } = require('./helpers/commentIfDeactivated'); const { joinActivatedAndDeactivatedStatements } = require('./utils/joinActivatedAndDeactivatedStatements'); +const { getTerminator } = require('./helpers/optionsHelper'); +const { assignTemplates } = require('./utils/assignTemplates'); +const { clean, divideIntoActivatedAndDeactivated, tab } = require('./utils/general'); +const keyHelper = require('./helpers/keyHelper'); +const { + wrapIfNotExistDatabase, + wrapIfNotExistSchema, + wrapIfNotExistTable, + wrapIfNotExistView, +} = require('./helpers/ifNotExistStatementHelper'); +const { + canHaveIdentity, + decorateDefault, + decorateType, + getEncryptedWith, + getIdentity, +} = require('./helpers/columnDefinitionHelper'); +const { + checkIndexActivated, + getCollation, + getDefaultConstraints, + getTableName, + getTableOptions, + getViewData, + hasType, + setPersistenceSpecificName, +} = require('./helpers/general'); +const { + createMemoryOptimizedIndex, + createTableIndex, + getMemoryOptimizedIndexes, + hydrateTableIndex, +} = require('./helpers/indexHelper'); +const { + createKeyConstraint, + createDefaultConstraint, + generateConstraintsString, +} = require('./helpers/constraintsHelper'); const provider = (baseProvider, options, app) => { - const { getTerminator } = require('./helpers/optionsHelper'); - const { assignTemplates } = app.require('@hackolade/ddl-fe-utils'); - const { divideIntoActivatedAndDeactivated, clean, tab } = app.require('@hackolade/ddl-fe-utils').general; - - const { wrapIfNotExistSchema, wrapIfNotExistDatabase, wrapIfNotExistTable, wrapIfNotExistView } = - require('./helpers/ifNotExistStatementHelper')(app); - - const { - decorateType, - getIdentity, - getEncryptedWith, - decorateDefault, - canHaveIdentity, - } = require('./helpers/columnDefinitionHelper'); - - const { getMemoryOptimizedIndexes, createMemoryOptimizedIndex, hydrateTableIndex, createTableIndex } = - require('./helpers/indexHelper')(app); - - const { - getTableName, - getTableOptions, - hasType, - getDefaultConstraints, - checkIndexActivated, - getViewData, - getCollation, - setPersistenceSpecificName, - } = require('./helpers/general')(app); - - const { createKeyConstraint, createDefaultConstraint, generateConstraintsString } = - require('./helpers/constraintsHelper')(app); - - const keyHelper = require('./helpers/keyHelper')(app); - const terminator = getTerminator(options); return { @@ -143,17 +147,17 @@ const provider = (baseProvider, options, app) => { : getTableName(columnDefinition.type, columnDefinition.schemaName); const notNull = columnDefinition.nullable ? '' : ' NOT NULL'; const primaryKey = columnDefinition.primaryKey ? ' PRIMARY KEY NONCLUSTERED NOT ENFORCED' : ''; - const defaultValue = !_.isUndefined(columnDefinition.default) - ? ' DEFAULT ' + decorateDefault(type, columnDefinition.default) - : ''; + const defaultValue = _.isUndefined(columnDefinition.default) + ? '' + : ' DEFAULT ' + decorateDefault(type, columnDefinition.default); const sparse = columnDefinition.sparse ? ' SPARSE' : ''; const maskedWithFunction = columnDefinition.maskedWithFunction ? ` MASKED WITH (FUNCTION='${columnDefinition.maskedWithFunction}')` : ''; const identityContainer = columnDefinition.identity && { identity: getIdentity(columnDefinition.identity) }; - const encryptedWith = !_.isEmpty(columnDefinition.encryption) - ? getEncryptedWith(columnDefinition.encryption[0]) - : ''; + const encryptedWith = _.isEmpty(columnDefinition.encryption) + ? '' + : getEncryptedWith(columnDefinition.encryption[0]); const unique = columnDefinition.unique ? ' UNIQUE NOT ENFORCED' : ''; return commentIfDeactivated( @@ -177,7 +181,7 @@ const provider = (baseProvider, options, app) => { createIndex(tableName, index, dbData, isParentActivated = true) { const isActivated = checkIndexActivated(index); if (!isParentActivated) { - return createTableIndex(terminator, tableName, index, isActivated && isParentActivated); + return createTableIndex(terminator, tableName, index, isParentActivated); } return commentIfDeactivated( createTableIndex(terminator, tableName, index, isActivated && isParentActivated), @@ -312,7 +316,8 @@ const provider = (baseProvider, options, app) => { const isTempTableEndTimeColumnHidden = _.get(parentJsonSchema, 'periodForSystemTime[0].startTime[0].type', '') === 'hidden'; - return Object.assign({}, columnDefinition, { + return { + ...columnDefinition, default: jsonSchema.defaultConstraintName ? '' : columnDefinition.default, defaultConstraint: { name: jsonSchema.defaultConstraintName, @@ -350,7 +355,7 @@ const provider = (baseProvider, options, app) => { increment: Number(_.get(jsonSchema, 'identity.identityIncrement', 0)), }, }), - }); + }; }, hydrateIndex(indexData, tableData, schemaData) { @@ -388,7 +393,8 @@ const provider = (baseProvider, options, app) => { idToNameHashTable[_.get(jsonSchema, 'periodForSystemTime[0].startTime[0].keyId', '')]; const temporalTableTimeEndColumnName = idToNameHashTable[_.get(jsonSchema, 'periodForSystemTime[0].endTime[0].keyId', '')]; - return Object.assign({}, tableData, { + return { + ...tableData, foreignKeyConstraints: tableData.foreignKeyConstraints || [], keyConstraints: keyHelper.getTableKeyConstraints({ jsonSchema }), defaultConstraints: getDefaultConstraints(tableData.columnDefinitions), @@ -424,7 +430,7 @@ const provider = (baseProvider, options, app) => { memoryOptimizedIndexes: isMemoryOptimized ? getMemoryOptimizedIndexes(entityData, tableData.schemaData) : [], - }); + }; }, hydrateViewColumn(data) { diff --git a/forward_engineering/helpers/alterScriptFromDeltaHelper.js b/forward_engineering/helpers/alterScriptFromDeltaHelper.js index 6dd5717..46110e4 100644 --- a/forward_engineering/helpers/alterScriptFromDeltaHelper.js +++ b/forward_engineering/helpers/alterScriptFromDeltaHelper.js @@ -7,17 +7,18 @@ const getAlterContainersScripts = (collection, app, options) => { const addedContainers = collection.properties?.containers?.properties?.added?.items; const deletedContainers = collection.properties?.containers?.properties?.deleted?.items; - const addContainersScripts = [] - .concat(addedContainers) + const addContainersScripts = [addedContainers] + .flat() .filter(Boolean) .map(container => ({ ...Object.values(container.properties)[0], name: Object.keys(container.properties)[0] })) .map(getAddContainerScript); - const deleteContainersScripts = [] - .concat(deletedContainers) + + const deleteContainersScripts = [deletedContainers] + .flat() .filter(Boolean) .map(container => getDeleteContainerScript(Object.keys(container.properties)[0])); - return [].concat(addContainersScripts).concat(deleteContainersScripts); + return [...addContainersScripts, ...deleteContainersScripts]; }; const getAlterCollectionsScripts = (collection, app, options) => { @@ -30,38 +31,43 @@ const getAlterCollectionsScripts = (collection, app, options) => { getModifyCollectionScript, } = require('./alterScriptHelpers/alterEntityHelper')(app, options); - const createCollectionsScripts = [] - .concat(collection.properties?.entities?.properties?.added?.items) + const createCollectionsScripts = [collection.properties?.entities?.properties?.added?.items] + .flat() .filter(Boolean) .map(item => Object.values(item.properties)[0]) .filter(collection => collection.compMod?.created) .map(getAddCollectionScript); - const deleteCollectionScripts = [] - .concat(collection.properties?.entities?.properties?.deleted?.items) + + const deleteCollectionScripts = [collection.properties?.entities?.properties?.deleted?.items] + .flat() .filter(Boolean) .map(item => Object.values(item.properties)[0]) .filter(collection => collection.compMod?.deleted) .map(getDeleteCollectionScript); - const modifyCollectionScripts = [] - .concat(collection.properties?.entities?.properties?.modified?.items) + + const modifyCollectionScripts = [collection.properties?.entities?.properties?.modified?.items] + .flat() .filter(Boolean) .map(item => Object.values(item.properties)[0]) .filter(collection => collection.compMod?.modified) .map(getModifyCollectionScript); - const addColumnScripts = [] - .concat(collection.properties?.entities?.properties?.added?.items) + + const addColumnScripts = [collection.properties?.entities?.properties?.added?.items] + .flat() .filter(Boolean) .map(item => Object.values(item.properties)[0]) .filter(collection => !collection.compMod?.created) .flatMap(getAddColumnScript); - const deleteColumnScripts = [] - .concat(collection.properties?.entities?.properties?.deleted?.items) + + const deleteColumnScripts = [collection.properties?.entities?.properties?.deleted?.items] + .flat() .filter(Boolean) .map(item => Object.values(item.properties)[0]) .filter(collection => !collection.compMod?.deleted) .flatMap(getDeleteColumnScript); - const modifyColumnScript = [] - .concat(collection.properties?.entities?.properties?.modified?.items) + + const modifyColumnScript = [collection.properties?.entities?.properties?.modified?.items] + .flat() .filter(Boolean) .map(item => Object.values(item.properties)[0]) .flatMap(getModifyColumnScript); @@ -82,27 +88,27 @@ const getAlterViewScripts = (collection, app, options) => { const { getAddViewScript, getDeleteViewScript, getModifiedViewScript } = require('./alterScriptHelpers/alterViewHelper')(app, options); - const createViewsScripts = [] - .concat(collection.properties?.views?.properties?.added?.items) + const createViewsScripts = [collection.properties?.views?.properties?.added?.items] + .flat() .filter(Boolean) .map(item => Object.values(item.properties)[0]) - .map(view => ({ ...view, ...(view.role || {}) })) + .map(view => ({ ...view, ...view.role })) .filter(view => view.compMod?.created) .map(getAddViewScript); - const deleteViewsScripts = [] - .concat(collection.properties?.views?.properties?.deleted?.items) + const deleteViewsScripts = [collection.properties?.views?.properties?.deleted?.items] + .flat() .filter(Boolean) .map(item => Object.values(item.properties)[0]) - .map(view => ({ ...view, ...(view.role || {}) })) + .map(view => ({ ...view, ...view.role })) .filter(view => view.compMod?.deleted) .map(getDeleteViewScript); - const modifiedViewsScripts = [] - .concat(collection.properties?.views?.properties?.modified?.items) + const modifiedViewsScripts = [collection.properties?.views?.properties?.modified?.items] + .flat() .filter(Boolean) .map(item => Object.values(item.properties)[0]) - .map(view => ({ ...view, ...(view.role || {}) })) + .map(view => ({ ...view, ...view.role })) .filter(view => !view.compMod?.created && !view.compMod?.deleted) .map(getModifiedViewScript); diff --git a/forward_engineering/helpers/alterScriptHelpers/alterContainerHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterContainerHelper.js index 0425174..a06eeee 100644 --- a/forward_engineering/helpers/alterScriptHelpers/alterContainerHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/alterContainerHelper.js @@ -1,7 +1,7 @@ const _ = require('lodash'); +const { getDbData } = require('../../utils/general'); -module.exports = (app, options) => { - const { getDbData } = app.require('@hackolade/ddl-fe-utils').general; +const alterContainerHelper = (app, options) => { const ddlProvider = require('../../ddlProvider')(null, options, app); const getAddContainerScript = containerData => { @@ -20,3 +20,5 @@ module.exports = (app, options) => { getDeleteContainerScript, }; }; + +module.exports = alterContainerHelper; diff --git a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js index 36b130d..b458109 100644 --- a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js @@ -1,17 +1,17 @@ const _ = require('lodash'); +const { getTableName } = require('../general'); +const { getEntityName } = require('../../utils/general'); +const { createColumnDefinitionBySchema } = require('./createColumnDefinition'); +const { checkFieldPropertiesChanged, modifyGroupItems, setIndexKeys } = require('./common'); -module.exports = (app, options) => { - const { getEntityName } = app.require('@hackolade/ddl-fe-utils').general; - const { createColumnDefinitionBySchema } = require('./createColumnDefinition'); - const { getTableName } = require('../general')(app); +const alterEntityHelper = (app, options) => { const ddlProvider = require('../../ddlProvider')(null, options, app); const { generateIdToNameHashTable, generateIdToActivatedHashTable } = app.require('@hackolade/ddl-fe-utils'); - const { checkFieldPropertiesChanged, modifyGroupItems, setIndexKeys } = require('./common'); const getAddCollectionScript = collection => { const schemaName = collection.compMod.keyspaceName; const schemaData = { schemaName }; - const jsonSchema = { ...collection, ...(collection?.role || {}) }; + const jsonSchema = { ...collection, ...collection?.role }; const tableName = getEntityName(jsonSchema); const idToNameHashTable = generateIdToNameHashTable(jsonSchema); const idToActivatedHashTable = generateIdToActivatedHashTable(jsonSchema); @@ -52,7 +52,7 @@ module.exports = (app, options) => { }; const getDeleteCollectionScript = collection => { - const jsonSchema = { ...collection, ...(collection?.role || {}) }; + const jsonSchema = { ...collection, ...collection?.role }; const tableName = getEntityName(jsonSchema); const schemaName = collection.compMod.keyspaceName; const fullName = getTableName(tableName, schemaName); @@ -61,7 +61,7 @@ module.exports = (app, options) => { }; const getModifyCollectionScript = collection => { - const jsonSchema = { ...collection, ...(collection?.role || {}) }; + const jsonSchema = { ...collection, ...collection?.role }; const schemaName = collection.compMod.keyspaceName; const schemaData = { schemaName }; const idToNameHashTable = generateIdToNameHashTable(jsonSchema); @@ -84,11 +84,11 @@ module.exports = (app, options) => { drop: (tableName, index) => ddlProvider.dropIndex(tableName, index), }); - return [].concat(indexesScripts).filter(Boolean).join('\n\n'); + return [indexesScripts].flat().filter(Boolean).join('\n\n'); }; const getAddColumnScript = collection => { - const collectionSchema = { ...collection, ...(_.omit(collection?.role, 'properties') || {}) }; + const collectionSchema = { ...collection, ..._.omit(collection?.role, 'properties') }; const tableName = collectionSchema?.code || collectionSchema?.collectionName || collectionSchema?.name; const schemaName = collectionSchema.compMod?.keyspaceName; const fullName = getTableName(tableName, schemaName); @@ -110,7 +110,7 @@ module.exports = (app, options) => { }; const getDeleteColumnScript = collection => { - const collectionSchema = { ...collection, ...(_.omit(collection?.role, 'properties') || {}) }; + const collectionSchema = { ...collection, ..._.omit(collection?.role, 'properties') }; const tableName = collectionSchema?.code || collectionSchema?.collectionName || collectionSchema?.name; const schemaName = collectionSchema.compMod?.keyspaceName; const fullName = getTableName(tableName, schemaName); @@ -121,7 +121,7 @@ module.exports = (app, options) => { }; const getModifyColumnScript = collection => { - const collectionSchema = { ...collection, ...(_.omit(collection?.role, 'properties') || {}) }; + const collectionSchema = { ...collection, ..._.omit(collection?.role, 'properties') }; const tableName = collectionSchema?.code || collectionSchema?.collectionName || collectionSchema?.name; const schemaName = collectionSchema.compMod?.keyspaceName; const fullName = getTableName(tableName, schemaName); @@ -134,7 +134,7 @@ module.exports = (app, options) => { ); const changeTypeScripts = _.toPairs(collection.properties) - .filter(([name, jsonSchema]) => checkFieldPropertiesChanged(jsonSchema.compMod, ['type', 'mode'])) + .filter(([, jsonSchema]) => checkFieldPropertiesChanged(jsonSchema.compMod, ['type', 'mode'])) .map(([name, jsonSchema]) => { const columnDefinition = createColumnDefinitionBySchema({ name, @@ -167,3 +167,5 @@ module.exports = (app, options) => { getModifyColumnScript, }; }; + +module.exports = alterEntityHelper; diff --git a/forward_engineering/helpers/alterScriptHelpers/alterViewHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterViewHelper.js index 2826e1a..f48f429 100644 --- a/forward_engineering/helpers/alterScriptHelpers/alterViewHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/alterViewHelper.js @@ -1,13 +1,13 @@ const _ = require('lodash'); +const { getTableName } = require('../general'); -module.exports = (app, options) => { +const alterViewHelper = (app, options) => { const { mapProperties } = app.require('@hackolade/ddl-fe-utils'); const { checkCompModEqual } = require('./common'); const ddlProvider = require('../../ddlProvider')(null, options, app); - const { getTableName } = require('../general')(app); const getAddViewScript = view => { - const viewSchema = { ...view, ...(view.role ?? {}) }; + const viewSchema = { ...view, ...view.role }; const viewData = { name: viewSchema.code || viewSchema.name, @@ -26,7 +26,7 @@ module.exports = (app, options) => { }; const getModifiedViewScript = view => { - const viewSchema = { ...view, ...(view.role ?? {}) }; + const viewSchema = { ...view, ...view.role }; const schemaData = { schemaName: viewSchema.compMod.keyspaceName }; const viewData = { name: viewSchema.code || viewSchema.name, @@ -97,3 +97,5 @@ module.exports = (app, options) => { getModifiedViewScript, }; }; + +module.exports = alterViewHelper; diff --git a/forward_engineering/helpers/alterScriptHelpers/common.js b/forward_engineering/helpers/alterScriptHelpers/common.js index dd303e9..17b3287 100644 --- a/forward_engineering/helpers/alterScriptHelpers/common.js +++ b/forward_engineering/helpers/alterScriptHelpers/common.js @@ -14,7 +14,7 @@ const modifyGroupItems = ({ data, key, hydrate, drop, create }) => { const addedScripts = added.map(item => create(parentName, item)); const modifiedScripts = modified.map(item => create(parentName, { ...item, orReplace: true })); - return [].concat(modifiedScripts).concat(removedScripts).concat(addedScripts).filter(Boolean).join('\n\n'); + return [modifiedScripts].flat().concat(removedScripts).concat(addedScripts).filter(Boolean).join('\n\n'); }; const getModifiedGroupItems = ({ new: newItems = [], old: oldItems = [] }, hydrate) => { diff --git a/forward_engineering/helpers/alterScriptHelpers/createColumnDefinition.js b/forward_engineering/helpers/alterScriptHelpers/createColumnDefinition.js index b731478..79c2450 100644 --- a/forward_engineering/helpers/alterScriptHelpers/createColumnDefinition.js +++ b/forward_engineering/helpers/alterScriptHelpers/createColumnDefinition.js @@ -1,20 +1,18 @@ const { isBoolean, isNumber } = require('lodash'); const createColumnDefinition = data => { - return Object.assign( - { - name: '', - type: '', - nullable: true, - primaryKey: false, - default: '', - length: '', - scale: '', - precision: '', - hasMaxLength: false, - }, - data, - ); + return { + name: '', + type: '', + nullable: true, + primaryKey: false, + default: '', + length: '', + scale: '', + precision: '', + hasMaxLength: false, + ...data, + }; }; const isNullable = (parentSchema, propertyName) => { @@ -101,6 +99,7 @@ const createColumnDefinitionBySchema = ({ name, jsonSchema, parentJsonSchema, dd schemaData, }); }; + module.exports = { createColumnDefinitionBySchema, }; diff --git a/forward_engineering/helpers/applyToInstanceHelper.js b/forward_engineering/helpers/applyToInstanceHelper.js index d1b1fdc..9ece971 100644 --- a/forward_engineering/helpers/applyToInstanceHelper.js +++ b/forward_engineering/helpers/applyToInstanceHelper.js @@ -26,21 +26,23 @@ const applyToInstance = async (connectionInfo, logger, app) => { } }; +const isGoStatement = query => query.endsWith(GO_STATEMENT) && query.length === 2; + const getQueries = (script = '') => { script = filterDeactivatedQuery(script); + const queries = script .split('\n\n') .map(script => script.trim()) .filter(query => { - if (!Boolean(query)) { - return false; - } else if (query.endsWith(GO_STATEMENT) && query.length === 2) { + if (!query || isGoStatement(query)) { return false; } return !queryIsDeactivated(query); }) .map(query => (query.endsWith(GO_STATEMENT) ? query.slice(0, -3) + ';' : query)); + return queries; }; diff --git a/forward_engineering/helpers/columnDefinitionHelper.js b/forward_engineering/helpers/columnDefinitionHelper.js index 0840775..99a0cbd 100644 --- a/forward_engineering/helpers/columnDefinitionHelper.js +++ b/forward_engineering/helpers/columnDefinitionHelper.js @@ -58,7 +58,7 @@ const decorateType = (type, columnDefinition) => { const isString = type => ['CHAR', 'VARCHAR', 'NCHAR', 'NVARCHAR', 'TEXT', 'NTEXT'].includes(_.toUpper(type)); -const escapeQuotes = str => _.trim(str).replace(/(\')+/g, "'$1"); +const escapeQuotes = str => _.trim(str).replaceAll(/(')+/g, "'$1"); const decorateDefault = (type, defaultValue) => { if (isString(type) && defaultValue !== 'NULL') { @@ -83,10 +83,10 @@ const addClustered = (statement, columnDefinition) => { return ''; } - if (!columnDefinition.clustered) { - return statement + ' NONCLUSTERED'; - } else { + if (columnDefinition.clustered) { return statement + ' CLUSTERED'; + } else { + return statement + ' NONCLUSTERED'; } }; diff --git a/forward_engineering/helpers/commentIfDeactivated.js b/forward_engineering/helpers/commentIfDeactivated.js index cb75603..a5cefbe 100644 --- a/forward_engineering/helpers/commentIfDeactivated.js +++ b/forward_engineering/helpers/commentIfDeactivated.js @@ -1,5 +1,5 @@ const BEFORE_DEACTIVATED_STATEMENT = '-- '; -const REG_FOR_MULTYLINE_COMMENT = /(\n\/\*\n[\s\S]*?\n\s\*\/\n)|((\n\/\*\n[\s\S]*?\n\s\*\/)$)/gi; +const REG_FOR_MULTILINE_COMMENT = /(\n\/\*\n[\s\S]*?\n\s\*\/\n)|((\n\/\*\n[\s\S]*?\n\s\*\/)$)/gi; const commentIfDeactivated = (statement, data, isPartOfLine) => { if (data.isActivated === false) { @@ -18,7 +18,7 @@ const queryIsDeactivated = (query = '') => { return query.startsWith(BEFORE_DEACTIVATED_STATEMENT); }; -const filterDeactivatedQuery = query => query.replace(REG_FOR_MULTYLINE_COMMENT, ''); +const filterDeactivatedQuery = query => query.replaceAll(REG_FOR_MULTILINE_COMMENT, ''); module.exports = { commentIfDeactivated, diff --git a/forward_engineering/helpers/constraintsHelper.js b/forward_engineering/helpers/constraintsHelper.js index 887ef6a..0e04176 100644 --- a/forward_engineering/helpers/constraintsHelper.js +++ b/forward_engineering/helpers/constraintsHelper.js @@ -1,72 +1,68 @@ const _ = require('lodash'); const { commentIfDeactivated } = require('./commentIfDeactivated'); +const { trimBraces } = require('./general'); +const { checkAllKeysDeactivated, divideIntoActivatedAndDeactivated } = require('../utils/general'); +const { assignTemplates } = require('../utils/assignTemplates'); -module.exports = app => { - const { assignTemplates } = app.require('@hackolade/ddl-fe-utils'); - const { checkAllKeysDeactivated, divideIntoActivatedAndDeactivated } = - app.require('@hackolade/ddl-fe-utils').general; - const { trimBraces } = require('./general')(app); +const createKeyConstraint = (templates, terminator, isParentActivated) => keyData => { + const partition = keyData.partition ? ` ON [${keyData.partition}]` : ''; + const columnMapToString = ({ name }) => `[${name}]`.trim(); - const createKeyConstraint = (templates, terminator, isParentActivated) => keyData => { - const partition = keyData.partition ? ` ON [${keyData.partition}]` : ''; - const columnMapToString = ({ name }) => `[${name}]`.trim(); + const isAllColumnsDeactivated = checkAllKeysDeactivated(keyData.columns); - const isAllColumnsDeactivated = checkAllKeysDeactivated(keyData.columns); + const dividedColumns = divideIntoActivatedAndDeactivated(keyData.columns, columnMapToString); + const deactivatedColumnsAsString = dividedColumns.deactivatedItems.length + ? commentIfDeactivated(dividedColumns.deactivatedItems.join(', '), { isActivated: false }, true) + : ''; - const dividedColumns = divideIntoActivatedAndDeactivated(keyData.columns, columnMapToString); - const deactivatedColumnsAsString = dividedColumns.deactivatedItems.length - ? commentIfDeactivated(dividedColumns.deactivatedItems.join(', '), { isActivated: false }, true) - : ''; + const columns = + !isAllColumnsDeactivated && isParentActivated + ? ' (' + dividedColumns.activatedItems.join(', ') + deactivatedColumnsAsString + ')' + : ' (' + keyData.columns.map(columnMapToString).join(', ') + ')'; - const columns = - !isAllColumnsDeactivated && isParentActivated - ? ' (' + dividedColumns.activatedItems.join(', ') + deactivatedColumnsAsString + ')' - : ' (' + keyData.columns.map(columnMapToString).join(', ') + ')'; - - return { - statement: assignTemplates(templates.createKeyConstraint, { - constraintName: keyData.name ? `CONSTRAINT [${keyData.name}] ` : '', - keyType: keyData.keyType, - clustered: ' NONCLUSTERED', - columns, - options: ' NOT ENFORCED', - partition, - terminator, - }), - isActivated: !isAllColumnsDeactivated, - }; - }; - - const createDefaultConstraint = (templates, terminator) => (constraintData, tableName) => { - return assignTemplates(templates.createDefaultConstraint, { - tableName, - constraintName: constraintData.constraintName, - columnName: constraintData.columnName, - default: trimBraces(constraintData.value), + return { + statement: assignTemplates(templates.createKeyConstraint, { + constraintName: keyData.name ? `CONSTRAINT [${keyData.name}] ` : '', + keyType: keyData.keyType, + clustered: ' NONCLUSTERED', + columns, + options: ' NOT ENFORCED', + partition, terminator, - }); + }), + isActivated: !isAllColumnsDeactivated, }; +}; - const generateConstraintsString = (dividedConstraints, isParentActivated) => { - const activatedConstraints = dividedConstraints.activatedItems.length - ? ',\n\t' + dividedConstraints.activatedItems.join(',\n\t') - : ''; +const createDefaultConstraint = (templates, terminator) => (constraintData, tableName) => { + return assignTemplates(templates.createDefaultConstraint, { + tableName, + constraintName: constraintData.constraintName, + columnName: constraintData.columnName, + default: trimBraces(constraintData.value), + terminator, + }); +}; - const deactivatedConstraints = dividedConstraints.deactivatedItems.length - ? '\n\t' + - commentIfDeactivated( - dividedConstraints.deactivatedItems.join(',\n\t'), - { isActivated: !isParentActivated }, - true, - ) - : ''; +const generateConstraintsString = (dividedConstraints, isParentActivated) => { + const activatedConstraints = dividedConstraints.activatedItems.length + ? ',\n\t' + dividedConstraints.activatedItems.join(',\n\t') + : ''; - return activatedConstraints + deactivatedConstraints; - }; + const deactivatedConstraints = dividedConstraints.deactivatedItems.length + ? '\n\t' + + commentIfDeactivated( + dividedConstraints.deactivatedItems.join(',\n\t'), + { isActivated: !isParentActivated }, + true, + ) + : ''; - return { - createDefaultConstraint, - createKeyConstraint, - generateConstraintsString, - }; + return activatedConstraints + deactivatedConstraints; +}; + +module.exports = { + createDefaultConstraint, + createKeyConstraint, + generateConstraintsString, }; diff --git a/forward_engineering/helpers/general.js b/forward_engineering/helpers/general.js index e34ec4f..4d7023f 100644 --- a/forward_engineering/helpers/general.js +++ b/forward_engineering/helpers/general.js @@ -2,278 +2,264 @@ const _ = require('lodash'); const { commentIfDeactivated } = require('./commentIfDeactivated'); const types = require('../configs/types'); const templates = require('../configs/templates'); +const { decorateDefault } = require('./columnDefinitionHelper'); +const { checkAllKeysDeactivated } = require('../utils/general'); +const { assignTemplates } = require('../utils/assignTemplates'); + +const ORDERED_INDEX = 'clustered columnstore index order'; +const CLUSTERED_INDEX = 'clustered index'; +const HASH_DISTRIBUTION = 'hash'; + +const isString = type => ['VARCHAR', 'CHAR', 'NCHAR', 'NVARCHAR'].includes(_.toUpper(type)); + +const getTableName = (tableName, schemaName) => { + if (schemaName) { + return `[${schemaName}].[${tableName}]`; + } else { + return `[${tableName}]`; + } +}; -module.exports = app => { - const generalHasType = app.require('@hackolade/ddl-fe-utils').general.hasType; - const { decorateDefault } = require('./columnDefinitionHelper'); - const { checkAllKeysDeactivated } = app.require('@hackolade/ddl-fe-utils').general; - const { assignTemplates } = app.require('@hackolade/ddl-fe-utils'); - - const ORDERED_INDEX = 'clustered columnstore index order'; - const CLUSTERED_INDEX = 'clustered index'; - const HASH_DISTRIBUTION = 'hash'; - - const isString = type => ['VARCHAR', 'CHAR', 'NCHAR', 'NVARCHAR'].includes(_.toUpper(type)); - - const getTableName = (tableName, schemaName) => { - if (schemaName) { - return `[${schemaName}].[${tableName}]`; - } else { - return `[${tableName}]`; - } - }; +const getDefaultValue = (defaultValue, defaultConstraintName, type) => { + if (_.isUndefined(defaultValue)) { + return ''; + } + if (!_.isUndefined(defaultConstraintName)) { + return ''; + } + return ` DEFAULT ${decorateDefault(type, defaultValue)}`; +}; - const getDefaultValue = (defaultValue, defaultConstraintName, type) => { - if (_.isUndefined(defaultValue)) { - return ''; - } - if (!_.isUndefined(defaultConstraintName)) { - return ''; - } - return ` DEFAULT ${decorateDefault(type, defaultValue)}`; - }; +const getKeyWithAlias = key => { + if (!key) { + return ''; + } - const getKeyWithAlias = key => { - if (!key) { - return ''; - } + if (key.alias) { + return `[${key.name}] as [${key.alias}]`; + } else { + return `[${key.name}]`; + } +}; - if (key.alias) { - return `[${key.name}] as [${key.alias}]`; - } else { - return `[${key.name}]`; +const getTableOptions = options => { + if (!options) { + return ''; + } + + const partition = _.get(options, 'partition', {}); + let optionsStatements = []; + if (options.indexing) { + let statement = _.toUpper(options.indexing); + if (options.indexing === ORDERED_INDEX) { + statement += '('; + statement += options.indexingOrderColumn.map(({ name }) => `[${name}]`).join(', '); + statement += ')'; } - }; - const getTableOptions = options => { - if (!options) { - return ''; + if (options.indexing === CLUSTERED_INDEX) { + statement += '('; + statement += options.clusteringColumn.map(({ name }) => `[${name}]`).join(', '); + statement += ')'; } - const partition = _.get(options, 'partition', {}); - let optionsStatements = []; - if (options.indexing) { - let statement = _.toUpper(options.indexing); - if (options.indexing === ORDERED_INDEX) { - statement += '('; - statement += options.indexingOrderColumn.map(({ name }) => `[${name}]`).join(', '); - statement += ')'; - } + optionsStatements.push(statement); + } - if (options.indexing === CLUSTERED_INDEX) { - statement += '('; - statement += options.clusteringColumn.map(({ name }) => `[${name}]`).join(', '); - statement += ')'; - } + if (partition.name) { + const range = _.toUpper(partition.rangeForValues || 'LEFT'); + const values = partition.boundaryValue || ''; + const statement = assignTemplates(templates.partition, { name: partition.name, range, values }); - optionsStatements.push(statement); - } + optionsStatements.push(commentIfDeactivated(statement, { isActivated: partition.isActivated })); + } - if (partition.name) { - const range = _.toUpper(partition.rangeForValues || 'LEFT'); - const values = partition.boundaryValue || ''; - const statement = assignTemplates(templates.partition, { name: partition.name, range, values }); + if (options.distribution) { + let statement = `DISTRIBUTION = ${_.toUpper(options.distribution)}`; - optionsStatements.push(commentIfDeactivated(statement, { isActivated: partition.isActivated })); + if (options.distribution === HASH_DISTRIBUTION) { + statement += '('; + statement += options.hashColumn.map(({ name }) => `[${name}]`).join(', '); + statement += ')'; } - if (options.distribution) { - let statement = `DISTRIBUTION = ${_.toUpper(options.distribution)}`; - - if (options.distribution === HASH_DISTRIBUTION) { - statement += '('; - statement += options.hashColumn.map(({ name }) => `[${name}]`).join(', '); - statement += ')'; - } - - optionsStatements.push(statement); - } + optionsStatements.push(statement); + } - if (options.forAppend) { - optionsStatements.push('FOR_APPEND'); - } + if (options.forAppend) { + optionsStatements.push('FOR_APPEND'); + } - if (_.isEmpty(optionsStatements)) { - return ''; - } + if (_.isEmpty(optionsStatements)) { + return ''; + } - return `WITH (\n\t${optionsStatements.join(',\n\t')}\n)`; - }; + return `WITH (\n\t${optionsStatements.join(',\n\t')}\n)`; +}; - const hasType = type => { - return generalHasType(types, type); - }; +const hasType = type => { + return Object.keys(types).map(_.toLower).includes(_.toLower(type)); +}; - const getViewData = (keys, schemaData) => { - if (!Array.isArray(keys)) { - return { tables: [], columns: [] }; - } +const getViewData = (keys, schemaData) => { + if (!Array.isArray(keys)) { + return { tables: [], columns: [] }; + } - return keys.reduce( - (result, key) => { - if (!key.tableName) { - result.columns.push(getKeyWithAlias(key)); + return keys.reduce( + (result, key) => { + if (!key.tableName) { + result.columns.push(getKeyWithAlias(key)); - return result; - } + return result; + } - let tableName = getTableName(key.tableName, key.schemaName); + let tableName = getTableName(key.tableName, key.schemaName); - if (key.dbName && key.dbName !== schemaData.databaseName) { - tableName = `[${key.dbName}].` + tableName; - } + if (key.dbName && key.dbName !== schemaData.databaseName) { + tableName = `[${key.dbName}].` + tableName; + } - if (!result.tables.includes(tableName)) { - result.tables.push(tableName); - } + if (!result.tables.includes(tableName)) { + result.tables.push(tableName); + } - result.columns.push({ - statement: `${tableName}.${getKeyWithAlias(key)}`, - isActivated: key.isActivated, - }); + result.columns.push({ + statement: `${tableName}.${getKeyWithAlias(key)}`, + isActivated: key.isActivated, + }); + + return result; + }, + { + tables: [], + columns: [], + }, + ); +}; - return result; - }, - { - tables: [], - columns: [], - }, - ); - }; - - const filterColumnStoreProperties = index => { - if (index.type !== 'columnstore') { - return index; +const filterColumnStoreProperties = index => { + if (index.type !== 'columnstore') { + return index; + } + const unsupportedProperties = new Set([ + 'allowRowLocks', + 'allowPageLocks', + 'padIndex', + 'fillFactor', + 'ignoreDuplicateKey', + ]); + + return Object.keys(index).reduce((result, property) => { + if (unsupportedProperties.has(property)) { + return result; + } else { + return { ...result, [property]: index[property] }; } - const unsupportedProperties = [ - 'allowRowLocks', - 'allowPageLocks', - 'padIndex', - 'fillFactor', - 'ignoreDuplicateKey', - ]; - - return Object.keys(index).reduce((result, property) => { - if (unsupportedProperties.includes(property)) { - return result; - } else { - return Object.assign({}, result, { - [property]: index[property], - }); - } - }, {}); - }; + }, {}); +}; - const getDefaultConstraints = columnDefinitions => { - if (!Array.isArray(columnDefinitions)) { - return []; - } +const getDefaultConstraints = columnDefinitions => { + if (!Array.isArray(columnDefinitions)) { + return []; + } + + return columnDefinitions + .filter(column => _.get(column, 'defaultConstraint.name') && !_.isNil(_.get(column, 'defaultConstraint.value'))) + .map(column => ({ + columnName: column.name, + constraintName: column.defaultConstraint.name, + value: decorateDefault(column.type, column.defaultConstraint.value), + })); +}; - return columnDefinitions - .filter( - column => _.get(column, 'defaultConstraint.name') && !_.isNil(_.get(column, 'defaultConstraint.value')), - ) - .map(column => ({ - columnName: column.name, - constraintName: column.defaultConstraint.name, - value: decorateDefault(column.type, column.defaultConstraint.value), - })); - }; - - const foreignKeysToString = keys => { - if (Array.isArray(keys)) { - const activatedKeys = keys - .filter(key => _.get(key, 'isActivated', true)) - .map(key => `[${key.name.trim()}]`); - const deactivatedKeys = keys - .filter(key => !_.get(key, 'isActivated', true)) - .map(key => `[${key.name.trim()}]`); - const deactivatedKeysAsString = deactivatedKeys.length - ? commentIfDeactivated(deactivatedKeys, { isActivated: false }, true) - : ''; - - return activatedKeys.join(', ') + deactivatedKeysAsString; - } - return keys; - }; +const foreignKeysToString = keys => { + if (Array.isArray(keys)) { + const activatedKeys = keys.filter(key => _.get(key, 'isActivated', true)).map(key => `[${key.name.trim()}]`); + const deactivatedKeys = keys.filter(key => !_.get(key, 'isActivated', true)).map(key => `[${key.name.trim()}]`); + const deactivatedKeysAsString = deactivatedKeys.length + ? commentIfDeactivated(deactivatedKeys, { isActivated: false }, true) + : ''; + + return activatedKeys.join(', ') + deactivatedKeysAsString; + } + return keys; +}; - const foreignActiveKeysToString = keys => { - return keys.map(key => key.name.trim()).join(', '); - }; +const foreignActiveKeysToString = keys => { + return keys.map(key => key.name.trim()).join(', '); +}; - const trimBraces = expression => - /^\(([\s\S]+?)\)$/i.test(_.trim(expression)) - ? _.trim(expression).replace(/^\(([\s\S]+?)\)$/i, '$1') - : expression; +const trimBraces = expression => + /^\(([\s\S]+?)\)$/i.test(_.trim(expression)) ? _.trim(expression).replace(/^\(([\s\S]+?)\)$/i, '$1') : expression; - const checkIndexActivated = index => { - if (index.isActivated === false) { - return false; - } +const checkIndexActivated = index => { + if (index.isActivated === false) { + return false; + } - const isAllKeysDeactivated = checkAllKeysDeactivated(_.get(index, 'keys', [])); - const isAllIncludesDeactivated = checkAllKeysDeactivated(_.get(index, 'include', [])); - const isColumnDeactivated = !_.get(index, 'column.isActivated', true); + const isAllKeysDeactivated = checkAllKeysDeactivated(_.get(index, 'keys', [])); + const isAllIncludesDeactivated = checkAllKeysDeactivated(_.get(index, 'include', [])); + const isColumnDeactivated = !_.get(index, 'column.isActivated', true); - return !isAllKeysDeactivated && !isAllIncludesDeactivated && !isColumnDeactivated; - }; + return !isAllKeysDeactivated && !isAllIncludesDeactivated && !isColumnDeactivated; +}; - const getTempTableTime = (isTempTableStartTimeColumn, isTempTableEndTimeColumn, isHidden) => { - if (isTempTableStartTimeColumn) { - return ` GENERATED ALWAYS AS ROW START${isHidden ? ' HIDDEN' : ''}`; - } - if (isTempTableEndTimeColumn) { - return ` GENERATED ALWAYS AS ROW END${isHidden ? ' HIDDEN' : ''}`; - } +const getTempTableTime = (isTempTableStartTimeColumn, isTempTableEndTimeColumn, isHidden) => { + if (isTempTableStartTimeColumn) { + return ` GENERATED ALWAYS AS ROW START${isHidden ? ' HIDDEN' : ''}`; + } + if (isTempTableEndTimeColumn) { + return ` GENERATED ALWAYS AS ROW END${isHidden ? ' HIDDEN' : ''}`; + } + return ''; +}; + +const getCollation = (type, collation) => { + if (!isString(type)) { return ''; - }; + } - const getCollation = (type, collation) => { - if (!isString(type)) { - return ''; - } + if (_.isEmpty(collation)) { + return ''; + } + + return ( + ' COLLATE ' + + Object.entries(collation) + .map(([, collationValue]) => { + return collationValue; + }) + .join('_') + ); +}; - if (_.isEmpty(collation)) { - return ''; - } +const setPersistenceSpecificName = (persistence, name) => { + if (persistence !== 'temporary') { + return name; + } - return ( - ' COLLATE ' + - Object.entries(collation) - .map(([key, collationValue]) => { - return collationValue; - }) - .join('_') - ); - }; - - const setPersistenceSpecificName = (persistence, name) => { - if (persistence !== 'temporary') { - return name; - } + if (_.first(name) === '#') { + return name; + } - if (_.first(name) === '#') { - return name; - } + return `#${name}`; +}; - return `#${name}`; - }; - - return { - filterColumnStoreProperties, - getKeyWithAlias, - getTableName, - getTableOptions, - hasType, - getViewData, - getDefaultConstraints, - foreignKeysToString, - trimBraces, - checkIndexActivated, - foreignActiveKeysToString, - getDefaultValue, - getTempTableTime, - getCollation, - setPersistenceSpecificName, - }; +module.exports = { + filterColumnStoreProperties, + getKeyWithAlias, + getTableName, + getTableOptions, + hasType, + getViewData, + getDefaultConstraints, + foreignKeysToString, + trimBraces, + checkIndexActivated, + foreignActiveKeysToString, + getDefaultValue, + getTempTableTime, + getCollation, + setPersistenceSpecificName, }; diff --git a/forward_engineering/helpers/ifNotExistStatementHelper.js b/forward_engineering/helpers/ifNotExistStatementHelper.js index 9b98bca..f339358 100644 --- a/forward_engineering/helpers/ifNotExistStatementHelper.js +++ b/forward_engineering/helpers/ifNotExistStatementHelper.js @@ -1,45 +1,42 @@ const _ = require('lodash'); +const { assignTemplates } = require('../utils/assignTemplates'); +const { tab } = require('../utils/general'); -module.exports = app => { - const { assignTemplates } = app.require('@hackolade/ddl-fe-utils'); - const { tab } = app.require('@hackolade/ddl-fe-utils').general; - - const wrapIfNotExistSchema = ({ templates, schemaStatement, schemaName, terminator }) => { - return assignTemplates(templates.ifNotExistSchema, { - statement: _.trim(tab(schemaStatement)), - schemaName, - terminator, - }); - }; +const wrapIfNotExistSchema = ({ templates, schemaStatement, schemaName, terminator }) => { + return assignTemplates(templates.ifNotExistSchema, { + statement: _.trim(tab(schemaStatement)), + schemaName, + terminator, + }); +}; - const wrapIfNotExistDatabase = ({ templates, databaseStatement, databaseName, terminator }) => { - return assignTemplates(templates.ifNotExistDatabase, { - statement: tab(databaseStatement), - databaseName, - terminator, - }); - }; +const wrapIfNotExistDatabase = ({ templates, databaseStatement, databaseName, terminator }) => { + return assignTemplates(templates.ifNotExistDatabase, { + statement: tab(databaseStatement), + databaseName, + terminator, + }); +}; - const wrapIfNotExistTable = ({ templates, tableStatement, tableName, terminator }) => { - return assignTemplates(templates.ifNotExistTable, { - statement: tab(tableStatement), - tableName, - terminator, - }); - }; +const wrapIfNotExistTable = ({ templates, tableStatement, tableName, terminator }) => { + return assignTemplates(templates.ifNotExistTable, { + statement: tab(tableStatement), + tableName, + terminator, + }); +}; - const wrapIfNotExistView = ({ templates, viewStatement, viewName, terminator }) => { - return assignTemplates(templates.ifNotExistView, { - statement: tab(viewStatement), - viewName, - terminator, - }); - }; +const wrapIfNotExistView = ({ templates, viewStatement, viewName, terminator }) => { + return assignTemplates(templates.ifNotExistView, { + statement: tab(viewStatement), + viewName, + terminator, + }); +}; - return { - wrapIfNotExistSchema, - wrapIfNotExistDatabase, - wrapIfNotExistTable, - wrapIfNotExistView, - }; +module.exports = { + wrapIfNotExistSchema, + wrapIfNotExistDatabase, + wrapIfNotExistTable, + wrapIfNotExistView, }; diff --git a/forward_engineering/helpers/indexHelper.js b/forward_engineering/helpers/indexHelper.js index 3a16636..385f3d2 100644 --- a/forward_engineering/helpers/indexHelper.js +++ b/forward_engineering/helpers/indexHelper.js @@ -1,343 +1,339 @@ const _ = require('lodash'); const templates = require('../configs/templates'); const { commentIfDeactivated } = require('./commentIfDeactivated'); +const { filterColumnStoreProperties, getTableName } = require('./general'); +const { assignTemplates } = require('../utils/assignTemplates'); +const { divideIntoActivatedAndDeactivated, checkAllKeysDeactivated } = require('../utils/general'); -module.exports = app => { - const { filterColumnStoreProperties, getTableName } = require('./general')(app); - const { assignTemplates } = app.require('@hackolade/ddl-fe-utils'); - const { divideIntoActivatedAndDeactivated, checkAllKeysDeactivated } = - app.require('@hackolade/ddl-fe-utils').general; +const getRelationOptionsIndex = index => { + let result = []; - const getRelationOptionsIndex = index => { - let result = []; + if (index.padIndex) { + result.push('PAD_INDEX = ON'); + } - if (index.padIndex) { - result.push('PAD_INDEX = ON'); - } + if (index.fillFactor) { + result.push('FILLFACTOR = ' + index.fillFactor); + } - if (index.fillFactor) { - result.push('FILLFACTOR = ' + index.fillFactor); - } + if (index.ignoreDuplicateKey) { + result.push('IGNORE_DUP_KEY = ON'); + } - if (index.ignoreDuplicateKey) { - result.push('IGNORE_DUP_KEY = ON'); - } + if (index.statisticsNoRecompute) { + result.push('STATISTICS_NORECOMPUTE = ON'); + } - if (index.statisticsNoRecompute) { - result.push('STATISTICS_NORECOMPUTE = ON'); - } + if (index.statisticsIncremental) { + result.push('STATISTICS_INCREMENTAL = ON'); + } - if (index.statisticsIncremental) { - result.push('STATISTICS_INCREMENTAL = ON'); - } + if (index.allowRowLocks === false) { + result.push('ALLOW_ROW_LOCKS = OFF'); + } - if (index.allowRowLocks === false) { - result.push('ALLOW_ROW_LOCKS = OFF'); - } + if (index.allowPageLocks === false) { + result.push('ALLOW_PAGE_LOCKS = OFF'); + } - if (index.allowPageLocks === false) { - result.push('ALLOW_PAGE_LOCKS = OFF'); - } + if (index.optimizeForSequentialKey) { + result.push('OPTIMIZE_FOR_SEQUENTIAL_KEY = ON'); + } - if (index.optimizeForSequentialKey) { - result.push('OPTIMIZE_FOR_SEQUENTIAL_KEY = ON'); - } + if (index.type === 'columnstore' && index.compressionDelay) { + result.push('COMPRESSION_DELAY = ' + index.compressionDelay); + } - if (index.type === 'columnstore' && index.compressionDelay) { - result.push('COMPRESSION_DELAY = ' + index.compressionDelay); - } + if (index.dataCompression && index.dataCompression !== 'NONE') { + result.push('DATA_COMPRESSION = ' + index.dataCompression); + } - if (index.dataCompression && index.dataCompression !== 'NONE') { - result.push('DATA_COMPRESSION = ' + index.dataCompression); - } + return result; +}; - return result; - }; +const getIndexOptions = indexData => { + let result = []; - const getIndexOptions = indexData => { - let result = []; + if (indexData.dropExisting) { + result.unshift(`DROP_EXISTING = ON`); + } + return result; +}; - if (indexData.dropExisting) { - result.unshift(`DROP_EXISTING = ON`); - } - return result; - }; +const createIndexOptions = options => { + return options.length ? '\n\tWITH (\n\t\t' + options.join(',\n\t\t') + '\n\t)' : ''; +}; - const createIndexOptions = options => { - return options.length ? '\n\tWITH (\n\t\t' + options.join(',\n\t\t') + '\n\t)' : ''; - }; +const getIndexKeys = (keys, iterate, isParentActivated) => { + const dividedKeys = divideIntoActivatedAndDeactivated(keys, iterate); - const getIndexKeys = (keys, iterate, isParentActivated) => { - const dividedKeys = divideIntoActivatedAndDeactivated(keys, iterate); + const deactivatedKeys = dividedKeys.deactivatedItems.join(', '); + const commentedKeys = deactivatedKeys ? commentIfDeactivated(deactivatedKeys, { isActivated: false }, true) : ''; - const deactivatedKeys = dividedKeys.deactivatedItems.join(', '); - const commentedKeys = deactivatedKeys - ? commentIfDeactivated(deactivatedKeys, { isActivated: false }, true) - : ''; + const activatedKeys = dividedKeys.activatedItems.join(', '); - const activatedKeys = dividedKeys.activatedItems.join(', '); + const delimiter = deactivatedKeys ? ', ' : ''; - return isParentActivated - ? activatedKeys + commentedKeys - : activatedKeys + (deactivatedKeys ? ', ' : '') + deactivatedKeys; - }; + return isParentActivated ? activatedKeys + commentedKeys : activatedKeys + delimiter + deactivatedKeys; +}; - const createIndex = (terminator, tableName, index, isParentActivated = true) => { - if (_.isEmpty(index.keys) || !index.name) { - return ''; - } +const createIndex = (terminator, tableName, index, isParentActivated = true) => { + if (_.isEmpty(index.keys) || !index.name) { + return ''; + } + + const indexOptions = getIndexOptions(index); + const keys = getIndexKeys( + index.keys, + key => `[${key.name}]` + (_.toLower(key.type) === 'descending' ? ' DESC' : ''), + isParentActivated, + ); + + const clustered = index.clustered ? ` CLUSTERED` : ' NONCLUSTERED'; + + return assignTemplates(templates.index, { + name: index.name, + clustered, + table: getTableName(tableName, index.schemaName), + keys, + index_options: createIndexOptions(indexOptions), + terminator, + }); +}; - const indexOptions = getIndexOptions(index); - const keys = getIndexKeys( - index.keys, - key => `[${key.name}]` + (_.toLower(key.type) === 'descending' ? ' DESC' : ''), - isParentActivated, - ); +const createColumnStoreIndex = (terminator, tableName, index, isParentActivated = true) => { + if (!index.name) { + return ''; + } + + const indexOptions = getIndexOptions(index); + const order = getIndexKeys(index.orderKeys || [], key => `[${key.name}]`, isParentActivated); + + return assignTemplates(templates.columnStoreIndex, { + name: index.name, + table: getTableName(tableName, index.schemaName), + order: order ? `\n\tORDER (${order})` : '', + index_options: createIndexOptions(indexOptions), + terminator, + }); +}; - const clustered = index.clustered ? ` CLUSTERED` : ' NONCLUSTERED'; +const createTableIndex = (terminator, tableName, index, isParentActivated) => { + if (index.type === 'columnstore') { + return createColumnStoreIndex(terminator, tableName, index, isParentActivated); + } + return createIndex(terminator, tableName, index, isParentActivated); +}; - return assignTemplates(templates.index, { - name: index.name, - clustered, - table: getTableName(tableName, index.schemaName), - keys, - index_options: createIndexOptions(indexOptions), - terminator, - }); - }; +const createMemoryOptimizedClusteredIndex = indexData => { + let index = 'CLUSTERED COLUMNSTORE'; - const createColumnStoreIndex = (terminator, tableName, index, isParentActivated = true) => { - if (!index.name) { - return ''; - } + if (indexData.compressionDelay) { + index += ` WITH (COMPRESSION_DELAY = ${indexData.compressionDelay})`; + } - const indexOptions = getIndexOptions(index); - const order = getIndexKeys(index.orderKeys || [], key => `[${key.name}]`, isParentActivated); + if (indexData.fileGroupName) { + index += ` ON ${indexData.fileGroupName}`; + } - return assignTemplates(templates.columnStoreIndex, { - name: index.name, - table: getTableName(tableName, index.schemaName), - order: order ? `\n\tORDER (${order})` : '', - index_options: createIndexOptions(indexOptions), - terminator, - }); - }; + return index; +}; - const createTableIndex = (terminator, tableName, index, isParentActivated) => { - if (index.type === 'columnstore') { - return createColumnStoreIndex(terminator, tableName, index, isParentActivated); - } - return createIndex(terminator, tableName, index, isParentActivated); - }; +const createMemoryOptimizedIndex = isParentActivated => indexData => { + let index = `INDEX ${indexData.name}`; - const createMemoryOptimizedClusteredIndex = indexData => { - let index = 'CLUSTERED COLUMNSTORE'; + if (indexData.clustered) { + return { statement: index + ' ' + createMemoryOptimizedClusteredIndex(indexData), isActivated: true }; + } - if (indexData.compressionDelay) { - index += ` WITH (COMPRESSION_DELAY = ${indexData.compressionDelay})`; - } + const isAllKeysDeactivated = checkAllKeysDeactivated(indexData.keys); - if (indexData.fileGroupName) { - index += ` ON ${indexData.fileGroupName}`; - } - - return index; - }; + index += ' NONCLUSTERED'; - const createMemoryOptimizedIndex = isParentActivated => indexData => { - let index = `INDEX ${indexData.name}`; + if (indexData.unique) { + index += ' UNIQUE'; + } - if (indexData.clustered) { - return { statement: index + ' ' + createMemoryOptimizedClusteredIndex(indexData), isActivated: true }; - } + if (indexData.hash) { + const keys = divideIntoActivatedAndDeactivated(indexData.keys, key => `[${key.name}]`); + const activatedKeys = keys.activatedItems.join(', '); + const deactivatedKeys = keys.deactivatedItems.length + ? commentIfDeactivated( + keys.deactivatedItems.join(', '), + { + isActivated: !isParentActivated, + }, + true, + ) + : ''; - const isAllKeysDeactivated = checkAllKeysDeactivated(indexData.keys); + const keysDelimiter = + activatedKeys.length && deactivatedKeys.length && !deactivatedKeys.startsWith('/*') ? ', ' : ''; - index += ' NONCLUSTERED'; + index += ` HASH (${activatedKeys}${keysDelimiter}${deactivatedKeys})`; - if (indexData.unique) { - index += ' UNIQUE'; + if (indexData.bucketCount) { + index += ` WITH (BUCKET_COUNT=${indexData.bucketCount})`; } + } else { + const keys = divideIntoActivatedAndDeactivated( + indexData.keys, + key => `[${key.name}]${_.toLower(key.type) === 'descending' ? ' DESC' : ''}`, + ); + const activatedKeys = keys.activatedItems.join(', '); + const deactivatedKeys = keys.deactivatedItems.length + ? commentIfDeactivated( + keys.deactivatedItems.join(', '), + { + isActivated: !isParentActivated, + }, + true, + ) + : ''; - if (indexData.hash) { - const keys = divideIntoActivatedAndDeactivated(indexData.keys, key => `[${key.name}]`); - const activatedKeys = keys.activatedItems.join(', '); - const deactivatedKeys = keys.deactivatedItems.length - ? commentIfDeactivated( - keys.deactivatedItems.join(', '), - { - isActivated: !isParentActivated, - }, - true, - ) - : ''; - index += ` HASH (${activatedKeys}${ - activatedKeys.length && deactivatedKeys.length && !deactivatedKeys.startsWith('/*') ? ', ' : '' - }${deactivatedKeys})`; - - if (indexData.bucketCount) { - index += ` WITH (BUCKET_COUNT=${indexData.bucketCount})`; - } - } else { - const keys = divideIntoActivatedAndDeactivated( - indexData.keys, - key => `[${key.name}]${_.toLower(key.type) === 'descending' ? ' DESC' : ''}`, - ); - const activatedKeys = keys.activatedItems.join(', '); - const deactivatedKeys = keys.deactivatedItems.length - ? commentIfDeactivated( - keys.deactivatedItems.join(', '), - { - isActivated: !isParentActivated, - }, - true, - ) - : ''; - - index += ` (${activatedKeys}${ - activatedKeys.length && deactivatedKeys.length && !deactivatedKeys.startsWith('/*') ? ', ' : '' - }${deactivatedKeys})`; - - if (indexData.fileGroupName) { - index += ` ON ${indexData.fileGroupName}`; - } + index += ` (${activatedKeys}${ + activatedKeys.length && deactivatedKeys.length && !deactivatedKeys.startsWith('/*') ? ', ' : '' + }${deactivatedKeys})`; + + if (indexData.fileGroupName) { + index += ` ON ${indexData.fileGroupName}`; } + } - return { statement: index, isActivated: !isAllKeysDeactivated }; - }; + return { statement: index, isActivated: !isAllKeysDeactivated }; +}; - const hydrateIndex = (indexData, schemaData) => { - const toArray = value => (Array.isArray(value) ? value : []); - - return filterColumnStoreProperties({ - name: indexData.indxName, - isActivated: indexData.isActivated, - type: _.toLower(indexData.indxType), - clustered: indexData.clusteredIndx, - keys: toArray(indexData.indxKey), - orderKeys: toArray(indexData.orderKey), - dropExisting: indexData.DROP_EXISTING, - schemaName: schemaData.schemaName, - }); - }; +const hydrateIndex = (indexData, schemaData) => { + const toArray = value => (Array.isArray(value) ? value : []); + + return filterColumnStoreProperties({ + name: indexData.indxName, + isActivated: indexData.isActivated, + type: _.toLower(indexData.indxType), + clustered: indexData.clusteredIndx, + keys: toArray(indexData.indxKey), + orderKeys: toArray(indexData.orderKey), + dropExisting: indexData.DROP_EXISTING, + schemaName: schemaData.schemaName, + }); +}; - const hydrateMemoryOptimizedIndex = schemaData => indexData => { - let index = hydrateIndex(indexData, schemaData); - - return { - name: index.name, - isActivated: index.isActivated, - clustered: index.clustered, - hash: indexData.indxHash, - unique: index.unique, - keys: index.keys, - bucketCount: !isNaN(indexData.indxBucketCount) ? indexData.indxBucketCount : -1, - fileGroupName: indexData.indxFileGroupName, - compressionDelay: index.compressionDelay, - }; - }; +const hydrateMemoryOptimizedIndex = schemaData => indexData => { + let index = hydrateIndex(indexData, schemaData); - const hydrateFullTextIndex = (indexData, schemaData) => { - const generalIndex = hydrateIndex(indexData, schemaData); - - return { - type: 'fulltext', - isActivated: indexData.isActivated, - keys: Array.isArray(indexData.indxFullTextKeysProperties) - ? generalIndex.keys.map((item, i) => { - const properties = indexData.indxFullTextKeysProperties[i]; - - if (!properties) { - return item; - } else { - return { - ...item, - columnType: properties.columnType, - languageTerm: properties.languageTerm, - statisticalSemantics: properties.statisticalSemantics, - }; - } - }) - : generalIndex.keys, - keyIndex: indexData.indxFullTextKeyIndex, - catalogName: indexData.indxFullTextCatalogName, - fileGroup: indexData.indxFullTextFileGroup, - changeTracking: - indexData.indxFullTextChangeTracking === 'OFF' && indexData.indxFullTextNoPopulation - ? 'OFF, NO POPULATION' - : indexData.indxFullTextChangeTracking, - stopList: - indexData.indxFullTextStopList === 'Stoplist name' - ? indexData.indxFullTextStopListName - : indexData.indxFullTextStopList, - searchPropertyList: indexData.indxFullTextSearchPropertyList, - schemaName: schemaData.schemaName, - }; + return { + name: index.name, + isActivated: index.isActivated, + clustered: index.clustered, + hash: indexData.indxHash, + unique: index.unique, + keys: index.keys, + bucketCount: Number.isNaN(indexData.indxBucketCount) ? -1 : indexData.indxBucketCount, + fileGroupName: indexData.indxFileGroupName, + compressionDelay: index.compressionDelay, }; +}; - const hydrateSpatialIndex = (indexData, schemaData) => { - const generalIndex = hydrateIndex(indexData, schemaData); - - return { - ..._.pick(generalIndex, [ - 'name', - 'type', - 'padIndex', - 'fillFactor', - 'ignoreDuplicateKey', - 'statisticsNoRecompute', - 'allowRowLocks', - 'allowPageLocks', - 'dataCompression', - 'isActivated', - ]), - column: generalIndex.keys[0], - using: indexData.indxUsing, - boundingBox: - !_.isEmpty(indexData.indxBoundingBox) && - ['GEOMETRY_AUTO_GRID', 'GEOMETRY_GRID'].includes(indexData.indxUsing) - ? indexData.indxBoundingBox - : {}, - grids: - !_.isEmpty(indexData.indxGrids) && ['GEOMETRY_GRID', 'GEOGRAPHY_GRID'].includes(indexData.indxUsing) - ? indexData.indxGrids - : [], - cellsPerObject: indexData.CELLS_PER_OBJECT, - sortInTempdb: indexData.SORT_IN_TEMPDB, - dropExisting: indexData.DROP_EXISTING, - maxdop: indexData.MAXDOP, - schemaName: schemaData.schemaName, - }; +const hydrateFullTextIndex = (indexData, schemaData) => { + const generalIndex = hydrateIndex(indexData, schemaData); + + return { + type: 'fulltext', + isActivated: indexData.isActivated, + keys: Array.isArray(indexData.indxFullTextKeysProperties) + ? generalIndex.keys.map((item, i) => { + const properties = indexData.indxFullTextKeysProperties[i]; + + if (properties) { + return { + ...item, + columnType: properties.columnType, + languageTerm: properties.languageTerm, + statisticalSemantics: properties.statisticalSemantics, + }; + } else { + return item; + } + }) + : generalIndex.keys, + keyIndex: indexData.indxFullTextKeyIndex, + catalogName: indexData.indxFullTextCatalogName, + fileGroup: indexData.indxFullTextFileGroup, + changeTracking: + indexData.indxFullTextChangeTracking === 'OFF' && indexData.indxFullTextNoPopulation + ? 'OFF, NO POPULATION' + : indexData.indxFullTextChangeTracking, + stopList: + indexData.indxFullTextStopList === 'Stoplist name' + ? indexData.indxFullTextStopListName + : indexData.indxFullTextStopList, + searchPropertyList: indexData.indxFullTextSearchPropertyList, + schemaName: schemaData.schemaName, }; +}; - const hydrateTableIndex = (indexData, schemaData) => { - if (indexData.indxType === 'Spatial') { - return hydrateSpatialIndex(indexData, schemaData); - } else if (indexData.indxType === 'FullText') { - return hydrateFullTextIndex(indexData, schemaData); - } else { - return hydrateIndex(indexData, schemaData); - } +const hydrateSpatialIndex = (indexData, schemaData) => { + const generalIndex = hydrateIndex(indexData, schemaData); + + return { + ..._.pick(generalIndex, [ + 'name', + 'type', + 'padIndex', + 'fillFactor', + 'ignoreDuplicateKey', + 'statisticsNoRecompute', + 'allowRowLocks', + 'allowPageLocks', + 'dataCompression', + 'isActivated', + ]), + column: generalIndex.keys[0], + using: indexData.indxUsing, + boundingBox: + !_.isEmpty(indexData.indxBoundingBox) && + ['GEOMETRY_AUTO_GRID', 'GEOMETRY_GRID'].includes(indexData.indxUsing) + ? indexData.indxBoundingBox + : {}, + grids: + !_.isEmpty(indexData.indxGrids) && ['GEOMETRY_GRID', 'GEOGRAPHY_GRID'].includes(indexData.indxUsing) + ? indexData.indxGrids + : [], + cellsPerObject: indexData.CELLS_PER_OBJECT, + sortInTempdb: indexData.SORT_IN_TEMPDB, + dropExisting: indexData.DROP_EXISTING, + maxdop: indexData.MAXDOP, + schemaName: schemaData.schemaName, }; +}; - const getMemoryOptimizedIndexes = (tableData, schemaData) => { - const indexTab = tableData.find(tab => _.has(tab, 'Indxs')); +const hydrateTableIndex = (indexData, schemaData) => { + if (indexData.indxType === 'Spatial') { + return hydrateSpatialIndex(indexData, schemaData); + } else if (indexData.indxType === 'FullText') { + return hydrateFullTextIndex(indexData, schemaData); + } else { + return hydrateIndex(indexData, schemaData); + } +}; - if (!indexTab) { - return []; - } +const getMemoryOptimizedIndexes = (tableData, schemaData) => { + const indexTab = tableData.find(tab => _.has(tab, 'Indxs')); - return indexTab.Indxs.map(hydrateMemoryOptimizedIndex(schemaData)); - }; + if (!indexTab) { + return []; + } - return { - getRelationOptionsIndex, - createIndex, - hydrateIndex, - hydrateMemoryOptimizedIndex, - createMemoryOptimizedIndex, - hydrateTableIndex, - createTableIndex, - getMemoryOptimizedIndexes, - }; + return indexTab.Indxs.map(hydrateMemoryOptimizedIndex(schemaData)); +}; + +module.exports = { + getRelationOptionsIndex, + createIndex, + hydrateIndex, + hydrateMemoryOptimizedIndex, + createMemoryOptimizedIndex, + hydrateTableIndex, + createTableIndex, + getMemoryOptimizedIndexes, }; diff --git a/forward_engineering/helpers/keyHelper.js b/forward_engineering/helpers/keyHelper.js index 6785b73..332f0f5 100644 --- a/forward_engineering/helpers/keyHelper.js +++ b/forward_engineering/helpers/keyHelper.js @@ -5,252 +5,248 @@ */ const _ = require('lodash'); +const { clean } = require('../utils/general'); -module.exports = app => { - const { clean } = app.require('@hackolade/ddl-fe-utils').general; +const mapProperties = (jsonSchema, iteratee) => { + return Object.entries(jsonSchema.properties).map(iteratee); +}; - const mapProperties = (jsonSchema, iteratee) => { - return Object.entries(jsonSchema.properties).map(iteratee); - }; +const isInlineUnique = column => { + if (column.compositeUniqueKey) { + return false; + } else if (!column.unique) { + return false; + } else if (!_.isEmpty(column.uniqueKeyOptions)) { + return false; + } else { + return true; + } +}; - const isInlineUnique = column => { - if (column.compositeUniqueKey) { - return false; - } else if (!column.unique) { - return false; - } else if (!_.isEmpty(column.uniqueKeyOptions)) { - return false; - } else { - return true; - } - }; +const isInlinePrimaryKey = column => { + if (column.compositeUniqueKey) { + return false; + } else if (column.compositePrimaryKey) { + return false; + } else if (!column.primaryKey) { + return false; + } else if (!_.isEmpty(column.primaryKeyOptions)) { + return false; + } else { + return true; + } +}; - const isInlinePrimaryKey = column => { - if (column.compositeUniqueKey) { - return false; - } else if (column.compositePrimaryKey) { - return false; - } else if (!column.primaryKey) { - return false; - } else if (!_.isEmpty(column.primaryKeyOptions)) { - return false; - } else { - return true; - } - }; +const isUnique = column => { + if (column.compositeUniqueKey) { + return false; + } else if (!column.unique) { + return false; + } else if (_.isEmpty(column.uniqueKeyOptions)) { + return false; + } else { + return true; + } +}; - const isUnique = column => { - if (column.compositeUniqueKey) { - return false; - } else if (!column.unique) { - return false; - } else if (_.isEmpty(column.uniqueKeyOptions)) { - return false; - } else { - return true; - } - }; +const isPrimaryKey = column => { + if (column.compositeUniqueKey) { + return false; + } else if (column.compositePrimaryKey) { + return false; + } else if (!column.primaryKey) { + return false; + } else if (_.isEmpty(column.primaryKeyOptions)) { + return false; + } else { + return true; + } +}; - const isPrimaryKey = column => { - if (column.compositeUniqueKey) { - return false; - } else if (column.compositePrimaryKey) { - return false; - } else if (!column.primaryKey) { - return false; - } else if (_.isEmpty(column.primaryKeyOptions)) { - return false; - } else { - return true; - } - }; +const hydrateUniqueOptions = (options, columnName, isActivated) => + clean({ + keyType: 'UNIQUE', + name: options['constraintName'], + columns: [ + { + name: columnName, + isActivated: isActivated, + }, + ], + partition: options['partitionName'], + clustered: options['clustered'], + indexOption: clean({ + statisticsNoRecompute: options['staticticsNorecompute'], + statisticsIncremental: options['statisticsIncremental'], + ignoreDuplicateKey: options['ignoreDuplicate'], + fillFactor: options['fillFactor'], + allowRowLocks: Boolean(options['allowRowLocks']), + allowPageLocks: Boolean(options['allowPageLocks']), + optimizeForSequentialKey: options['isOptimizedForSequentialKey'], + padIndex: options['isPadded'], + dataCompression: options['dataCompression'], + }), + }); + +const hydratePrimaryKeyOptions = (options, columnName, isActivated) => + clean({ + keyType: 'PRIMARY KEY', + name: options['constraintName'], + columns: [ + { + name: columnName, + isActivated: isActivated, + }, + ], + partition: options['partitionName'], + clustered: options['clustered'], + indexOption: clean({ + statisticsNoRecompute: options['staticticsNorecompute'], + statisticsIncremental: options['statisticsIncremental'], + ignoreDuplicateKey: options['ignoreDuplicate'], + fillFactor: options['fillFactor'], + allowRowLocks: Boolean(options['allowRowLocks']), + allowPageLocks: Boolean(options['allowPageLocks']), + optimizeForSequentialKey: options['isOptimizedForSequentialKey'], + padIndex: options['isPadded'], + dataCompression: options['dataCompression'], + }), + }); + +const findName = (keyId, properties) => { + return Object.keys(properties).find(name => properties[name].GUID === keyId); +}; - const hydrateUniqueOptions = (options, columnName, isActivated) => - clean({ - keyType: 'UNIQUE', - name: options['constraintName'], - columns: [ - { - name: columnName, - isActivated: isActivated, - }, - ], - partition: options['partitionName'], - clustered: options['clustered'], - indexOption: clean({ - statisticsNoRecompute: options['staticticsNorecompute'], - statisticsIncremental: options['statisticsIncremental'], - ignoreDuplicateKey: options['ignoreDuplicate'], - fillFactor: options['fillFactor'], - allowRowLocks: Boolean(options['allowRowLocks']), - allowPageLocks: Boolean(options['allowPageLocks']), - optimizeForSequentialKey: options['isOptimizedForSequentialKey'], - padIndex: options['isPadded'], - dataCompression: options['dataCompression'], - }), - }); +const checkIfActivated = (keyId, properties) => { + return _.get( + Object.values(properties).find(prop => prop.GUID === keyId), + 'isActivated', + true, + ); +}; - const hydratePrimaryKeyOptions = (options, columnName, isActivated) => - clean({ - keyType: 'PRIMARY KEY', - name: options['constraintName'], - columns: [ - { - name: columnName, - isActivated: isActivated, - }, - ], - partition: options['partitionName'], - clustered: options['clustered'], - indexOption: clean({ - statisticsNoRecompute: options['staticticsNorecompute'], - statisticsIncremental: options['statisticsIncremental'], - ignoreDuplicateKey: options['ignoreDuplicate'], - fillFactor: options['fillFactor'], - allowRowLocks: Boolean(options['allowRowLocks']), - allowPageLocks: Boolean(options['allowPageLocks']), - optimizeForSequentialKey: options['isOptimizedForSequentialKey'], - padIndex: options['isPadded'], - dataCompression: options['dataCompression'], - }), - }); +const getKeys = (keys, jsonSchema) => { + return keys.map(key => { + return { + name: findName(key.keyId, jsonSchema.properties), + isActivated: checkIfActivated(key.keyId, jsonSchema.properties), + }; + }); +}; - const findName = (keyId, properties) => { - return Object.keys(properties).find(name => properties[name].GUID === keyId); - }; +const getCompositePrimaryKeys = jsonSchema => { + if (!Array.isArray(jsonSchema.primaryKey)) { + return []; + } + + return jsonSchema.primaryKey + .filter(primaryKey => !_.isEmpty(primaryKey.compositePrimaryKey)) + .map(primaryKey => ({ + ...hydratePrimaryKeyOptions(primaryKey), + columns: getKeys(primaryKey.compositePrimaryKey, jsonSchema), + })); +}; - const checkIfActivated = (keyId, properties) => { - return _.get( - Object.values(properties).find(prop => prop.GUID === keyId), - 'isActivated', - true, - ); - }; +const getCompositeUniqueKeys = jsonSchema => { + if (!Array.isArray(jsonSchema.uniqueKey)) { + return []; + } + + return jsonSchema.uniqueKey + .filter(uniqueKey => !_.isEmpty(uniqueKey.compositeUniqueKey)) + .map(uniqueKey => ({ + ...hydrateUniqueOptions(uniqueKey), + columns: getKeys(uniqueKey.compositeUniqueKey, jsonSchema), + })); +}; - const getKeys = (keys, jsonSchema) => { - return keys.map(key => { - return { - name: findName(key.keyId, jsonSchema.properties), - isActivated: checkIfActivated(key.keyId, jsonSchema.properties), - }; - }); - }; +const getTableKeyConstraints = ({ jsonSchema }) => { + if (!jsonSchema.properties) { + return []; + } - const getCompositePrimaryKeys = jsonSchema => { - if (!Array.isArray(jsonSchema.primaryKey)) { - return []; + const uniqueConstraints = mapProperties(jsonSchema, ([name, columnSchema]) => { + if (isUnique(columnSchema)) { + return columnSchema.uniqueKeyOptions.map(options => + hydrateUniqueOptions(options, name, columnSchema.isActivated), + ); } - return jsonSchema.primaryKey - .filter(primaryKey => !_.isEmpty(primaryKey.compositePrimaryKey)) - .map(primaryKey => ({ - ...hydratePrimaryKeyOptions(primaryKey), - columns: getKeys(primaryKey.compositePrimaryKey, jsonSchema), - })); - }; + return []; + }) + .flat() + .filter(Boolean); - const getCompositeUniqueKeys = jsonSchema => { - if (!Array.isArray(jsonSchema.uniqueKey)) { - return []; + const primaryKeyConstraints = mapProperties(jsonSchema, ([name, columnSchema]) => { + if (isPrimaryKey(columnSchema)) { + return hydratePrimaryKeyOptions(columnSchema.primaryKeyOptions, name, columnSchema.isActivated); } + }).filter(Boolean); + + return [ + ...getCompositePrimaryKeys(jsonSchema), + ...primaryKeyConstraints, + ...getCompositeUniqueKeys(jsonSchema), + ...uniqueConstraints, + ]; +}; - return jsonSchema.uniqueKey - .filter(uniqueKey => !_.isEmpty(uniqueKey.compositeUniqueKey)) - .map(uniqueKey => ({ - ...hydrateUniqueOptions(uniqueKey), - columns: getKeys(uniqueKey.compositeUniqueKey, jsonSchema), - })); - }; - - const getTableKeyConstraints = ({ jsonSchema }) => { - if (!jsonSchema.properties) { - return []; - } - - const uniqueConstraints = _.flatten( - mapProperties(jsonSchema, ([name, columnSchema]) => { - if (!isUnique(columnSchema)) { - return []; - } else { - return columnSchema.uniqueKeyOptions.map(options => - hydrateUniqueOptions(options, name, columnSchema.isActivated), - ); - } - }), - ).filter(Boolean); - const primaryKeyConstraints = mapProperties(jsonSchema, ([name, columnSchema]) => { - if (!isPrimaryKey(columnSchema)) { - return; - } else { - return hydratePrimaryKeyOptions(columnSchema.primaryKeyOptions, name, columnSchema.isActivated); - } - }).filter(Boolean); - - return [ - ...getCompositePrimaryKeys(jsonSchema), - ...primaryKeyConstraints, - ...getCompositeUniqueKeys(jsonSchema), - ...uniqueConstraints, - ]; - }; - - const getTablePartitionKey = jsonSchema => { - const partitionKeys = getKeys(jsonSchema.partition || [], jsonSchema); - return { - ..._.get(partitionKeys, '[0]', {}), - boundaryValue: jsonSchema.boundaryValue, - rangeForValues: jsonSchema.rangeForValues, - }; +const getTablePartitionKey = jsonSchema => { + const partitionKeys = getKeys(jsonSchema.partition || [], jsonSchema); + return { + ..._.get(partitionKeys, '[0]', {}), + boundaryValue: jsonSchema.boundaryValue, + rangeForValues: jsonSchema.rangeForValues, }; +}; - /** - * @param {{ columnDefinition: ColumnDefinition }} - * @returns {ConstraintDto | undefined} - */ - const getPrimaryKeyConstraint = ({ columnDefinition }) => { - if (!isPrimaryKey(columnDefinition) && !isInlinePrimaryKey(columnDefinition)) { - return; - } +/** + * @param {{ columnDefinition: ColumnDefinition }} + * @returns {ConstraintDto | undefined} + */ +const getPrimaryKeyConstraint = ({ columnDefinition }) => { + if (!isPrimaryKey(columnDefinition) && !isInlinePrimaryKey(columnDefinition)) { + return; + } - return hydratePrimaryKeyOptions(_.get(columnDefinition, 'primaryKeyOptions.[0]', {})); - }; + return hydratePrimaryKeyOptions(_.get(columnDefinition, 'primaryKeyOptions.[0]', {})); +}; - /** - * @param {{ columnDefinition: ColumnDefinition }} - * @returns {ConstraintDto | undefined} - */ - const getUniqueKeyConstraint = ({ columnDefinition }) => { - if (!isUnique(columnDefinition) && !isInlineUnique(columnDefinition)) { - return; - } +/** + * @param {{ columnDefinition: ColumnDefinition }} + * @returns {ConstraintDto | undefined} + */ +const getUniqueKeyConstraint = ({ columnDefinition }) => { + if (!isUnique(columnDefinition) && !isInlineUnique(columnDefinition)) { + return; + } - return hydrateUniqueOptions(_.get(columnDefinition, 'uniqueKeyOptions.[0]', {})); - }; + return hydrateUniqueOptions(_.get(columnDefinition, 'uniqueKeyOptions.[0]', {})); +}; - const getCompositeKeyConstraints = ({ jsonSchema }) => { - const compositePrimaryKeys = getCompositePrimaryKeys(jsonSchema); - const compositeUniqueKeys = getCompositeUniqueKeys(jsonSchema); +const getCompositeKeyConstraints = ({ jsonSchema }) => { + const compositePrimaryKeys = getCompositePrimaryKeys(jsonSchema); + const compositeUniqueKeys = getCompositeUniqueKeys(jsonSchema); - return [...compositePrimaryKeys, ...compositeUniqueKeys]; - }; + return [...compositePrimaryKeys, ...compositeUniqueKeys]; +}; - /** - * @param {{ columnDefinition: ColumnDefinition }} - * @returns {ConstraintDto[]} - */ - const getColumnConstraints = ({ columnDefinition }) => { - const primaryKeyConstraint = getPrimaryKeyConstraint({ columnDefinition }); - const uniqueKeyConstraint = getUniqueKeyConstraint({ columnDefinition }); +/** + * @param {{ columnDefinition: ColumnDefinition }} + * @returns {ConstraintDto[]} + */ +const getColumnConstraints = ({ columnDefinition }) => { + const primaryKeyConstraint = getPrimaryKeyConstraint({ columnDefinition }); + const uniqueKeyConstraint = getUniqueKeyConstraint({ columnDefinition }); - return [primaryKeyConstraint, uniqueKeyConstraint].filter(Boolean); - }; + return [primaryKeyConstraint, uniqueKeyConstraint].filter(Boolean); +}; - return { - getTableKeyConstraints, - isInlineUnique, - isInlinePrimaryKey, - getTablePartitionKey, - getCompositeKeyConstraints, - getColumnConstraints, - }; +module.exports = { + getTableKeyConstraints, + isInlineUnique, + isInlinePrimaryKey, + getTablePartitionKey, + getCompositeKeyConstraints, + getColumnConstraints, }; diff --git a/forward_engineering/utils/assignTemplates.js b/forward_engineering/utils/assignTemplates.js new file mode 100644 index 0000000..95bd1bc --- /dev/null +++ b/forward_engineering/utils/assignTemplates.js @@ -0,0 +1,15 @@ +const template = (modifiers = '') => new RegExp('\\$\\{(.*?)}', modifiers); +const getAllTemplates = str => str.match(template('gi')) || []; +const parseTemplate = str => (str.match(template('i')) || [])[1]; + +const assignTemplates = (str, templates) => { + return getAllTemplates(str).reduce((result, item) => { + const templateName = parseTemplate(item); + + return result.replace(item, () => { + return templates[templateName] || templates[templateName] === 0 ? templates[templateName] : ''; + }); + }, str); +}; + +module.exports = { assignTemplates }; diff --git a/forward_engineering/utils/general.js b/forward_engineering/utils/general.js new file mode 100644 index 0000000..9812e8c --- /dev/null +++ b/forward_engineering/utils/general.js @@ -0,0 +1,42 @@ +const _ = require('lodash'); + +const checkAllKeysDeactivated = keys => (keys.length ? keys.every(key => !_.get(key, 'isActivated', true)) : false); + +const clean = obj => + Object.entries(obj) + .filter(([name, value]) => !_.isNil(value)) + .reduce((result, [name, value]) => ({ ...result, [name]: value }), {}); + +const divideIntoActivatedAndDeactivated = (items, mapFunction) => { + const activatedItems = items.filter(item => _.get(item, 'isActivated', true)).map(mapFunction); + const deactivatedItems = items.filter(item => !_.get(item, 'isActivated', true)).map(mapFunction); + return { activatedItems, deactivatedItems }; +}; + +const getDbData = containerData => { + return { ..._.get(containerData, '[0]', {}), name: getDbName(containerData) }; +}; + +const getDbName = containerData => { + return _.get(containerData, '[0].code') || _.get(containerData, '[0].name', ''); +}; + +const getEntityName = entityData => { + return (entityData && (entityData.code || entityData.collectionName)) || ''; +}; + +const tab = (text, tab = '\t') => + text + .split('\n') + .map(line => tab + line) + .join('\n'); + +module.exports = { + checkAllKeysDeactivated, + clean, + divideIntoActivatedAndDeactivated, + getDbData, + getDbName, + getEntityName, + tab, +}; From 9ac85a248cbcfa165d5494975b1fd3afdd12a1b5 Mon Sep 17 00:00:00 2001 From: chulanovskyi Date: Tue, 4 Nov 2025 01:34:15 +0200 Subject: [PATCH 03/10] feat: removed invalid script option entries --- forward_engineering/config.json | 172 -------------------------------- 1 file changed, 172 deletions(-) diff --git a/forward_engineering/config.json b/forward_engineering/config.json index 3100863..dd1d98a 100644 --- a/forward_engineering/config.json +++ b/forward_engineering/config.json @@ -296,178 +296,6 @@ } } ] - }, - { - "keyword": "schemaComments", - "label": "FE_SCRIPT_GENERATION_OPTIONS___SCHEMA_COMMENTS", - "disabled": false, - "value": { - "inline": { - "default": true, - "disabled": false, - "disabledLabel": "" - }, - "separate": { - "default": false, - "disabled": false, - "disabledLabel": "" - }, - "ignore": { - "default": false, - "disabled": false, - "disabledLabel": "" - } - }, - "adapters": [ - { - "dependency": { - "type": "and", - "values": [ - { - "key": "type", - "value": "bucket" - }, - { - "key": "description", - "exist": true - } - ] - }, - "defaultValue": { - "description": "" - } - } - ] - }, - { - "keyword": "tableComments", - "label": "FE_SCRIPT_GENERATION_OPTIONS___TABLE_COMMENTS", - "disabled": false, - "value": { - "inline": { - "default": true, - "disabled": false, - "disabledLabel": "" - }, - "separate": { - "default": false, - "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": true, - "disabled": false, - "disabledLabel": "" - }, - "separate": { - "default": false, - "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": true, - "disabled": false, - "disabledLabel": "" - }, - "separate": { - "default": false, - "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": "" - } - } - ] } ] } From 660edb60a86cd7a7e61895193657a5227c2f3ce8 Mon Sep 17 00:00:00 2001 From: chulanovskyi Date: Tue, 4 Nov 2025 01:47:41 +0200 Subject: [PATCH 04/10] feat: added dedicated fe/api --- api/fe.js | 11 ++ esbuild.package.js | 1 + forward_engineering/api.js | 121 ++---------------- forward_engineering/api/applyToInstance.js | 18 +++ .../api/generateContainerScript.js | 20 +++ forward_engineering/api/generateScript.js | 35 +++++ forward_engineering/api/generateViewScript.js | 7 + .../api/getExternalBrowserUrl.js | 9 ++ forward_engineering/api/isDropInStatements.js | 25 ++++ forward_engineering/api/testConnection.js | 21 +++ 10 files changed, 161 insertions(+), 107 deletions(-) create mode 100644 api/fe.js create mode 100644 forward_engineering/api/applyToInstance.js create mode 100644 forward_engineering/api/generateContainerScript.js create mode 100644 forward_engineering/api/generateScript.js create mode 100644 forward_engineering/api/generateViewScript.js create mode 100644 forward_engineering/api/getExternalBrowserUrl.js create mode 100644 forward_engineering/api/isDropInStatements.js create mode 100644 forward_engineering/api/testConnection.js diff --git a/api/fe.js b/api/fe.js new file mode 100644 index 0000000..c61aabc --- /dev/null +++ b/api/fe.js @@ -0,0 +1,11 @@ +const { generateScript } = require('../forward_engineering/api/generateScript'); +const { generateViewScript } = require('../forward_engineering/api/generateViewScript'); +const { generateContainerScript } = require('../forward_engineering/api/generateContainerScript'); +const { isDropInStatements } = require('../forward_engineering/api/isDropInStatements'); + +module.exports = { + generateScript, + generateViewScript, + generateContainerScript, + isDropInStatements, +}; diff --git a/esbuild.package.js b/esbuild.package.js index 2cb44c0..a64cf2b 100644 --- a/esbuild.package.js +++ b/esbuild.package.js @@ -12,6 +12,7 @@ const RELEASE_FOLDER_PATH = path.join(DEFAULT_RELEASE_FOLDER_PATH, `${packageDat esbuild .build({ entryPoints: [ + path.resolve(__dirname, 'api', 'fe.js'), path.resolve(__dirname, 'forward_engineering', 'api.js'), path.resolve(__dirname, 'forward_engineering', 'ddlProvider.js'), path.resolve(__dirname, 'forward_engineering', 'dbtProvider.js'), diff --git a/forward_engineering/api.js b/forward_engineering/api.js index c5b4c31..239ce48 100644 --- a/forward_engineering/api.js +++ b/forward_engineering/api.js @@ -1,110 +1,17 @@ -const { commentDropStatements } = require('./helpers/commentDropStatements'); -const { DROP_STATEMENTS } = require('./helpers/constants'); -const { connect, getExternalBrowserUrl } = require('../reverse_engineering/api'); -const { logInfo } = require('../reverse_engineering/helpers/logInfo'); -const applyToInstanceHelper = require('./helpers/applyToInstanceHelper'); +const { applyToInstance } = require('./api/applyToInstance'); +const { generateContainerScript } = require('./api/generateContainerScript'); +const { generateScript } = require('./api/generateScript'); +const { generateViewScript } = require('./api/generateViewScript'); +const { getExternalBrowserUrl } = require('../reverse_engineering/api'); +const { isDropInStatements } = require('./api/isDropInStatements'); +const { testConnection } = require('./api/testConnection'); module.exports = { - generateScript(data, logger, callback, app) { - try { - const { - getAlterContainersScripts, - getAlterCollectionsScripts, - getAlterViewScripts, - } = require('./helpers/alterScriptFromDeltaHelper'); - - const collection = JSON.parse(data.jsonSchema); - if (!collection) { - throw new Error( - '"comparisonModelCollection" is not found. Alter script can be generated only from Delta model', - ); - } - - const containersScripts = getAlterContainersScripts(collection, app, data.options); - const collectionsScripts = getAlterCollectionsScripts(collection, app, data.options); - const viewScripts = getAlterViewScripts(collection, app, data.options); - const script = [...containersScripts, ...collectionsScripts, ...viewScripts].join('\n\n'); - - const applyDropStatements = data.options?.additionalOptions?.some( - option => option.id === 'applyDropStatements' && option.value, - ); - callback(null, applyDropStatements ? script : commentDropStatements(script)); - } catch (error) { - logger.log( - 'error', - { message: error.message, stack: error.stack }, - 'Azure Synapse Forward-Engineering Error', - ); - - callback({ message: error.message, stack: error.stack }); - } - }, - - generateViewScript(data, logger, callback, app) { - callback(new Error('Forward-Engineering of delta model on view level is not supported')); - }, - - generateContainerScript(data, logger, callback, app) { - try { - data.jsonSchema = data.collections[0]; - this.generateScript(data, logger, callback, app); - } catch (error) { - logger.log( - 'error', - { message: error.message, stack: error.stack }, - 'Azure Synapse Server Forward-Engineering Error', - ); - - callback({ message: error.message, stack: error.stack }); - } - }, - - isDropInStatements(data, logger, callback, app) { - try { - const cb = (error, script = '') => - callback( - error, - DROP_STATEMENTS.some(statement => script.includes(statement)), - ); - - if (data.level === 'container') { - this.generateContainerScript(data, logger, cb, app); - } else { - this.generateScript(data, logger, cb, app); - } - } catch (e) { - callback({ message: e.message, stack: e.stack }); - } - }, - - async testConnection(connectionInfo, logger, callback, app) { - try { - logInfo('Test connection', connectionInfo, logger); - if (connectionInfo.authMethod === 'Azure Active Directory (MFA)') { - await getExternalBrowserUrl(connectionInfo, logger, callback); - } else { - await connect(connectionInfo, logger); - } - callback(null); - } catch (error) { - logger.log('error', { message: error.message, stack: error.stack, error }, 'Test connection'); - callback({ message: error.message, stack: error.stack }); - } - }, - - async applyToInstance(connectionInfo, logger, callback, app) { - logger.clear(); - logInfo('Apply To Instance', connectionInfo, logger); - - try { - await applyToInstanceHelper.applyToInstance(connectionInfo, logger, app); - callback(null); - } catch (error) { - callback(error); - } - }, - - async getExternalBrowserUrl(connectionInfo, logger, cb, app) { - return getExternalBrowserUrl(connectionInfo, logger, cb, app); - }, + applyToInstance, + generateContainerScript, + generateScript, + generateViewScript, + getExternalBrowserUrl, + isDropInStatements, + testConnection, }; diff --git a/forward_engineering/api/applyToInstance.js b/forward_engineering/api/applyToInstance.js new file mode 100644 index 0000000..6d22d2e --- /dev/null +++ b/forward_engineering/api/applyToInstance.js @@ -0,0 +1,18 @@ +const applyToInstanceHelper = require('../helpers/applyToInstanceHelper'); +const { logInfo } = require('../../reverse_engineering/helpers/logInfo'); + +async function applyToInstance(connectionInfo, logger, callback, app) { + logger.clear(); + logInfo('Apply To Instance', connectionInfo, logger); + + try { + await applyToInstanceHelper.applyToInstance(connectionInfo, logger, app); + callback(null); + } catch (error) { + callback(error); + } +} + +module.exports = { + applyToInstance, +}; diff --git a/forward_engineering/api/generateContainerScript.js b/forward_engineering/api/generateContainerScript.js new file mode 100644 index 0000000..c4d91ac --- /dev/null +++ b/forward_engineering/api/generateContainerScript.js @@ -0,0 +1,20 @@ +const { generateScript } = require('./generateScript'); + +function generateContainerScript(data, logger, callback, app) { + try { + data.jsonSchema = data.collections[0]; + generateScript(data, logger, callback, app); + } catch (error) { + logger.log( + 'error', + { message: error.message, stack: error.stack }, + 'Azure Synapse Server Forward-Engineering Error', + ); + + callback({ message: error.message, stack: error.stack }); + } +} + +module.exports = { + generateContainerScript, +}; diff --git a/forward_engineering/api/generateScript.js b/forward_engineering/api/generateScript.js new file mode 100644 index 0000000..d0db3ee --- /dev/null +++ b/forward_engineering/api/generateScript.js @@ -0,0 +1,35 @@ +const { + getAlterContainersScripts, + getAlterCollectionsScripts, + getAlterViewScripts, +} = require('../helpers/alterScriptFromDeltaHelper'); +const { commentDropStatements } = require('../helpers/commentDropStatements'); + +function generateScript(data, logger, callback, app) { + try { + const collection = JSON.parse(data.jsonSchema); + if (!collection) { + throw new Error( + '"comparisonModelCollection" is not found. Alter script can be generated only from Delta model', + ); + } + + const containersScripts = getAlterContainersScripts(collection, app, data.options); + const collectionsScripts = getAlterCollectionsScripts(collection, app, data.options); + const viewScripts = getAlterViewScripts(collection, app, data.options); + const script = [...containersScripts, ...collectionsScripts, ...viewScripts].join('\n\n'); + + const applyDropStatements = data.options?.additionalOptions?.some( + option => option.id === 'applyDropStatements' && option.value, + ); + callback(null, applyDropStatements ? script : commentDropStatements(script)); + } catch (error) { + logger.log('error', { message: error.message, stack: error.stack }, 'Azure Synapse Forward-Engineering Error'); + + callback({ message: error.message, stack: error.stack }); + } +} + +module.exports = { + generateScript, +}; diff --git a/forward_engineering/api/generateViewScript.js b/forward_engineering/api/generateViewScript.js new file mode 100644 index 0000000..ddb2b38 --- /dev/null +++ b/forward_engineering/api/generateViewScript.js @@ -0,0 +1,7 @@ +function generateViewScript(data, logger, callback, app) { + callback(new Error('Forward-Engineering of delta model on view level is not supported')); +} + +module.exports = { + generateViewScript, +}; diff --git a/forward_engineering/api/getExternalBrowserUrl.js b/forward_engineering/api/getExternalBrowserUrl.js new file mode 100644 index 0000000..b0c489d --- /dev/null +++ b/forward_engineering/api/getExternalBrowserUrl.js @@ -0,0 +1,9 @@ +const revEngApi = require('../../reverse_engineering/api'); + +async function getExternalBrowserUrl(connectionInfo, logger, cb, app) { + return revEngApi.getExternalBrowserUrl(connectionInfo, logger, cb, app); +} + +module.exports = { + getExternalBrowserUrl, +}; diff --git a/forward_engineering/api/isDropInStatements.js b/forward_engineering/api/isDropInStatements.js new file mode 100644 index 0000000..2c03578 --- /dev/null +++ b/forward_engineering/api/isDropInStatements.js @@ -0,0 +1,25 @@ +const { DROP_STATEMENTS } = require('../helpers/constants'); +const { generateContainerScript } = require('./generateContainerScript'); +const { generateScript } = require('./generateScript'); + +function isDropInStatements(data, logger, callback, app) { + try { + const cb = (error, script = '') => + callback( + error, + DROP_STATEMENTS.some(statement => script.includes(statement)), + ); + + if (data.level === 'container') { + generateContainerScript(data, logger, cb, app); + } else { + generateScript(data, logger, cb, app); + } + } catch (e) { + callback({ message: e.message, stack: e.stack }); + } +} + +module.exports = { + isDropInStatements, +}; diff --git a/forward_engineering/api/testConnection.js b/forward_engineering/api/testConnection.js new file mode 100644 index 0000000..0b25832 --- /dev/null +++ b/forward_engineering/api/testConnection.js @@ -0,0 +1,21 @@ +const { logInfo } = require('../../reverse_engineering/helpers/logInfo'); +const { getExternalBrowserUrl, connect } = require('../../reverse_engineering/api'); + +async function testConnection(connectionInfo, logger, callback, app) { + try { + logInfo('Test connection', connectionInfo, logger); + if (connectionInfo.authMethod === 'Azure Active Directory (MFA)') { + await getExternalBrowserUrl(connectionInfo, logger, callback); + } else { + await connect(connectionInfo, logger); + } + callback(null); + } catch (error) { + logger.log('error', { message: error.message, stack: error.stack, error }, 'Test connection'); + callback({ message: error.message, stack: error.stack }); + } +} + +module.exports = { + testConnection, +}; From b767d2e0ba08ded4789a7f3575a08116e147b44d Mon Sep 17 00:00:00 2001 From: chulanovskyi Date: Wed, 5 Nov 2025 18:15:26 +0200 Subject: [PATCH 05/10] fix: proper import --- forward_engineering/api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forward_engineering/api.js b/forward_engineering/api.js index 239ce48..d797226 100644 --- a/forward_engineering/api.js +++ b/forward_engineering/api.js @@ -2,7 +2,7 @@ const { applyToInstance } = require('./api/applyToInstance'); const { generateContainerScript } = require('./api/generateContainerScript'); const { generateScript } = require('./api/generateScript'); const { generateViewScript } = require('./api/generateViewScript'); -const { getExternalBrowserUrl } = require('../reverse_engineering/api'); +const { getExternalBrowserUrl } = require('./api/getExternalBrowserUrl'); const { isDropInStatements } = require('./api/isDropInStatements'); const { testConnection } = require('./api/testConnection'); From 406aa7c1f9d73c056187a55d7141e25e7b2fa1fe Mon Sep 17 00:00:00 2001 From: chulanovskyi Date: Thu, 6 Nov 2025 11:24:40 +0200 Subject: [PATCH 06/10] removed unused options --- forward_engineering/config.json | 65 --------------------------------- 1 file changed, 65 deletions(-) diff --git a/forward_engineering/config.json b/forward_engineering/config.json index dd1d98a..fd2bb5b 100644 --- a/forward_engineering/config.json +++ b/forward_engineering/config.json @@ -101,28 +101,6 @@ } ] }, - { - "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", @@ -221,49 +199,6 @@ } ] }, - { - "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": { - "type": "or", - "values": [ - { - "key": "chkConstr", - "valueType": "array" - }, - { - "key": "checkConstraint", - "valueType": "array" - } - ] - }, - "defaultValue": { - "chkConstr": [], - "checkConstraint": [] - } - } - ] - }, { "keyword": "columnDefaultValues", "label": "FE_SCRIPT_GENERATION_OPTIONS___COLUMN_DEFAULT_VALUES", From 408c3f480b9cdcd60d6196567cfa552a21463f61 Mon Sep 17 00:00:00 2001 From: Taras Dubyk Date: Thu, 6 Nov 2025 15:48:43 +0200 Subject: [PATCH 07/10] HCK-13407: add primary, unique constraints handling for the script options (#126) * add pk, uk script options * add commenting deactivated pk, uk constraints * remove drop inline pk, uk constraint * remove comment * refactor: reduce duplication --- .../helpers/alterScriptFromDeltaHelper.js | 8 + .../alterScriptHelpers/alterEntityHelper.js | 10 + .../entityHelper/primaryKeyHelper.js | 26 ++ .../entityHelper/sharedKeyConstraintHelper.js | 364 ++++++++++++++++++ .../entityHelper/uniqueKeyHelper.js | 26 ++ 5 files changed, 434 insertions(+) create mode 100644 forward_engineering/helpers/alterScriptHelpers/entityHelper/primaryKeyHelper.js create mode 100644 forward_engineering/helpers/alterScriptHelpers/entityHelper/sharedKeyConstraintHelper.js create mode 100644 forward_engineering/helpers/alterScriptHelpers/entityHelper/uniqueKeyHelper.js diff --git a/forward_engineering/helpers/alterScriptFromDeltaHelper.js b/forward_engineering/helpers/alterScriptFromDeltaHelper.js index 46110e4..10dfcd8 100644 --- a/forward_engineering/helpers/alterScriptFromDeltaHelper.js +++ b/forward_engineering/helpers/alterScriptFromDeltaHelper.js @@ -29,6 +29,7 @@ const getAlterCollectionsScripts = (collection, app, options) => { getDeleteColumnScript, getModifyColumnScript, getModifyCollectionScript, + getModifyCollectionKeysScript, } = require('./alterScriptHelpers/alterEntityHelper')(app, options); const createCollectionsScripts = [collection.properties?.entities?.properties?.added?.items] @@ -72,6 +73,12 @@ const getAlterCollectionsScripts = (collection, app, options) => { .map(item => Object.values(item.properties)[0]) .flatMap(getModifyColumnScript); + const modifyCollectionKeysScripts = [collection.properties?.entities?.properties?.modified?.items] + .flat() + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .flatMap(getModifyCollectionKeysScript); + return [ ...createCollectionsScripts, ...deleteCollectionScripts, @@ -79,6 +86,7 @@ const getAlterCollectionsScripts = (collection, app, options) => { ...modifyCollectionScripts, ...deleteColumnScripts, ...modifyColumnScript, + ...modifyCollectionKeysScripts, ] .filter(Boolean) .map(script => script.trim()); diff --git a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js index b458109..2e5f956 100644 --- a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js @@ -3,6 +3,8 @@ const { getTableName } = require('../general'); const { getEntityName } = require('../../utils/general'); const { createColumnDefinitionBySchema } = require('./createColumnDefinition'); const { checkFieldPropertiesChanged, modifyGroupItems, setIndexKeys } = require('./common'); +const { getModifyPkScripts } = require('./entityHelper/primaryKeyHelper'); +const { getModifyUkScripts } = require('./entityHelper/uniqueKeyHelper'); const alterEntityHelper = (app, options) => { const ddlProvider = require('../../ddlProvider')(null, options, app); @@ -150,6 +152,13 @@ const alterEntityHelper = (app, options) => { return [...renameColumnScripts, ...changeTypeScripts]; }; + const getModifyCollectionKeysScript = collection => { + const modifyPkScripts = getModifyPkScripts(collection, options); + const modifyUkScripts = getModifyUkScripts(collection, options); + + return [...modifyPkScripts, ...modifyUkScripts].filter(Boolean); + }; + const hydrateIndex = ({ idToNameHashTable, idToActivatedHashTable, ddlProvider, tableData, schemaData }) => index => { @@ -165,6 +174,7 @@ const alterEntityHelper = (app, options) => { getAddColumnScript, getDeleteColumnScript, getModifyColumnScript, + getModifyCollectionKeysScript, }; }; diff --git a/forward_engineering/helpers/alterScriptHelpers/entityHelper/primaryKeyHelper.js b/forward_engineering/helpers/alterScriptHelpers/entityHelper/primaryKeyHelper.js new file mode 100644 index 0000000..16ae297 --- /dev/null +++ b/forward_engineering/helpers/alterScriptHelpers/entityHelper/primaryKeyHelper.js @@ -0,0 +1,26 @@ +const { getModifyKeyScripts } = require('./sharedKeyConstraintHelper'); + +/** + * Primary Key constraint configuration + */ +const PRIMARY_KEY_CONFIG = { + constraintType: 'PRIMARY KEY', + compModKeyName: 'primaryKey', + columnKeyProperty: 'primaryKey', + compositeKeyProperty: 'compositePrimaryKey', +}; + +/** + * Get all modify PK scripts (both composite and regular) + * + * @param {Object} collection + * @param {Object} options + * @return {string[]} + */ +const getModifyPkScripts = (collection, options) => { + return getModifyKeyScripts(collection, PRIMARY_KEY_CONFIG, options); +}; + +module.exports = { + getModifyPkScripts, +}; diff --git a/forward_engineering/helpers/alterScriptHelpers/entityHelper/sharedKeyConstraintHelper.js b/forward_engineering/helpers/alterScriptHelpers/entityHelper/sharedKeyConstraintHelper.js new file mode 100644 index 0000000..68d54ab --- /dev/null +++ b/forward_engineering/helpers/alterScriptHelpers/entityHelper/sharedKeyConstraintHelper.js @@ -0,0 +1,364 @@ +const _ = require('lodash'); +const { getTableName } = require('../../general'); +const { getEntityName } = require('../../../utils/general'); +const { assignTemplates } = require('../../../utils/assignTemplates'); +const templates = require('../../../configs/templates'); +const { getTerminator } = require('../../optionsHelper'); +const { commentIfDeactivated } = require('../../commentIfDeactivated'); + +/** + * Convert keys to string with proper handling of activated/deactivated columns + * @param {Array<{name: string, isActivated: boolean}>} keys + * @param {boolean} isParentActivated - whether the parent table is activated + * @return {string} + */ +const keysToString = (keys, isParentActivated) => { + if (!Array.isArray(keys) || keys.length === 0) { + return ''; + } + + const splitter = ', '; + let deactivatedKeys = []; + const processedKeys = keys + .reduce((keysArray, key) => { + const keyName = `[${key.name}]`; + + if (!_.get(key, 'isActivated', true)) { + deactivatedKeys.push(keyName); + return keysArray; + } + + return [...keysArray, keyName]; + }, []) + .filter(Boolean); + + // If parent is not activated or no activated keys, + // return all keys without commenting, to avoid nested comments + if (!isParentActivated || processedKeys.length === 0) { + return keys.map(key => `[${key.name}]`).join(splitter); + } + + // If no deactivated keys, return activated keys only + if (deactivatedKeys.length === 0) { + return processedKeys.join(splitter); + } + + // Mix of activated and deactivated keys + return ( + processedKeys.join(splitter) + + commentIfDeactivated(splitter + deactivatedKeys.join(splitter), { isActivated: false }, true) + ); +}; + +/** + * Get only activated keys as string (for when we don't support partial deactivation) + * @param {Array<{name: string, isActivated: boolean}>} keys + * @return {string} + */ +const activeKeysToString = keys => { + return keys?.map(key => `[${key.name}]`).join(', '); +}; + +/** + * Configuration object for key constraint handling + * @typedef {Object} KeyConstraintConfig + * @property {string} constraintType - e.g., 'PRIMARY KEY' or 'UNIQUE' + * @property {string} compModKeyName - e.g., 'primaryKey' or 'uniqueKey' + * @property {string} columnKeyProperty - e.g., 'primaryKey' or 'unique' + * @property {string} compositeKeyProperty - e.g., 'compositePrimaryKey' or 'compositeUniqueKey' + */ + +/** + * Get column names from composite key by matching keyId with column GUID + * @param {Array<{ type: string, keyId: string}>} compositeKey + * @param {Object.} properties + * @param {KeyConstraintConfig} config + */ +const getCompositeKeyColumnNames = (compositeKey, properties, config) => { + return compositeKey + .map(keyDto => { + const column = Object.entries(properties).find(([name, col]) => col.GUID === keyDto.keyId); + return column ? { name: column[0], isActivated: column[1].isActivated } : null; + }) + .filter(Boolean); +}; + +/** + * Compare constraint details + * @param {Object} oldConstraint + * @param {Object} newConstraint + * @return {boolean} + */ +const areConstraintsEqual = (oldConstraint, newConstraint) => { + return _.isEqual(oldConstraint, newConstraint); +}; + +/** + * Check if composite keys have changed and return key data if so + * @param {Object} collection + * @param {KeyConstraintConfig} config + * @return {{hasChanges: boolean, newKeys: Array, oldKeys: Array, tableInfo: Object} | null} + */ +const getCompositeKeyChangeData = (collection, config) => { + const keyDto = collection?.role?.compMod?.[config.compModKeyName] || {}; + const newKeys = keyDto.new || []; + const oldKeys = keyDto.old || []; + + if (newKeys.length === 0 && oldKeys.length === 0) { + return null; + } + + if (newKeys.length === oldKeys.length) { + const areKeyArraysEqual = _(oldKeys).differenceWith(newKeys, _.isEqual).isEmpty(); + if (areKeyArraysEqual) { + return null; + } + } + + const collectionSchema = { ...collection, ..._.omit(collection?.role, 'properties') }; + const tableName = getEntityName(collectionSchema); + const schemaName = collection.compMod?.keyspaceName; + const fullName = getTableName(tableName, schemaName); + const isTableActivated = _.get(collectionSchema, 'isActivated', true); + + return { + hasChanges: true, + newKeys, + oldKeys, + tableInfo: { + fullName, + isTableActivated, + }, + }; +}; + +/** + * Get ADD CONSTRAINT scripts for composite keys + * @param {Object} collection + * @param {KeyConstraintConfig} config + * @param {Object} options + * @return {string[]} + */ +const getAddCompositeKeyScripts = (collection, config, options) => { + const changeData = getCompositeKeyChangeData(collection, config); + if (!changeData) { + return []; + } + + const terminator = getTerminator(options); + const { newKeys, tableInfo } = changeData; + const { fullName, isTableActivated } = tableInfo; + + return newKeys + .map(newKey => { + const columns = getCompositeKeyColumnNames( + newKey[config.compositeKeyProperty] || [], + collection.role.properties, + config, + ); + + if (_.isEmpty(columns)) { + return null; + } + + // For PK: use activeKeysToString (PK columns can't be deactivated) + // For UK: use keysToString to handle deactivated columns + const isPrimaryKey = config.constraintType === 'PRIMARY KEY'; + const columnsStr = isPrimaryKey ? activeKeysToString(columns) : keysToString(columns, isTableActivated); + + const constraintName = newKey.constraintName ? `[${newKey.constraintName}]` : ''; + + const statement = constraintName + ? `CONSTRAINT ${constraintName} ${config.constraintType} NONCLUSTERED (${columnsStr}) NOT ENFORCED` + : `${config.constraintType} NONCLUSTERED (${columnsStr}) NOT ENFORCED`; + + const script = assignTemplates(templates.alterTableAddConstraint, { + tableName: fullName, + constraint: statement, + terminator, + }); + + // Determine if the constraint should be activated + // For PK: all columns are always activated, so check table activation only + // For UK: check if at least one column is activated AND table is activated + const atLeastOneColumnActivated = isPrimaryKey || columns.some(col => _.get(col, 'isActivated', true)); + const isConstraintActivated = isTableActivated && atLeastOneColumnActivated; + + return commentIfDeactivated(script, { isActivated: isConstraintActivated }); + }) + .filter(Boolean); +}; + +/** + * Get DROP CONSTRAINT scripts for composite keys + * @param {Object} collection + * @param {KeyConstraintConfig} config + * @param {Object} options + * @return {string[]} + */ +const getDropCompositeKeyScripts = (collection, config, options) => { + const changeData = getCompositeKeyChangeData(collection, config); + if (!changeData) { + return []; + } + + const terminator = getTerminator(options); + const { oldKeys, tableInfo } = changeData; + const { fullName, isTableActivated } = tableInfo; + + return oldKeys + .map(oldKey => { + const constraintName = oldKey.constraintName; + if (!constraintName) { + return null; + } + + const script = assignTemplates(templates.alterTable, { + tableName: fullName, + command: `DROP CONSTRAINT [${constraintName}]`, + terminator, + }); + + return commentIfDeactivated(script, { isActivated: isTableActivated }); + }) + .filter(Boolean); +}; + +/** + * Get modify scripts for composite keys (drop + add) + * @param {Object} collection + * @param {KeyConstraintConfig} config + * @param {Object} options + * @return {string[]} + */ +const getModifyCompositeKeyScripts = (collection, config, options) => { + const dropCompositeKeyScripts = getDropCompositeKeyScripts(collection, config, options); + const addCompositeKeyScripts = getAddCompositeKeyScripts(collection, config, options); + return [...dropCompositeKeyScripts, ...addCompositeKeyScripts].filter(Boolean); +}; + +/** + * Check if field was changed to be a regular key + * @param {Object} columnJsonSchema + * @param {Object} collection + * @param {KeyConstraintConfig} config + * @return {boolean} + */ +const wasFieldChangedToBeARegularKey = (columnJsonSchema, collection, config) => { + const oldName = columnJsonSchema.compMod.oldField.name; + const oldColumnJsonSchema = collection.role.properties[oldName]; + + const isRegularKey = columnJsonSchema[config.columnKeyProperty] && !columnJsonSchema[config.compositeKeyProperty]; + const wasTheFieldAnyKey = Boolean(oldColumnJsonSchema?.[config.columnKeyProperty]); + + return isRegularKey && !wasTheFieldAnyKey; +}; + +/** + * Check if field is no longer a regular key + * @param {Object} columnJsonSchema + * @param {Object} collection + * @param {KeyConstraintConfig} config + * @return {boolean} + */ +const isFieldNoLongerARegularKey = (columnJsonSchema, collection, config) => { + const oldName = columnJsonSchema.compMod.oldField.name; + const oldJsonSchema = collection.role.properties[oldName]; + const wasTheFieldARegularKey = + oldJsonSchema?.[config.columnKeyProperty] && !oldJsonSchema?.[config.compositeKeyProperty]; + + const isNotAnyKey = !columnJsonSchema[config.columnKeyProperty] && !columnJsonSchema[config.compositeKeyProperty]; + return wasTheFieldARegularKey && isNotAnyKey; +}; + +/** + * Get ADD CONSTRAINT scripts for regular (column-level) keys + * Note: Synapse doesn't support named constraints for column-level keys + * @param {Object} collection + * @param {KeyConstraintConfig} config + * @param {Object} options + * @return {string[]} + */ +const getAddRegularKeyScripts = (collection, config, options) => { + const terminator = getTerminator(options); + const collectionSchema = { ...collection, ..._.omit(collection?.role, 'properties') }; + const tableName = getEntityName(collectionSchema); + const schemaName = collection.compMod?.keyspaceName; + const fullName = getTableName(tableName, schemaName); + + const isTableActivated = _.get(collectionSchema, 'isActivated', true); + + return _.toPairs(collection.properties) + .filter(([name, jsonSchema]) => { + return wasFieldChangedToBeARegularKey(jsonSchema, collection, config); + }) + .map(([name, jsonSchema]) => { + // Synapse doesn't support constraint names for column-level keys + const statement = `${config.constraintType} NONCLUSTERED ([${name}]) NOT ENFORCED`; + + const script = assignTemplates(templates.alterTableAddConstraint, { + tableName: fullName, + constraint: statement, + terminator, + }); + + // For PK: column is always activated (PK columns can't be deactivated) + // For UK: check column activation + const isPrimaryKey = config.constraintType === 'PRIMARY KEY'; + const isColumnActivated = isPrimaryKey || _.get(jsonSchema, 'isActivated', true); + const isConstraintActivated = isTableActivated && isColumnActivated; + + return commentIfDeactivated(script, { isActivated: isConstraintActivated }); + }) + .filter(Boolean); +}; + +/** + * Get DROP CONSTRAINT scripts for regular (column-level) keys + * Note: Synapse doesn't support named constraints for column-level keys, + * so we cannot generate DROP scripts for them. They would need to be + * handled by recreating the column or converting to composite constraints. + * @param {Object} collection + * @param {KeyConstraintConfig} config + * @param {Object} options + * @return {string[]} + */ +const getDropRegularKeyScripts = (collection, config, options) => { + // Synapse doesn't support dropping unnamed column-level constraints + // Return empty array - these constraints can only be removed by: + // 1. Dropping and recreating the column + // 2. Converting to composite constraint (which can be named and dropped) + return []; +}; + +/** + * Get modify scripts for regular keys (drop + add) + * @param {Object} collection + * @param {KeyConstraintConfig} config + * @param {Object} options + * @return {string[]} + */ +const getModifyRegularKeyScripts = (collection, config, options) => { + const dropKeyScripts = getDropRegularKeyScripts(collection, config, options); + const addKeyScripts = getAddRegularKeyScripts(collection, config, options); + return [...dropKeyScripts, ...addKeyScripts].filter(Boolean); +}; + +/** + * Get all modify key scripts (both composite and regular) + * + * @param {Object} collection + * @param {KeyConstraintConfig} config + * @param {Object} options + * @return {string[]} + */ +const getModifyKeyScripts = (collection, config, options) => { + const modifyCompositeKeyScripts = getModifyCompositeKeyScripts(collection, config, options); + const modifyRegularKeyScripts = getModifyRegularKeyScripts(collection, config, options); + + return [...modifyCompositeKeyScripts, ...modifyRegularKeyScripts].filter(Boolean); +}; + +module.exports = { + getModifyKeyScripts, +}; diff --git a/forward_engineering/helpers/alterScriptHelpers/entityHelper/uniqueKeyHelper.js b/forward_engineering/helpers/alterScriptHelpers/entityHelper/uniqueKeyHelper.js new file mode 100644 index 0000000..a4e4d8d --- /dev/null +++ b/forward_engineering/helpers/alterScriptHelpers/entityHelper/uniqueKeyHelper.js @@ -0,0 +1,26 @@ +const { getModifyKeyScripts } = require('./sharedKeyConstraintHelper'); + +/** + * Unique Key constraint configuration + */ +const UNIQUE_KEY_CONFIG = { + constraintType: 'UNIQUE', + compModKeyName: 'uniqueKey', + columnKeyProperty: 'unique', + compositeKeyProperty: 'compositeUniqueKey', +}; + +/** + * Get all modify UK scripts (both composite and regular) + * + * @param {Object} collection + * @param {Object} options + * @return {string[]} + */ +const getModifyUkScripts = (collection, options) => { + return getModifyKeyScripts(collection, UNIQUE_KEY_CONFIG, options); +}; + +module.exports = { + getModifyUkScripts, +}; From e3b2cb477468b1daceb48a70e37742fef0c38bfb Mon Sep 17 00:00:00 2001 From: chulanovskyi Date: Thu, 6 Nov 2025 18:31:11 +0200 Subject: [PATCH 08/10] removed foreign key and check constraints from FE (not supported) --- forward_engineering/configs/templates.js | 7 +---- forward_engineering/ddlProvider.js | 31 ------------------- .../alterScriptHelpers/alterEntityHelper.js | 6 +--- forward_engineering/helpers/general.js | 19 ------------ 4 files changed, 2 insertions(+), 61 deletions(-) diff --git a/forward_engineering/configs/templates.js b/forward_engineering/configs/templates.js index 04fac24..d95a7df 100644 --- a/forward_engineering/configs/templates.js +++ b/forward_engineering/configs/templates.js @@ -5,7 +5,7 @@ module.exports = { createTable: 'CREATE${external} TABLE ${name} (\n' + - '\t${column_definitions}${temporalTableTime}${keyConstraints}${checkConstraints}${foreignKeyConstraints}${memoryOptimizedIndexes}\n' + + '\t${column_definitions}${temporalTableTime}${keyConstraints}${memoryOptimizedIndexes}\n' + ')${options}${terminator}\n', columnDefinition: @@ -23,11 +23,6 @@ module.exports = { spatialIndex: 'CREATE SPATIAL INDEX ${name} ON ${table} (${column})${using}\n${options}${terminator}\n', - checkConstraint: 'CONSTRAINT [${name}] CHECK${notForReplication} (${expression})', - - createForeignKeyConstraint: - 'CONSTRAINT [${name}] FOREIGN KEY (${foreignKey}) REFERENCES ${primaryTable}(${primaryKey})', - createView: 'CREATE${materialized} VIEW ${name}\n${view_attribute}AS ${select_statement}${check_option}${options}${terminator}\n', diff --git a/forward_engineering/ddlProvider.js b/forward_engineering/ddlProvider.js index afe515e..17d5754 100644 --- a/forward_engineering/ddlProvider.js +++ b/forward_engineering/ddlProvider.js @@ -88,7 +88,6 @@ const provider = (baseProvider, options, app) => { { name, columns, - checkConstraints, keyConstraints, options, schemaData, @@ -112,8 +111,6 @@ const provider = (baseProvider, options, app) => { name: tableName, external: persistence === 'external' ? ' EXTERNAL' : '', column_definitions: columnStatements, - checkConstraints: checkConstraints.length ? ',\n\t' + checkConstraints.join(',\n\t') : '', - foreignKeyConstraints: '', options: getTableOptions(options), keyConstraints: keyConstraintsString, memoryOptimizedIndexes: memoryOptimizedIndexes.length @@ -191,23 +188,6 @@ const provider = (baseProvider, options, app) => { ); }, - createCheckConstraint(checkConstraint) { - return assignTemplates(templates.checkConstraint, { - name: checkConstraint.name, - notForReplication: checkConstraint.enforceForReplication ? '' : ' NOT FOR REPLICATION', - expression: _.trim(checkConstraint.expression).replace(/^\(([\s\S]*)\)$/, '$1'), - terminator, - }); - }, - - createForeignKeyConstraint() { - return ''; - }, - - createForeignKey() { - return ''; - }, - createView( { name, keys, selectStatement, options, materialized, schemaData, ifNotExist }, dbData, @@ -368,16 +348,6 @@ const provider = (baseProvider, options, app) => { return hydrateTableIndex(indexData, schemaData); }, - hydrateCheckConstraint(checkConstraint) { - return { - name: checkConstraint.chkConstrName, - expression: checkConstraint.constrExpression, - existingData: checkConstraint.constrCheck, - enforceForUpserts: checkConstraint.constrEnforceUpserts, - enforceForReplication: checkConstraint.constrEnforceReplication, - }; - }, - hydrateSchema(containerData) { return { schemaName: containerData.name, @@ -395,7 +365,6 @@ const provider = (baseProvider, options, app) => { idToNameHashTable[_.get(jsonSchema, 'periodForSystemTime[0].endTime[0].keyId', '')]; return { ...tableData, - foreignKeyConstraints: tableData.foreignKeyConstraints || [], keyConstraints: keyHelper.getTableKeyConstraints({ jsonSchema }), defaultConstraints: getDefaultConstraints(tableData.columnDefinitions), ifNotExist: jsonSchema.ifNotExist, diff --git a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js index 2e5f956..30d2fc5 100644 --- a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js @@ -26,14 +26,10 @@ const alterEntityHelper = (app, options) => { schemaData, }), ); - const checkConstraints = (jsonSchema.chkConstr || []).map(check => - ddlProvider.createCheckConstraint(ddlProvider.hydrateCheckConstraint(check)), - ); + const tableData = { name: tableName, columns: columnDefinitions.map(ddlProvider.convertColumnDefinition), - checkConstraints: checkConstraints, - foreignKeyConstraints: [], schemaData, columnDefinitions, }; diff --git a/forward_engineering/helpers/general.js b/forward_engineering/helpers/general.js index 4d7023f..5d28dd1 100644 --- a/forward_engineering/helpers/general.js +++ b/forward_engineering/helpers/general.js @@ -173,23 +173,6 @@ const getDefaultConstraints = columnDefinitions => { })); }; -const foreignKeysToString = keys => { - if (Array.isArray(keys)) { - const activatedKeys = keys.filter(key => _.get(key, 'isActivated', true)).map(key => `[${key.name.trim()}]`); - const deactivatedKeys = keys.filter(key => !_.get(key, 'isActivated', true)).map(key => `[${key.name.trim()}]`); - const deactivatedKeysAsString = deactivatedKeys.length - ? commentIfDeactivated(deactivatedKeys, { isActivated: false }, true) - : ''; - - return activatedKeys.join(', ') + deactivatedKeysAsString; - } - return keys; -}; - -const foreignActiveKeysToString = keys => { - return keys.map(key => key.name.trim()).join(', '); -}; - const trimBraces = expression => /^\(([\s\S]+?)\)$/i.test(_.trim(expression)) ? _.trim(expression).replace(/^\(([\s\S]+?)\)$/i, '$1') : expression; @@ -254,10 +237,8 @@ module.exports = { hasType, getViewData, getDefaultConstraints, - foreignKeysToString, trimBraces, checkIndexActivated, - foreignActiveKeysToString, getDefaultValue, getTempTableTime, getCollation, From 7f7f9a162d183cef4f6c2af2bf9d7eebd42d0976 Mon Sep 17 00:00:00 2001 From: chulanovskyi Date: Fri, 7 Nov 2025 09:05:12 +0200 Subject: [PATCH 09/10] feat: alter nullable --- forward_engineering/ddlProvider.js | 22 ++++++--- .../alterScriptHelpers/alterEntityHelper.js | 46 +++++++++++++------ .../helpers/alterScriptHelpers/common.js | 13 +++++- .../createColumnDefinition.js | 2 +- 4 files changed, 59 insertions(+), 24 deletions(-) diff --git a/forward_engineering/ddlProvider.js b/forward_engineering/ddlProvider.js index 17d5754..76f9ee8 100644 --- a/forward_engineering/ddlProvider.js +++ b/forward_engineering/ddlProvider.js @@ -493,16 +493,24 @@ const provider = (baseProvider, options, app) => { }); }, - alterColumn(fullTableName, columnDefinition) { - const type = hasType(columnDefinition.type) - ? _.toUpper(columnDefinition.type) - : getTableName(columnDefinition.type, columnDefinition.schemaName); - const notNull = columnDefinition.nullable ? ' NULL' : ' NOT NULL'; + alterColumn({ fullTableName, columnDefinition, alterType = true, alterNullable = true }) { + let type = ''; + let notNull = ''; + + if (alterType) { + type = hasType(columnDefinition.type) + ? _.toUpper(columnDefinition.type) + : getTableName(columnDefinition.type, columnDefinition.schemaName); + } + + if (alterNullable) { + notNull = columnDefinition.nullable ? 'NULL' : 'NOT NULL'; + } const command = assignTemplates(templates.alterColumn, { name: columnDefinition.name, - type: decorateType(type, columnDefinition), - not_null: notNull, + type, + not_null: type ? ` ${notNull}` : notNull, }); return assignTemplates(templates.alterTable, { diff --git a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js index 30d2fc5..f7b531e 100644 --- a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js @@ -2,7 +2,7 @@ const _ = require('lodash'); const { getTableName } = require('../general'); const { getEntityName } = require('../../utils/general'); const { createColumnDefinitionBySchema } = require('./createColumnDefinition'); -const { checkFieldPropertiesChanged, modifyGroupItems, setIndexKeys } = require('./common'); +const { checkFieldPropertiesChanged, modifyGroupItems, setIndexKeys, checkRequiredChanged } = require('./common'); const { getModifyPkScripts } = require('./entityHelper/primaryKeyHelper'); const { getModifyUkScripts } = require('./entityHelper/uniqueKeyHelper'); @@ -122,30 +122,46 @@ const alterEntityHelper = (app, options) => { const collectionSchema = { ...collection, ..._.omit(collection?.role, 'properties') }; const tableName = collectionSchema?.code || collectionSchema?.collectionName || collectionSchema?.name; const schemaName = collectionSchema.compMod?.keyspaceName; - const fullName = getTableName(tableName, schemaName); + const fullTableName = getTableName(tableName, schemaName); const schemaData = { schemaName }; const renameColumnScripts = _.values(collection.properties) .filter(jsonSchema => checkFieldPropertiesChanged(jsonSchema.compMod, ['name'])) .map(jsonSchema => - ddlProvider.renameColumn(fullName, jsonSchema.compMod.oldField.name, jsonSchema.compMod.newField.name), + ddlProvider.renameColumn( + fullTableName, + jsonSchema.compMod.oldField.name, + jsonSchema.compMod.newField.name, + ), ); - const changeTypeScripts = _.toPairs(collection.properties) - .filter(([, jsonSchema]) => checkFieldPropertiesChanged(jsonSchema.compMod, ['type', 'mode'])) - .map(([name, jsonSchema]) => { - const columnDefinition = createColumnDefinitionBySchema({ - name, - jsonSchema, - parentJsonSchema: collectionSchema, - ddlProvider, - schemaData, - }); + const alterColumnScripts = _.toPairs(collection.properties).reduce((acc, [name, jsonSchema]) => { + const fieldTypeChanged = checkFieldPropertiesChanged(jsonSchema.compMod, ['type', 'mode']); + const fieldRequiredChanged = checkRequiredChanged(collection, name); - return ddlProvider.alterColumn(fullName, columnDefinition); + const columnDefinition = createColumnDefinitionBySchema({ + name, + jsonSchema, + parentJsonSchema: collectionSchema, + ddlProvider, + schemaData, }); - return [...renameColumnScripts, ...changeTypeScripts]; + if (fieldTypeChanged || fieldRequiredChanged) { + acc.push( + ddlProvider.alterColumn({ + fullTableName, + columnDefinition, + alterType: fieldTypeChanged, + alterNullable: fieldRequiredChanged, + }), + ); + } + + return acc; + }, []); + + return [...renameColumnScripts, ...alterColumnScripts]; }; const getModifyCollectionKeysScript = collection => { diff --git a/forward_engineering/helpers/alterScriptHelpers/common.js b/forward_engineering/helpers/alterScriptHelpers/common.js index 17b3287..3e458bf 100644 --- a/forward_engineering/helpers/alterScriptHelpers/common.js +++ b/forward_engineering/helpers/alterScriptHelpers/common.js @@ -1,4 +1,4 @@ -const { isEqual } = require('lodash'); +const { isEqual, difference } = require('lodash'); const checkFieldPropertiesChanged = (compMod, propertiesToCheck) => { return propertiesToCheck.some(prop => compMod?.oldField[prop] !== compMod?.newField[prop]); @@ -82,10 +82,21 @@ const setIndexKeys = (idToNameHashTable, idToActivatedHashTable, index) => { }; }; +const checkRequiredChanged = (collection, propertyName) => { + const currentRequiredColumnNames = collection.required || []; + const previousRequiredColumnNames = collection.role.required || []; + + const isRequired = currentRequiredColumnNames.includes(propertyName); + const wasRequired = previousRequiredColumnNames.includes(propertyName); + + return isRequired !== wasRequired; +}; + module.exports = { checkFieldPropertiesChanged, getCompMod, modifyGroupItems, checkCompModEqual, setIndexKeys, + checkRequiredChanged, }; diff --git a/forward_engineering/helpers/alterScriptHelpers/createColumnDefinition.js b/forward_engineering/helpers/alterScriptHelpers/createColumnDefinition.js index 79c2450..2bb1a56 100644 --- a/forward_engineering/helpers/alterScriptHelpers/createColumnDefinition.js +++ b/forward_engineering/helpers/alterScriptHelpers/createColumnDefinition.js @@ -81,7 +81,7 @@ const getType = jsonSchema => { const createColumnDefinitionBySchema = ({ name, jsonSchema, parentJsonSchema, ddlProvider, schemaData }) => { const columnDefinition = createColumnDefinition({ - name: name, + name, type: getType(jsonSchema), nullable: isNullable(parentJsonSchema, name), default: getDefault(jsonSchema), From 7e7649454451b48ff612f6c9b0c923c52ab45412 Mon Sep 17 00:00:00 2001 From: chulanovskyi-bs <56116665+chulanovskyi-bs@users.noreply.github.com> Date: Fri, 7 Nov 2025 13:42:05 +0200 Subject: [PATCH 10/10] HCK-13329: alter default (#127) --- forward_engineering/config.json | 4 +- forward_engineering/configs/templates.js | 6 +- forward_engineering/ddlProvider.js | 47 +++++++++----- .../alterScriptHelpers/alterEntityHelper.js | 26 ++++++-- .../helpers/alterScriptHelpers/common.js | 13 +--- .../entityHelper/sharedKeyConstraintHelper.js | 2 +- .../helpers/constraintsHelper.js | 62 +++++++++---------- 7 files changed, 90 insertions(+), 70 deletions(-) diff --git a/forward_engineering/config.json b/forward_engineering/config.json index fd2bb5b..16b0046 100644 --- a/forward_engineering/config.json +++ b/forward_engineering/config.json @@ -178,8 +178,8 @@ }, "separate": { "default": false, - "disabled": false, - "disabledLabel": "" + "disabled": true, + "disabledLabel": "N/A" }, "ignore": { "default": false, diff --git a/forward_engineering/configs/templates.js b/forward_engineering/configs/templates.js index d95a7df..340390b 100644 --- a/forward_engineering/configs/templates.js +++ b/forward_engineering/configs/templates.js @@ -32,7 +32,9 @@ module.exports = { createKeyConstraint: '${constraintName}${keyType}${clustered}${columns}${options}${partition}', - createDefaultConstraint: + columnDefaultConstraint: 'CONSTRAINT [${constraintName}] DEFAULT (${default})', + + alterDefaultConstraint: 'ALTER TABLE ${tableName} ADD CONSTRAINT [${constraintName}] DEFAULT (${default}) FOR [${columnName}]${terminator}\n', ifNotExistSchema: @@ -63,7 +65,7 @@ module.exports = { addColumn: 'ADD ${script}', - alterColumn: 'ALTER COLUMN [${name}] ${type}${collation}${not_null}', + alterColumn: 'ALTER COLUMN [${name}] ${type}${collation}', renameColumn: "EXEC sp_rename '${fullTableName}.${oldColumnName}', '${newColumnName}', 'COLUMN';${terminator}", diff --git a/forward_engineering/ddlProvider.js b/forward_engineering/ddlProvider.js index 76f9ee8..9607804 100644 --- a/forward_engineering/ddlProvider.js +++ b/forward_engineering/ddlProvider.js @@ -102,11 +102,16 @@ const provider = (baseProvider, options, app) => { const tableName = getTableName(setPersistenceSpecificName(persistence, name), schemaData.schemaName); const dividedKeysConstraints = divideIntoActivatedAndDeactivated( - keyConstraints.map(createKeyConstraint(templates, tableTerminator, isActivated)), + keyConstraints.map( + createKeyConstraint({ terminator: tableTerminator, isParentActivated: isActivated }), + ), key => key.statement, ); + const keyConstraintsString = generateConstraintsString(dividedKeysConstraints, isActivated); + const columnStatements = joinActivatedAndDeactivatedStatements({ statements: columns, indent: '\n\t' }); + const tableStatement = assignTemplates(templates.createTable, { name: tableName, external: persistence === 'external' ? ' EXTERNAL' : '', @@ -122,11 +127,8 @@ const provider = (baseProvider, options, app) => { : '', terminator: tableTerminator, }); - const defaultConstraintsStatements = defaultConstraints - .map(data => createDefaultConstraint(templates, tableTerminator)(data, tableName)) - .join('\n'); - const fullTableStatement = [tableStatement, defaultConstraintsStatements].filter(Boolean).join('\n\n'); + const fullTableStatement = [tableStatement].filter(Boolean).join('\n\n'); return ifNotExist ? wrapIfNotExistTable({ @@ -144,9 +146,19 @@ const provider = (baseProvider, options, app) => { : getTableName(columnDefinition.type, columnDefinition.schemaName); const notNull = columnDefinition.nullable ? '' : ' NOT NULL'; const primaryKey = columnDefinition.primaryKey ? ' PRIMARY KEY NONCLUSTERED NOT ENFORCED' : ''; - const defaultValue = _.isUndefined(columnDefinition.default) - ? '' - : ' DEFAULT ' + decorateDefault(type, columnDefinition.default); + + const isInline = options?.scriptGenerationOptions?.feActiveOptions?.columnDefaultValues === 'inline'; + + let defaultValue; + + if (isInline) { + if (!_.isUndefined(columnDefinition.default)) { + defaultValue = ' DEFAULT ' + decorateDefault(type, columnDefinition.default); + } else if (columnDefinition.defaultConstraint.name) { + defaultValue = ` ${createDefaultConstraint({ constraint: columnDefinition.defaultConstraint })}`; + } + } + const sparse = columnDefinition.sparse ? ' SPARSE' : ''; const maskedWithFunction = columnDefinition.maskedWithFunction ? ` MASKED WITH (FUNCTION='${columnDefinition.maskedWithFunction}')` @@ -298,7 +310,7 @@ const provider = (baseProvider, options, app) => { return { ...columnDefinition, - default: jsonSchema.defaultConstraintName ? '' : columnDefinition.default, + default: jsonSchema.defaultConstraintName ? undefined : columnDefinition.default, defaultConstraint: { name: jsonSchema.defaultConstraintName, value: columnDefinition.default, @@ -493,9 +505,8 @@ const provider = (baseProvider, options, app) => { }); }, - alterColumn({ fullTableName, columnDefinition, alterType = true, alterNullable = true }) { + alterColumn({ fullTableName, columnDefinition, alterType = true }) { let type = ''; - let notNull = ''; if (alterType) { type = hasType(columnDefinition.type) @@ -503,14 +514,9 @@ const provider = (baseProvider, options, app) => { : getTableName(columnDefinition.type, columnDefinition.schemaName); } - if (alterNullable) { - notNull = columnDefinition.nullable ? 'NULL' : 'NOT NULL'; - } - const command = assignTemplates(templates.alterColumn, { name: columnDefinition.name, type, - not_null: type ? ` ${notNull}` : notNull, }); return assignTemplates(templates.alterTable, { @@ -520,6 +526,15 @@ const provider = (baseProvider, options, app) => { }); }, + alterColumnDefault({ fullTableName, constraint, columnName }) { + return assignTemplates(templates.alterDefaultConstraint, { + tableName: fullTableName, + constraintName: constraint.name, + default: constraint.value, + columnName, + }); + }, + dropView(fullViewName) { return assignTemplates(templates.dropView, { name: fullViewName, diff --git a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js index f7b531e..7410b7a 100644 --- a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js @@ -2,7 +2,7 @@ const _ = require('lodash'); const { getTableName } = require('../general'); const { getEntityName } = require('../../utils/general'); const { createColumnDefinitionBySchema } = require('./createColumnDefinition'); -const { checkFieldPropertiesChanged, modifyGroupItems, setIndexKeys, checkRequiredChanged } = require('./common'); +const { checkFieldPropertiesChanged, modifyGroupItems, setIndexKeys } = require('./common'); const { getModifyPkScripts } = require('./entityHelper/primaryKeyHelper'); const { getModifyUkScripts } = require('./entityHelper/uniqueKeyHelper'); @@ -135,9 +135,10 @@ const alterEntityHelper = (app, options) => { ), ); - const alterColumnScripts = _.toPairs(collection.properties).reduce((acc, [name, jsonSchema]) => { + const pairs = _.toPairs(collection.properties); + + const alterColumnScripts = pairs.reduce((acc, [name, jsonSchema]) => { const fieldTypeChanged = checkFieldPropertiesChanged(jsonSchema.compMod, ['type', 'mode']); - const fieldRequiredChanged = checkRequiredChanged(collection, name); const columnDefinition = createColumnDefinitionBySchema({ name, @@ -147,13 +148,12 @@ const alterEntityHelper = (app, options) => { schemaData, }); - if (fieldTypeChanged || fieldRequiredChanged) { + if (fieldTypeChanged) { acc.push( ddlProvider.alterColumn({ fullTableName, columnDefinition, alterType: fieldTypeChanged, - alterNullable: fieldRequiredChanged, }), ); } @@ -161,7 +161,21 @@ const alterEntityHelper = (app, options) => { return acc; }, []); - return [...renameColumnScripts, ...alterColumnScripts]; + const alterDefaultScripts = pairs + .filter( + ([, jsonSchema]) => + options?.scriptGenerationOptions?.feActiveOptions?.columnDefaultValues === 'separate' && + jsonSchema.defaultConstraintName, + ) + .map(([name, jsonSchema]) => { + return ddlProvider.alterColumnDefault({ + fullTableName, + columnName: name, + constraint: { name: jsonSchema.defaultConstraintName, value: jsonSchema.default }, + }); + }); + + return [...renameColumnScripts, ...alterColumnScripts, ...alterDefaultScripts]; }; const getModifyCollectionKeysScript = collection => { diff --git a/forward_engineering/helpers/alterScriptHelpers/common.js b/forward_engineering/helpers/alterScriptHelpers/common.js index 3e458bf..17b3287 100644 --- a/forward_engineering/helpers/alterScriptHelpers/common.js +++ b/forward_engineering/helpers/alterScriptHelpers/common.js @@ -1,4 +1,4 @@ -const { isEqual, difference } = require('lodash'); +const { isEqual } = require('lodash'); const checkFieldPropertiesChanged = (compMod, propertiesToCheck) => { return propertiesToCheck.some(prop => compMod?.oldField[prop] !== compMod?.newField[prop]); @@ -82,21 +82,10 @@ const setIndexKeys = (idToNameHashTable, idToActivatedHashTable, index) => { }; }; -const checkRequiredChanged = (collection, propertyName) => { - const currentRequiredColumnNames = collection.required || []; - const previousRequiredColumnNames = collection.role.required || []; - - const isRequired = currentRequiredColumnNames.includes(propertyName); - const wasRequired = previousRequiredColumnNames.includes(propertyName); - - return isRequired !== wasRequired; -}; - module.exports = { checkFieldPropertiesChanged, getCompMod, modifyGroupItems, checkCompModEqual, setIndexKeys, - checkRequiredChanged, }; diff --git a/forward_engineering/helpers/alterScriptHelpers/entityHelper/sharedKeyConstraintHelper.js b/forward_engineering/helpers/alterScriptHelpers/entityHelper/sharedKeyConstraintHelper.js index 68d54ab..73fc810 100644 --- a/forward_engineering/helpers/alterScriptHelpers/entityHelper/sharedKeyConstraintHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/entityHelper/sharedKeyConstraintHelper.js @@ -283,7 +283,7 @@ const getAddRegularKeyScripts = (collection, config, options) => { const terminator = getTerminator(options); const collectionSchema = { ...collection, ..._.omit(collection?.role, 'properties') }; const tableName = getEntityName(collectionSchema); - const schemaName = collection.compMod?.keyspaceName; + const schemaName = collectionSchema.compMod?.keyspaceName; const fullName = getTableName(tableName, schemaName); const isTableActivated = _.get(collectionSchema, 'isActivated', true); diff --git a/forward_engineering/helpers/constraintsHelper.js b/forward_engineering/helpers/constraintsHelper.js index 0e04176..7f2a9ce 100644 --- a/forward_engineering/helpers/constraintsHelper.js +++ b/forward_engineering/helpers/constraintsHelper.js @@ -3,44 +3,44 @@ const { commentIfDeactivated } = require('./commentIfDeactivated'); const { trimBraces } = require('./general'); const { checkAllKeysDeactivated, divideIntoActivatedAndDeactivated } = require('../utils/general'); const { assignTemplates } = require('../utils/assignTemplates'); +const templates = require('../configs/templates'); -const createKeyConstraint = (templates, terminator, isParentActivated) => keyData => { - const partition = keyData.partition ? ` ON [${keyData.partition}]` : ''; - const columnMapToString = ({ name }) => `[${name}]`.trim(); +const createKeyConstraint = + ({ terminator, isParentActivated }) => + keyData => { + const partition = keyData.partition ? ` ON [${keyData.partition}]` : ''; + const columnMapToString = ({ name }) => `[${name}]`.trim(); - const isAllColumnsDeactivated = checkAllKeysDeactivated(keyData.columns); + const isAllColumnsDeactivated = checkAllKeysDeactivated(keyData.columns); - const dividedColumns = divideIntoActivatedAndDeactivated(keyData.columns, columnMapToString); - const deactivatedColumnsAsString = dividedColumns.deactivatedItems.length - ? commentIfDeactivated(dividedColumns.deactivatedItems.join(', '), { isActivated: false }, true) - : ''; + const dividedColumns = divideIntoActivatedAndDeactivated(keyData.columns, columnMapToString); + const deactivatedColumnsAsString = dividedColumns.deactivatedItems.length + ? commentIfDeactivated(dividedColumns.deactivatedItems.join(', '), { isActivated: false }, true) + : ''; - const columns = - !isAllColumnsDeactivated && isParentActivated - ? ' (' + dividedColumns.activatedItems.join(', ') + deactivatedColumnsAsString + ')' - : ' (' + keyData.columns.map(columnMapToString).join(', ') + ')'; + const columns = + !isAllColumnsDeactivated && isParentActivated + ? ' (' + dividedColumns.activatedItems.join(', ') + deactivatedColumnsAsString + ')' + : ' (' + keyData.columns.map(columnMapToString).join(', ') + ')'; - return { - statement: assignTemplates(templates.createKeyConstraint, { - constraintName: keyData.name ? `CONSTRAINT [${keyData.name}] ` : '', - keyType: keyData.keyType, - clustered: ' NONCLUSTERED', - columns, - options: ' NOT ENFORCED', - partition, - terminator, - }), - isActivated: !isAllColumnsDeactivated, + return { + statement: assignTemplates(templates.createKeyConstraint, { + constraintName: keyData.name ? `CONSTRAINT [${keyData.name}] ` : '', + keyType: keyData.keyType, + clustered: ' NONCLUSTERED', + columns, + options: ' NOT ENFORCED', + partition, + terminator, + }), + isActivated: !isAllColumnsDeactivated, + }; }; -}; -const createDefaultConstraint = (templates, terminator) => (constraintData, tableName) => { - return assignTemplates(templates.createDefaultConstraint, { - tableName, - constraintName: constraintData.constraintName, - columnName: constraintData.columnName, - default: trimBraces(constraintData.value), - terminator, +const createDefaultConstraint = ({ constraint }) => { + return assignTemplates(templates.columnDefaultConstraint, { + constraintName: constraint.name, + default: trimBraces(constraint.value), }); };