diff --git a/forward_engineering/alterScript/alterScriptHelpers/alterContainerHelper.js b/forward_engineering/alterScript/alterScriptHelpers/alterContainerHelper.js index 9802738..2b6180f 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/alterContainerHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/alterContainerHelper.js @@ -1,5 +1,6 @@ const { getFullName } = require('../../helpers/utils'); const { checkCompModEqual, getCompMod } = require('./common'); +const { getModifyContainerOptionsScript } = require('./containerHelper/optionsHelper'); module.exports = (app, options) => { const _ = app.require('lodash'); @@ -20,26 +21,10 @@ module.exports = (app, options) => { return ddlProvider.dropDatabase(fullName); }; - const getModifiedContainer = modelData => containerData => { - const compMod = getCompMod(containerData); - const optionsProperties = [ - 'businessName', - 'description', - 'customerEncryptionKey', - 'defaultExpiration', - 'labels', - ]; - - const isAnyOptionChanged = _.some(optionsProperties, property => checkCompModEqual(compMod[property] ?? {})); - - if (!isAnyOptionChanged) { - return ''; - } - - const constructedDbData = getDbData([containerData]); - const dbData = ddlProvider.hydrateSchema(constructedDbData, { modelData }); - - return ddlProvider.alterDatabase(dbData); + const getModifiedContainer = modelData => jsonSchema => { + const containerData = getDbData([jsonSchema]); + const modifyContainerOptionsScript = getModifyContainerOptionsScript({ app, jsonSchema, containerData }); + return modifyContainerOptionsScript; }; return { diff --git a/forward_engineering/alterScript/alterScriptHelpers/alterViewHelper.js b/forward_engineering/alterScript/alterScriptHelpers/alterViewHelper.js index 8f2b20a..4d66285 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/alterViewHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/alterViewHelper.js @@ -1,4 +1,6 @@ +const { getName, getFullName } = require('../../helpers/utils'); const { checkCompModEqual, getCompMod, setEntityKeys } = require('./common'); +const { getModifyViewOptionsScript } = require('./viewHelpers/optionsHelper'); module.exports = (app, options) => { const _ = app.require('lodash'); @@ -32,31 +34,17 @@ module.exports = (app, options) => { }; const getModifiedViewScript = modelData => jsonSchema => { - const view = _.omit(jsonSchema, 'timeUnitpartitionKey', 'clusteringKey', 'rangePartitionKey'); - const idToNameHashTable = generateIdToNameHashTable(view); - const idToActivatedHashTable = generateIdToActivatedHashTable(view); - const viewSchema = setEntityKeys({ idToActivatedHashTable, idToNameHashTable, entity: view }); - const dbData = { databaseName: viewSchema.compMod.keyspaceName, projectId: _.first(modelData)?.projectId }; + const dbData = { databaseName: jsonSchema.compMod.keyspaceName, projectId: _.first(modelData)?.projectId }; + const viewName = getName(jsonSchema); + const fullTableName = getFullName(dbData.projectId, dbData.databaseName, viewName); + const viewData = { - name: viewSchema.code || viewSchema.name, - keys: getKeys(viewSchema, viewSchema.compMod?.collectionData?.collectionRefsDefinitionsMap ?? {}), - dbData, + name: fullTableName, }; - const optionsProperties = viewSchema.materialized - ? ['enableRefresh', 'refreshInterval', 'expiration', 'businessName', 'description', 'labels'] - : ['expiration', 'businessName', 'description', 'labels']; - - const compMod = getCompMod(view); - const isAnyOptionChanged = _.some(optionsProperties, property => !checkCompModEqual(compMod[property])); - - if (!isAnyOptionChanged) { - return ''; - } - - const hydratedView = ddlProvider.hydrateView({ viewData, entityData: [viewSchema] }); + const modifyViewOptionsScript = getModifyViewOptionsScript({ app, jsonSchema, viewData }); - return ddlProvider.alterView(hydratedView, dbData); + return modifyViewOptionsScript; }; const getKeys = (viewSchema, collectionRefsDefinitionsMap) => { diff --git a/forward_engineering/alterScript/alterScriptHelpers/common.js b/forward_engineering/alterScript/alterScriptHelpers/common.js index d25e194..10d053c 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/common.js +++ b/forward_engineering/alterScript/alterScriptHelpers/common.js @@ -1,3 +1,4 @@ +const { escapeQuotes, getTimestamp, getName } = require('../../helpers/utils'); const _ = require('lodash'); const getCompMod = containerData => containerData.role?.compMod ?? {}; @@ -33,8 +34,57 @@ const setEntityKeys = ({ idToNameHashTable, idToActivatedHashTable, entity }) => }; }; +const getModifyOptions = ({ jsonSchema, app, options }) => { + const { tab } = app.require('@hackolade/ddl-fe-utils').general; + const { getLabels } = require('../../helpers/general')(app); + const optionsToUpdate = []; + + Object.entries(options).forEach(([customOptionName, columnOptionName]) => { + const { new: newOptionValue, old: oldOptionValue } = jsonSchema.role.compMod[customOptionName] || {}; + + if (!_.isEqual(newOptionValue, oldOptionValue)) { + switch (customOptionName) { + case 'businessName': { + const name = getName(jsonSchema.role); + if (name !== newOptionValue) { + const value = newOptionValue ? `"${newOptionValue}"` : 'NULL'; + optionsToUpdate.push(`${columnOptionName}=${value}`); + } + break; + } + case 'description': { + const value = newOptionValue ? `"${escapeQuotes(newOptionValue)}"` : 'NULL'; + optionsToUpdate.push(`${columnOptionName}=${value}`); + break; + } + case 'expiration': { + const value = newOptionValue ? `TIMESTAMP "${getTimestamp(newOptionValue)}"` : 'NULL'; + optionsToUpdate.push(`${columnOptionName}=${value}`); + break; + } + case 'labels': { + const value = newOptionValue.length ? `[\n${tab(getLabels(newOptionValue))}\n]` : 'NULL'; + optionsToUpdate.push(`labels=${value}`); + break; + } + default: { + const value = newOptionValue === undefined || newOptionValue === '' ? 'NULL' : newOptionValue; + optionsToUpdate.push(`${columnOptionName}=${value}`); + } + } + } + }); + + if (!optionsToUpdate.length) { + return ''; + } + + return tab(optionsToUpdate.join(',\n')); +}; + module.exports = { getCompMod, checkCompModEqual, setEntityKeys, + getModifyOptions, }; diff --git a/forward_engineering/alterScript/alterScriptHelpers/containerHelper/optionsHelper.js b/forward_engineering/alterScript/alterScriptHelpers/containerHelper/optionsHelper.js new file mode 100644 index 0000000..b7add12 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/containerHelper/optionsHelper.js @@ -0,0 +1,30 @@ +const _ = require('lodash'); +const { wrapByBackticks } = require('../../../helpers/utils'); +const templates = require('../../../configs/templates'); +const { getModifyOptions } = require('../common'); + +const options = { + businessName: 'friendly_name', + description: 'description', + customerEncryptionKey: 'default_kms_key_name', + defaultExpiration: 'default_table_expiration_days', + labels: 'labels', +}; + +const getModifyContainerOptionsScript = ({ jsonSchema, containerData, app }) => { + const { assignTemplates } = app.require('@hackolade/ddl-fe-utils'); + const optionsToUpdate = getModifyOptions({ jsonSchema, app, options }); + + if (!optionsToUpdate) { + return ''; + } + + return assignTemplates(templates.alterDatabaseOptions, { + name: wrapByBackticks(containerData.name), + options: optionsToUpdate, + }); +}; + +module.exports = { + getModifyContainerOptionsScript, +}; diff --git a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/optionsHelper.js b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/optionsHelper.js index 7f976f5..cd1e0b5 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/optionsHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/optionsHelper.js @@ -1,56 +1,27 @@ const _ = require('lodash'); -const { wrapByBackticks, getFullName, escapeQuotes, getTimestamp } = require('../../../helpers/utils'); const templates = require('../../../configs/templates'); +const { getModifyOptions } = require('../common'); -const columnOptions = { - 'description': 'description', - 'partitioningFilterRequired': 'require_partition_filter', - 'expiration': 'expiration_timestamp', - 'customerEncryptionKey': 'kms_key_name', - 'labels': 'labels', +const options = { + businessName: 'friendly_name', + description: 'description', + partitioningFilterRequired: 'require_partition_filter', + expiration: 'expiration_timestamp', + customerEncryptionKey: 'kms_key_name', + labels: 'labels', }; const getModifyCollectionOptionsScript = ({ jsonSchema, tableData, app }) => { const { assignTemplates } = app.require('@hackolade/ddl-fe-utils'); - const { tab } = app.require('@hackolade/ddl-fe-utils').general; - const { getLabels } = require('../../../helpers/general')(app); - const optionsToUpdate = []; + const optionsToUpdate = getModifyOptions({ jsonSchema, app, options }); - Object.entries(columnOptions).forEach(([customOptionName, columnOptionName]) => { - const { new: newOptionValue, old: oldOptionValue } = jsonSchema.compMod[customOptionName] || {}; - - if (!_.isEqual(newOptionValue, oldOptionValue)) { - switch (customOptionName) { - case 'description': { - const value = newOptionValue ? `"${escapeQuotes(newOptionValue)}"` : 'NULL'; - optionsToUpdate.push(`description=${value}`); - break; - } - case 'expiration': { - const value = newOptionValue ? `TIMESTAMP "${getTimestamp(newOptionValue)}"` : 'NULL'; - optionsToUpdate.push(`${columnOptionName}=${value}`); - break; - } - case 'labels': { - const value = newOptionValue.length ? `[\n${tab(getLabels(newOptionValue))}\n]` : 'NULL'; - optionsToUpdate.push(`labels=${value}`); - break; - } - default: { - const value = newOptionValue === undefined || newOptionValue === '' ? 'NULL' : newOptionValue; - optionsToUpdate.push(`${columnOptionName}=${value}`); - } - } - } - }); - - if (!optionsToUpdate.length) { + if (!optionsToUpdate) { return ''; } return assignTemplates(templates.alterTableSetOptions, { tableName: tableData.name, - options: tab(optionsToUpdate.join(',\n')), + options: optionsToUpdate, }); }; diff --git a/forward_engineering/alterScript/alterScriptHelpers/viewHelpers/optionsHelper.js b/forward_engineering/alterScript/alterScriptHelpers/viewHelpers/optionsHelper.js new file mode 100644 index 0000000..383dd4f --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/viewHelpers/optionsHelper.js @@ -0,0 +1,38 @@ +const _ = require('lodash'); +const templates = require('../../../configs/templates'); +const { getModifyOptions } = require('../common'); + +const viewOptions = { + businessName: 'friendly_name', + description: 'description', + expiration: 'expiration_timestamp', + labels: 'labels', +}; + +const materializedViewOptions = { + ...viewOptions, + enableRefresh: 'enable_refresh', + refreshInterval: 'refresh_interval_minutes', + maxStaleness: 'max_staleness', + allowNonIncrementalDefinition: 'allow_non_incremental_definition', +}; + +const getModifyViewOptionsScript = ({ jsonSchema, viewData, app }) => { + const { assignTemplates } = app.require('@hackolade/ddl-fe-utils'); + const options = jsonSchema.materialized ? materializedViewOptions : viewOptions; + const optionsToUpdate = getModifyOptions({ jsonSchema, app, options }); + + if (!optionsToUpdate) { + return ''; + } + + return assignTemplates(templates.alterViewOptions, { + materialized: jsonSchema.materialized ? 'MATERIALIZED ' : '', + name: viewData.name, + options: optionsToUpdate, + }); +}; + +module.exports = { + getModifyViewOptionsScript, +}; diff --git a/forward_engineering/config.json b/forward_engineering/config.json index 1b54200..766d5c5 100644 --- a/forward_engineering/config.json +++ b/forward_engineering/config.json @@ -55,5 +55,320 @@ }, "container": true, "model": 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": "columnNotNullConstraints", + "label": "FE_SCRIPT_GENERATION_OPTIONS___COLUMN_NOT_NULL", + "disabled": false, + "value": { + "inline": { + "default": true, + "disabled": false, + "disabledLabel": "" + }, + "separate": { + "default": false, + "disabled": true, + "disabledLabel": "" + }, + "ignore": { + "default": false, + "disabled": false, + "disabledLabel": "" + } + }, + "adapters": [ + { + "dependency": { + "key": "dataTypeMode", + "value": "Required" + }, + "defaultValue": { + "dataTypeMode": "Nullable" + } + } + ] + }, + { + "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": { + "key": "type", + "value": "bucket" + }, + "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": "" + } + } + ] + } + ] } diff --git a/forward_engineering/configs/templates.js b/forward_engineering/configs/templates.js index f22e711..cf00225 100644 --- a/forward_engineering/configs/templates.js +++ b/forward_engineering/configs/templates.js @@ -10,11 +10,11 @@ module.exports = { '${constraintName}FOREIGN KEY (${foreignKeys}) REFERENCES ${primaryTableName}(${primaryKeys}) NOT ENFORCED', createView: - 'CREATE ${orReplace}${materialized}VIEW ${ifNotExist}${name}${columns}${partitions}${clustering}${options} AS ${selectStatement};\n', + 'CREATE ${orReplace}${materialized}VIEW ${ifNotExist}${name}${columns}${partitions}${clustering}${options} AS${selectStatement};\n', dropDatabase: 'DROP SCHEMA IF EXISTS ${name};', - alterDatabase: 'ALTER SCHEMA IF EXISTS ${name} SET ${dbOptions};', + alterDatabaseOptions: 'ALTER SCHEMA IF EXISTS ${name}\nSET OPTIONS (\n${options}\n);', dropTable: 'DROP TABLE IF EXISTS ${name};', @@ -40,7 +40,7 @@ module.exports = { dropView: 'DROP VIEW IF EXISTS ${name};', - alterViewOptions: 'ALTER ${materialized}VIEW ${name} SET ${options};', + alterViewOptions: 'ALTER ${materialized}VIEW ${name}\nSET OPTIONS (\n${options}\n);', alterTableStatement: 'ALTER TABLE ${name}\n${alterStatements};', diff --git a/forward_engineering/ddlProvider.js b/forward_engineering/ddlProvider.js index b21b85a..e9771ea 100644 --- a/forward_engineering/ddlProvider.js +++ b/forward_engineering/ddlProvider.js @@ -287,7 +287,7 @@ module.exports = (baseProvider, options, app) => { return { statement: assignTemplates(templates.createForeignKeyConstraint, { - constraintName: name ? `CONSTRAINT ${prepareConstraintName(name)} ` : '', + constraintName: name ? `CONSTRAINT ${wrapByBackticks(prepareConstraintName(name))} ` : '', foreignKeys: isActivatedBasedOnTableData ? foreignKeysToString(foreignKey) : foreignActiveKeysToString(foreignKey), @@ -482,27 +482,6 @@ module.exports = (baseProvider, options, app) => { return assignTemplates(templates.dropDatabase, { name }); }, - alterDatabase({ - databaseName, - friendlyName, - description, - projectId, - defaultExpiration, - customerEncryptionKey, - labels, - }) { - return assignTemplates(templates.alterDatabase, { - name: getFullName(projectId, databaseName), - dbOptions: getContainerOptions({ - friendlyName, - description, - defaultExpiration, - customerEncryptionKey, - labels, - }), - }); - }, - dropTable(tableName, databaseName, projectId) { return assignTemplates(templates.dropTable, { name: getFullName(projectId, databaseName, tableName), @@ -532,15 +511,5 @@ module.exports = (baseProvider, options, app) => { name: getFullName(projectId, databaseName, viewName), }); }, - - alterView(viewData, dbData) { - const viewName = getFullName(dbData.projectId, dbData.databaseName, viewData.name); - - return assignTemplates(templates.alterViewOptions, { - materialized: viewData.materialized ? 'MATERIALIZED ' : '', - name: viewName, - options: getViewOptions(viewData), - }); - }, }; }; diff --git a/localization/en.json b/localization/en.json index 3c8013f..3421416 100644 --- a/localization/en.json +++ b/localization/en.json @@ -175,5 +175,10 @@ "FE_LEVEL_SELECTOR_TITLE": "Level", "FE_LEVEL_SELECTOR_CONTAINER": "Dataset", "FE_LEVEL_SELECTOR_MODEL": "Model", - "FE_LEVEL_SELECTOR_ENTITY": "Table" + "FE_LEVEL_SELECTOR_ENTITY": "Table", + + "FE_SCRIPT_GENERATION_OPTIONS___SCHEMA_COMMENTS": "Dataset description", + "FE_SCRIPT_GENERATION_OPTIONS___TABLE_COMMENTS": "Table description", + "FE_SCRIPT_GENERATION_OPTIONS___VIEW_COMMENTS": "View description", + "FE_SCRIPT_GENERATION_OPTIONS___COLUMN_COMMENTS": "Column description" }