From 379bbd9cce3e946953d6c1f6cb46a9360698c59d Mon Sep 17 00:00:00 2001 From: Alik Rakhmonov Date: Fri, 5 Dec 2025 15:44:53 +0100 Subject: [PATCH 1/2] HCK-13793: Oracle - handle NOT NULL constraint name --- .../columnHelpers/nonNullConstraintHelper.js | 77 +++++++++++++------ .../ddlHelpers/columnDefinitionHelper.js | 2 +- .../ddlProvider/ddlProvider.js | 27 ++++--- forward_engineering/ddlProvider/templates.js | 14 ++-- 4 files changed, 82 insertions(+), 38 deletions(-) diff --git a/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js index 22bb9d1..3660930 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js @@ -9,18 +9,6 @@ const { prepareNameForScriptFormat, } = require('../../../utils/general'); -/** - * @param {string} tableName - * @param {string} columnName - * @return {string} - * */ -const setNotNullConstraint = (tableName, columnName) => { - return assignTemplates(templates.addNotNullConstraint, { - tableName, - columnName, - }); -}; - /** * @param {object} params * @property {string} [scriptFormat] @@ -35,34 +23,77 @@ const getModifyNonNullColumnsScriptDtos = ({ scriptFormat, collection }) => { const currentRequiredColumnNames = collection.required || []; const previousRequiredColumnNames = collection.role.required || []; - const columnNamesToAddNotNullConstraint = _.difference(currentRequiredColumnNames, previousRequiredColumnNames); - const columnNamesToRemoveNotNullConstraint = _.difference(previousRequiredColumnNames, currentRequiredColumnNames); - const addNotNullConstraintsScript = _.toPairs(collection.properties) .map(([name, jsonSchema]) => { const oldName = jsonSchema.compMod.oldField.name; - const shouldRemoveForOldName = columnNamesToRemoveNotNullConstraint.includes(oldName); - const shouldAddForNewName = columnNamesToAddNotNullConstraint.includes(name); + + const newConstraintName = jsonSchema.notNullConstraintName || ''; + const oldConstraintName = collection.role.properties[oldName]?.notNullConstraintName || ''; + const isNameChanged = newConstraintName !== oldConstraintName; + + const isOldRequired = previousRequiredColumnNames.includes(oldName); + const isNewRequired = currentRequiredColumnNames.includes(name); + const scriptParams = { tableName: fullTableName, columnName: prepareName(name), }; - let script = null; + const scripts = []; - if (shouldAddForNewName && !shouldRemoveForOldName) { - script = assignTemplates(templates.addNotNullConstraint, scriptParams); - } else if (!shouldAddForNewName && shouldRemoveForOldName) { - script = assignTemplates(templates.dropNotNullConstraint, scriptParams); + if (isOldRequired && (!isNewRequired || isNameChanged)) { + const template = oldConstraintName ? templates.dropConstraint : templates.alterNullableConstraint; + scripts.push( + assignTemplates(template, { ...scriptParams, constraintName: prepareName(oldConstraintName) }), + ); } - return script && AlterScriptDto.getInstance([script], true, false); + if (isNewRequired && (!isOldRequired || isNameChanged)) { + const template = newConstraintName + ? templates.alterNamedNotNullConstraint + : templates.alterNotNullConstraint; + scripts.push( + assignTemplates(template, { ...scriptParams, constraintName: prepareName(newConstraintName) }), + ); + } + + return scripts.length && AlterScriptDto.getInstance(scripts, true, false); }) .filter(Boolean); return addNotNullConstraintsScript; }; +const createNotNullConstraintScript = ({ scriptFormat, constraintName, columnName }) => { + const prepareName = prepareNameForScriptFormat(scriptFormat); + return assignTemplates(templates.notNullConstraint, { + constraintName: prepareName(constraintName), + columnName: prepareName(columnName), + }); +}; + +/** + * Get named NOT NULL constraints data + * @param {object} jsonSchema + * @param {string} scriptFormat + * @returns {Array<{ statement: string, isActivated: boolean }>} + */ +const getNotNullConstraints = (jsonSchema, scriptFormat) => { + return _.toPairs(jsonSchema.properties) + .filter( + ([name, columnSchema]) => jsonSchema.required?.includes(name) && columnSchema.notNullConstraintName?.trim(), + ) + .map(([name, columnSchema]) => ({ + statement: createNotNullConstraintScript({ + scriptFormat, + constraintName: columnSchema.notNullConstraintName, + columnName: name, + }), + isActivated: columnSchema.isActivated, + })); +}; + module.exports = { getModifyNonNullColumnsScriptDtos, + getNotNullConstraints, }; diff --git a/forward_engineering/ddlProvider/ddlHelpers/columnDefinitionHelper.js b/forward_engineering/ddlProvider/ddlHelpers/columnDefinitionHelper.js index cb557f4..7b69902 100644 --- a/forward_engineering/ddlProvider/ddlHelpers/columnDefinitionHelper.js +++ b/forward_engineering/ddlProvider/ddlHelpers/columnDefinitionHelper.js @@ -36,7 +36,7 @@ module.exports = ({ assignTemplates, templates, commentIfDeactivated, wrapCommen ); const primaryKeyString = primaryKey ? ` PRIMARY KEY` : ''; const uniqueKeyString = unique ? ` UNIQUE` : ''; - const nullableString = nullable ? '' : ' NOT NULL'; + const nullableString = nullable || primaryKey ? '' : ' NOT NULL'; return `${nullableString}${constraintString}${primaryKeyString}${uniqueKeyString}${statement}`; }; diff --git a/forward_engineering/ddlProvider/ddlProvider.js b/forward_engineering/ddlProvider/ddlProvider.js index d42018c..ba39637 100644 --- a/forward_engineering/ddlProvider/ddlProvider.js +++ b/forward_engineering/ddlProvider/ddlProvider.js @@ -22,6 +22,7 @@ const { } = require('../utils/general'); const { assignTemplates } = require('../utils/assignTemplates'); const { decorateType } = require('./ddlHelpers/columnDefinitionHelpers/decorateType'); +const { getNotNullConstraints } = require('../alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper'); /** * @param dbVersion {string} DB version in "21ai" format @@ -35,10 +36,9 @@ const shouldUseTryCatchIfNotExistsWrapper = dbVersion => { module.exports = (baseProvider, options, app) => { const toArray = val => (_.isArray(val) ? val : [val]); - const prepareName = prepareNameForScriptFormat(options?.targetScriptOptions?.keyword); - const getNamePrefixedWithSchemaName = getNamePrefixedWithSchemaNameForScriptFormat( - options?.targetScriptOptions?.keyword, - ); + const scriptFormat = options?.targetScriptOptions?.keyword; + const prepareName = prepareNameForScriptFormat(scriptFormat); + const getNamePrefixedWithSchemaName = getNamePrefixedWithSchemaNameForScriptFormat(scriptFormat); const keyHelper = require('./ddlHelpers/keyHelper')(clean); @@ -183,7 +183,7 @@ module.exports = (baseProvider, options, app) => { primaryKeyOptions: jsonSchema.primaryKeyOptions, unique: keyHelper.isInlineUnique(jsonSchema), uniqueKeyOptions: jsonSchema.uniqueKeyOptions, - nullable: columnDefinition.nullable, + nullable: columnDefinition.nullable || Boolean(jsonSchema.notNullConstraintName?.trim()), default: columnDefinition.default, comment: jsonSchema.refDescription || jsonSchema.description || definitionJsonSchema.description, isActivated: columnDefinition.isActivated, @@ -342,12 +342,12 @@ module.exports = (baseProvider, options, app) => { * @param fkConstraintName {string} * @return string * */ - dropForeignKey(tableName, fkConstraintName) { + dropForeignKey(tableName, constraintName) { const templateConfig = { tableName, - fkConstraintName, + constraintName, }; - return assignTemplates(templates.dropForeignKey, templateConfig); + return assignTemplates(templates.dropConstraint, templateConfig); }, hydrateTable({ tableData, entityData, jsonSchema }) { @@ -358,6 +358,7 @@ module.exports = (baseProvider, options, app) => { return { ...tableData, keyConstraints: keyHelper.getTableKeyConstraints(jsonSchema), + notNullConstraints: getNotNullConstraints(jsonSchema, scriptFormat), selectStatement: _.trim(detailsTab.selectStatement), partitioning: _.assign({}, partitioning, { compositePartitionKey }), ..._.pick( @@ -405,6 +406,7 @@ module.exports = (baseProvider, options, app) => { ifNotExist, tableProperties, synonyms, + notNullConstraints, }, isActivated, ) { @@ -428,11 +430,18 @@ module.exports = (baseProvider, options, app) => { const columnDescriptions = getColumnComments(tableName, columnDefinitions); + const dividedNotNullConstraints = divideIntoActivatedAndDeactivated( + notNullConstraints, + key => key.statement, + ); + const notNullConstraintsString = generateConstraintsString(dividedNotNullConstraints, isActivated); + const tableProps = assignTemplates(templates.createTableProps, { columnDefinitions: _.join(columns, ',\n\t'), foreignKeyConstraints: foreignKeyConstraintsString, keyConstraints: keyConstraintsString, - checkConstraints: !_.isEmpty(checkConstraints) ? ',\n\t' + _.join(checkConstraints, ',\n\t') : '', + checkConstraints: _.isEmpty(checkConstraints) ? '' : ',\n\t' + _.join(checkConstraints, ',\n\t'), + notNullConstraints: notNullConstraintsString, }); const synonymsStatements = generateSynonymStatements(synonyms, tableName, schemaData.schemaName); diff --git a/forward_engineering/ddlProvider/templates.js b/forward_engineering/ddlProvider/templates.js index 4cada44..82dce34 100644 --- a/forward_engineering/ddlProvider/templates.js +++ b/forward_engineering/ddlProvider/templates.js @@ -5,7 +5,8 @@ module.exports = { createTable: 'CREATE${tableType} TABLE${ifNotExists} ${name}${tableProps}${options}', - createTableProps: '${columnDefinitions}${keyConstraints}${checkConstraints}${foreignKeyConstraints}', + createTableProps: + '${columnDefinitions}${keyConstraints}${checkConstraints}${foreignKeyConstraints}${notNullConstraints}', columnDefinition: '${name}${type}${default}${encrypt}${constraints}', @@ -19,8 +20,6 @@ module.exports = { createForeignKey: 'ALTER TABLE ${foreignTable} ADD CONSTRAINT ${name} FOREIGN KEY (${foreignKey}) REFERENCES ${primaryTable} (${primaryKey})${onDelete};', - dropForeignKey: 'ALTER TABLE ${tableName} DROP CONSTRAINT ${fkConstraintName};', - createIndex: `CREATE$\{indexType} INDEX$\{ifNotExists}$\{name} ON $\{tableName}$\{keys}$\{options};\n`, dropIndex: 'DROP INDEX ${name};', @@ -84,9 +83,14 @@ module.exports = { addPkConstraint: 'ALTER TABLE ${tableName} ADD ${constraintStatement};', - addNotNullConstraint: 'ALTER TABLE ${tableName} MODIFY ${columnName} NOT NULL;', + notNullConstraint: 'CONSTRAINT ${constraintName} CHECK (${columnName} IS NOT NULL)', + + alterNotNullConstraint: 'ALTER TABLE ${tableName} MODIFY ${columnName} NOT NULL;', + + alterNamedNotNullConstraint: + 'ALTER TABLE ${tableName} ADD CONSTRAINT ${constraintName} CHECK (${columnName} IS NOT NULL);', - dropNotNullConstraint: 'ALTER TABLE ${tableName} MODIFY ${columnName} NULL;', + alterNullableConstraint: 'ALTER TABLE ${tableName} MODIFY ${columnName} NULL;', updateColumnDefaultValue: 'ALTER TABLE ${tableName} MODIFY ${columnName}${defaultValue};', From 18363278a7cf9cdf627bea2d6a17b7c3461c88c0 Mon Sep 17 00:00:00 2001 From: Alik Rakhmonov Date: Fri, 5 Dec 2025 15:51:23 +0100 Subject: [PATCH 2/2] fix type --- .../alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js index 3660930..9655c2e 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js @@ -57,7 +57,7 @@ const getModifyNonNullColumnsScriptDtos = ({ scriptFormat, collection }) => { ); } - return scripts.length && AlterScriptDto.getInstance(scripts, true, false); + return scripts.length ? AlterScriptDto.getInstance(scripts, true, false) : null; }) .filter(Boolean);