diff --git a/forward_engineering/alterScript/alterScriptBuilder.js b/forward_engineering/alterScript/alterScriptBuilder.js new file mode 100644 index 0000000..f2609e1 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptBuilder.js @@ -0,0 +1,103 @@ +const {getAlterScriptDtos} = require("./alterScriptFromDeltaHelper"); + +const {AlterScriptDto} = require('./types/AlterScriptDto'); + +/** + * @return {(dtos: AlterScriptDto[], shouldApplyDropStatements: boolean) => string} + * */ +const joinAlterScriptDtosIntoScript = (_) => (dtos, shouldApplyDropStatements) => { + const {commentIfDeactivated} = require('../utils/general')(_); + return dtos.map((dto) => { + if (dto.isActivated === false) { + return dto.scripts + .map((scriptDto) => commentIfDeactivated(scriptDto.script, { + isActivated: false, + isPartOfLine: false, + })); + } + if (!shouldApplyDropStatements) { + return dto.scripts + .map((scriptDto) => commentIfDeactivated(scriptDto.script, { + isActivated: !scriptDto.isDropScript, + isPartOfLine: false, + })); + } + return dto.scripts.map((scriptDto) => scriptDto.script); + }) + .flat() + .filter(Boolean) + .map((scriptLine) => scriptLine.trim()) + .filter(Boolean) + .join('\n\n'); +} + +/** + * @param data {CoreData} + * @param app {App} + * @return {string} + * */ +const buildEntityLevelAlterScript = (data, app) => { + const _ = app.require('lodash'); + const alterScriptDtos = getAlterScriptDtos(data, app); + const shouldApplyDropStatements = data.options?.additionalOptions?.some( + option => option.id === 'applyDropStatements' && option.value, + ); + + return joinAlterScriptDtosIntoScript(_)(alterScriptDtos, shouldApplyDropStatements); +} + +/** + * @param data {CoreData} + * @param app {App} + * @return { boolean} + * */ +const doesEntityLevelAlterScriptContainDropStatements = (data, app) => { + const alterScriptDtos = getAlterScriptDtos(data, app); + return alterScriptDtos + .some(alterScriptDto => alterScriptDto.isActivated && alterScriptDto + .scripts.some(scriptModificationDto => scriptModificationDto.isDropScript)); +} + +const mapCoreDataForContainerLevelScripts = (data) => { + return { + ...data, + jsonSchema: data.collections[0], + internalDefinitions: Object.values(data.internalDefinitions)[0], + } +} + +/** + * @param data {CoreData} + * @param app {App} + * @return {string} + * */ +const buildContainerLevelAlterScript = (data, app) => { + const preparedData = mapCoreDataForContainerLevelScripts(data); + const _ = app.require('lodash'); + const alterScriptDtos = getAlterScriptDtos(preparedData, app); + const shouldApplyDropStatements = preparedData.options?.additionalOptions?.some( + option => option.id === 'applyDropStatements' && option.value, + ); + + return joinAlterScriptDtosIntoScript(_)(alterScriptDtos, shouldApplyDropStatements); +} + +/** + * @param data {CoreData} + * @param app {App} + * @return { boolean} + * */ +const doesContainerLevelAlterScriptContainDropStatements = (data, app) => { + const preparedData = mapCoreDataForContainerLevelScripts(data); + const alterScriptDtos = getAlterScriptDtos(preparedData, app); + return alterScriptDtos + .some(alterScriptDto => alterScriptDto.isActivated && alterScriptDto + .scripts.some(scriptModificationDto => scriptModificationDto.isDropScript)); +} + +module.exports = { + buildEntityLevelAlterScript, + doesEntityLevelAlterScriptContainDropStatements, + buildContainerLevelAlterScript, + doesContainerLevelAlterScriptContainDropStatements +} diff --git a/forward_engineering/alterScript/alterScriptFromDeltaHelper.js b/forward_engineering/alterScript/alterScriptFromDeltaHelper.js new file mode 100644 index 0000000..7c33454 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptFromDeltaHelper.js @@ -0,0 +1,354 @@ +const { + getAddContainerScriptDto, + getDeleteContainerScriptDto, + getModifyContainerScriptDtos +} = require('./alterScriptHelpers/alterContainerHelper'); +const { + getAddCollectionScriptDto, + getDeleteCollectionScriptDto, + getAddColumnScriptDtos, + getDeleteColumnScriptDtos, + getModifyColumnScriptDtos, + getModifyCollectionScriptDtos, +} = require('./alterScriptHelpers/alterEntityHelper'); +const { + getDeleteUdtScriptDto, + getCreateUdtScriptDto, + getAddColumnToTypeScriptDtos, + getDeleteColumnFromTypeScriptDtos, + getModifyColumnOfTypeScriptDtos, +} = require('./alterScriptHelpers/alterUdtHelper'); +const { + getAddViewScriptDto, + getDeleteViewScriptDto, + getModifyViewScriptDtos +} = require('./alterScriptHelpers/alterViewHelper'); +const { + getModifyForeignKeyScriptDtos, + getDeleteForeignKeyScriptDtos, + getAddForeignKeyScriptDtos +} = require("./alterScriptHelpers/alterRelationshipsHelper"); +const {AlterScriptDto, ModificationScript} = require("./types/AlterScriptDto"); +const {App, CoreData} = require("../types/coreApplicationTypes"); +const {InternalDefinitions, ModelDefinitions, ExternalDefinitions} = require("../types/coreApplicationDataTypes"); + + +/** + * @param dto {{ + * collection: Object, + * app: App, + * }} + * @return {AlterScriptDto[]} + * */ +const getAlterContainersScriptDtos = ({collection, app}) => { + const addedContainers = collection.properties?.containers?.properties?.added?.items; + const deletedContainers = collection.properties?.containers?.properties?.deleted?.items; + const modifiedContainers = collection.properties?.containers?.properties?.modified?.items; + + const addContainersScriptDtos = [] + .concat(addedContainers) + .filter(Boolean) + .map(container => getAddContainerScriptDto(app)(Object.keys(container.properties)[0])); + const deleteContainersScriptDtos = [] + .concat(deletedContainers) + .filter(Boolean) + .map(container => getDeleteContainerScriptDto(app)(Object.keys(container.properties)[0])); + const modifyContainersScriptDtos = [] + .concat(modifiedContainers) + .filter(Boolean) + .map(containerWrapper => Object.values(containerWrapper.properties)[0]) + .flatMap(container => getModifyContainerScriptDtos(app)(container)) + + return [ + ...addContainersScriptDtos, + ...deleteContainersScriptDtos, + ...modifyContainersScriptDtos, + ].filter(Boolean); +}; + + +/** + * @param dto {{ + * collection: Object, + * app: App, + * dbVersion: string, + * modelDefinitions: ModelDefinitions, + * internalDefinitions: InternalDefinitions, + * externalDefinitions: ExternalDefinitions, + * }} + * @return {AlterScriptDto[]} + * */ +const getAlterCollectionsScriptDtos = ({ + collection, + app, + dbVersion, + modelDefinitions, + internalDefinitions, + externalDefinitions, + }) => { + const createCollectionsScriptDtos = [] + .concat(collection.properties?.entities?.properties?.added?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .filter(collection => collection.compMod?.created) + .map(getAddCollectionScriptDto({app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions})); + const deleteCollectionScriptDtos = [] + .concat(collection.properties?.entities?.properties?.deleted?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .filter(collection => collection.compMod?.deleted) + .map(getDeleteCollectionScriptDto(app)); + const modifyCollectionScriptDtos = [] + .concat(collection.properties?.entities?.properties?.modified?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .flatMap(getModifyCollectionScriptDtos(app)); + const addColumnScriptDtos = [] + .concat(collection.properties?.entities?.properties?.added?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .filter(collection => !collection.compMod) + .flatMap(getAddColumnScriptDtos({app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions})); + const deleteColumnScriptDtos = [] + .concat(collection.properties?.entities?.properties?.deleted?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .filter(collection => !collection.compMod) + .flatMap(getDeleteColumnScriptDtos(app)); + const modifyColumnScriptDtos = [] + .concat(collection.properties?.entities?.properties?.modified?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .filter(collection => !collection.compMod) + .flatMap(getModifyColumnScriptDtos(app)); + + return [ + ...createCollectionsScriptDtos, + ...deleteCollectionScriptDtos, + ...modifyCollectionScriptDtos, + ...addColumnScriptDtos, + ...deleteColumnScriptDtos, + ...modifyColumnScriptDtos, + ].filter(Boolean); +}; + +/** + * @param collection {Object} + * @param app {App} + * @return {AlterScriptDto[]} + * */ +const getAlterViewScriptDtos = (collection, app) => { + const createViewsScriptDtos = [] + .concat(collection.properties?.views?.properties?.added?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .map(view => ({...view, ...(view.role || {})})) + .filter(view => view.compMod?.created && view.selectStatement) + .map(getAddViewScriptDto(app)); + + const deleteViewsScriptDtos = [] + .concat(collection.properties?.views?.properties?.deleted?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .map(view => ({...view, ...(view.role || {})})) + .map(getDeleteViewScriptDto(app)); + + const modifyViewsScriptDtos = [] + .concat(collection.properties?.views?.properties?.modified?.items) + .filter(Boolean) + .map(viewWrapper => Object.values(viewWrapper.properties)[0]) + .map(view => ({...view, ...(view.role || {})})) + .flatMap(view => getModifyViewScriptDtos(app)(view)); + + return [ + ...deleteViewsScriptDtos, + ...createViewsScriptDtos, + ...modifyViewsScriptDtos, + ].filter(Boolean); +}; + +/** + * @param dto {{ + * collection: Object, + * app: App, + * dbVersion: string, + * modelDefinitions: ModelDefinitions, + * internalDefinitions: InternalDefinitions, + * externalDefinitions: ExternalDefinitions, + * }} + * @return {AlterScriptDto[]} + * */ +const getAlterModelDefinitionsScriptDtos = ({ + collection, + app, + dbVersion, + modelDefinitions, + internalDefinitions, + externalDefinitions, + }) => { + const createUdtScriptDtos = [] + .concat(collection.properties?.modelDefinitions?.properties?.added?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .map(item => ({...item, ...(app.require('lodash').omit(item.role, 'properties') || {})})) + .filter(item => item.compMod?.created) + .map(getCreateUdtScriptDto({app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions})); + const deleteUdtScriptDtos = [] + .concat(collection.properties?.modelDefinitions?.properties?.deleted?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .map(item => ({...item, ...(app.require('lodash').omit(item.role, 'properties') || {})})) + .filter(collection => collection.compMod?.deleted) + .map(getDeleteUdtScriptDto(app)); + const addColumnScriptDtos = [] + .concat(collection.properties?.modelDefinitions?.properties?.added?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .filter(item => !item.compMod) + .map(item => ({...item, ...(app.require('lodash').omit(item.role, 'properties') || {})})) + .filter(item => item.childType === 'composite') + .flatMap( + getAddColumnToTypeScriptDtos({app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions}), + ); + const deleteColumnScriptDtos = [] + .concat(collection.properties?.modelDefinitions?.properties?.deleted?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .filter(item => !item.compMod) + .map(item => ({...item, ...(app.require('lodash').omit(item.role, 'properties') || {})})) + .filter(item => item.childType === 'composite') + .flatMap(getDeleteColumnFromTypeScriptDtos(app)); + + const modifyColumnScriptDtos = [] + .concat(collection.properties?.modelDefinitions?.properties?.modified?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .filter(item => !item.compMod) + .map(item => ({...item, ...(app.require('lodash').omit(item.role, 'properties') || {})})) + .filter(item => item.childType === 'composite') + .flatMap(getModifyColumnOfTypeScriptDtos(app)); + + return [ + ...deleteUdtScriptDtos, + ...createUdtScriptDtos, + ...addColumnScriptDtos, + ...deleteColumnScriptDtos, + ...modifyColumnScriptDtos, + ].filter(Boolean); +}; + +/** + * @return Array + * */ +const getAlterRelationshipsScriptDtos = ({ + collection, + app, + }) => { + const _ = app.require('lodash'); + const ddlProvider = require('../ddlProvider/ddlProvider')(null, null, app); + + const addedRelationships = [] + .concat(collection.properties?.relationships?.properties?.added?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .filter(relationship => relationship?.role?.compMod?.created); + const deletedRelationships = [] + .concat(collection.properties?.relationships?.properties?.deleted?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .filter(relationship => relationship?.role?.compMod?.deleted); + const modifiedRelationships = [] + .concat(collection.properties?.relationships?.properties?.modified?.items) + .filter(Boolean) + .map(item => Object.values(item.properties)[0]) + .filter(relationship => relationship?.role?.compMod?.modified); + + const deleteFkScriptDtos = getDeleteForeignKeyScriptDtos(ddlProvider, _)(deletedRelationships); + const addFkScriptDtos = getAddForeignKeyScriptDtos(ddlProvider, _)(addedRelationships); + const modifiedFkScriptDtos = getModifyForeignKeyScriptDtos(ddlProvider, _)(modifiedRelationships); + + return [ + ...deleteFkScriptDtos, + ...addFkScriptDtos, + ...modifiedFkScriptDtos, + ].filter(Boolean); +} + +/** + * @param dto {AlterScriptDto} + * @return {AlterScriptDto | undefined} + */ +const prettifyAlterScriptDto = (dto) => { + if (!dto) { + return undefined; + } + /** + * @type {Array} + * */ + const nonEmptyScriptModificationDtos = dto.scripts + .map((scriptDto) => ({ + ...scriptDto, + script: (scriptDto.script || '').trim() + })) + .filter((scriptDto) => Boolean(scriptDto.script)); + if (!nonEmptyScriptModificationDtos.length) { + return undefined; + } + return { + ...dto, + scripts: nonEmptyScriptModificationDtos + } +} + +/** + * @param data {CoreData} + * @param app {App} + * @return {Array} + * */ +const getAlterScriptDtos = (data, app) => { + 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 modelDefinitions = JSON.parse(data.modelDefinitions); + const internalDefinitions = JSON.parse(data.internalDefinitions); + const externalDefinitions = JSON.parse(data.externalDefinitions); + const dbVersion = data.modelData[0]?.dbVersion; + const containersScriptDtos = getAlterContainersScriptDtos({collection, app}); + const collectionsScriptDtos = getAlterCollectionsScriptDtos({ + collection, + app, + dbVersion, + modelDefinitions, + internalDefinitions, + externalDefinitions, + }); + const viewScriptDtos = getAlterViewScriptDtos(collection, app); + const modelDefinitionsScriptDtos = getAlterModelDefinitionsScriptDtos({ + collection, + app, + dbVersion, + modelDefinitions, + internalDefinitions, + externalDefinitions, + }); + const relationshipScriptDtos = getAlterRelationshipsScriptDtos({collection, app}); + + return [ + ...containersScriptDtos, + ...modelDefinitionsScriptDtos, + ...collectionsScriptDtos, + ...viewScriptDtos, + ...relationshipScriptDtos, + ] + .filter(Boolean) + .map((dto) => prettifyAlterScriptDto(dto)) + .filter(Boolean); +}; + +module.exports = { + getAlterScriptDtos, +}; diff --git a/forward_engineering/alterScript/alterScriptHelpers/alterContainerHelper.js b/forward_engineering/alterScript/alterScriptHelpers/alterContainerHelper.js new file mode 100644 index 0000000..1e11841 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/alterContainerHelper.js @@ -0,0 +1,45 @@ +const {getModifySchemaCommentsScriptDtos} = require("./containerHelpers/commentsHelper"); +const {AlterScriptDto} = require("../types/AlterScriptDto"); + +/** + * @return {(containerName: string) => AlterScriptDto | undefined} + * */ +const getAddContainerScriptDto = (app) => (containerName) => { + const _ = app.require('lodash'); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + const {wrapInQuotes} = require('../../utils/general')(_); + const script = ddlProvider.createSchemaOnly(wrapInQuotes(containerName)); + return AlterScriptDto.getInstance([script], true, false); +}; + +/** + * @return {(containerName: string) => AlterScriptDto | undefined} + * */ +const getDeleteContainerScriptDto = (app) => (containerName) => { + const _ = app.require('lodash'); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + const {wrapInQuotes} = require('../../utils/general')(_); + + const script = ddlProvider.dropSchema(wrapInQuotes(containerName)); + return AlterScriptDto.getInstance([script], true, true); +}; + +/** + * @return {(container: Object) => Array} + * */ +const getModifyContainerScriptDtos = (app) => (container) => { + const _ = app.require('lodash'); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + + const modifyCommentScriptDtos = getModifySchemaCommentsScriptDtos(_, ddlProvider)(container); + + return [ + ...modifyCommentScriptDtos + ]; +} + +module.exports = { + getAddContainerScriptDto, + getDeleteContainerScriptDto, + getModifyContainerScriptDtos +}; diff --git a/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js b/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js new file mode 100644 index 0000000..87c3ae8 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js @@ -0,0 +1,185 @@ +const {getModifyCheckConstraintScriptDtos} = require("./entityHelpers/checkConstraintHelper"); +const {getModifyEntityCommentsScriptDtos} = require("./entityHelpers/commentsHelper"); +const {getUpdateTypesScriptDtos} = require("./columnHelpers/alterTypeHelper"); +const {getModifyNonNullColumnsScriptDtos} = require("./columnHelpers/nonNullConstraintHelper"); +const {getModifiedCommentOnColumnScriptDtos} = require("./columnHelpers/commentsHelper"); +const {getRenameColumnScriptDtos} = require("./columnHelpers/renameColumnHelper"); +const {AlterScriptDto} = require("../types/AlterScriptDto"); +const {AlterCollectionDto} = require('../types/AlterCollectionDto'); +const {getModifyPkConstraintsScriptDtos} = require("./entityHelpers/primaryKeyHelper"); + + +/** + * @return {(collection: AlterCollectionDto) => AlterScriptDto | undefined} + * */ +const getAddCollectionScriptDto = + ({app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions}) => + collection => { + const _ = app.require('lodash'); + const {getEntityName} = require('../../utils/general')(_); + const {createColumnDefinitionBySchema} = require('./createColumnDefinition')(app); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + const {getDefinitionByReference} = app.require('@hackolade/ddl-fe-utils'); + + const schemaName = collection.compMod.keyspaceName; + const schemaData = {schemaName, dbVersion}; + const jsonSchema = {...collection, ...(_.omit(collection?.role, 'properties') || {})}; + const columnDefinitions = _.toPairs(jsonSchema.properties).map(([name, column]) => { + const definitionJsonSchema = getDefinitionByReference({ + propertySchema: column, + modelDefinitions, + internalDefinitions, + externalDefinitions, + }); + + return createColumnDefinitionBySchema({ + name, + jsonSchema: column, + parentJsonSchema: jsonSchema, + ddlProvider, + schemaData, + definitionJsonSchema, + }); + }); + const checkConstraints = (jsonSchema.chkConstr || []).map(check => + ddlProvider.createCheckConstraint(ddlProvider.hydrateCheckConstraint(check)), + ); + const tableData = { + name: getEntityName(jsonSchema), + columns: columnDefinitions.map(ddlProvider.convertColumnDefinition), + checkConstraints: checkConstraints, + foreignKeyConstraints: [], + schemaData, + columnDefinitions, + dbData: {dbVersion}, + }; + const hydratedTable = ddlProvider.hydrateTable({tableData, entityData: [jsonSchema], jsonSchema}); + + const script = ddlProvider.createTable(hydratedTable, jsonSchema.isActivated); + return AlterScriptDto.getInstance([script], true, false) + }; + +/** + * @return {(collection: AlterCollectionDto) => AlterScriptDto | undefined} + * */ +const getDeleteCollectionScriptDto = app => collection => { + const _ = app.require('lodash'); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + const {getFullTableName} = require('../../utils/general')(_); + + const fullName = getFullTableName(collection); + const script = ddlProvider.dropTable(fullName); + return AlterScriptDto.getInstance([script], true, true); +}; + +/** + * @return {(collection: AlterCollectionDto) => AlterScriptDto[]} + * */ +const getModifyCollectionScriptDtos = (app) => (collection) => { + const _ = app.require('lodash'); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + + const modifyCheckConstraintScriptDtos = getModifyCheckConstraintScriptDtos(_, ddlProvider)(collection); + const modifyCommentScriptDtos = getModifyEntityCommentsScriptDtos(_, ddlProvider)(collection); + const modifyPKConstraintDtos = getModifyPkConstraintsScriptDtos(_, ddlProvider)(collection); + return [ + ...modifyCheckConstraintScriptDtos, + ...modifyCommentScriptDtos, + ...modifyPKConstraintDtos + ].filter(Boolean); +} + +/** + * @return {(collection: Object) => AlterScriptDto[]} + * */ +const getAddColumnScriptDtos = + ({app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions}) => + collection => { + const _ = app.require('lodash'); + const {getEntityName, getNamePrefixedWithSchemaName} = require('../../utils/general')(_); + const {createColumnDefinitionBySchema} = require('./createColumnDefinition')(app); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + const {getDefinitionByReference} = app.require('@hackolade/ddl-fe-utils'); + + const collectionSchema = {...collection, ...(_.omit(collection?.role, 'properties') || {})}; + const tableName = getEntityName(collectionSchema); + const schemaName = collectionSchema.compMod?.keyspaceName; + const fullName = getNamePrefixedWithSchemaName(tableName, schemaName); + const schemaData = {schemaName, dbVersion}; + + return _.toPairs(collection.properties) + .filter(([name, jsonSchema]) => !jsonSchema.compMod) + .map(([name, jsonSchema]) => { + const definitionJsonSchema = getDefinitionByReference({ + propertySchema: jsonSchema, + modelDefinitions, + internalDefinitions, + externalDefinitions, + }); + + return createColumnDefinitionBySchema({ + name, + jsonSchema, + parentJsonSchema: collectionSchema, + ddlProvider, + schemaData, + definitionJsonSchema, + }); + }) + .map(ddlProvider.convertColumnDefinition) + .map(columnDefinition => ddlProvider.addColumn(fullName, columnDefinition)) + .map(addColumnScript => AlterScriptDto.getInstance([addColumnScript], true, false)) + .filter(Boolean); + }; + +/** + * @return {(collection: Object) => AlterScriptDto[]} + * */ +const getDeleteColumnScriptDtos = app => collection => { + const _ = app.require('lodash'); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + const {getEntityName, getNamePrefixedWithSchemaName, wrapInQuotes} = require('../../utils/general')(_); + + const collectionSchema = {...collection, ...(_.omit(collection?.role, 'properties') || {})}; + const tableName = getEntityName(collectionSchema); + const schemaName = collectionSchema.compMod?.keyspaceName; + const fullTableName = getNamePrefixedWithSchemaName(tableName, schemaName); + + return _.toPairs(collection.properties) + .filter(([name, jsonSchema]) => !jsonSchema.compMod) + .map(([name]) => { + const columnNameForDDL = wrapInQuotes(name); + return ddlProvider.dropColumn(fullTableName, columnNameForDDL) + }) + .map(dropColumnScript => AlterScriptDto.getInstance([dropColumnScript], true, true)) + .filter(Boolean); +}; + +/** + * @return {(collection: Object) => AlterScriptDto[]} + * */ +const getModifyColumnScriptDtos = app => collection => { + const _ = app.require('lodash'); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + + const renameColumnScriptDtos = getRenameColumnScriptDtos(_, ddlProvider)(collection); + const updateTypeScriptDtos = getUpdateTypesScriptDtos(_, ddlProvider)(collection); + const modifyNotNullScriptDtos = getModifyNonNullColumnsScriptDtos(_, ddlProvider)(collection); + const modifyCommentScriptDtos = getModifiedCommentOnColumnScriptDtos(_, ddlProvider)(collection); + + return [ + ...renameColumnScriptDtos, + ...updateTypeScriptDtos, + ...modifyNotNullScriptDtos, + ...modifyCommentScriptDtos, + ].filter(Boolean); +}; + +module.exports = { + getAddCollectionScriptDto, + getDeleteCollectionScriptDto, + getModifyCollectionScriptDtos, + getAddColumnScriptDtos, + getDeleteColumnScriptDtos, + getModifyColumnScriptDtos, +}; diff --git a/forward_engineering/alterScript/alterScriptHelpers/alterRelationshipsHelper.js b/forward_engineering/alterScript/alterScriptHelpers/alterRelationshipsHelper.js new file mode 100644 index 0000000..a86bbc9 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/alterRelationshipsHelper.js @@ -0,0 +1,161 @@ +const {AlterScriptDto} = require("../types/AlterScriptDto"); +const { + AlterRelationshipDto +} = require('../types/AlterRelationshipDto'); + + +/** + * @param relationship {AlterRelationshipDto} + * @return string + * */ +const getRelationshipName = (relationship) => { + return relationship.role.name; +} + +/** + * @return {(relationship: AlterRelationshipDto) => string} + * */ +const getFullChildTableName = (_) => (relationship) => { + const {getNamePrefixedWithSchemaName} = require('../../utils/general')(_); + const compMod = relationship.role.compMod; + + const childBucketName = compMod.child.bucket.name; + const childEntityName = compMod.child.collection.name; + return getNamePrefixedWithSchemaName(childEntityName, childBucketName); +} + +/** + * @return {(relationship: AlterRelationshipDto) => { + * isActivated: boolean, + * statement: string, + * }} + * */ +const getAddSingleForeignKeyStatementDto = (ddlProvider, _) => (relationship) => { + const compMod = relationship.role.compMod; + + const relationshipName = compMod.name?.new || getRelationshipName(relationship) || ''; + + return ddlProvider.createForeignKey({ + name: relationshipName, + foreignKey: compMod.child.collection.fkFields, + primaryKey: compMod.parent.collection.fkFields, + customProperties: compMod.customProperties?.new, + foreignTable: compMod.child.collection.name, + foreignSchemaName: compMod.child.bucket.name, + foreignTableActivated: compMod.child.collection.isActivated, + primaryTable: compMod.parent.collection.name, + primarySchemaName: compMod.parent.bucket.name, + primaryTableActivated: compMod.parent.collection.isActivated, + isActivated: Boolean(relationship.role?.compMod?.isActivated?.new), + }); +} + +/** + * @param relationship {AlterRelationshipDto} + * @return boolean + * */ +const canRelationshipBeAdded = (relationship) => { + const compMod = relationship.role.compMod; + if (!compMod) { + return false; + } + return [ + (compMod.name?.new || getRelationshipName(relationship)), + compMod.parent?.bucket, + compMod.parent?.collection, + compMod.parent?.collection?.fkFields?.length, + compMod.child?.bucket, + compMod.child?.collection, + compMod.child?.collection?.fkFields?.length, + ].every(property => Boolean(property)); +} + +/** + * @return {(addedRelationships: Array) => Array} + * */ +const getAddForeignKeyScriptDtos = (ddlProvider, _) => (addedRelationships) => { + return addedRelationships + .filter((relationship) => canRelationshipBeAdded(relationship)) + .map(relationship => { + const scriptDto = getAddSingleForeignKeyStatementDto(ddlProvider, _)(relationship); + return AlterScriptDto.getInstance([scriptDto.statement], scriptDto.isActivated, false); + }) + .filter(Boolean) + .filter(res => res.scripts.some(scriptDto => Boolean(scriptDto.script))); +} + +/** + * @return {(relationship: AlterRelationshipDto) => { + * isActivated: boolean, + * statement: string, + * }} + * */ +const getDeleteSingleForeignKeyStatementDto = (ddlProvider, _) => (relationship) => { + const {wrapInQuotes} = require('../../utils/general')(_); + const compMod = relationship.role.compMod; + + const ddlChildEntityName = getFullChildTableName(_)(relationship); + + const relationshipName = compMod.name?.old || getRelationshipName(relationship) || ''; + const ddlRelationshipName = wrapInQuotes(relationshipName); + const statement = ddlProvider.dropForeignKey(ddlChildEntityName, ddlRelationshipName); + + const isRelationshipActivated = Boolean(relationship.role?.compMod?.isActivated?.new); + const isChildTableActivated = compMod.child.collection.isActivated; + return { + statement, + isActivated: isRelationshipActivated && isChildTableActivated, + } +} + +/** + * @param relationship {AlterRelationshipDto} + * @return {boolean} + * */ +const canRelationshipBeDeleted = (relationship) => { + const compMod = relationship.role.compMod; + if (!compMod) { + return false; + } + return [ + (compMod.name?.old || getRelationshipName(relationship)), + compMod.child?.bucket, + compMod.child?.collection, + ].every(property => Boolean(property)); +} + +/** + * @return {(deletedRelationships: Array) => Array} + * */ +const getDeleteForeignKeyScriptDtos = (ddlProvider, _) => (deletedRelationships) => { + return deletedRelationships + .filter((relationship) => canRelationshipBeDeleted(relationship)) + .map(relationship => { + const scriptDto = getDeleteSingleForeignKeyStatementDto(ddlProvider, _)(relationship); + return AlterScriptDto.getInstance([scriptDto.statement], scriptDto.isActivated, true); + }) + .filter(Boolean) + .filter(res => res.scripts.some(scriptDto => Boolean(scriptDto.script))); +} + +/** + * @return {(modifiedRelationships: Array) => Array} + * */ +const getModifyForeignKeyScriptDtos = (ddlProvider, _) => (modifiedRelationships) => { + return modifiedRelationships + .filter(relationship => canRelationshipBeAdded(relationship) && canRelationshipBeDeleted(relationship)) + .map(relationship => { + const deleteScriptDto = getDeleteSingleForeignKeyStatementDto(ddlProvider, _)(relationship); + const addScriptDto = getAddSingleForeignKeyStatementDto(ddlProvider, _)(relationship); + const isActivated = addScriptDto.isActivated && deleteScriptDto.isActivated; + return AlterScriptDto.getDropAndRecreateInstance(deleteScriptDto.statement, addScriptDto.statement, isActivated); + }) + .filter(Boolean) + .filter(res => res.scripts.some(scriptDto => Boolean(scriptDto.script))); +} + +module.exports = { + getDeleteForeignKeyScriptDtos, + getModifyForeignKeyScriptDtos, + getAddForeignKeyScriptDtos, +} diff --git a/forward_engineering/alterScript/alterScriptHelpers/alterUdtHelper.js b/forward_engineering/alterScript/alterScriptHelpers/alterUdtHelper.js new file mode 100644 index 0000000..f316599 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/alterUdtHelper.js @@ -0,0 +1,168 @@ +const {AlterScriptDto} = require("../types/AlterScriptDto"); + +/** + * @return {(jsonSchema: Object) => AlterScriptDto | undefined} + * */ +const getCreateUdtScriptDto = + ({app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions}) => + jsonSchema => { + const _ = app.require('lodash'); + const {createColumnDefinitionBySchema} = require('./createColumnDefinition')(app); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + const {getDefinitionByReference} = app.require('@hackolade/ddl-fe-utils'); + + const schemaData = {dbVersion}; + + const columnDefinitions = _.toPairs(jsonSchema.properties || {}).map(([name, column]) => { + const definitionJsonSchema = getDefinitionByReference({ + propertySchema: column, + modelDefinitions, + internalDefinitions, + externalDefinitions, + }); + + return createColumnDefinitionBySchema({ + name, + jsonSchema: column, + parentJsonSchema: jsonSchema, + ddlProvider, + schemaData, + definitionJsonSchema, + }); + }); + + const updatedUdt = createColumnDefinitionBySchema({ + name: jsonSchema.code || jsonSchema.name, + jsonSchema: jsonSchema, + parentJsonSchema: {required: []}, + definitionJsonSchema: {}, + ddlProvider, + schemaData, + }); + + const udt = {...updatedUdt, properties: columnDefinitions}; + + const script = ddlProvider.createUdt(udt); + return AlterScriptDto.getInstance([script], true, false); + }; + + +/** + * @return {(udt: Object) => AlterScriptDto | undefined} + * */ +const getDeleteUdtScriptDto = app => udt => { + const _ = app.require('lodash'); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + + const {getUdtName, wrapInQuotes} = require('../../utils/general')(_); + + const ddlUdtName = wrapInQuotes(getUdtName(udt)); + if (udt.type === 'domain') { + const script = ddlProvider.dropDomain(ddlUdtName); + return AlterScriptDto.getInstance([script], true, true); + } else { + const script = ddlProvider.dropType(ddlUdtName); + return AlterScriptDto.getInstance([script], true, true); + } +}; + +/** + * @return {(udt: Object) => AlterScriptDto[]} + * */ +const getAddColumnToTypeScriptDtos = + ({app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions}) => + udt => { + const _ = app.require('lodash'); + const {createColumnDefinitionBySchema} = require('./createColumnDefinition')(app); + const {getUdtName, wrapInQuotes} = require('../../utils/general')(_); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + const {getDefinitionByReference} = app.require('@hackolade/ddl-fe-utils'); + + const fullName = wrapInQuotes(getUdtName(udt)); + const schemaData = {dbVersion}; + + return _.toPairs(udt.properties) + .filter(([name, jsonSchema]) => !jsonSchema.compMod) + .map(([name, jsonSchema]) => { + const definitionJsonSchema = getDefinitionByReference({ + propertySchema: jsonSchema, + modelDefinitions, + internalDefinitions, + externalDefinitions, + }); + + return createColumnDefinitionBySchema({ + name, + jsonSchema, + parentJsonSchema: {required: []}, + ddlProvider, + schemaData, + definitionJsonSchema, + }); + }) + .map(ddlProvider.convertColumnDefinition) + .map(columnDefinition => ddlProvider.alterTypeAddAttribute(fullName, columnDefinition)) + .map(script => AlterScriptDto.getInstance([script], true, false)) + .filter(Boolean); + }; + +/** + * @return {(udt: Object) => AlterScriptDto[]} + * */ +const getDeleteColumnFromTypeScriptDtos = app => udt => { + const _ = app.require('lodash'); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + + const {wrapInQuotes} = require('../../utils/general')(_); + + const fullName = wrapInQuotes(udt.code || udt.name); + + return _.toPairs(udt.properties) + .filter(([name, jsonSchema]) => !jsonSchema.compMod) + .map(([name]) => ddlProvider.alterTypeDropAttribute(fullName, wrapInQuotes(name))) + .map(script => AlterScriptDto.getInstance([script], true, true)) + .filter(Boolean); +}; + +/** + * @return {(udt: Object) => AlterScriptDto[]} + * */ +const getModifyColumnOfTypeScriptDtos = app => udt => { + const _ = app.require('lodash'); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + + const {checkFieldPropertiesChanged, wrapInQuotes} = require('../../utils/general')(_); + + const fullName = wrapInQuotes(udt.code || udt.name); + + const renameColumnScripts = _.values(udt.properties) + .filter(jsonSchema => checkFieldPropertiesChanged(jsonSchema.compMod, ['name'])) + .map((jsonSchema) => { + const oldAttributeDDLName = wrapInQuotes(jsonSchema.compMod.oldField.name); + const newAttributeDDLName = wrapInQuotes(jsonSchema.compMod.newField.name); + return ddlProvider.alterTypeRenameAttribute(fullName, oldAttributeDDLName, newAttributeDDLName); + }) + .map(script => AlterScriptDto.getInstance([script], true, false)); + + const changeTypeScripts = _.toPairs(udt.properties) + .filter(([name, jsonSchema]) => checkFieldPropertiesChanged(jsonSchema.compMod, ['type', 'mode'])) + .map(([name, jsonSchema]) => { + const attributeDDLName = wrapInQuotes(name); + const newDataType = jsonSchema.compMod.newField.mode || jsonSchema.compMod.newField.type; + return ddlProvider.alterTypeChangeAttributeType(fullName, attributeDDLName, newDataType); + }) + .map(script => AlterScriptDto.getInstance([script], true, false)); + + return [ + ...renameColumnScripts, + ...changeTypeScripts + ].filter(Boolean); +}; + +module.exports = { + getCreateUdtScriptDto, + getDeleteUdtScriptDto, + getAddColumnToTypeScriptDtos, + getDeleteColumnFromTypeScriptDtos, + getModifyColumnOfTypeScriptDtos, +}; diff --git a/forward_engineering/alterScript/alterScriptHelpers/alterViewHelper.js b/forward_engineering/alterScript/alterScriptHelpers/alterViewHelper.js new file mode 100644 index 0000000..4d69fe4 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/alterViewHelper.js @@ -0,0 +1,52 @@ +const {getModifyViewCommentsScriptDtos} = require("./viewHelpers/commentsHelper"); +const {AlterScriptDto} = require("../types/AlterScriptDto"); + +/** + * @return {(view: Object) => AlterScriptDto | undefined} + * */ +const getAddViewScriptDto = app => view => { + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + + const viewData = { + name: view.code || view.name, + keys: [], + schemaData: { schemaName: '' }, + }; + const hydratedView = ddlProvider.hydrateView({ viewData, entityData: [view] }); + + const script = ddlProvider.createView(hydratedView, {}, view.isActivated); + return AlterScriptDto.getInstance([script], true, false); +}; + +/** + * @return {(view: Object) => AlterScriptDto | undefined} + * */ +const getDeleteViewScriptDto = app => view => { + const _ = app.require('lodash'); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + const { wrapInQuotes } = require('../../utils/general')(_); + const viewName = wrapInQuotes(view.code || view.name); + + const script = ddlProvider.dropView(viewName); + return AlterScriptDto.getInstance([script], true, true); +}; + +/** + * @return {(view: Object) => AlterScriptDto[]} + * */ +const getModifyViewScriptDtos = (app) => (view) => { + const _ = app.require('lodash'); + const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app); + + const modifyCommentsScriptDtos = getModifyViewCommentsScriptDtos(_, ddlProvider)(view); + + return [ + ...modifyCommentsScriptDtos, + ].filter(Boolean); +} + +module.exports = { + getAddViewScriptDto, + getDeleteViewScriptDto, + getModifyViewScriptDtos, +}; diff --git a/forward_engineering/helpers/alterScriptHelpers/columnHelpers/alterTypeHelper.js b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/alterTypeHelper.js similarity index 74% rename from forward_engineering/helpers/alterScriptHelpers/columnHelpers/alterTypeHelper.js rename to forward_engineering/alterScript/alterScriptHelpers/columnHelpers/alterTypeHelper.js index 1a382e6..b3446ba 100644 --- a/forward_engineering/helpers/alterScriptHelpers/columnHelpers/alterTypeHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/alterTypeHelper.js @@ -1,7 +1,8 @@ -const {getFullTableName} = require("../ddlHelper"); -const {checkFieldPropertiesChanged} = require("../common"); - +const {AlterScriptDto} = require("../../types/AlterScriptDto"); +/** + * @return {boolean} + * */ const hasLengthChanged = (collection, oldFieldName, currentJsonSchema) => { const oldProperty = collection.role.properties[oldFieldName]; @@ -10,6 +11,9 @@ const hasLengthChanged = (collection, oldFieldName, currentJsonSchema) => { return previousLength !== newLength; } +/** + * @return {boolean} + * */ const hasPrecisionOrScaleChanged = (collection, oldFieldName, currentJsonSchema) => { const oldProperty = collection.role.properties[oldFieldName]; @@ -21,11 +25,14 @@ const hasPrecisionOrScaleChanged = (collection, oldFieldName, currentJsonSchema) return previousPrecision !== newPrecision || previousScale !== newScale; } -const getUpdateTypesScripts = (_, ddlProvider) => (collection) => { - const fullTableName = getFullTableName(_)(collection); - const {wrapInQuotes} = require('../../general')({_}); +/** + * @return {(collection: Object) => AlterScriptDto[]} + * */ +const getUpdateTypesScriptDtos = (_, ddlProvider) => (collection) => { + const {checkFieldPropertiesChanged, getFullTableName, wrapInQuotes} = require('../../../utils/general')(_); + const fullTableName = getFullTableName(collection); - const changeTypeScripts = _.toPairs(collection.properties) + return _.toPairs(collection.properties) .filter(([name, jsonSchema]) => { const hasTypeChanged = checkFieldPropertiesChanged(jsonSchema.compMod, ['type', 'mode']); if (!hasTypeChanged) { @@ -43,10 +50,10 @@ const getUpdateTypesScripts = (_, ddlProvider) => (collection) => { const typeConfig = _.pick(jsonSchema, ['length', 'precision', 'scale']); return ddlProvider.alterColumnType(fullTableName, columnName, typeName, typeConfig); } - ); - return [...changeTypeScripts]; + ) + .map(script => AlterScriptDto.getInstance([script], true, false)); } module.exports = { - getUpdateTypesScripts + getUpdateTypesScriptDtos } diff --git a/forward_engineering/helpers/alterScriptHelpers/columnHelpers/commentsHelper.js b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/commentsHelper.js similarity index 54% rename from forward_engineering/helpers/alterScriptHelpers/columnHelpers/commentsHelper.js rename to forward_engineering/alterScript/alterScriptHelpers/columnHelpers/commentsHelper.js index 2f5cca3..1b0cbde 100644 --- a/forward_engineering/helpers/alterScriptHelpers/columnHelpers/commentsHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/commentsHelper.js @@ -1,7 +1,10 @@ -const {getFullColumnName} = require("../ddlHelper"); +const {AlterScriptDto} = require("../../types/AlterScriptDto"); -const getUpdatedCommentOnColumnScripts = (_, ddlProvider) => (collection) => { - const {wrapComment} = require('../../general')({_}); +/** + * @return {(collection: Object) => AlterScriptDto[]} + * */ +const getUpdatedCommentOnColumnScriptDtos = (_, ddlProvider) => (collection) => { + const {getFullColumnName, wrapComment} = require('../../../utils/general')(_); return _.toPairs(collection.properties) .filter(([name, jsonSchema]) => { const newComment = jsonSchema.description; @@ -12,12 +15,18 @@ const getUpdatedCommentOnColumnScripts = (_, ddlProvider) => (collection) => { .map(([name, jsonSchema]) => { const newComment = jsonSchema.description; const ddlComment = wrapComment(newComment); - const columnName = getFullColumnName(_)(collection, name); + const columnName = getFullColumnName(collection, name); return ddlProvider.updateColumnComment(columnName, ddlComment); - }); + }) + .map(script => AlterScriptDto.getInstance([script], true, false)); } -const getDeletedCommentOnColumnScripts = (_, ddlProvider) => (collection) => { +/** + * @return {(collection: Object) => AlterScriptDto[]} + * */ +const getDeletedCommentOnColumnScriptDtos = (_, ddlProvider) => (collection) => { + const {getFullColumnName} = require('../../../utils/general')(_); + return _.toPairs(collection.properties) .filter(([name, jsonSchema]) => { const newComment = jsonSchema.description; @@ -26,17 +35,21 @@ const getDeletedCommentOnColumnScripts = (_, ddlProvider) => (collection) => { return oldComment && !newComment; }) .map(([name, jsonSchema]) => { - const columnName = getFullColumnName(_)(collection, name); + const columnName = getFullColumnName(collection, name); return ddlProvider.dropColumnComment(columnName); - }); + }) + .map(script => AlterScriptDto.getInstance([script], true, true)); } -const getModifiedCommentOnColumnScripts = (_, ddlProvider) => (collection) => { - const updatedCommentScripts = getUpdatedCommentOnColumnScripts(_, ddlProvider)(collection); - const deletedCommentScripts = getDeletedCommentOnColumnScripts(_, ddlProvider)(collection); +/** + * @return {(collection: Object) => AlterScriptDto[]} + * */ +const getModifiedCommentOnColumnScriptDtos = (_, ddlProvider) => (collection) => { + const updatedCommentScripts = getUpdatedCommentOnColumnScriptDtos(_, ddlProvider)(collection); + const deletedCommentScripts = getDeletedCommentOnColumnScriptDtos(_, ddlProvider)(collection); return [...updatedCommentScripts, ...deletedCommentScripts]; } module.exports = { - getModifiedCommentOnColumnScripts + getModifiedCommentOnColumnScriptDtos } diff --git a/forward_engineering/helpers/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js similarity index 71% rename from forward_engineering/helpers/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js rename to forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js index 090bfa3..456bfaa 100644 --- a/forward_engineering/helpers/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/nonNullConstraintHelper.js @@ -1,8 +1,11 @@ -const {getFullTableName} = require("../ddlHelper"); +const {AlterScriptDto} = require("../../types/AlterScriptDto"); -const getModifyNonNullColumnsScripts = (_, ddlProvider) => (collection) => { - const fullTableName = getFullTableName(_)(collection); - const {wrapInQuotes} = require('../../general')({_}); +/** + * @return {(collection: Object) => AlterScriptDto[]} + * */ +const getModifyNonNullColumnsScriptDtos = (_, ddlProvider) => (collection) => { + const {getFullTableName, wrapInQuotes} = require('../../../utils/general')(_); + const fullTableName = getFullTableName(collection); const currentRequiredColumnNames = collection.required || []; const previousRequiredColumnNames = collection.role.required || []; @@ -17,7 +20,9 @@ const getModifyNonNullColumnsScripts = (_, ddlProvider) => (collection) => { const shouldAddForNewName = columnNamesToAddNotNullConstraint.includes(name); return shouldAddForNewName && !shouldRemoveForOldName; }) - .map(([columnName]) => ddlProvider.setNotNullConstraint(fullTableName, wrapInQuotes(columnName))); + .map(([columnName]) => ddlProvider.setNotNullConstraint(fullTableName, wrapInQuotes(columnName))) + .map(script => AlterScriptDto.getInstance([script], true, false)); + const removeNotNullConstraint = _.toPairs(collection.properties) .filter(([name, jsonSchema]) => { const oldName = jsonSchema.compMod.oldField.name; @@ -25,11 +30,12 @@ const getModifyNonNullColumnsScripts = (_, ddlProvider) => (collection) => { const shouldAddForNewName = columnNamesToAddNotNullConstraint.includes(name); return shouldRemoveForOldName && !shouldAddForNewName; }) - .map(([name]) => ddlProvider.dropNotNullConstraint(fullTableName, wrapInQuotes(name))); + .map(([name]) => ddlProvider.dropNotNullConstraint(fullTableName, wrapInQuotes(name))) + .map(script => AlterScriptDto.getInstance([script], true, true)); return [...addNotNullConstraintsScript, ...removeNotNullConstraint]; } module.exports = { - getModifyNonNullColumnsScripts + getModifyNonNullColumnsScriptDtos } diff --git a/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/renameColumnHelper.js b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/renameColumnHelper.js new file mode 100644 index 0000000..9d423e0 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/columnHelpers/renameColumnHelper.js @@ -0,0 +1,24 @@ +const {AlterScriptDto} = require("../../types/AlterScriptDto"); + +/** + * @return {(collection: Object) => AlterScriptDto[]} + * */ +const getRenameColumnScriptDtos = (_, ddlProvider) => (collection) => { + const {checkFieldPropertiesChanged, getFullTableName, wrapInQuotes} = require('../../../utils/general')(_); + const fullTableName = getFullTableName(collection); + + return _.values(collection.properties) + .filter(jsonSchema => checkFieldPropertiesChanged(jsonSchema.compMod, ['name'])) + .map( + jsonSchema => { + const oldColumnName = wrapInQuotes(jsonSchema.compMod.oldField.name); + const newColumnName = wrapInQuotes(jsonSchema.compMod.newField.name); + return ddlProvider.renameColumn(fullTableName, oldColumnName, newColumnName); + } + ) + .map(script => AlterScriptDto.getInstance([script], true, false)); +} + +module.exports = { + getRenameColumnScriptDtos +} diff --git a/forward_engineering/alterScript/alterScriptHelpers/containerHelpers/commentsHelper.js b/forward_engineering/alterScript/alterScriptHelpers/containerHelpers/commentsHelper.js new file mode 100644 index 0000000..f6e75c3 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/containerHelpers/commentsHelper.js @@ -0,0 +1,52 @@ +const {AlterScriptDto} = require("../../types/AlterScriptDto"); + +const extractDescription = (container) => { + return container?.role?.compMod?.description || {}; +} + +/** + * @return {(collection: Object) => AlterScriptDto | undefined} + * */ +const getUpsertCommentsScriptDto = (_, ddlProvider) => (container) => { + const {wrapComment, wrapInQuotes} = require('../../../utils/general')(_); + + const description = extractDescription(container); + if (description.new && description.new !== description.old) { + const wrappedComment = wrapComment(description.new); + const wrappedSchemaName = wrapInQuotes(container.role.name); + const script = ddlProvider.updateSchemaComment(wrappedSchemaName, wrappedComment); + return AlterScriptDto.getInstance([script], true, false); + } + return undefined; +} + +/** + * @return {(collection: Object) => AlterScriptDto | undefined} + * */ +const getDropCommentsScriptDto = (_, ddlProvider) => (container) => { + const {wrapInQuotes} = require('../../../utils/general')(_); + + const description = extractDescription(container); + if (description.old && !description.new) { + const wrappedSchemaName = wrapInQuotes(container.role.name); + const script = ddlProvider.dropSchemaComment(wrappedSchemaName); + return AlterScriptDto.getInstance([script], true, true); + } + return undefined; +} + +/** + * @return {(collection: Object) => AlterScriptDto[]} + * */ +const getModifySchemaCommentsScriptDtos = (_, ddlProvider) => (container) => { + const upsertCommentScript = getUpsertCommentsScriptDto(_, ddlProvider)(container); + const dropCommentScript = getDropCommentsScriptDto(_, ddlProvider)(container); + return [ + upsertCommentScript, + dropCommentScript + ].filter(Boolean); +} + +module.exports = { + getModifySchemaCommentsScriptDtos +} diff --git a/forward_engineering/helpers/alterScriptHelpers/createColumnDefinition.js b/forward_engineering/alterScript/alterScriptHelpers/createColumnDefinition.js similarity index 100% rename from forward_engineering/helpers/alterScriptHelpers/createColumnDefinition.js rename to forward_engineering/alterScript/alterScriptHelpers/createColumnDefinition.js diff --git a/forward_engineering/helpers/alterScriptHelpers/entityHelpers/checkConstraintHelper.js b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/checkConstraintHelper.js similarity index 64% rename from forward_engineering/helpers/alterScriptHelpers/entityHelpers/checkConstraintHelper.js rename to forward_engineering/alterScript/alterScriptHelpers/entityHelpers/checkConstraintHelper.js index 9730c3e..cdc0601 100644 --- a/forward_engineering/helpers/alterScriptHelpers/entityHelpers/checkConstraintHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/checkConstraintHelper.js @@ -1,3 +1,6 @@ +const {AlterCollectionDto} = require('../../types/AlterCollectionDto'); +const {AlterScriptDto} = require("../../types/AlterScriptDto"); + /** * @typedef {{ * id: string, @@ -11,11 +14,8 @@ * }} CheckConstraintHistoryEntry * */ - -const {getFullTableName} = require("../ddlHelper"); - /** - * @return {(collection: Object) => Array} + * @return {(collection: AlterCollectionDto) => Array} * */ const mapCheckConstraintNamesToChangeHistory = (_) => (collection) => { const checkConstraintHistory = collection?.compMod?.chkConstr; @@ -38,38 +38,40 @@ const mapCheckConstraintNamesToChangeHistory = (_) => (collection) => { } /** - * @return {(constraintHistory: Array, fullTableName: string) => Array} + * @return {(constraintHistory: Array, fullTableName: string) => Array} * */ -const getDropCheckConstraintScripts = (_, ddlProvider) => (constraintHistory, fullTableName) => { - const {wrapInQuotes} = require('../../general')({_}); +const getDropCheckConstraintScriptDtos = (_, ddlProvider) => (constraintHistory, fullTableName) => { + const {wrapInQuotes} = require('../../../utils/general')(_); return constraintHistory .filter(historyEntry => historyEntry.old && !historyEntry.new) .map(historyEntry => { const wrappedConstraintName = wrapInQuotes(historyEntry.old.chkConstrName); return ddlProvider.dropConstraint(fullTableName, wrappedConstraintName); - }); + }) + .map(script => AlterScriptDto.getInstance([script], true, true)); } /** - * @return {(constraintHistory: Array, fullTableName: string) => Array} + * @return {(constraintHistory: Array, fullTableName: string) => Array} * */ -const getAddCheckConstraintScripts = (_, ddlProvider) => (constraintHistory, fullTableName) => { - const {wrapInQuotes} = require('../../general')({_}); +const getAddCheckConstraintScriptDtos = (_, ddlProvider) => (constraintHistory, fullTableName) => { + const {wrapInQuotes} = require('../../../utils/general')(_); return constraintHistory .filter(historyEntry => historyEntry.new && !historyEntry.old) .map(historyEntry => { const { chkConstrName, constrExpression } = historyEntry.new; return ddlProvider.addCheckConstraint(fullTableName, wrapInQuotes(chkConstrName), constrExpression); - }); + }) + .map(script => AlterScriptDto.getInstance([script], true, false)); } /** - * @return {(constraintHistory: Array, fullTableName: string) => Array} + * @return {(constraintHistory: Array, fullTableName: string) => Array} * */ -const getUpdateCheckConstraintScripts = (_, ddlProvider) => (constraintHistory, fullTableName) => { - const {wrapInQuotes} = require('../../general')({_}); +const getUpdateCheckConstraintScriptDtos = (_, ddlProvider) => (constraintHistory, fullTableName) => { + const {wrapInQuotes} = require('../../../utils/general')(_); return constraintHistory .filter(historyEntry => { @@ -87,21 +89,25 @@ const getUpdateCheckConstraintScripts = (_, ddlProvider) => (constraintHistory, const { chkConstrName: newConstrainName, constrExpression: newConstraintExpression } = historyEntry.new; const addConstraintScript = ddlProvider.addCheckConstraint(fullTableName, wrapInQuotes(newConstrainName), newConstraintExpression); - return [dropConstraintScript, addConstraintScript]; + return [ + AlterScriptDto.getInstance([dropConstraintScript], true, true), + AlterScriptDto.getInstance([addConstraintScript], true, false), + ]; }) .flat(); } /** - * @return (collection: Object) => Array + * @return {(collection: AlterCollectionDto) => Array} * */ -const getModifyCheckConstraintScripts = (_, ddlProvider) => (collection) => { - const fullTableName = getFullTableName(_)(collection); +const getModifyCheckConstraintScriptDtos = (_, ddlProvider) => (collection) => { + const {getFullTableName} = require('../../../utils/general')(_); + const fullTableName = getFullTableName(collection); const constraintHistory = mapCheckConstraintNamesToChangeHistory(_)(collection); - const addCheckConstraintScripts = getAddCheckConstraintScripts(_, ddlProvider)(constraintHistory, fullTableName); - const dropCheckConstraintScripts = getDropCheckConstraintScripts(_, ddlProvider)(constraintHistory, fullTableName); - const updateCheckConstraintScripts = getUpdateCheckConstraintScripts(_, ddlProvider)(constraintHistory, fullTableName); + const addCheckConstraintScripts = getAddCheckConstraintScriptDtos(_, ddlProvider)(constraintHistory, fullTableName); + const dropCheckConstraintScripts = getDropCheckConstraintScriptDtos(_, ddlProvider)(constraintHistory, fullTableName); + const updateCheckConstraintScripts = getUpdateCheckConstraintScriptDtos(_, ddlProvider)(constraintHistory, fullTableName); return [ ...addCheckConstraintScripts, @@ -111,5 +117,5 @@ const getModifyCheckConstraintScripts = (_, ddlProvider) => (collection) => { } module.exports = { - getModifyCheckConstraintScripts + getModifyCheckConstraintScriptDtos } diff --git a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/commentsHelper.js b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/commentsHelper.js new file mode 100644 index 0000000..7b9fbd6 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/commentsHelper.js @@ -0,0 +1,64 @@ +const {AlterScriptDto} = require("../../types/AlterScriptDto"); +const {AlterCollectionDto} = require('../../types/AlterCollectionDto'); + +/** + * @return {(collection: AlterCollectionDto) => AlterScriptDto} + */ +const getUpdatedCommentOnCollectionScriptDto = (_, ddlProvider) => (collection) => { + const {getFullTableName, wrapComment} = require('../../../utils/general')(_); + + const descriptionInfo = collection?.role.compMod?.description; + if (!descriptionInfo) { + return undefined; + } + + const {old: oldComment, new: newComment} = descriptionInfo; + if (!newComment || newComment === oldComment) { + return undefined; + } + + const tableName = getFullTableName(collection); + const comment = wrapComment(newComment); + + const script = ddlProvider.updateTableComment(tableName, comment); + return AlterScriptDto.getInstance([script], true, false); +} + +/** + * @return {(collection: AlterCollectionDto) => AlterScriptDto} + */ +const getDeletedCommentOnCollectionScriptDto = (_, ddlProvider) => (collection) => { + const {getFullTableName} = require('../../../utils/general')(_); + + const descriptionInfo = collection?.role.compMod?.description; + if (!descriptionInfo) { + return undefined; + } + + const {old: oldComment, new: newComment} = descriptionInfo; + if (!oldComment || newComment) { + return undefined; + } + + const tableName = getFullTableName(collection); + + const script = ddlProvider.dropTableComment(tableName); + return AlterScriptDto.getInstance([script], true, true); +} + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getModifyEntityCommentsScriptDtos = (_, ddlProvider) => collection => { + const updatedCommentScript = getUpdatedCommentOnCollectionScriptDto(_, ddlProvider)(collection); + const deletedCommentScript = getDeletedCommentOnCollectionScriptDto(_, ddlProvider)(collection); + + return [ + updatedCommentScript, + deletedCommentScript + ].filter(Boolean); +}; + +module.exports = { + getModifyEntityCommentsScriptDtos +} diff --git a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/primaryKeyHelper.js b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/primaryKeyHelper.js new file mode 100644 index 0000000..bc910b4 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/primaryKeyHelper.js @@ -0,0 +1,419 @@ +const {AlterScriptDto} = require('../../types/AlterScriptDto'); +const { + AlterCollectionDto, + AlterCollectionColumnDto, + AlterCollectionRoleCompModPKDto, + AlterCollectionColumnPrimaryKeyOptionDto +} = require('../../types/AlterCollectionDto'); + +/** + * @return {(collection: AlterCollectionDto) => boolean} + * */ +const didCompositePkChange = (_) => (collection) => { + const pkDto = collection?.role?.compMod?.primaryKey || {}; + const newPrimaryKeys = pkDto.new || []; + const oldPrimaryKeys = pkDto.old || []; + if (newPrimaryKeys.length !== oldPrimaryKeys.length) { + return true; + } + if (newPrimaryKeys.length === 0 && oldPrimaryKeys.length === 0) { + return false; + } + const areKeyArraysEqual = _(oldPrimaryKeys).differenceWith(newPrimaryKeys, _.isEqual).isEmpty(); + return !areKeyArraysEqual; +} + +/** + * @param entityName {string} + * @return {string} + * */ +const getDefaultConstraintName = (entityName) => { + return `${entityName}_pk`; +} + +/** + * @param primaryKey {AlterCollectionRoleCompModPKDto} + * @param entityName {string} + * @return {string} + * */ +const getConstraintNameForCompositePk = (primaryKey, entityName) => { + if (primaryKey.constraintName) { + return primaryKey.constraintName; + } + return getDefaultConstraintName(entityName); +} + +/** + * @param _ + * @return {( + * primaryKey: AlterCollectionRoleCompModPKDto, + * entityName: string, + * entityJsonSchema: AlterCollectionDto, + * ) => { + * name: string, + * keyType: string, + * columns: Array<{ + * isActivated: boolean, + * name: string, + * }>, + * include: Array<{ + * isActivated: boolean, + * name: string, + * }>, + * storageParameters: string, + * tablespace: string, + * } + * } + * */ +const getCreateCompositePKDDLProviderConfig = (_) => ( + primaryKey, + entityName, + entity +) => { + const constraintName = getConstraintNameForCompositePk(primaryKey, entityName); + const pkColumns = _.toPairs(entity.role.properties) + .filter(([name, jsonSchema]) => Boolean(primaryKey.compositePrimaryKey.find(keyDto => keyDto.keyId === jsonSchema.GUID))) + .map(([name, jsonSchema]) => ({ + name, + isActivated: jsonSchema.isActivated, + })); + + let storageParameters = ''; + let indexTablespace = ''; + let includeColumns = []; + if (primaryKey.indexStorageParameters) { + storageParameters = primaryKey.indexStorageParameters; + } + if (primaryKey.indexTablespace) { + indexTablespace = primaryKey.indexTablespace; + } + if (primaryKey.indexInclude) { + includeColumns = _.toPairs(entity.role.properties) + .filter(([name, jsonSchema]) => Boolean(primaryKey.indexInclude.find(keyDto => keyDto.keyId === jsonSchema.GUID))) + .map(([name, jsonSchema]) => ({ + name, + isActivated: jsonSchema.isActivated, + })); + } + + return { + name: constraintName, + keyType: 'PRIMARY KEY', + columns: pkColumns, + include: includeColumns, + storageParameters, + tablespace: indexTablespace, + } +} + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getAddCompositePkScripts = (_, ddlProvider) => (collection) => { + const { + getFullCollectionName, + getSchemaOfAlterCollection, + getEntityName, + } = require('../../../utils/general')(_); + + const didPkChange = didCompositePkChange(_)(collection); + if (!didPkChange) { + return [] + } + + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(collectionSchema); + const entityName = getEntityName(collectionSchema); + + const pkDto = collection?.role?.compMod?.primaryKey || {}; + /** + * @type {Array} + * */ + const newPrimaryKeys = pkDto.new || []; + + return newPrimaryKeys + .map((newPk) => { + const ddlConfig = getCreateCompositePKDDLProviderConfig(_)(newPk, entityName, collection); + return ddlProvider.createKeyConstraint( + fullTableName, + collection.isActivated, + ddlConfig + ); + }) + .filter(Boolean) + .map(scriptDto => AlterScriptDto.getInstance([scriptDto.statement], scriptDto.isActivated, false)) + .filter(Boolean); +} + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getDropCompositePkScripts = (_, ddlProvider) => (collection) => { + const { + getFullCollectionName, + getSchemaOfAlterCollection, + getEntityName, + wrapInQuotes + } = require('../../../utils/general')(_); + + const didPkChange = didCompositePkChange(_)(collection); + if (!didPkChange) { + return []; + } + + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(collectionSchema); + const entityName = getEntityName(collectionSchema); + + const pkDto = collection?.role?.compMod?.primaryKey || {}; + /** + * @type {AlterCollectionRoleCompModPKDto[]} + * */ + const oldPrimaryKeys = pkDto.old || []; + + return oldPrimaryKeys + .map((oldPk) => { + let constraintName = wrapInQuotes(getDefaultConstraintName(entityName)); + if (oldPk.constraintName) { + constraintName = wrapInQuotes(oldPk.constraintName); + } + return ddlProvider.dropPkConstraint(fullTableName, constraintName); + }) + .map(scriptLine => AlterScriptDto.getInstance([scriptLine], collection.isActivated, true)) + .filter(Boolean); +} + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getModifyCompositePkScripts = (_, ddlProvider) => (collection) => { + const dropCompositePkScripts = getDropCompositePkScripts(_, ddlProvider)(collection); + const addCompositePkScripts = getAddCompositePkScripts(_, ddlProvider)(collection); + + return [ + ...dropCompositePkScripts, + ...addCompositePkScripts, + ].filter(Boolean); +} + +/** + * @param columnJsonSchema {AlterCollectionColumnDto} + * @param entityName {string} + * @return {string} + * */ +const getConstraintNameForRegularPk = (columnJsonSchema, entityName) => { + const constraintOptions = columnJsonSchema.primaryKeyOptions; + if (constraintOptions?.length && constraintOptions?.length > 0) { + /** + * @type {AlterCollectionColumnPrimaryKeyOptionDto} + * */ + const constraintOption = constraintOptions[0]; + if (constraintOption.constraintName) { + return constraintOption.constraintName; + } + } + return getDefaultConstraintName(entityName); +} + +/** + * @param _ + * @return {( + * name: string, + * columnJsonSchema: AlterCollectionColumnDto, + * entityName: string, + * entityJsonSchema: AlterCollectionDto, + * ) => { + * name: string, + * keyType: string, + * columns: Array<{ + * isActivated: boolean, + * name: string, + * }>, + * include: Array<{ + * isActivated: boolean, + * name: string, + * }>, + * storageParameters: string, + * tablespace: string, + * } + * } + * */ +const getCreateRegularPKDDLProviderConfig = (_) => ( + columnName, + columnJsonSchema, + entityName, + entity +) => { + const constraintName = getConstraintNameForRegularPk(columnJsonSchema, entityName); + const pkColumns = [{ + name: columnName, + isActivated: columnJsonSchema.isActivated, + }]; + + let storageParameters = ''; + let indexTablespace = ''; + let includeColumns = []; + const constraintOptions = columnJsonSchema.primaryKeyOptions; + if (constraintOptions?.length && constraintOptions?.length > 0) { + /** + * @type {AlterCollectionColumnPrimaryKeyOptionDto} + * */ + const constraintOption = constraintOptions[0]; + if (constraintOption.indexStorageParameters) { + storageParameters = constraintOption.indexStorageParameters; + } + if (constraintOption.indexTablespace) { + indexTablespace = constraintOption.indexTablespace; + } + if (constraintOption.indexInclude) { + includeColumns = _.toPairs(entity.role.properties) + .filter(([name, jsonSchema]) => Boolean(constraintOption.indexInclude.find(keyDto => keyDto.keyId === jsonSchema.GUID))) + .map(([name, jsonSchema]) => ({ + name, + isActivated: jsonSchema.isActivated, + })); + } + } + + return { + name: constraintName, + keyType: 'PRIMARY KEY', + columns: pkColumns, + include: includeColumns, + storageParameters, + tablespace: indexTablespace, + } +} + + +/** + * @return {(columnJsonSchema: AlterCollectionColumnDto, collection: AlterCollectionDto) => boolean} + * */ +const wasFieldChangedToBeARegularPk = (_) => (columnJsonSchema, collection) => { + const oldName = columnJsonSchema.compMod.oldField.name; + + const isRegularPrimaryKey = columnJsonSchema.primaryKey && !columnJsonSchema.compositePrimaryKey; + const wasTheFieldAPrimaryKey = Boolean(collection.role.properties[oldName]?.primaryKey); + return isRegularPrimaryKey && !wasTheFieldAPrimaryKey; +} + +/** + * @return {(columnJsonSchema: AlterCollectionColumnDto, collection: AlterCollectionDto) => boolean} + * */ +const isFieldNoLongerARegularPk = (_) => (columnJsonSchema, collection) => { + const oldName = columnJsonSchema.compMod.oldField.name; + + const oldJsonSchema = collection.role.properties[oldName]; + const wasTheFieldARegularPrimaryKey = oldJsonSchema?.primaryKey && !oldJsonSchema?.compositePrimaryKey; + + const isNotAPrimaryKey = !columnJsonSchema.primaryKey && !columnJsonSchema.compositePrimaryKey; + return wasTheFieldARegularPrimaryKey && isNotAPrimaryKey; +} + +/** + * @return {(columnJsonSchema: AlterCollectionColumnDto, collection: AlterCollectionDto) => boolean} + * */ +const wasRegularPkModified = (_) => (columnJsonSchema, collection) => { + const oldName = columnJsonSchema.compMod.oldField.name; + const oldJsonSchema = collection.role.properties[oldName]; + + const isRegularPrimaryKey = columnJsonSchema.primaryKey && !columnJsonSchema.compositePrimaryKey; + const wasTheFieldARegularPrimaryKey = oldJsonSchema?.primaryKey && !oldJsonSchema?.compositePrimaryKey; + + if (!(isRegularPrimaryKey && wasTheFieldARegularPrimaryKey)) { + return false; + } + const constraintOptions = columnJsonSchema.primaryKeyOptions; + const oldConstraintOptions = oldJsonSchema?.primaryKeyOptions; + const areOptionsEqual = _(oldConstraintOptions).differenceWith(constraintOptions, _.isEqual).isEmpty(); + return !areOptionsEqual; +} + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getAddPkScripts = (_, ddlProvider) => (collection) => { + const { + getFullCollectionName, + getSchemaOfAlterCollection, + getEntityName, + } = require('../../../utils/general')(_); + + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(collectionSchema); + const entityName = getEntityName(collectionSchema); + + return _.toPairs(collection.properties) + .filter(([name, jsonSchema]) => { + return wasFieldChangedToBeARegularPk(_)(jsonSchema, collection) || wasRegularPkModified(_)(jsonSchema, collection); + }) + .map(([name, jsonSchema]) => { + const ddlConfig = getCreateRegularPKDDLProviderConfig(_)(name, jsonSchema, entityName, collection); + return ddlProvider.createKeyConstraint( + fullTableName, + collection.isActivated, + ddlConfig + ); + }) + .map(scriptDto => AlterScriptDto.getInstance([scriptDto.statement], scriptDto.isActivated, false)) + .filter(Boolean); +} + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getDropPkScript = (_, ddlProvider) => (collection) => { + const { + getFullCollectionName, + getSchemaOfAlterCollection, + getEntityName, + wrapInQuotes + } = require('../../../utils/general')(_); + + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(collectionSchema); + const entityName = getEntityName(collectionSchema); + + return _.toPairs(collection.properties) + .filter(([name, jsonSchema]) => { + return isFieldNoLongerARegularPk(_)(jsonSchema, collection) || wasRegularPkModified(_)(jsonSchema, collection); + }) + .map(([name, jsonSchema]) => { + const oldName = jsonSchema.compMod.oldField.name; + const oldJsonSchema = collection.role.properties[oldName]; + const constraintName = wrapInQuotes(getConstraintNameForRegularPk(oldJsonSchema, entityName)); + return ddlProvider.dropPkConstraint(fullTableName, constraintName); + }) + .map(scriptLine => AlterScriptDto.getInstance([scriptLine], collection.isActivated, true)) + .filter(Boolean); +} + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getModifyPkScripts = (_, ddlProvider) => (collection) => { + const dropPkScripts = getDropPkScript(_, ddlProvider)(collection); + const addPkScripts = getAddPkScripts(_, ddlProvider)(collection); + + return [ + ...dropPkScripts, + ...addPkScripts, + ].filter(Boolean); +} + +/** + * @return {(collection: AlterCollectionDto) => Array} + * */ +const getModifyPkConstraintsScriptDtos = (_, ddlProvider) => (collection) => { + const modifyCompositePkScripts = getModifyCompositePkScripts(_, ddlProvider)(collection); + const modifyPkScripts = getModifyPkScripts(_, ddlProvider)(collection); + + return [ + ...modifyCompositePkScripts, + ...modifyPkScripts, + ].filter(Boolean); +} + +module.exports = { + getModifyPkConstraintsScriptDtos, +} diff --git a/forward_engineering/alterScript/alterScriptHelpers/viewHelpers/commentsHelper.js b/forward_engineering/alterScript/alterScriptHelpers/viewHelpers/commentsHelper.js new file mode 100644 index 0000000..a96f0c1 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/viewHelpers/commentsHelper.js @@ -0,0 +1,52 @@ +const {AlterScriptDto} = require("../../types/AlterScriptDto"); + +const extractDescription = (view) => { + return view?.role?.compMod?.description || {}; +} + +/** + * @return {(view: Object) => AlterScriptDto | undefined} + * */ +const getUpsertCommentsScriptDto = (_, ddlProvider) => (view) => { + const {getFullViewName, wrapComment} = require('../../../utils/general')(_); + + const description = extractDescription(view); + if (description.new && description.new !== description.old) { + const wrappedComment = wrapComment(description.new); + const viewName = getFullViewName(view); + const script = ddlProvider.updateViewComment(viewName, wrappedComment); + return AlterScriptDto.getInstance([script], true, false); + } + return undefined; +} + +/** + * @return {(view: Object) => AlterScriptDto | undefined} + * */ +const getDropCommentsScriptDto = (_, ddlProvider) => (view) => { + const description = extractDescription(view); + const {getFullViewName} = require('../../../utils/general')(_); + + if (description.old && !description.new) { + const viewName = getFullViewName(view); + const script = ddlProvider.dropViewComment(viewName); + return AlterScriptDto.getInstance([script], true, true); + } + return undefined; +} + +/** + * @return {(view: Object) => AlterScriptDto[]} + * */ +const getModifyViewCommentsScriptDtos = (_, ddlProvider) => (view) => { + const upsertCommentScript = getUpsertCommentsScriptDto(_, ddlProvider)(view); + const dropCommentScript = getDropCommentsScriptDto(_, ddlProvider)(view); + return [ + upsertCommentScript, + dropCommentScript + ].filter(Boolean); +} + +module.exports = { + getModifyViewCommentsScriptDtos +} diff --git a/forward_engineering/alterScript/types/AlterCollectionDto.js b/forward_engineering/alterScript/types/AlterCollectionDto.js new file mode 100644 index 0000000..095bff4 --- /dev/null +++ b/forward_engineering/alterScript/types/AlterCollectionDto.js @@ -0,0 +1,413 @@ +class ColumnCompModField { + + /** + * @type {string} + */ + type + + /** + * @type {string} + */ + name + + /** + * @type {string} + */ + mode +} + +class AlterCollectionColumnCompModDto { + + /** + * @type {ColumnCompModField} + * */ + oldField + + /** + * @type {ColumnCompModField} + * */ + newField + +} + +class AlterCollectionColumnPrimaryKeyOptionDto { + /** + * @type {string} + * */ + id + + /** + * @type {string} + * */ + constraintName + + /** + * @type {string} + * */ + indexStorageParameters + + /** + * @type {string} + * */ + indexTablespace + + /** + * @type {Array<{ + * keyId: string + * }>} + * */ + indexInclude +} + +class AlterCollectionColumnDto { + /** + * @type {string} + */ + type + + /** + * @type {boolean} + */ + isActivated + + /** + * @type {boolean} + */ + primaryKey + + /** + * @type {boolean} + */ + unique + + /** + * @type {string} + */ + mode + + /** + * @type {number} + */ + length + + /** + * @type {[ + * "compositePartitionKey", + * "compositePrimaryKey", + * "compositeUniqueKey", + * "triggerUpdateColumns", + * ]} + */ + compositeKey + + /** + * @type {boolean} + */ + compositePartitionKey + + /** + * @type {boolean} + */ + compositePrimaryKey + + /** + * @type {boolean} + */ + compositeUniqueKey + + /** + * @type {Array | undefined} + * */ + primaryKeyOptions + + /** + * @type {boolean} + */ + triggerUpdateColumns + + /** + * @type {AlterCollectionColumnCompModDto} + * */ + compMod + + /** + * @type {string} + */ + GUID +} + +class AlterCollectionRoleDefinitionDto { + + /** + * @type {string} + */ + id + + /** + * @type {string} + */ + type + + /** + * @type {Array} + */ + properties +} + +class AlterCollectionRoleCompModPKDto extends AlterCollectionColumnPrimaryKeyOptionDto{ + + /** + * @type {Array<{ + * type: string, + * keyId: string, + * }>} + * */ + compositePrimaryKey + +} + +class AlterCollectionRoleCompModDto { + /** + * @type {string} + */ + keyspaceName + + /** + * @type {{ + * name: string, + * isActivated: boolean, + * ifNotExist: boolean, + * }} + */ + bucketProperties + + /** + * @type {{ + * new: string, + * old: string, + * }} + */ + collectionName + + /** + * @type {{ + * new: boolean, + * old: boolean, + * }} + */ + isActivated + + /** + * @type {{ + * new: string, + * old: string, + * }} + */ + bucketId + + /** + * @type {{ + * new: boolean, + * old: boolean, + * }} + */ + ifNotExist + + /** + * @type {{ + * new: string, + * old: string, + * }} + */ + on_commit + + /** + * @type {{ + * new: Array, + * old: Array, + * }} + */ + primaryKey + + /** + * @type {{ + * new: string, + * old: string, + * }} + */ + table_tablespace_name + + /** + * @type {Array<{ + * [propertyName: string]: AlterCollectionColumnDto + * }>} + */ + newProperties +} + +class AlterCollectionRoleDto { + + /** + * @type {string} + */ + id + + /** + * @type {"object"} + */ + type + + /** + * @type {string} + */ + collectionName + + /** + * @type {{ + * [propertyName: string]: AlterCollectionColumnDto + * }} + */ + properties + + /** + * @type {AlterCollectionRoleDefinitionDto} + * */ + definitions + + /** + * @type {boolean} + */ + isActivated + + /** + * @type {boolean} + */ + additionalProperties + + /** + * @type {boolean} + */ + memory_optimized + + /** + * @type {Array} + */ + collectionUsers + + /** + * @type {boolean} + */ + ifNotExist + + /** + * @type {string} + */ + on_commit + + /** + * @type {string} + */ + table_tablespace_name + + /** + * @type {string} + */ + bucketId + + /** + * @type {AlterCollectionRoleCompModDto} + * */ + compMod + + /** + * @type {string} + */ + name + + /** + * @type {"entity"} + */ + roleType + + /** + * @type {Array} + */ + patternProperties +} + +class AlterCollectionDto { + + /** + * @type {"object"} + */ + type + + /** + * @type {boolean} + */ + isActivated + + /** + * @type {boolean} + */ + unique + + /** + * @type {"object"} + */ + subtype + + /** + * @type {{ + * [preopertyName: string]: AlterCollectionColumnDto + * }} + * */ + properties + + /** + * @type {[ + * "compositePartitionKey", + * "compositePrimaryKey", + * "compositeUniqueKey", + * "triggerUpdateColumns", + * ]} + */ + compositeKey + + /** + * @type {boolean} + */ + compositePartitionKey + + /** + * @type {boolean} + */ + compositePrimaryKey + + /** + * @type {boolean} + */ + compositeUniqueKey + + /** + * @type {boolean} + */ + triggerUpdateColumns + + /** + * @type {AlterCollectionRoleDto} + * */ + role + + /** + * @type {string} + */ + GUID +} + +module.exports = { + AlterCollectionDto, + AlterCollectionRoleDto, + AlterCollectionColumnDto, + AlterCollectionRoleCompModPKDto, +} diff --git a/forward_engineering/alterScript/types/AlterRelationshipDto.js b/forward_engineering/alterScript/types/AlterRelationshipDto.js new file mode 100644 index 0000000..eee563e --- /dev/null +++ b/forward_engineering/alterScript/types/AlterRelationshipDto.js @@ -0,0 +1,274 @@ +class AlterRelationshipFKField { + + /** + * @type {boolean} + */ + isActivated + + /** + * @type {string} + */ + name +} + +class AlterRelationshipParentDto { + + /** + * @type {{ + * name: string, + * isActivated: boolean + * }} + */ + bucket + + /** + * @type {{ + * name: string, + * isActivated: boolean, + * fkFields: Array + * }} + */ + collection +} + +class AlterRelationshipChildDto { + + /** + * @type {{ + * name: string, + * isActivated: boolean + * }} + */ + bucket + + /** + * @type {{ + * name: string, + * isActivated: boolean, + * fkFields: Array + * }} + */ + collection +} + +class AlterRelationshipCustomProperties { + + /** + * @type {string} + */ + relationshipOnDelete + + /** + * @type {string} + */ + relationshipOnUpdate + + /** + * @type {string} + */ + relationshipMatch + +} + +class AlterRelationshipRoleCompModDto { + + /** + * @type {boolean} + */ + created + + /** + * @type {boolean} + */ + deleted + + /** + * @type {boolean | undefined} + */ + modified + + /** + * @type {AlterRelationshipParentDto} + * */ + parent + + /** + * @type {AlterRelationshipChildDto} + * */ + child + + /** + * @type {{ + * new: string, + * old: string, + * } | undefined} + */ + name + + /** + * @type {{ + * new: string, + * old: string, + * } | undefined} + */ + description + + /** + * @type {{ + * old?: AlterRelationshipCustomProperties, + * new?: AlterRelationshipCustomProperties + * } | undefined} + * */ + customProperties + + /** + * @type {{ + * new?: boolean, + * old?: boolean, + * }} + */ + isActivated +} + +class AlterRelationshipRoleDto { + + /** + * @type {string} + */ + id + + /** + * @type {string} + */ + name + + /** + * @type {"Foreign Key"} + */ + relationshipType + + /** + * @type {Array>} + */ + parentField + + /** + * @type {string} + */ + parentCardinality + + /** + * @type {Array>} + */ + childField + + /** + * @type {boolean} + */ + isActivated + + /** + * @type {string} + */ + childCardinality + + /** + * @type {string} + */ + parentCollection + + /** + * @type {string} + */ + childCollection + + /** + * @type {Object} + */ + hackoladeStyles + + /** + * @type {AlterRelationshipRoleCompModDto} + * */ + compMod + + /** + * @type {"relationship"} + */ + roleType +} + +class AlterRelationshipDto { + + /** + * @type {"object"} + */ + type + + /** + * @type {boolean} + */ + isActivated + + /** + * @type {boolean} + */ + unique + + /** + * @type {"object"} + */ + subtype + + /** + * @type {[ + * "compositePartitionKey", + * "compositePrimaryKey", + * "compositeUniqueKey", + * "triggerUpdateColumns", + * ]} + */ + compositeKey + + /** + * @type {boolean} + */ + compositePartitionKey + + /** + * @type {boolean} + */ + compositePrimaryKey + + /** + * @type {boolean} + */ + compositeUniqueKey + + /** + * @type {boolean} + */ + triggerUpdateColumns + + /** + * @type {AlterRelationshipRoleDto} + */ + role + + /** + * @type {string} + */ + GUID + +} + + +module.exports = { + AlterRelationshipRoleCompModDto, + AlterRelationshipRoleDto, + AlterRelationshipDto, + AlterRelationshipFKField, + AlterRelationshipParentDto, + AlterRelationshipChildDto, + AlterRelationshipCustomProperties +} diff --git a/forward_engineering/alterScript/types/AlterScriptDto.js b/forward_engineering/alterScript/types/AlterScriptDto.js new file mode 100644 index 0000000..2cc8551 --- /dev/null +++ b/forward_engineering/alterScript/types/AlterScriptDto.js @@ -0,0 +1,99 @@ +class ModificationScript { + /** + * @type string + * */ + script + + /** + * @type boolean + * */ + isDropScript +} + +class AlterScriptDto { + /** + * @type {boolean | undefined} + * */ + isActivated + + /** + * @type {Array} + * */ + scripts + + /** + * @param scripts {Array} + * @param isActivated {boolean} + * @param isDropScripts {boolean} + * @return {Array} + * */ + static getInstances(scripts, isActivated, isDropScripts) { + return (scripts || []) + .filter(Boolean) + .map(script => ({ + isActivated, + scripts: [{ + isDropScript: isDropScripts, + script + }] + })); + } + + /** + * @param scripts {Array} + * @param isActivated {boolean} + * @param isDropScripts {boolean} + * @return {AlterScriptDto | undefined} + * */ + static getInstance(scripts, isActivated, isDropScripts) { + if (!scripts?.filter(Boolean)?.length) { + return undefined; + } + return { + isActivated, + scripts: scripts + .filter(Boolean) + .map(script => ({ + isDropScript: isDropScripts, + script, + })) + } + } + + /** + * @param dropScript {string | undefined} + * @param createScript {string | undefined} + * @param isActivated {boolean} + * @return {AlterScriptDto | undefined} + * */ + static getDropAndRecreateInstance(dropScript, createScript, isActivated) { + /** + * @type {ModificationScript[]} + * */ + const scriptModificationDtos = []; + if (Boolean(dropScript)) { + scriptModificationDtos.push({ + isDropScript: true, + script: dropScript, + }) + } + if (Boolean(createScript)) { + scriptModificationDtos.push({ + isDropScript: false, + script: createScript, + }); + } + if (!scriptModificationDtos?.length) { + return undefined; + } + return { + isActivated, + scripts: scriptModificationDtos, + } + } +} + +module.exports = { + ModificationScript, + AlterScriptDto, +} diff --git a/forward_engineering/api.js b/forward_engineering/api.js index 818fd12..971c9d4 100644 --- a/forward_engineering/api.js +++ b/forward_engineering/api.js @@ -1,119 +1,79 @@ const reApi = require('../reverse_engineering/api'); -const { createLogger } = require('../reverse_engineering/helpers/loggerHelper'); +const {createLogger} = require('../reverse_engineering/helpers/loggerHelper'); const applyToInstanceHelper = require('./applyToInstanceHelper'); -const { commentDropStatements, doesScriptContainDropStatements} = require('./helpers/commentDropStatements'); +const { + buildEntityLevelAlterScript, + buildContainerLevelAlterScript, + doesContainerLevelAlterScriptContainDropStatements, + doesEntityLevelAlterScriptContainDropStatements +} = require("./alterScript/alterScriptBuilder"); module.exports = { - generateScript(data, logger, callback, app) { - try { - const { - getAlterContainersScripts, - getAlterCollectionsScripts, - getAlterViewScripts, - getAlterModelDefinitionsScripts, - } = require('./helpers/alterScriptFromDeltaHelper'); + generateScript(data, logger, callback, app) { + try { + const script = buildEntityLevelAlterScript(data, app); + callback(null, script); + } catch (error) { + logger.log('error', {message: error.message, stack: error.stack}, 'PostgreSQL Forward-Engineering Error'); - const collection = JSON.parse(data.jsonSchema); - if (!collection) { - throw new Error( - '"comparisonModelCollection" is not found. Alter script can be generated only from Delta model', - ); - } + callback({message: error.message, stack: error.stack}); + } + }, - const modelDefinitions = JSON.parse(data.modelDefinitions); - const internalDefinitions = JSON.parse(data.internalDefinitions); - const externalDefinitions = JSON.parse(data.externalDefinitions); - const dbVersion = data.modelData[0]?.dbVersion; - const containersScripts = getAlterContainersScripts({collection, app}); - const collectionsScripts = getAlterCollectionsScripts({ - collection, - app, - dbVersion, - modelDefinitions, - internalDefinitions, - externalDefinitions, - }); - const viewScripts = getAlterViewScripts(collection, app); - const modelDefinitionsScripts = getAlterModelDefinitionsScripts({ - collection, - app, - dbVersion, - modelDefinitions, - internalDefinitions, - externalDefinitions, - }); - const script = [ - ...containersScripts, - ...modelDefinitionsScripts, - ...collectionsScripts, - ...viewScripts, - ].join('\n\n'); + generateViewScript(data, logger, callback, app) { + callback(new Error('Forward-Engineering of delta model on view level is not supported')); + }, - const applyDropStatements = data.options?.additionalOptions?.some( - option => option.id === 'applyDropStatements' && option.value, - ); + generateContainerScript(data, logger, callback, app) { + try { + const script = buildContainerLevelAlterScript(data, app); + callback(null, script); + } catch (error) { + logger.log('error', {message: error.message, stack: error.stack}, 'PostgreSQL Forward-Engineering Error'); - callback(null, applyDropStatements ? script : commentDropStatements(script)); - } catch (error) { - logger.log('error', { message: error.message, stack: error.stack }, 'PostgreSQL Forward-Engineering Error'); + callback({message: error.message, stack: error.stack}); + } + }, - 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]; - data.internalDefinitions = Object.values(data.internalDefinitions)[0]; - this.generateScript(data, logger, callback, app); - } catch (error) { - logger.log('error', { message: error.message, stack: error.stack }, 'PostgreSQL Forward-Engineering Error'); + getDatabases(connectionInfo, logger, callback, app) { + logger.progress({message: 'Find all databases'}); - callback({ message: error.message, stack: error.stack }); - } - }, - getDatabases(connectionInfo, logger, callback, app) { - logger.progress({ message: 'Find all databases' }); + reApi.getDatabases(connectionInfo, logger, callback, app); + }, - reApi.getDatabases(connectionInfo, logger, callback, app); - }, - applyToInstance(connectionInfo, logger, callback, app) { - logger.clear(); - logger.log( - 'info', - app.require('lodash').omit(connectionInfo, 'script', 'containerData'), - 'connectionInfo', - connectionInfo.hiddenKeys, - ); + applyToInstance(connectionInfo, logger, callback, app) { + logger.clear(); + logger.log( + 'info', + app.require('lodash').omit(connectionInfo, 'script', 'containerData'), + 'connectionInfo', + connectionInfo.hiddenKeys, + ); - const postgresLogger = createLogger({ - title: 'Apply to instance', - hiddenKeys: connectionInfo.hiddenKeys, - logger, - }); + const postgresLogger = createLogger({ + title: 'Apply to instance', + hiddenKeys: connectionInfo.hiddenKeys, + logger, + }); - applyToInstanceHelper.applyToInstance(connectionInfo, postgresLogger, app).then(callback, callback); - }, - testConnection(connectionInfo, logger, callback, app) { - reApi.testConnection(connectionInfo, logger, callback, app).then(callback, callback); - }, - isDropInStatements(data, logger, callback, app) { - try { - const cb = (error, script = '') => - callback( - error, - doesScriptContainDropStatements(script), - ); + applyToInstanceHelper.applyToInstance(connectionInfo, postgresLogger, app).then(callback, callback); + }, - 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 }); - } - }, + testConnection(connectionInfo, logger, callback, app) { + reApi.testConnection(connectionInfo, logger, callback, app).then(callback, callback); + }, + + isDropInStatements(data, logger, callback, app) { + try { + if (data.level === 'container') { + const containsDropStatements = doesContainerLevelAlterScriptContainDropStatements(data, app); + callback(null, containsDropStatements); + } else { + const containsDropStatements = doesEntityLevelAlterScriptContainDropStatements(data, app); + callback(null, containsDropStatements); + } + } catch (e) { + callback({message: e.message, stack: e.stack}); + } + }, }; diff --git a/forward_engineering/configs/types.js b/forward_engineering/configs/descriptors.js similarity index 100% rename from forward_engineering/configs/types.js rename to forward_engineering/configs/descriptors.js diff --git a/forward_engineering/ddlProvider.js b/forward_engineering/ddlProvider.js index cf19aef..a76ecbe 100644 --- a/forward_engineering/ddlProvider.js +++ b/forward_engineering/ddlProvider.js @@ -1,936 +1,4 @@ -const defaultTypes = require('./configs/defaultTypes'); -const types = require('./configs/types'); -const templates = require('./configs/templates'); -const assignTemplates = require("./utils/assignTemplates"); +// This file reexports actual DDL Provider. +// Core application needs this file to generate FE scripts -module.exports = (baseProvider, options, app) => { - const _ = app.require('lodash'); - const { - tab, - commentIfDeactivated, - checkAllKeysDeactivated, - divideIntoActivatedAndDeactivated, - hasType, - wrap, - clean, - } = require('./utils/general')(_); - const assignTemplates = require('./utils/assignTemplates'); - const { - getFunctionArguments, - wrapInQuotes, - getNamePrefixedWithSchemaName, - getColumnsList, - getViewData, - wrapComment, - getDbVersion, - } = require('./helpers/general')({ - _, - divideIntoActivatedAndDeactivated, - commentIfDeactivated, - }); - const { - generateConstraintsString, - foreignKeysToString, - foreignActiveKeysToString, - createKeyConstraint, - getConstraintsWarnings, - additionalPropertiesForForeignKey, - } = require('./helpers/constraintsHelper')({ - _, - commentIfDeactivated, - checkAllKeysDeactivated, - assignTemplates, - getColumnsList, - wrapInQuotes, - }); - const keyHelper = require('./helpers/keyHelper')(_, clean); - - const { getFunctionsScript } = require('./helpers/functionHelper')({ - _, - templates, - assignTemplates, - getFunctionArguments, - getNamePrefixedWithSchemaName, - }); - - const { getProceduresScript } = require('./helpers/procedureHelper')({ - _, - templates, - assignTemplates, - getFunctionArguments, - getNamePrefixedWithSchemaName, - }); - - const { getTableTemporaryValue, getTableOptions } = require('./helpers/tableHelper')({ - _, - checkAllKeysDeactivated, - getColumnsList, - }); - - const { getUserDefinedType, isNotPlainType } = require('./helpers/udtHelper')({ - _, - commentIfDeactivated, - assignTemplates, - templates, - getNamePrefixedWithSchemaName, - wrapComment, - }); - - const { getIndexKeys, getIndexOptions } = require('./helpers/indexHelper')({ - _, - wrapInQuotes, - checkAllKeysDeactivated, - getColumnsList, - }); - - const { decorateType, decorateDefault, getColumnComments, replaceTypeByVersion } = - require('./helpers/columnDefinitionHelper')({ - _, - wrap, - assignTemplates, - templates, - commentIfDeactivated, - wrapInQuotes, - wrapComment, - }); - - const { getTriggersScript, hydrateTriggers } = require('./helpers/triggerHelper')({ - _, - wrap, - assignTemplates, - templates, - getNamePrefixedWithSchemaName, - commentIfDeactivated, - }); - - const { getLocaleProperties } = require('./helpers/databaseHelper')(); - - return { - createDatabase(modelData) { - if (!modelData.databaseName) { - return ''; - } - - const { locale, collate, characterClassification } = getLocaleProperties(modelData); - - return assignTemplates(templates.createDatabase, { - name: wrapInQuotes(modelData.databaseName), - template: modelData.template ? `\n\tTEMPLATE ${modelData.template}` : '', - encoding: modelData.encoding ? `\n\tENCODING ${modelData.encoding}` : '', - locale: locale ? `\n\tLOCALE '${modelData.locale}'` : '', - collate: collate ? `\n\tLC_COLLATE '${modelData.collate}'` : '', - characterClassification: characterClassification ? `\n\tLC_CTYPE '${characterClassification}'` : '', - tablespace: modelData.tablespace ? `\n\tTABLESPACE '${modelData.tablespace}'` : '', - }); - }, - - createSchema({ schemaName, ifNotExist, comments, udfs, procedures }) { - const comment = assignTemplates(templates.comment, { - object: 'SCHEMA', - objectName: wrapInQuotes(schemaName), - comment: wrapComment(comments), - }); - - const schemaStatement = assignTemplates(templates.createSchema, { - name: wrapInQuotes(schemaName), - ifNotExist: ifNotExist ? ' IF NOT EXISTS' : '', - comment: comments ? comment : '', - }); - - const createFunctionStatement = getFunctionsScript(schemaName, udfs); - const createProceduresStatement = getProceduresScript(schemaName, procedures); - - return _.chain([schemaStatement, createFunctionStatement, createProceduresStatement]) - .compact() - .map(_.trim) - .join('\n\n') - .trim() - .value(); - }, - - createTable( - { - name, - columns, - checkConstraints, - foreignKeyConstraints, - schemaData, - columnDefinitions, - keyConstraints, - inherits, - description, - ifNotExist, - usingMethod, - on_commit, - partitioning, - storage_parameter, - table_tablespace_name, - temporary, - unlogged, - selectStatement, - triggers, - partitionOf, - partitionBounds, - }, - isActivated, - ) { - const ifNotExistStr = ifNotExist ? ' IF NOT EXISTS' : ''; - const tableName = getNamePrefixedWithSchemaName(name, schemaData.schemaName); - const comment = assignTemplates(templates.comment, { - object: 'TABLE', - objectName: tableName, - comment: wrapComment(description), - }); - - const dividedKeysConstraints = divideIntoActivatedAndDeactivated( - keyConstraints - .filter(({ errorMessage }) => !errorMessage) - .map(createKeyConstraint(templates, isActivated)), - key => key.statement, - ); - const constraintWarnings = getConstraintsWarnings( - keyConstraints.filter(({ errorMessage }) => errorMessage), - ); - const keyConstraintsString = `${generateConstraintsString( - dividedKeysConstraints, - isActivated, - )}${constraintWarnings}`; - const keyConstraintsValue = partitionOf ? keyConstraintsString?.slice(1) : keyConstraintsString; - - const dividedForeignKeys = divideIntoActivatedAndDeactivated(foreignKeyConstraints, key => key.statement); - const foreignKeyConstraintsString = generateConstraintsString(dividedForeignKeys, isActivated); - - const columnDescriptions = '\n' + getColumnComments(tableName, columnDefinitions); - const template = partitionOf ? templates.createTablePartitionOf : templates.createTable; - - const checkConstraintPrefix = partitionOf && !keyConstraintsString ? '\n\t' : ',\n\t'; - const checkConstraintsValue = !_.isEmpty(checkConstraints) - ? wrap(_.join(checkConstraints, ',\n\t'), checkConstraintPrefix, '') - : ''; - - const isEmptyPartitionBody = - partitionOf && !keyConstraintsValue && !checkConstraintsValue && !foreignKeyConstraintsString; - const openParenthesis = isEmptyPartitionBody ? '' : '('; - const closeParenthesis = isEmptyPartitionBody ? '' : ')'; - - const tableStatement = assignTemplates(template, { - temporary: getTableTemporaryValue(temporary, unlogged), - ifNotExist: ifNotExistStr, - name: tableName, - columnDefinitions: !partitionOf ? '\t' + _.join(columns, ',\n\t') : '', - keyConstraints: keyConstraintsValue, - checkConstraints: checkConstraintsValue, - foreignKeyConstraints: foreignKeyConstraintsString, - options: getTableOptions({ - inherits, - partitioning, - usingMethod, - on_commit, - storage_parameter, - table_tablespace_name, - selectStatement, - partitionBounds, - }), - comment: description ? comment : '', - partitionOf: partitionOf ? ` PARTITION OF ${partitionOf} ` : '', - columnDescriptions, - openParenthesis, - closeParenthesis, - }); - - const createTriggerStatements = getTriggersScript({ - dbVersion: schemaData.dbVersion, - tableName, - triggers, - }); - - return commentIfDeactivated( - [tableStatement, createTriggerStatements].map(_.trim).join('\n\n').trim() + '\n', - { isActivated }, - ); - }, - - convertColumnDefinition(columnDefinition) { - const type = replaceTypeByVersion(columnDefinition.type, columnDefinition.dbVersion); - const notNull = columnDefinition.nullable ? '' : ' NOT NULL'; - const primaryKey = columnDefinition.primaryKey - ? ' ' + createKeyConstraint(templates, true)(columnDefinition.primaryKeyOptions).statement - : ''; - const uniqueKey = columnDefinition.unique - ? ' ' + createKeyConstraint(templates, true)(columnDefinition.uniqueKeyOptions).statement - : ''; - const collation = columnDefinition.collationRule ? ` COLLATE "${columnDefinition.collationRule}"` : ''; - const defaultValue = !_.isUndefined(columnDefinition.default) - ? ' DEFAULT ' + decorateDefault(type, columnDefinition.default) - : ''; - - return commentIfDeactivated( - assignTemplates(templates.columnDefinition, { - name: wrapInQuotes(columnDefinition.name), - type: decorateType(type, columnDefinition), - notNull, - primaryKey, - uniqueKey, - collation, - defaultValue, - }), - { - isActivated: columnDefinition.isActivated, - }, - ); - }, - - createIndex(tableName, index, dbData, isParentActivated = true) { - const isUnique = index.unique && index.index_method === 'btree'; - const name = wrapInQuotes(index.indxName); - const unique = isUnique ? ' UNIQUE' : ''; - const concurrently = index.concurrently ? ' CONCURRENTLY' : ''; - const ifNotExist = index.ifNotExist ? ' IF NOT EXISTS' : ''; - const only = index.only ? ' ONLY' : ''; - const using = index.index_method ? ` USING ${_.toUpper(index.index_method)}` : ''; - const dbVersion = getDbVersion(_.get(dbData, 'dbVersion', '')); - const nullsDistinct = isUnique && index.nullsDistinct && dbVersion >= 15 ? `\n ${index.nullsDistinct}` : ''; - - const keys = getIndexKeys( - index.index_method === 'btree' - ? index.columns - : _.map(index.columns, column => _.omit(column, 'sortOrder', 'nullsOrder')), - isParentActivated, - ); - const options = getIndexOptions(index, isParentActivated); - - return commentIfDeactivated( - assignTemplates(templates.index, { - unique, - concurrently, - ifNotExist, - name, - only, - using, - keys, - options, - nullsDistinct, - tableName: getNamePrefixedWithSchemaName(tableName, index.schemaName), - }), - { - isActivated: index.isActivated, - }, - ); - }, - - createCheckConstraint(checkConstraint) { - return assignTemplates(templates.checkConstraint, { - name: checkConstraint.name ? `CONSTRAINT ${wrapInQuotes(checkConstraint.name)}` : '', - expression: _.trim(checkConstraint.expression).replace(/^\(([\s\S]*)\)$/, '$1'), - noInherit: checkConstraint.noInherit ? ' NO INHERIT' : '', - }); - }, - - createForeignKeyConstraint( - { - name, - foreignKey, - primaryTable, - primaryKey, - primaryTableActivated, - foreignTableActivated, - foreignSchemaName, - primarySchemaName, - customProperties, - }, - dbData, - schemaData, - ) { - const isAllPrimaryKeysDeactivated = checkAllKeysDeactivated(primaryKey); - const isAllForeignKeysDeactivated = checkAllKeysDeactivated(foreignKey); - const isActivated = - !isAllPrimaryKeysDeactivated && - !isAllForeignKeysDeactivated && - primaryTableActivated && - foreignTableActivated; - - const { foreignOnDelete, foreignOnUpdate, foreignMatch } = - additionalPropertiesForForeignKey(customProperties); - - const foreignKeyStatement = assignTemplates(templates.createForeignKeyConstraint, { - primaryTable: getNamePrefixedWithSchemaName(primaryTable, primarySchemaName || schemaData.schemaName), - name: name ? `CONSTRAINT ${wrapInQuotes(name)}` : '', - foreignKey: isActivated ? foreignKeysToString(foreignKey) : foreignActiveKeysToString(foreignKey), - primaryKey: isActivated ? foreignKeysToString(primaryKey) : foreignActiveKeysToString(primaryKey), - onDelete: foreignOnDelete ? ` ON DELETE ${foreignOnDelete}` : '', - onUpdate: foreignOnUpdate ? ` ON UPDATE ${foreignOnUpdate}` : '', - match: foreignMatch ? ` MATCH ${foreignMatch}` : '', - }); - - return { - statement: _.trim(foreignKeyStatement), - isActivated, - }; - }, - - createForeignKey( - { - name, - foreignTable, - foreignKey, - primaryTable, - primaryKey, - primaryTableActivated, - foreignTableActivated, - foreignSchemaName, - primarySchemaName, - customProperties, - }, - dbData, - schemaData, - ) { - const isAllPrimaryKeysDeactivated = checkAllKeysDeactivated(primaryKey); - const isAllForeignKeysDeactivated = checkAllKeysDeactivated(foreignKey); - const isActivated = - !isAllPrimaryKeysDeactivated && - !isAllForeignKeysDeactivated && - primaryTableActivated && - foreignTableActivated; - - const { foreignOnDelete, foreignOnUpdate, foreignMatch } = - additionalPropertiesForForeignKey(customProperties); - - const foreignKeyStatement = assignTemplates(templates.createForeignKey, { - primaryTable: getNamePrefixedWithSchemaName(primaryTable, primarySchemaName || schemaData.schemaName), - foreignTable: getNamePrefixedWithSchemaName(foreignTable, foreignSchemaName || schemaData.schemaName), - name: name ? wrapInQuotes(name) : '', - foreignKey: isActivated ? foreignKeysToString(foreignKey) : foreignActiveKeysToString(foreignKey), - primaryKey: isActivated ? foreignKeysToString(primaryKey) : foreignActiveKeysToString(primaryKey), - onDelete: foreignOnDelete ? ` ON DELETE ${foreignOnDelete}` : '', - onUpdate: foreignOnUpdate ? ` ON UPDATE ${foreignOnUpdate}` : '', - match: foreignMatch ? ` MATCH ${foreignMatch}` : '', - }); - - return { - statement: _.trim(foreignKeyStatement), - isActivated, - }; - }, - - createView(viewData, dbData, isActivated) { - const viewName = getNamePrefixedWithSchemaName(viewData.name, viewData.schemaName); - - const comment = assignTemplates(templates.comment, { - object: 'VIEW', - objectName: viewName, - comment: wrapComment(viewData.comment), - }); - - const allDeactivated = checkAllKeysDeactivated(viewData.keys || []); - const deactivatedWholeStatement = allDeactivated || !isActivated; - const { columns, tables } = getViewData(viewData.keys); - let columnsAsString = columns.map(column => column.statement).join(',\n\t\t'); - - if (!deactivatedWholeStatement) { - const dividedColumns = divideIntoActivatedAndDeactivated(columns, column => column.statement); - const deactivatedColumnsString = dividedColumns.deactivatedItems.length - ? commentIfDeactivated(dividedColumns.deactivatedItems.join(',\n\t\t'), { - isActivated: false, - isPartOfLine: true, - }) - : ''; - columnsAsString = dividedColumns.activatedItems.join(',\n\t\t') + deactivatedColumnsString; - } - - const selectStatement = _.trim(viewData.selectStatement) - ? _.trim(tab(viewData.selectStatement)) - : assignTemplates(templates.viewSelectStatement, { - tableName: tables.join(', '), - keys: columnsAsString, - }); - - const check_option = viewData.viewOptions?.check_option - ? `check_option=${viewData.viewOptions?.check_option}` - : ''; - const security_barrier = viewData.viewOptions?.security_barrier ? `security_barrier` : ''; - const dbVersionWhereSecurityInvokerAppeared = 15; - const security_invoker = - viewData.viewOptions?.security_invoker && - getDbVersion(dbData.dbVersion) >= dbVersionWhereSecurityInvokerAppeared - ? 'security_invoker' - : ''; - const withOptions = - check_option || security_barrier || security_invoker - ? `\n\tWITH (${_.compact([check_option, security_barrier, security_invoker]).join(',')})` - : ''; - - const getCheckOption = viewData => { - if (viewData.withCheckOption && viewData.checkTestingScope) { - return `\n\tWITH ${viewData.checkTestingScope} CHECK OPTION`; - } else if (viewData.withCheckOption) { - return '\n\tWITH CHECK OPTION'; - } else { - return ''; - } - }; - - const createViewScript = commentIfDeactivated( - assignTemplates(templates.createView, { - name: viewName, - orReplace: viewData.orReplace ? ' OR REPLACE' : '', - temporary: viewData.temporary ? ' TEMPORARY' : '', - checkOption: getCheckOption(viewData), - comment: viewData.comment ? comment : '', - withOptions, - selectStatement, - }), - { isActivated: !deactivatedWholeStatement }, - ); - - const createTriggersStatements = getTriggersScript({ - dbVersion: viewData.dbVersion, - tableName: viewName, - triggers: viewData.triggers, - }); - - return [createViewScript, createTriggersStatements].map(_.trim).join('\n\n').trim() + '\n'; - }, - - /** - * @param viewName {string} - * @return string - * */ - dropView(viewName) { - const templatesConfig = { - viewName, - } - return assignTemplates(templates.dropView, templatesConfig); - }, - - createViewIndex() { - return ''; - }, - - createUdt(udt) { - const columns = _.map(udt.properties, this.convertColumnDefinition); - - return getUserDefinedType(udt, columns); - }, - - getDefaultType(type) { - return defaultTypes[type]; - }, - - getTypesDescriptors() { - return types; - }, - - hasType(type) { - return hasType(types, type); - }, - - hydrateDatabase({ modelData }) { - modelData = _.get(modelData, '0', {}); - - return { - databaseName: modelData.database_name, - tablespace: modelData.tablespace_name, - encoding: modelData.encoding, - template: modelData.template, - collate: modelData.LC_COLLATE, - characterClassification: modelData.LC_CTYPE, - dbVersion: modelData.dbVersion, - locale: modelData.locale, - }; - }, - - hydrateColumn({ columnDefinition, jsonSchema, schemaData, definitionJsonSchema = {}, parentJsonSchema }) { - const collationRule = _.includes(['char', 'varchar', 'text'], columnDefinition.type) - ? jsonSchema.collationRule - : ''; - const timeTypes = ['time', 'timestamp']; - const timePrecision = _.includes(timeTypes, columnDefinition.type) ? jsonSchema.timePrecision : ''; - const timezone = _.includes(timeTypes, columnDefinition.type) ? jsonSchema.timezone : ''; - const intervalOptions = columnDefinition.type === 'interval' ? jsonSchema.intervalOptions : ''; - const dbVersion = getDbVersion(schemaData.dbVersion) - const primaryKeyOptions = _.omit( - keyHelper.hydratePrimaryKeyOptions( - _.first(jsonSchema.primaryKeyOptions) || {}, - columnDefinition.name, - columnDefinition.isActivated, - parentJsonSchema, - ), - 'columns', - ); - const uniqueKeyOptions = _.omit( - keyHelper.hydrateUniqueOptions({ - options: _.first(jsonSchema.uniqueKeyOptions) || {}, - columnName: columnDefinition.name, - isActivated: columnDefinition.isActivated, - jsonSchema: parentJsonSchema, - dbVersion, - }), - 'columns', - ); - - return { - name: columnDefinition.name, - type: columnDefinition.type, - primaryKey: keyHelper.isInlinePrimaryKey(jsonSchema), - primaryKeyOptions, - unique: keyHelper.isInlineUnique(jsonSchema), - uniqueKeyOptions, - nullable: columnDefinition.nullable, - default: columnDefinition.default, - comment: jsonSchema.refDescription || jsonSchema.description || definitionJsonSchema.description, - isActivated: columnDefinition.isActivated, - scale: columnDefinition.scale, - precision: columnDefinition.precision, - length: columnDefinition.length, - enum: jsonSchema.enum, - array_type: jsonSchema.array_type, - unit: jsonSchema.unit, - rangeSubtype: jsonSchema.rangeSubtype, - operatorClass: jsonSchema.operatorClass, - collation: jsonSchema.collation, - canonicalFunction: jsonSchema.canonicalFunction, - subtypeDiffFunction: jsonSchema.subtypeDiffFunction, - multiRangeType: jsonSchema.multiRangeType, - schemaName: schemaData.schemaName, - underlyingType: jsonSchema.underlyingType, - checkConstraints: jsonSchema.checkConstraints, - typeModifier: jsonSchema.typeModifier, - srid: jsonSchema.srid, - collationRule, - timePrecision, - timezone, - intervalOptions, - dbVersion, - }; - }, - - hydrateJsonSchemaColumn(jsonSchema, definitionJsonSchema) { - if (!jsonSchema.$ref || _.isEmpty(definitionJsonSchema) || isNotPlainType(definitionJsonSchema)) { - return jsonSchema; - } - - jsonSchema = _.omit(jsonSchema, '$ref'); - return { ...definitionJsonSchema, ...jsonSchema }; - }, - - hydrateIndex(indexData, tableData, schemaData) { - return { ...indexData, schemaName: schemaData.schemaName }; - }, - - hydrateViewIndex(indexData) { - return {}; - }, - - hydrateCheckConstraint(checkConstraint) { - return { - name: checkConstraint.chkConstrName, - expression: checkConstraint.constrExpression, - noInherit: checkConstraint.noInherit, - }; - }, - - hydrateSchema(containerData, data) { - const dbVersion = _.get(data, 'modelData.0.dbVersion'); - - return { - schemaName: containerData.name, - ifNotExist: containerData.ifNotExist, - comments: containerData.description, - udfs: data?.udfs || [], - procedures: data?.procedures || [], - dbVersion, - }; - }, - - hydrateTable({ tableData, entityData, jsonSchema }) { - const detailsTab = entityData[0]; - const parentTables = _.chain(detailsTab.inherits) - .map(({ parentTable }) => _.get(tableData, `relatedSchemas[${parentTable}]`, '')) - .compact() - .map(table => table.code || table.collectionName) - .join(', ') - .thru(value => (value ? `(${value})` : '')) - .value(); - - const partitioning = _.first(detailsTab.partitioning) || {}; - const compositePartitionKey = keyHelper.getKeys(partitioning.compositePartitionKey, jsonSchema); - const partitionParent = _.get(tableData, `relatedSchemas[${detailsTab.partitionOf}]`); - const partitionOf = partitionParent - ? getNamePrefixedWithSchemaName(partitionParent.collectionName, partitionParent.bucketName) - : ''; - const triggers = hydrateTriggers(entityData, tableData.relatedSchemas); - const dbVersion = getDbVersion(_.get(tableData, 'dbData.dbVersion', '')); - - return { - ...tableData, - triggers, - partitionOf, - keyConstraints: keyHelper.getTableKeyConstraints(jsonSchema, dbVersion), - inherits: parentTables, - selectStatement: _.trim(detailsTab.selectStatement), - partitioning: _.assign({}, partitioning, { compositePartitionKey }), - ..._.pick( - detailsTab, - 'temporary', - 'unlogged', - 'description', - 'ifNotExist', - 'usingMethod', - 'on_commit', - 'storage_parameter', - 'table_tablespace_name', - 'partitionBounds', - ), - }; - }, - - hydrateViewColumn(data) { - return { - name: data.name, - tableName: data.entityName, - alias: data.alias, - isActivated: data.isActivated, - }; - }, - - hydrateView({ viewData, entityData, relatedSchemas }) { - const detailsTab = entityData[0]; - const triggers = hydrateTriggers(entityData, relatedSchemas); - - return { - name: viewData.name, - keys: viewData.keys, - comment: detailsTab.description, - orReplace: detailsTab.orReplace, - temporary: detailsTab.temporary, - recursive: detailsTab.recursive, - viewOptions: detailsTab.viewOptions, - selectStatement: detailsTab.selectStatement, - withCheckOption: detailsTab.withCheckOption, - checkTestingScope: detailsTab.withCheckOption ? detailsTab.checkTestingScope : '', - schemaName: viewData.schemaData.schemaName, - triggers, - }; - }, - - commentIfDeactivated(statement, data, isPartOfLine) { - return statement; - }, - - /** - * @param tableName {string} - * @param columnName {string} - * @param dataType {string} - * @param dataTypeProperties {{ - * length?: number, - * scale?: number, - * precision?: number - * }} - * @return string - * */ - alterColumnType(tableName, columnName, dataType, dataTypeProperties) { - let dataTypeString = dataType; - if (dataTypeProperties.length) { - dataTypeString += `(${dataTypeProperties.length})`; - } else if (dataTypeProperties.precision && dataTypeProperties.scale) { - dataTypeString += `(${dataTypeProperties.precision},${dataTypeProperties.scale})`; - } else if (dataTypeProperties.precision) { - dataTypeString += `(${dataTypeProperties.precision})`; - } - - return assignTemplates(templates.alterColumnType, { - tableName, - columnName, - dataType: dataTypeString, - }) - }, - - /** - * @param tableName {string} - * @param columnName {string} - * @return string - * */ - setNotNullConstraint(tableName, columnName) { - return assignTemplates(templates.addNotNullConstraint, { - tableName, - columnName - }); - }, - - /** - * @param tableName {string} - * @param columnName {string} - * @return string - * */ - dropNotNullConstraint(tableName, columnName) { - return assignTemplates(templates.dropNotNullConstraint, { - tableName, - columnName - }); - }, - - /** - * @param tableName {string} - * @param oldColumnName {string} - * @param newColumnName {string} - * @return string - * */ - renameColumn(tableName, oldColumnName, newColumnName) { - return assignTemplates(templates.renameColumn, { - tableName, - oldColumnName, - newColumnName - }); - }, - - /** - * @param tableName {string} - * @param constraintName {string} - * @param expression {expression} - * @return string - * */ - addCheckConstraint(tableName, constraintName, expression) { - const templateConfig = { - tableName, - constraintName, - expression - }; - return assignTemplates(templates.addCheckConstraint, templateConfig); - }, - - /** - * @param tableName {string} - * @param constraintName {string} - * @return string - * */ - dropConstraint(tableName, constraintName) { - const templateConfig = { - tableName, - constraintName, - }; - return assignTemplates(templates.dropConstraint, templateConfig); - }, - - /** - * @param tableName {string} - * @param comment {string} - * @return string - * */ - updateTableComment(tableName, comment) { - const templateConfig = { - tableName, - comment - } - return assignTemplates(templates.updateCommentOnTable, templateConfig); - }, - - /** - * @param tableName {string} - * @return string - * */ - dropTableComment(tableName) { - const templateConfig = { - tableName, - comment: 'NULL' - } - return assignTemplates(templates.updateCommentOnTable, templateConfig); - }, - - /** - * @param columnName {string} - * @param comment {string} - * @return string - * */ - updateColumnComment(columnName, comment) { - const templateConfig = { - columnName, - comment - } - return assignTemplates(templates.updateCommentOnColumn, templateConfig); - }, - - /** - * @param columnName {string} - * @return string - * */ - dropColumnComment(columnName) { - const templateConfig = { - columnName, - comment: 'NULL' - } - return assignTemplates(templates.updateCommentOnColumn, templateConfig); - }, - - /** - * @param schemaName {string} - * @param comment {string} - * @return string - * */ - updateSchemaComment(schemaName, comment) { - const templateConfig = { - schemaName, - comment - } - return assignTemplates(templates.updateCommentOnSchema, templateConfig); - }, - - /** - * @param schemaName {string} - * @return string - * */ - dropSchemaComment(schemaName) { - const templateConfig = { - schemaName, - comment: 'NULL' - } - return assignTemplates(templates.updateCommentOnSchema, templateConfig); - }, - - /** - * @param viewName {string} - * @param comment {string} - * @return string - * */ - updateViewComment(viewName, comment) { - const templateConfig = { - viewName, - comment - } - return assignTemplates(templates.updateCommentOnView, templateConfig); - }, - - /** - * @param viewName {string} - * @return string - * */ - dropViewComment(viewName) { - const templateConfig = { - viewName, - comment: 'NULL' - } - return assignTemplates(templates.updateCommentOnView, templateConfig); - }, - - /** - * @param schemaName {string} - * @return string - * */ - createSchemaOnly(schemaName) { - const templateConfig = { - schemaName, - } - return assignTemplates(templates.createSchemaOnly, templateConfig); - }, - - /** - * @param schemaName {string} - * @return string - * */ - dropSchema(schemaName) { - const templateConfig = { - schemaName, - } - return assignTemplates(templates.dropSchema, templateConfig); - }, - }; -}; +module.exports = require('./ddlProvider/ddlProvider'); diff --git a/forward_engineering/helpers/columnDefinitionHelper.js b/forward_engineering/ddlProvider/ddlHelpers/columnDefinitionHelper.js similarity index 97% rename from forward_engineering/helpers/columnDefinitionHelper.js rename to forward_engineering/ddlProvider/ddlHelpers/columnDefinitionHelper.js index 63de6d3..0a0326e 100644 --- a/forward_engineering/helpers/columnDefinitionHelper.js +++ b/forward_engineering/ddlProvider/ddlHelpers/columnDefinitionHelper.js @@ -1,4 +1,4 @@ -module.exports = ({ _, wrap, assignTemplates, templates, commentIfDeactivated, wrapComment, wrapInQuotes }) => { +module.exports = ({ _, assignTemplates, templates, commentIfDeactivated, wrapComment, wrapInQuotes }) => { const addLength = (type, length) => { return `${type}(${length})`; }; diff --git a/forward_engineering/ddlProvider/ddlHelpers/constraintsHelper.js b/forward_engineering/ddlProvider/ddlHelpers/constraintsHelper.js new file mode 100644 index 0000000..86cde7b --- /dev/null +++ b/forward_engineering/ddlProvider/ddlHelpers/constraintsHelper.js @@ -0,0 +1,129 @@ +module.exports = ({ + _, + commentIfDeactivated, + checkAllKeysDeactivated, + assignTemplates, + wrapInQuotes, + getColumnsList, + }) => { + const generateConstraintsString = (dividedConstraints, isParentActivated) => { + const deactivatedItemsAsString = commentIfDeactivated( + (dividedConstraints?.deactivatedItems || []).join(',\n\t'), + { + isActivated: !isParentActivated, + isPartOfLine: true, + }, + ); + const activatedConstraints = dividedConstraints?.activatedItems?.length + ? ',\n\t' + dividedConstraints.activatedItems.join(',\n\t') + : ''; + + const deactivatedConstraints = dividedConstraints?.deactivatedItems?.length + ? '\n\t' + deactivatedItemsAsString + : ''; + + return activatedConstraints + deactivatedConstraints; + }; + + const foreignKeysToString = keys => { + if (Array.isArray(keys)) { + const activatedKeys = keys + .filter(key => _.get(key, 'isActivated', true)) + .map(key => wrapInQuotes(_.trim(key.name))); + const deactivatedKeys = keys + .filter(key => !_.get(key, 'isActivated', true)) + .map(key => wrapInQuotes(_.trim(key.name))); + const deactivatedKeysAsString = deactivatedKeys.length + ? commentIfDeactivated(deactivatedKeys, {isActivated: false, isPartOfLine: true}) + : ''; + + return activatedKeys.join(', ') + deactivatedKeysAsString; + } + return keys; + }; + + const foreignActiveKeysToString = keys => { + return keys.map(key => _.trim(key.name)).join(', '); + }; + + /** + * @param templates {Object} + * @param isParentActivated {boolean} + * @return {( + * keyData: { + * name: string, + * keyType: string, + * columns: Array<{ + * isActivated: boolean, + * name: string, + * }>, + * include: Array<{ + * isActivated: boolean, + * name: string, + * }>, + * storageParameters: string, + * tablespace: string, + * } + * ) => { + * statement: string, + * isActivated: boolean, + * }} + * */ + const createKeyConstraint = (templates, isParentActivated) => keyData => { + const constraintName = wrapInQuotes(_.trim(keyData.name)); + const isAllColumnsDeactivated = checkAllKeysDeactivated(keyData.columns || []); + const columns = !_.isEmpty(keyData.columns) + ? getColumnsList(keyData.columns, isAllColumnsDeactivated, isParentActivated) + : ''; + const includeNonKey = keyData.include.length + ? ` INCLUDE${getColumnsList(keyData.include, isAllColumnsDeactivated, isParentActivated)}` + : ''; + const storageParameters = keyData.storageParameters ? ` WITH (${keyData.storageParameters})` : ''; + const tablespace = keyData.tablespace ? ` USING INDEX TABLESPACE ${wrapInQuotes(keyData.tablespace)}` : ''; + + return { + statement: assignTemplates(templates.createKeyConstraint, { + constraintName: keyData.name ? `CONSTRAINT ${constraintName} ` : '', + keyType: keyData.keyType, + columns, + includeNonKey, + storageParameters, + tablespace, + }), + isActivated: !isAllColumnsDeactivated, + }; + }; + + const getConstraintsWarnings = (invalidConstraints = []) => { + if (_.isEmpty(invalidConstraints)) { + return ''; + } + + return ( + '\n\t' + + invalidConstraints + .map(keyData => { + const constraintName = keyData.name ? ` [constraint name: ${keyData.name}]` : ''; + + return `-- ${keyData.errorMessage}${constraintName}`; + }) + .join('\n\t') + ); + }; + + const additionalPropertiesForForeignKey = relationship => { + const foreignOnDelete = _.get(relationship, 'relationshipOnDelete', ''); + const foreignOnUpdate = _.get(relationship, 'relationshipOnUpdate', ''); + const foreignMatch = _.get(relationship, 'relationshipMatch', ''); + return {foreignOnDelete, foreignOnUpdate, foreignMatch}; + }; + + return { + generateConstraintsString, + foreignKeysToString, + foreignActiveKeysToString, + createKeyConstraint, + getConstraintsWarnings, + additionalPropertiesForForeignKey, + }; +}; diff --git a/forward_engineering/helpers/databaseHelper.js b/forward_engineering/ddlProvider/ddlHelpers/databaseHelper.js similarity index 100% rename from forward_engineering/helpers/databaseHelper.js rename to forward_engineering/ddlProvider/ddlHelpers/databaseHelper.js diff --git a/forward_engineering/helpers/functionHelper.js b/forward_engineering/ddlProvider/ddlHelpers/functionHelper.js similarity index 100% rename from forward_engineering/helpers/functionHelper.js rename to forward_engineering/ddlProvider/ddlHelpers/functionHelper.js diff --git a/forward_engineering/helpers/indexHelper.js b/forward_engineering/ddlProvider/ddlHelpers/indexHelper.js similarity index 100% rename from forward_engineering/helpers/indexHelper.js rename to forward_engineering/ddlProvider/ddlHelpers/indexHelper.js diff --git a/forward_engineering/helpers/keyHelper.js b/forward_engineering/ddlProvider/ddlHelpers/keyHelper.js similarity index 100% rename from forward_engineering/helpers/keyHelper.js rename to forward_engineering/ddlProvider/ddlHelpers/keyHelper.js diff --git a/forward_engineering/helpers/procedureHelper.js b/forward_engineering/ddlProvider/ddlHelpers/procedureHelper.js similarity index 100% rename from forward_engineering/helpers/procedureHelper.js rename to forward_engineering/ddlProvider/ddlHelpers/procedureHelper.js diff --git a/forward_engineering/helpers/tableHelper.js b/forward_engineering/ddlProvider/ddlHelpers/tableHelper.js similarity index 100% rename from forward_engineering/helpers/tableHelper.js rename to forward_engineering/ddlProvider/ddlHelpers/tableHelper.js diff --git a/forward_engineering/helpers/triggerHelper.js b/forward_engineering/ddlProvider/ddlHelpers/triggerHelper.js similarity index 100% rename from forward_engineering/helpers/triggerHelper.js rename to forward_engineering/ddlProvider/ddlHelpers/triggerHelper.js diff --git a/forward_engineering/helpers/udtHelper.js b/forward_engineering/ddlProvider/ddlHelpers/udtHelper.js similarity index 100% rename from forward_engineering/helpers/udtHelper.js rename to forward_engineering/ddlProvider/ddlHelpers/udtHelper.js diff --git a/forward_engineering/ddlProvider/ddlProvider.js b/forward_engineering/ddlProvider/ddlProvider.js new file mode 100644 index 0000000..cfdd133 --- /dev/null +++ b/forward_engineering/ddlProvider/ddlProvider.js @@ -0,0 +1,1170 @@ +const defaultTypes = require('../configs/defaultTypes'); +const descriptors = require('../configs/descriptors'); +const templates = require('./templates'); + + +module.exports = (baseProvider, options, app) => { + const _ = app.require('lodash'); + const { + tab, + commentIfDeactivated, + checkAllKeysDeactivated, + divideIntoActivatedAndDeactivated, + hasType, + wrap, + clean, + wrapComment, + getFunctionArguments, + wrapInQuotes, + getNamePrefixedWithSchemaName, + getColumnsList, + getViewData, + } = require('../utils/general')(_); + const assignTemplates = require('../utils/assignTemplates'); + + const { + generateConstraintsString, + foreignKeysToString, + foreignActiveKeysToString, + createKeyConstraint, + getConstraintsWarnings, + additionalPropertiesForForeignKey, + } = require('./ddlHelpers/constraintsHelper')({ + _, + commentIfDeactivated, + checkAllKeysDeactivated, + assignTemplates, + getColumnsList, + wrapInQuotes, + }); + const keyHelper = require('./ddlHelpers/keyHelper')(_, clean); + + const { getFunctionsScript } = require('./ddlHelpers/functionHelper')({ + _, + templates, + assignTemplates, + getFunctionArguments, + getNamePrefixedWithSchemaName, + }); + + const { getProceduresScript } = require('./ddlHelpers/procedureHelper')({ + _, + templates, + assignTemplates, + getFunctionArguments, + getNamePrefixedWithSchemaName, + }); + + const { getTableTemporaryValue, getTableOptions } = require('./ddlHelpers/tableHelper')({ + _, + checkAllKeysDeactivated, + getColumnsList, + }); + + const { getUserDefinedType, isNotPlainType } = require('./ddlHelpers/udtHelper')({ + _, + commentIfDeactivated, + assignTemplates, + templates, + getNamePrefixedWithSchemaName, + wrapComment, + }); + + const { getIndexKeys, getIndexOptions } = require('./ddlHelpers/indexHelper')({ + _, + wrapInQuotes, + checkAllKeysDeactivated, + getColumnsList, + }); + + const { decorateType, decorateDefault, getColumnComments, replaceTypeByVersion } = + require('./ddlHelpers/columnDefinitionHelper')({ + _, + wrap, + assignTemplates, + templates, + commentIfDeactivated, + wrapInQuotes, + wrapComment, + }); + + const { getTriggersScript, hydrateTriggers } = require('./ddlHelpers/triggerHelper')({ + _, + wrap, + assignTemplates, + templates, + getNamePrefixedWithSchemaName, + commentIfDeactivated, + }); + + const { getLocaleProperties } = require('./ddlHelpers/databaseHelper')(); + + return { + createDatabase(modelData) { + if (!modelData.databaseName) { + return ''; + } + + const { locale, collate, characterClassification } = getLocaleProperties(modelData); + + return assignTemplates(templates.createDatabase, { + name: wrapInQuotes(modelData.databaseName), + template: modelData.template ? `\n\tTEMPLATE ${modelData.template}` : '', + encoding: modelData.encoding ? `\n\tENCODING ${modelData.encoding}` : '', + locale: locale ? `\n\tLOCALE '${modelData.locale}'` : '', + collate: collate ? `\n\tLC_COLLATE '${modelData.collate}'` : '', + characterClassification: characterClassification ? `\n\tLC_CTYPE '${characterClassification}'` : '', + tablespace: modelData.tablespace ? `\n\tTABLESPACE '${modelData.tablespace}'` : '', + }); + }, + + createSchema({ schemaName, ifNotExist, comments, udfs, procedures }) { + const comment = assignTemplates(templates.comment, { + object: 'SCHEMA', + objectName: wrapInQuotes(schemaName), + comment: wrapComment(comments), + }); + + const schemaStatement = assignTemplates(templates.createSchema, { + name: wrapInQuotes(schemaName), + ifNotExist: ifNotExist ? ' IF NOT EXISTS' : '', + comment: comments ? comment : '', + }); + + const createFunctionStatement = getFunctionsScript(schemaName, udfs); + const createProceduresStatement = getProceduresScript(schemaName, procedures); + + return _.chain([schemaStatement, createFunctionStatement, createProceduresStatement]) + .compact() + .map(_.trim) + .join('\n\n') + .trim() + .value(); + }, + + createTable( + { + name, + columns, + checkConstraints, + foreignKeyConstraints, + schemaData, + columnDefinitions, + keyConstraints, + inherits, + description, + ifNotExist, + usingMethod, + on_commit, + partitioning, + storage_parameter, + table_tablespace_name, + temporary, + unlogged, + selectStatement, + triggers, + partitionOf, + partitionBounds, + }, + isActivated, + ) { + const ifNotExistStr = ifNotExist ? ' IF NOT EXISTS' : ''; + const tableName = getNamePrefixedWithSchemaName(name, schemaData.schemaName); + const comment = assignTemplates(templates.comment, { + object: 'TABLE', + objectName: tableName, + comment: wrapComment(description), + }); + + const dividedKeysConstraints = divideIntoActivatedAndDeactivated( + keyConstraints + .filter(({ errorMessage }) => !errorMessage) + .map(createKeyConstraint(templates, isActivated)), + key => key.statement, + ); + const constraintWarnings = getConstraintsWarnings( + keyConstraints.filter(({ errorMessage }) => errorMessage), + ); + const keyConstraintsString = `${generateConstraintsString( + dividedKeysConstraints, + isActivated, + )}${constraintWarnings}`; + const keyConstraintsValue = partitionOf ? keyConstraintsString?.slice(1) : keyConstraintsString; + + const dividedForeignKeys = divideIntoActivatedAndDeactivated(foreignKeyConstraints, key => key.statement); + const foreignKeyConstraintsString = generateConstraintsString(dividedForeignKeys, isActivated); + + const columnDescriptions = '\n' + getColumnComments(tableName, columnDefinitions); + const template = partitionOf ? templates.createTablePartitionOf : templates.createTable; + + const checkConstraintPrefix = partitionOf && !keyConstraintsString ? '\n\t' : ',\n\t'; + const checkConstraintsValue = !_.isEmpty(checkConstraints) + ? wrap(_.join(checkConstraints, ',\n\t'), checkConstraintPrefix, '') + : ''; + + const isEmptyPartitionBody = + partitionOf && !keyConstraintsValue && !checkConstraintsValue && !foreignKeyConstraintsString; + const openParenthesis = isEmptyPartitionBody ? '' : '('; + const closeParenthesis = isEmptyPartitionBody ? '' : ')'; + + const tableStatement = assignTemplates(template, { + temporary: getTableTemporaryValue(temporary, unlogged), + ifNotExist: ifNotExistStr, + name: tableName, + columnDefinitions: !partitionOf ? '\t' + _.join(columns, ',\n\t') : '', + keyConstraints: keyConstraintsValue, + checkConstraints: checkConstraintsValue, + foreignKeyConstraints: foreignKeyConstraintsString, + options: getTableOptions({ + inherits, + partitioning, + usingMethod, + on_commit, + storage_parameter, + table_tablespace_name, + selectStatement, + partitionBounds, + }), + comment: description ? comment : '', + partitionOf: partitionOf ? ` PARTITION OF ${partitionOf} ` : '', + columnDescriptions, + openParenthesis, + closeParenthesis, + }); + + const createTriggerStatements = getTriggersScript({ + dbVersion: schemaData.dbVersion, + tableName, + triggers, + }); + + return commentIfDeactivated( + [tableStatement, createTriggerStatements].map(_.trim).join('\n\n').trim() + '\n', + { isActivated }, + ); + }, + + convertColumnDefinition(columnDefinition) { + const type = replaceTypeByVersion(columnDefinition.type, columnDefinition.dbVersion); + const notNull = columnDefinition.nullable ? '' : ' NOT NULL'; + const primaryKey = columnDefinition.primaryKey + ? ' ' + createKeyConstraint(templates, true)(columnDefinition.primaryKeyOptions).statement + : ''; + const uniqueKey = columnDefinition.unique + ? ' ' + createKeyConstraint(templates, true)(columnDefinition.uniqueKeyOptions).statement + : ''; + const collation = columnDefinition.collationRule ? ` COLLATE "${columnDefinition.collationRule}"` : ''; + const defaultValue = !_.isUndefined(columnDefinition.default) + ? ' DEFAULT ' + decorateDefault(type, columnDefinition.default) + : ''; + + return commentIfDeactivated( + assignTemplates(templates.columnDefinition, { + name: wrapInQuotes(columnDefinition.name), + type: decorateType(type, columnDefinition), + notNull, + primaryKey, + uniqueKey, + collation, + defaultValue, + }), + { + isActivated: columnDefinition.isActivated, + }, + ); + }, + + createIndex(tableName, index, dbData, isParentActivated = true) { + const isUnique = index.unique && index.index_method === 'btree'; + const name = wrapInQuotes(index.indxName); + const unique = isUnique ? ' UNIQUE' : ''; + const concurrently = index.concurrently ? ' CONCURRENTLY' : ''; + const ifNotExist = index.ifNotExist ? ' IF NOT EXISTS' : ''; + const only = index.only ? ' ONLY' : ''; + const using = index.index_method ? ` USING ${_.toUpper(index.index_method)}` : ''; + const { getDbVersion } = require('../utils/general')(_); + const dbVersion = getDbVersion(_.get(dbData, 'dbVersion', '')); + const nullsDistinct = isUnique && index.nullsDistinct && dbVersion >= 15 ? `\n ${index.nullsDistinct}` : ''; + + const keys = getIndexKeys( + index.index_method === 'btree' + ? index.columns + : _.map(index.columns, column => _.omit(column, 'sortOrder', 'nullsOrder')), + isParentActivated, + ); + const options = getIndexOptions(index, isParentActivated); + + return commentIfDeactivated( + assignTemplates(templates.index, { + unique, + concurrently, + ifNotExist, + name, + only, + using, + keys, + options, + nullsDistinct, + tableName: getNamePrefixedWithSchemaName(tableName, index.schemaName), + }), + { + isActivated: index.isActivated, + }, + ); + }, + + createCheckConstraint(checkConstraint) { + return assignTemplates(templates.checkConstraint, { + name: checkConstraint.name ? `CONSTRAINT ${wrapInQuotes(checkConstraint.name)}` : '', + expression: _.trim(checkConstraint.expression).replace(/^\(([\s\S]*)\)$/, '$1'), + noInherit: checkConstraint.noInherit ? ' NO INHERIT' : '', + }); + }, + + /** + * @param name {string} + * @param isActivated {boolean} + * @param customProperties {{ + * relationshipOnDelete?: string, + * relationshipOnUpdate?: string, + * relationshipMatch?: string, + * }} + * @param primaryTableActivated {boolean} + * @param foreignTableActivated {boolean} + * @param foreignSchemaName {string} + * @param primarySchemaName {string} + * @param primaryTable {string} + * @param primaryKey {Array<{ + * isActivated: boolean, + * name: string, + * }>} + * @param foreignKey {Array<{ + * isActivated: boolean, + * name: string, + * }>} + * @param schemaData {{ + * schemaName: string + * }} + * @param dbData {any} + * @return {{ + * statement: string, + * isActivated: boolean, + * }} + * */ + createForeignKeyConstraint( + { + name, + foreignKey, + primaryTable, + primaryKey, + primaryTableActivated, + foreignTableActivated, + foreignSchemaName, + primarySchemaName, + customProperties, + isActivated + }, + dbData, + schemaData, + ) { + const isAllPrimaryKeysDeactivated = checkAllKeysDeactivated(primaryKey); + const isAllForeignKeysDeactivated = checkAllKeysDeactivated(foreignKey); + const areKeysActivated = + !isAllPrimaryKeysDeactivated && + !isAllForeignKeysDeactivated && + primaryTableActivated && + foreignTableActivated; + + const { foreignOnDelete, foreignOnUpdate, foreignMatch } = + additionalPropertiesForForeignKey(customProperties); + + const foreignKeyStatement = assignTemplates(templates.createForeignKeyConstraint, { + primaryTable: getNamePrefixedWithSchemaName(primaryTable, primarySchemaName || schemaData.schemaName), + name: name ? `CONSTRAINT ${wrapInQuotes(name)}` : '', + foreignKey: areKeysActivated ? foreignKeysToString(foreignKey) : foreignActiveKeysToString(foreignKey), + primaryKey: areKeysActivated ? foreignKeysToString(primaryKey) : foreignActiveKeysToString(primaryKey), + onDelete: foreignOnDelete ? ` ON DELETE ${foreignOnDelete}` : '', + onUpdate: foreignOnUpdate ? ` ON UPDATE ${foreignOnUpdate}` : '', + match: foreignMatch ? ` MATCH ${foreignMatch}` : '', + }); + + return { + statement: _.trim(foreignKeyStatement), + isActivated: areKeysActivated && isActivated, + }; + }, + + /** + * @param name {string} + * @param isActivated {boolean} + * @param customProperties {{ + * relationshipOnDelete?: string, + * relationshipOnUpdate?: string, + * relationshipMatch?: string, + * }} + * @param primaryTableActivated {boolean} + * @param foreignTableActivated {boolean} + * @param foreignSchemaName {string} + * @param foreignTable {string} + * @param primarySchemaName {string} + * @param primaryTable {string} + * @param primaryKey {Array<{ + * isActivated: boolean, + * name: string, + * }>} + * @param foreignKey {Array<{ + * isActivated: boolean, + * name: string, + * }>} + * @param schemaData {{ + * schemaName: string + * }} + * @param dbData {any} + * @return {{ + * statement: string, + * isActivated: boolean, + * }} + * */ + createForeignKey( + { + name, + foreignTable, + foreignKey, + primaryTable, + primaryKey, + primaryTableActivated, + foreignTableActivated, + foreignSchemaName, + primarySchemaName, + customProperties, + isActivated + }, + dbData, + schemaData, + ) { + const isAllPrimaryKeysDeactivated = checkAllKeysDeactivated(primaryKey); + const isAllForeignKeysDeactivated = checkAllKeysDeactivated(foreignKey); + const areKeysActivated = + !isAllPrimaryKeysDeactivated && + !isAllForeignKeysDeactivated && + primaryTableActivated && + foreignTableActivated; + + const { foreignOnDelete, foreignOnUpdate, foreignMatch } = + additionalPropertiesForForeignKey(customProperties); + + const foreignKeyStatement = assignTemplates(templates.createForeignKey, { + primaryTable: getNamePrefixedWithSchemaName(primaryTable, primarySchemaName || schemaData.schemaName), + foreignTable: getNamePrefixedWithSchemaName(foreignTable, foreignSchemaName || schemaData.schemaName), + name: name ? wrapInQuotes(name) : '', + foreignKey: areKeysActivated ? foreignKeysToString(foreignKey) : foreignActiveKeysToString(foreignKey), + primaryKey: areKeysActivated ? foreignKeysToString(primaryKey) : foreignActiveKeysToString(primaryKey), + onDelete: foreignOnDelete ? ` ON DELETE ${foreignOnDelete}` : '', + onUpdate: foreignOnUpdate ? ` ON UPDATE ${foreignOnUpdate}` : '', + match: foreignMatch ? ` MATCH ${foreignMatch}` : '', + }); + + return { + statement: _.trim(foreignKeyStatement), + isActivated: areKeysActivated && isActivated, + }; + }, + + createView(viewData, dbData, isActivated) { + const viewName = getNamePrefixedWithSchemaName(viewData.name, viewData.schemaName); + + const comment = assignTemplates(templates.comment, { + object: 'VIEW', + objectName: viewName, + comment: wrapComment(viewData.comment), + }); + + const allDeactivated = checkAllKeysDeactivated(viewData.keys || []); + const deactivatedWholeStatement = allDeactivated || !isActivated; + const { columns, tables } = getViewData(viewData.keys); + let columnsAsString = columns.map(column => column.statement).join(',\n\t\t'); + + if (!deactivatedWholeStatement) { + const dividedColumns = divideIntoActivatedAndDeactivated(columns, column => column.statement); + const deactivatedColumnsString = dividedColumns.deactivatedItems.length + ? commentIfDeactivated(dividedColumns.deactivatedItems.join(',\n\t\t'), { + isActivated: false, + isPartOfLine: true, + }) + : ''; + columnsAsString = dividedColumns.activatedItems.join(',\n\t\t') + deactivatedColumnsString; + } + + const selectStatement = _.trim(viewData.selectStatement) + ? _.trim(tab(viewData.selectStatement)) + : assignTemplates(templates.viewSelectStatement, { + tableName: tables.join(', '), + keys: columnsAsString, + }); + + const check_option = viewData.viewOptions?.check_option + ? `check_option=${viewData.viewOptions?.check_option}` + : ''; + const security_barrier = viewData.viewOptions?.security_barrier ? `security_barrier` : ''; + const dbVersionWhereSecurityInvokerAppeared = 15; + const { getDbVersion } = require('../utils/general')(_); + const security_invoker = + viewData.viewOptions?.security_invoker && + getDbVersion(dbData.dbVersion) >= dbVersionWhereSecurityInvokerAppeared + ? 'security_invoker' + : ''; + const withOptions = + check_option || security_barrier || security_invoker + ? `\n\tWITH (${_.compact([check_option, security_barrier, security_invoker]).join(',')})` + : ''; + + const getCheckOption = viewData => { + if (viewData.withCheckOption && viewData.checkTestingScope) { + return `\n\tWITH ${viewData.checkTestingScope} CHECK OPTION`; + } else if (viewData.withCheckOption) { + return '\n\tWITH CHECK OPTION'; + } else { + return ''; + } + }; + + const createViewScript = commentIfDeactivated( + assignTemplates(templates.createView, { + name: viewName, + orReplace: viewData.orReplace ? ' OR REPLACE' : '', + temporary: viewData.temporary ? ' TEMPORARY' : '', + checkOption: getCheckOption(viewData), + comment: viewData.comment ? comment : '', + withOptions, + selectStatement, + }), + { isActivated: !deactivatedWholeStatement }, + ); + + const createTriggersStatements = getTriggersScript({ + dbVersion: viewData.dbVersion, + tableName: viewName, + triggers: viewData.triggers, + }); + + return [createViewScript, createTriggersStatements].map(_.trim).join('\n\n').trim() + '\n'; + }, + + /** + * @param viewName {string} + * @return string + * */ + dropView(viewName) { + const templatesConfig = { + viewName, + } + return assignTemplates(templates.dropView, templatesConfig); + }, + + createViewIndex() { + return ''; + }, + + createUdt(udt) { + const columns = _.map(udt.properties, this.convertColumnDefinition); + + return getUserDefinedType(udt, columns); + }, + + getDefaultType(type) { + return defaultTypes[type]; + }, + + getTypesDescriptors() { + return descriptors; + }, + + hasType(type) { + return hasType(descriptors, type); + }, + + hydrateDatabase({ modelData }) { + modelData = _.get(modelData, '0', {}); + + return { + databaseName: modelData.database_name, + tablespace: modelData.tablespace_name, + encoding: modelData.encoding, + template: modelData.template, + collate: modelData.LC_COLLATE, + characterClassification: modelData.LC_CTYPE, + dbVersion: modelData.dbVersion, + locale: modelData.locale, + }; + }, + + hydrateColumn({ columnDefinition, jsonSchema, schemaData, definitionJsonSchema = {}, parentJsonSchema }) { + const collationRule = _.includes(['char', 'varchar', 'text'], columnDefinition.type) + ? jsonSchema.collationRule + : ''; + const timeTypes = ['time', 'timestamp']; + const timePrecision = _.includes(timeTypes, columnDefinition.type) ? jsonSchema.timePrecision : ''; + const timezone = _.includes(timeTypes, columnDefinition.type) ? jsonSchema.timezone : ''; + const intervalOptions = columnDefinition.type === 'interval' ? jsonSchema.intervalOptions : ''; + const { getDbVersion } = require('../utils/general')(_); + const dbVersion = getDbVersion(schemaData.dbVersion) + const primaryKeyOptions = _.omit( + keyHelper.hydratePrimaryKeyOptions( + _.first(jsonSchema.primaryKeyOptions) || {}, + columnDefinition.name, + columnDefinition.isActivated, + parentJsonSchema, + ), + 'columns', + ); + const uniqueKeyOptions = _.omit( + keyHelper.hydrateUniqueOptions({ + options: _.first(jsonSchema.uniqueKeyOptions) || {}, + columnName: columnDefinition.name, + isActivated: columnDefinition.isActivated, + jsonSchema: parentJsonSchema, + dbVersion, + }), + 'columns', + ); + + return { + name: columnDefinition.name, + type: columnDefinition.type, + primaryKey: keyHelper.isInlinePrimaryKey(jsonSchema), + primaryKeyOptions, + unique: keyHelper.isInlineUnique(jsonSchema), + uniqueKeyOptions, + nullable: columnDefinition.nullable, + default: columnDefinition.default, + comment: jsonSchema.refDescription || jsonSchema.description || definitionJsonSchema.description, + isActivated: columnDefinition.isActivated, + scale: columnDefinition.scale, + precision: columnDefinition.precision, + length: columnDefinition.length, + enum: jsonSchema.enum, + array_type: jsonSchema.array_type, + unit: jsonSchema.unit, + rangeSubtype: jsonSchema.rangeSubtype, + operatorClass: jsonSchema.operatorClass, + collation: jsonSchema.collation, + canonicalFunction: jsonSchema.canonicalFunction, + subtypeDiffFunction: jsonSchema.subtypeDiffFunction, + multiRangeType: jsonSchema.multiRangeType, + schemaName: schemaData.schemaName, + underlyingType: jsonSchema.underlyingType, + checkConstraints: jsonSchema.checkConstraints, + typeModifier: jsonSchema.typeModifier, + srid: jsonSchema.srid, + collationRule, + timePrecision, + timezone, + intervalOptions, + dbVersion, + }; + }, + + hydrateJsonSchemaColumn(jsonSchema, definitionJsonSchema) { + if (!jsonSchema.$ref || _.isEmpty(definitionJsonSchema) || isNotPlainType(definitionJsonSchema)) { + return jsonSchema; + } + + jsonSchema = _.omit(jsonSchema, '$ref'); + return { ...definitionJsonSchema, ...jsonSchema }; + }, + + hydrateIndex(indexData, tableData, schemaData) { + return { ...indexData, schemaName: schemaData.schemaName }; + }, + + hydrateViewIndex(indexData) { + return {}; + }, + + hydrateCheckConstraint(checkConstraint) { + return { + name: checkConstraint.chkConstrName, + expression: checkConstraint.constrExpression, + noInherit: checkConstraint.noInherit, + }; + }, + + hydrateSchema(containerData, data) { + const dbVersion = _.get(data, 'modelData.0.dbVersion'); + + return { + schemaName: containerData.name, + ifNotExist: containerData.ifNotExist, + comments: containerData.description, + udfs: data?.udfs || [], + procedures: data?.procedures || [], + dbVersion, + }; + }, + + hydrateTable({ tableData, entityData, jsonSchema }) { + const detailsTab = entityData[0]; + const parentTables = _.chain(detailsTab.inherits) + .map(({ parentTable }) => _.get(tableData, `relatedSchemas[${parentTable}]`, '')) + .compact() + .map(table => table.code || table.collectionName) + .join(', ') + .thru(value => (value ? `(${value})` : '')) + .value(); + + const partitioning = _.first(detailsTab.partitioning) || {}; + const compositePartitionKey = keyHelper.getKeys(partitioning.compositePartitionKey, jsonSchema); + const partitionParent = _.get(tableData, `relatedSchemas[${detailsTab.partitionOf}]`); + const partitionOf = partitionParent + ? getNamePrefixedWithSchemaName(partitionParent.collectionName, partitionParent.bucketName) + : ''; + const triggers = hydrateTriggers(entityData, tableData.relatedSchemas); + const { getDbVersion } = require('../utils/general')(_); + const dbVersion = getDbVersion(_.get(tableData, 'dbData.dbVersion', '')); + + return { + ...tableData, + triggers, + partitionOf, + keyConstraints: keyHelper.getTableKeyConstraints(jsonSchema, dbVersion), + inherits: parentTables, + selectStatement: _.trim(detailsTab.selectStatement), + partitioning: _.assign({}, partitioning, { compositePartitionKey }), + ..._.pick( + detailsTab, + 'temporary', + 'unlogged', + 'description', + 'ifNotExist', + 'usingMethod', + 'on_commit', + 'storage_parameter', + 'table_tablespace_name', + 'partitionBounds', + ), + }; + }, + + hydrateViewColumn(data) { + return { + name: data.name, + tableName: data.entityName, + alias: data.alias, + isActivated: data.isActivated, + }; + }, + + hydrateView({ viewData, entityData, relatedSchemas }) { + const detailsTab = entityData[0]; + const triggers = hydrateTriggers(entityData, relatedSchemas); + + return { + name: viewData.name, + keys: viewData.keys, + comment: detailsTab.description, + orReplace: detailsTab.orReplace, + temporary: detailsTab.temporary, + recursive: detailsTab.recursive, + viewOptions: detailsTab.viewOptions, + selectStatement: detailsTab.selectStatement, + withCheckOption: detailsTab.withCheckOption, + checkTestingScope: detailsTab.withCheckOption ? detailsTab.checkTestingScope : '', + schemaName: viewData.schemaData.schemaName, + triggers, + }; + }, + + commentIfDeactivated(statement, data, isPartOfLine) { + return statement; + }, + + /** + * @param tableName {string} + * @param columnName {string} + * @param dataType {string} + * @param dataTypeProperties {{ + * length?: number, + * scale?: number, + * precision?: number + * }} + * @return string + * */ + alterColumnType(tableName, columnName, dataType, dataTypeProperties) { + let dataTypeString = dataType; + if (dataTypeProperties.length) { + dataTypeString += `(${dataTypeProperties.length})`; + } else if (dataTypeProperties.precision && dataTypeProperties.scale) { + dataTypeString += `(${dataTypeProperties.precision},${dataTypeProperties.scale})`; + } else if (dataTypeProperties.precision) { + dataTypeString += `(${dataTypeProperties.precision})`; + } + + return assignTemplates(templates.alterColumnType, { + tableName, + columnName, + dataType: dataTypeString, + }) + }, + + /** + * @param tableName {string} + * @param columnName {string} + * @return string + * */ + setNotNullConstraint(tableName, columnName) { + return assignTemplates(templates.addNotNullConstraint, { + tableName, + columnName + }); + }, + + /** + * @param tableName {string} + * @param columnName {string} + * @return string + * */ + dropNotNullConstraint(tableName, columnName) { + return assignTemplates(templates.dropNotNullConstraint, { + tableName, + columnName + }); + }, + + /** + * @param tableName {string} + * @param oldColumnName {string} + * @param newColumnName {string} + * @return string + * */ + renameColumn(tableName, oldColumnName, newColumnName) { + return assignTemplates(templates.renameColumn, { + tableName, + oldColumnName, + newColumnName + }); + }, + + /** + * @param tableName {string} + * @param constraintName {string} + * @param expression {expression} + * @return string + * */ + addCheckConstraint(tableName, constraintName, expression) { + const templateConfig = { + tableName, + constraintName, + expression + }; + return assignTemplates(templates.addCheckConstraint, templateConfig); + }, + + /** + * @param tableName {string} + * @param constraintName {string} + * @return string + * */ + dropConstraint(tableName, constraintName) { + const templateConfig = { + tableName, + constraintName, + }; + return assignTemplates(templates.dropConstraint, templateConfig); + }, + + /** + * @param tableName {string} + * @param comment {string} + * @return string + * */ + updateTableComment(tableName, comment) { + const templateConfig = { + tableName, + comment + } + return assignTemplates(templates.updateCommentOnTable, templateConfig); + }, + + /** + * @param tableName {string} + * @return string + * */ + dropTableComment(tableName) { + const templateConfig = { + tableName, + comment: 'NULL' + } + return assignTemplates(templates.updateCommentOnTable, templateConfig); + }, + + /** + * @param columnName {string} + * @param comment {string} + * @return string + * */ + updateColumnComment(columnName, comment) { + const templateConfig = { + columnName, + comment + } + return assignTemplates(templates.updateCommentOnColumn, templateConfig); + }, + + /** + * @param columnName {string} + * @return string + * */ + dropColumnComment(columnName) { + const templateConfig = { + columnName, + comment: 'NULL' + } + return assignTemplates(templates.updateCommentOnColumn, templateConfig); + }, + + /** + * @param schemaName {string} + * @param comment {string} + * @return string + * */ + updateSchemaComment(schemaName, comment) { + const templateConfig = { + schemaName, + comment + } + return assignTemplates(templates.updateCommentOnSchema, templateConfig); + }, + + /** + * @param schemaName {string} + * @return string + * */ + dropSchemaComment(schemaName) { + const templateConfig = { + schemaName, + comment: 'NULL' + } + return assignTemplates(templates.updateCommentOnSchema, templateConfig); + }, + + /** + * @param viewName {string} + * @param comment {string} + * @return string + * */ + updateViewComment(viewName, comment) { + const templateConfig = { + viewName, + comment + } + return assignTemplates(templates.updateCommentOnView, templateConfig); + }, + + /** + * @param viewName {string} + * @return string + * */ + dropViewComment(viewName) { + const templateConfig = { + viewName, + comment: 'NULL' + } + return assignTemplates(templates.updateCommentOnView, templateConfig); + }, + + /** + * @param schemaName {string} + * @return string + * */ + createSchemaOnly(schemaName) { + const templateConfig = { + schemaName, + } + return assignTemplates(templates.createSchemaOnly, templateConfig); + }, + + /** + * @param schemaName {string} + * @return string + * */ + dropSchema(schemaName) { + const templateConfig = { + schemaName, + } + return assignTemplates(templates.dropSchema, templateConfig); + }, + + /** + * @param tableName {string} + * @return string + * */ + dropTable(tableName) { + const templateConfig = { + tableName, + } + return assignTemplates(templates.dropTable, templateConfig); + }, + + /** + * @param tableName {string} + * @param columnDefinition {string} + * @return string + * */ + addColumn(tableName, columnDefinition) { + const templateConfig = { + tableName, + columnDefinition, + } + return assignTemplates(templates.addColumn, templateConfig); + }, + + /** + * @param tableName {string} + * @param columnName {string} + * @return string + * */ + dropColumn(tableName, columnName) { + const templateConfig = { + tableName, + columnName, + } + return assignTemplates(templates.dropColumn, templateConfig); + }, + + /** + * @param udtName {string} + * @return string + * */ + dropDomain(udtName,) { + const templateConfig = { + udtName, + } + return assignTemplates(templates.dropDomain, templateConfig); + }, + + /** + * @param udtName {string} + * @return string + * */ + dropType(udtName,) { + const templateConfig = { + udtName, + } + return assignTemplates(templates.dropType, templateConfig); + }, + + /** + * @param udtName {string} + * @param columnDefinition {string} + * @return string + * */ + alterTypeAddAttribute(udtName, columnDefinition) { + const templateConfig = { + udtName, + columnDefinition, + } + return assignTemplates(templates.alterTypeAddAttribute, templateConfig); + }, + + /** + * @param udtName {string} + * @param attributeName {string} + * @return string + * */ + alterTypeDropAttribute(udtName, attributeName) { + const templateConfig = { + udtName, + attributeName, + } + return assignTemplates(templates.alterTypeDropAttribute, templateConfig); + }, + + /** + * @param udtName {string} + * @param oldAttributeName {string} + * @param newAttributeName {string} + * @return string + * */ + alterTypeRenameAttribute(udtName, oldAttributeName, newAttributeName) { + const templateConfig = { + udtName, + oldAttributeName, + newAttributeName, + } + return assignTemplates(templates.alterTypeRenameAttribute, templateConfig); + }, + + /** + * @param udtName {string} + * @param attributeName {string} + * @param newDataType {string} + * @return string + * */ + alterTypeChangeAttributeType(udtName, attributeName, newDataType) { + const templateConfig = { + udtName, + attributeName, + newDataType, + } + return assignTemplates(templates.alterTypeChangeAttributeType, templateConfig); + }, + + /** + * @param tableName {string} + * @param fkConstraintName {string} + * @return string + * */ + dropForeignKey(tableName, fkConstraintName) { + const templateConfig = { + tableName, + fkConstraintName, + } + return assignTemplates(templates.dropForeignKey, templateConfig); + }, + + /** + * @param tableName {string} + * @param isParentActivated {boolean} + * @param keyData {{ + * name: string, + * keyType: string, + * columns: Array<{ + * isActivated: boolean, + * name: string, + * }>, + * include: Array<{ + * isActivated: boolean, + * name: string, + * }>, + * storageParameters: string, + * tablespace: string, + * }} + * @return {{ + * statement: string, + * isActivated: boolean, + * }} + * */ + createKeyConstraint(tableName, isParentActivated, keyData) { + const constraintStatementDto = createKeyConstraint(templates, isParentActivated)(keyData); + return { + statement: assignTemplates(templates.addPkConstraint, { + constraintStatement: (constraintStatementDto.statement || '').trim(), + tableName, + }), + isActivated: constraintStatementDto.isActivated, + } + }, + + /** + * @param tableName {string} + * @param constraintName {string} + * */ + dropPkConstraint(tableName, constraintName) { + const templatesConfig = { + tableName, + constraintName, + } + return assignTemplates(templates.dropConstraint, templatesConfig); + }, + }; +}; diff --git a/forward_engineering/configs/templates.js b/forward_engineering/ddlProvider/templates.js similarity index 80% rename from forward_engineering/configs/templates.js rename to forward_engineering/ddlProvider/templates.js index 81be654..b7eb3b0 100644 --- a/forward_engineering/configs/templates.js +++ b/forward_engineering/ddlProvider/templates.js @@ -39,6 +39,28 @@ module.exports = { createForeignKey: 'ALTER TABLE IF EXISTS ${foreignTable} ADD CONSTRAINT ${name} FOREIGN KEY (${foreignKey}) REFERENCES ${primaryTable}(${primaryKey})${match}${onDelete}${onUpdate};', + dropForeignKey: 'ALTER TABLE ${tableName} DROP CONSTRAINT ${fkConstraintName};', + + addPkConstraint: 'ALTER TABLE IF EXISTS ${tableName} ADD ${constraintStatement};', + + dropTable: 'DROP TABLE IF EXISTS ${tableName};', + + addColumn: 'ALTER TABLE IF EXISTS ${tableName} ADD COLUMN IF NOT EXISTS ${columnDefinition};', + + dropColumn: 'ALTER TABLE IF EXISTS ${tableName} DROP COLUMN IF EXISTS ${columnName};', + + dropDomain: 'DROP DOMAIN IF EXISTS ${udtName};', + + dropType: 'DROP TYPE IF EXISTS ${udtName};', + + alterTypeAddAttribute: 'ALTER TYPE ${udtName} ADD ATTRIBUTE ${columnDefinition};', + + alterTypeDropAttribute: 'ALTER TYPE ${udtName} DROP ATTRIBUTE IF EXISTS ${attributeName};', + + alterTypeRenameAttribute: 'ALTER TYPE ${udtName} RENAME ATTRIBUTE ${oldAttributeName} TO ${newAttributeName};', + + alterTypeChangeAttributeType: 'ALTER TYPE ${udtName} ALTER ATTRIBUTE ${attributeName} SET DATA TYPE ${newDataType};', + updateCommentOnTable: 'COMMENT ON TABLE ${tableName} IS ${comment};', updateCommentOnColumn: 'COMMENT ON COLUMN ${columnName} IS ${comment};', diff --git a/forward_engineering/enums/reservedWords.js b/forward_engineering/enums/reservedWords.js new file mode 100644 index 0000000..f1ee24f --- /dev/null +++ b/forward_engineering/enums/reservedWords.js @@ -0,0 +1,103 @@ +const ReservedWords = Object.freeze({ + ALL: 'ALL', + ANALYSE: 'ANALYSE', + ANALYZE: 'ANALYZE', + AND: 'AND', + ANY: 'ANY', + ARRAY: 'ARRAY', + ASC: 'ASC', + ASYMMETRIC: 'ASYMMETRIC', + AUTHORIZATION: 'AUTHORIZATION', + BINARY: 'BINARY', + BOTH: 'BOTH', + CASE: 'CASE', + CAST: 'CAST', + CHECK: 'CHECK', + COLLATE: 'COLLATE', + COLUMN: 'COLUMN', + CONCURRENTLY: 'CONCURRENTLY', + CONSTRAINT: 'CONSTRAINT', + CREATE: 'CREATE', + CROSS: 'CROSS', + CURRENT_CATALOG: 'CURRENT_CATALOG', + CURRENT_DATE: 'CURRENT_DATE', + CURRENT_ROLE: 'CURRENT_ROLE', + CURRENT_SCHEMA: 'CURRENT_SCHEMA', + CURRENT_TIME: 'CURRENT_TIME', + CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP', + CURRENT_USER: 'CURRENT_USER', + DEFAULT: 'DEFAULT', + DEFERRABLE: 'DEFERRABLE', + DESC: 'DESC', + DISTINCT: 'DISTINCT', + DO: 'DO', + ELSE: 'ELSE', + END: 'END', + EXCEPT: 'EXCEPT', + FALSE: 'FALSE', + FOR: 'FOR', + FOREIGN: 'FOREIGN', + FREEZE: 'FREEZE', + FROM: 'FROM', + FULL: 'FULL', + GRANT: 'GRANT', + GROUP: 'GROUP', + HAVING: 'HAVING', + ILIKE: 'ILIKE', + IN: 'IN', + INITIALLY: 'INITIALLY', + INTERSECT: 'INTERSECT', + INTO: 'INTO', + IS: 'IS', + ISNULL: 'ISNULL', + JOIN: 'JOIN', + LATERAL: 'LATERAL', + LEADING: 'LEADING', + LEFT: 'LEFT', + LIKE: 'LIKE', + LIMIT: 'LIMIT', + LOCALTIME: 'LOCALTIME', + LOCALTIMESTAMP: 'LOCALTIMESTAMP', + NATURAL: 'NATURAL', + NOT: 'NOT', + NULL: 'NULL', + OFFSET: 'OFFSET', + ON: 'ON', + ONLY: 'ONLY', + OR: 'OR', + ORDER: 'ORDER', + OUTER: 'OUTER', + OVERLAPS: 'OVERLAPS', + PLACING: 'PLACING', + PRIMARY: 'PRIMARY', + REFERENCES: 'REFERENCES', + RETURNING: 'RETURNING', + RIGHT: 'RIGHT', + SELECT: 'SELECT', + SESSION_USER: 'SESSION_USER', + SIMILAR: 'SIMILAR', + SOME: 'SOME', + SYMMETRIC: 'SYMMETRIC', + TABLE: 'TABLE', + TABLESAMPLE: 'TABLESAMPLE', + THEN: 'THEN', + TO: 'TO', + TRAILING: 'TRAILING', + TRUE: 'TRUE', + UNION: 'UNION', + UNIQUE: 'UNIQUE', + USER: 'USER', + USING: 'USING', + VARIADIC: 'VARIADIC', + VERBOSE: 'VERBOSE', + WHEN: 'WHEN', + WHERE: 'WHERE', + WINDOW: 'WINDOW', + WITH: 'WITH', +}); + +const ReservedWordsAsArray = Object.values(ReservedWords); + +module.exports = { + ReservedWordsAsArray +} diff --git a/forward_engineering/helpers/alterScriptFromDeltaHelper.js b/forward_engineering/helpers/alterScriptFromDeltaHelper.js deleted file mode 100644 index ee5bed7..0000000 --- a/forward_engineering/helpers/alterScriptFromDeltaHelper.js +++ /dev/null @@ -1,202 +0,0 @@ -const { getAddContainerScript, getDeleteContainerScript, getModifyContainerScript} = require('./alterScriptHelpers/alterContainerHelper'); -const { - getAddCollectionScript, - getDeleteCollectionScript, - getAddColumnScript, - getDeleteColumnScript, - getModifyColumnScript, getModifyCollectionScript, -} = require('./alterScriptHelpers/alterEntityHelper'); -const { - getDeleteUdtScript, - getCreateUdtScript, - getAddColumnToTypeScript, - getDeleteColumnFromTypeScript, - getModifyColumnOfTypeScript, -} = require('./alterScriptHelpers/alterUdtHelper'); -const { getAddViewScript, getDeleteViewScript, getModifyViewScript} = require('./alterScriptHelpers/alterViewHelper'); - -const getComparisonModelCollection = collections => { - return collections - .map(collection => JSON.parse(collection)) - .find(collection => collection.collectionName === 'comparisonModelCollection'); -}; - -const getAlterContainersScripts = ({ collection, app}) => { - const addedContainers = collection.properties?.containers?.properties?.added?.items; - const deletedContainers = collection.properties?.containers?.properties?.deleted?.items; - const modifiedContainers = collection.properties?.containers?.properties?.modified?.items; - - const addContainersScripts = [] - .concat(addedContainers) - .filter(Boolean) - .map(container => getAddContainerScript(app)(Object.keys(container.properties)[0])); - const deleteContainersScripts = [] - .concat(deletedContainers) - .filter(Boolean) - .map(container => getDeleteContainerScript(app)(Object.keys(container.properties)[0])); - const modifyContainersScripts = [] - .concat(modifiedContainers) - .filter(Boolean) - .map(containerWrapper => Object.values(containerWrapper.properties)[0]) - .map(container => getModifyContainerScript(app)(container)) - - return [ - ...addContainersScripts, - ...deleteContainersScripts, - ...modifyContainersScripts, - ]; -}; - -const getAlterCollectionsScripts = ({ - collection, - app, - dbVersion, - modelDefinitions, - internalDefinitions, - externalDefinitions, -}) => { - const createCollectionsScripts = [] - .concat(collection.properties?.entities?.properties?.added?.items) - .filter(Boolean) - .map(item => Object.values(item.properties)[0]) - .filter(collection => collection.compMod?.created) - .map(getAddCollectionScript({ app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions })); - const deleteCollectionScripts = [] - .concat(collection.properties?.entities?.properties?.deleted?.items) - .filter(Boolean) - .map(item => Object.values(item.properties)[0]) - .filter(collection => collection.compMod?.deleted) - .map(getDeleteCollectionScript(app)); - const modifyCollectionScripts = [] - .concat(collection.properties?.entities?.properties?.modified?.items) - .filter(Boolean) - .map(item => Object.values(item.properties)[0]) - .map(getModifyCollectionScript(app)) - .flat(); - const addColumnScripts = [] - .concat(collection.properties?.entities?.properties?.added?.items) - .filter(Boolean) - .map(item => Object.values(item.properties)[0]) - .filter(collection => !collection.compMod) - .flatMap(getAddColumnScript({ app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions })); - const deleteColumnScripts = [] - .concat(collection.properties?.entities?.properties?.deleted?.items) - .filter(Boolean) - .map(item => Object.values(item.properties)[0]) - .filter(collection => !collection.compMod) - .flatMap(getDeleteColumnScript(app)); - const modifyColumnScript = [] - .concat(collection.properties?.entities?.properties?.modified?.items) - .filter(Boolean) - .map(item => Object.values(item.properties)[0]) - .filter(collection => !collection.compMod) - .flatMap(getModifyColumnScript(app)); - - return [ - ...createCollectionsScripts, - ...deleteCollectionScripts, - ...modifyCollectionScripts, - ...addColumnScripts, - ...deleteColumnScripts, - ...modifyColumnScript, - ].map(script => script.trim()); -}; - -const getAlterViewScripts = (collection, app) => { - const createViewsScripts = [] - .concat(collection.properties?.views?.properties?.added?.items) - .filter(Boolean) - .map(item => Object.values(item.properties)[0]) - .map(view => ({ ...view, ...(view.role || {}) })) - .filter(view => view.compMod?.created && view.selectStatement) - .map(getAddViewScript(app)); - - const deleteViewsScripts = [] - .concat(collection.properties?.views?.properties?.deleted?.items) - .filter(Boolean) - .map(item => Object.values(item.properties)[0]) - .map(view => ({ ...view, ...(view.role || {}) })) - .map(getDeleteViewScript(app)); - - const modifyViewsScripts = [] - .concat(collection.properties?.views?.properties?.modified?.items) - .filter(Boolean) - .map(viewWrapper => Object.values(viewWrapper.properties)[0]) - .map(view => ({ ...view, ...(view.role || {}) })) - .flatMap(view => getModifyViewScript(app)(view)); - - return [ - ...deleteViewsScripts, - ...createViewsScripts, - ...modifyViewsScripts, - ].map(script => script.trim()); -}; - -const getAlterModelDefinitionsScripts = ({ - collection, - app, - dbVersion, - modelDefinitions, - internalDefinitions, - externalDefinitions, -}) => { - const createUdtScripts = [] - .concat(collection.properties?.modelDefinitions?.properties?.added?.items) - .filter(Boolean) - .map(item => Object.values(item.properties)[0]) - .map(item => ({ ...item, ...(app.require('lodash').omit(item.role, 'properties') || {}) })) - .filter(item => item.compMod?.created) - .map(getCreateUdtScript({ app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions })); - const deleteUdtScripts = [] - .concat(collection.properties?.modelDefinitions?.properties?.deleted?.items) - .filter(Boolean) - .map(item => Object.values(item.properties)[0]) - .map(item => ({ ...item, ...(app.require('lodash').omit(item.role, 'properties') || {}) })) - .filter(collection => collection.compMod?.deleted) - .map(getDeleteUdtScript(app)); - const addColumnScripts = [] - .concat(collection.properties?.modelDefinitions?.properties?.added?.items) - .filter(Boolean) - .map(item => Object.values(item.properties)[0]) - .filter(item => !item.compMod) - .map(item => ({ ...item, ...(app.require('lodash').omit(item.role, 'properties') || {}) })) - .filter(item => item.childType === 'composite') - .flatMap( - getAddColumnToTypeScript({ app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions }), - ); - const deleteColumnScripts = [] - .concat(collection.properties?.modelDefinitions?.properties?.deleted?.items) - .filter(Boolean) - .map(item => Object.values(item.properties)[0]) - .filter(item => !item.compMod) - .map(item => ({ ...item, ...(app.require('lodash').omit(item.role, 'properties') || {}) })) - .filter(item => item.childType === 'composite') - .flatMap(getDeleteColumnFromTypeScript(app)); - - const modifyColumnScripts = [] - .concat(collection.properties?.modelDefinitions?.properties?.modified?.items) - .filter(Boolean) - .map(item => Object.values(item.properties)[0]) - .filter(item => !item.compMod) - .map(item => ({ ...item, ...(app.require('lodash').omit(item.role, 'properties') || {}) })) - .filter(item => item.childType === 'composite') - .flatMap(getModifyColumnOfTypeScript(app)); - - return [ - ...deleteUdtScripts, - ...createUdtScripts, - ...addColumnScripts, - ...deleteColumnScripts, - ...modifyColumnScripts, - ] - .filter(Boolean) - .map(script => script.trim()); -}; - -module.exports = { - getComparisonModelCollection, - getAlterContainersScripts, - getAlterCollectionsScripts, - getAlterViewScripts, - getAlterModelDefinitionsScripts, -}; diff --git a/forward_engineering/helpers/alterScriptHelpers/alterContainerHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterContainerHelper.js deleted file mode 100644 index f286044..0000000 --- a/forward_engineering/helpers/alterScriptHelpers/alterContainerHelper.js +++ /dev/null @@ -1,35 +0,0 @@ -const {getModifySchemaCommentsScripts} = require("./containerHelpers/commentsHelper"); -const getAddContainerScript = (app) => (containerName) => { - const _ = app.require('lodash'); - const ddlProvider = require('../../ddlProvider')(null, null, app); - const {wrapInQuotes} = require('../general')({_}); - return ddlProvider.createSchemaOnly(wrapInQuotes(containerName)); -}; - -const getDeleteContainerScript = (app) => (containerName) => { - const _ = app.require('lodash'); - const ddlProvider = require('../../ddlProvider')(null, null, app); - const {wrapInQuotes} = require('../general')({_}); - - return ddlProvider.dropSchema(wrapInQuotes(containerName)); -}; - -/** - * @return (collection: Object) => Array - * */ -const getModifyContainerScript = (app) => (container) => { - const _ = app.require('lodash'); - const ddlProvider = require('../../ddlProvider')(null, null, app); - - const modifyCommentScripts = getModifySchemaCommentsScripts(_, ddlProvider)(container); - - return [ - ...modifyCommentScripts - ]; -} - -module.exports = { - getAddContainerScript, - getDeleteContainerScript, - getModifyContainerScript -}; diff --git a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js deleted file mode 100644 index 2d6eb4d..0000000 --- a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js +++ /dev/null @@ -1,154 +0,0 @@ -const {getModifyCheckConstraintScripts} = require("./entityHelpers/checkConstraintHelper"); -const {getFullTableName} = require("./ddlHelper"); -const {getModifyEntityCommentsScripts} = require("./entityHelpers/commentsHelper"); -const {getUpdateTypesScripts} = require("./columnHelpers/alterTypeHelper"); -const {getModifyNonNullColumnsScripts} = require("./columnHelpers/nonNullConstraintHelper"); -const {getModifiedCommentOnColumnScripts} = require("./columnHelpers/commentsHelper"); -const {getRenameColumnScripts} = require("./columnHelpers/renameColumnHelper"); - -const getAddCollectionScript = - ({app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions}) => - collection => { - const _ = app.require('lodash'); - const {getEntityName} = require('../../utils/general')(_); - const {createColumnDefinitionBySchema} = require('./createColumnDefinition')(app); - const ddlProvider = require('../../ddlProvider')(null, null, app); - const {getDefinitionByReference} = app.require('@hackolade/ddl-fe-utils'); - - const schemaName = collection.compMod.keyspaceName; - const schemaData = {schemaName, dbVersion}; - const jsonSchema = {...collection, ...(_.omit(collection?.role, 'properties') || {})}; - const columnDefinitions = _.toPairs(jsonSchema.properties).map(([name, column]) => { - const definitionJsonSchema = getDefinitionByReference({ - propertySchema: column, - modelDefinitions, - internalDefinitions, - externalDefinitions, - }); - - return createColumnDefinitionBySchema({ - name, - jsonSchema: column, - parentJsonSchema: jsonSchema, - ddlProvider, - schemaData, - definitionJsonSchema, - }); - }); - const checkConstraints = (jsonSchema.chkConstr || []).map(check => - ddlProvider.createCheckConstraint(ddlProvider.hydrateCheckConstraint(check)), - ); - const tableData = { - name: getEntityName(jsonSchema), - columns: columnDefinitions.map(ddlProvider.convertColumnDefinition), - checkConstraints: checkConstraints, - foreignKeyConstraints: [], - schemaData, - columnDefinitions, - dbData: {dbVersion}, - }; - const hydratedTable = ddlProvider.hydrateTable({tableData, entityData: [jsonSchema], jsonSchema}); - - return ddlProvider.createTable(hydratedTable, jsonSchema.isActivated); - }; - -const getDeleteCollectionScript = app => collection => { - const _ = app.require('lodash'); - const fullName = getFullTableName(_)(collection); - return `DROP TABLE IF EXISTS ${fullName};`; -}; - -/** - * @return (collection: Object) => Array - * */ -const getModifyCollectionScript = (app) => (collection) => { - const _ = app.require('lodash'); - const ddlProvider = require('../../ddlProvider')(null, null, app); - - const modifyCheckConstraintScripts = getModifyCheckConstraintScripts(_, ddlProvider)(collection); - const modifyCommentScripts = getModifyEntityCommentsScripts(_, ddlProvider)(collection); - return [ - ...modifyCheckConstraintScripts, - ...modifyCommentScripts - ]; -} - -const getAddColumnScript = - ({app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions}) => - collection => { - const _ = app.require('lodash'); - const {getEntityName} = require('../../utils/general')(_); - const {getNamePrefixedWithSchemaName} = require('../general')({_}); - const {createColumnDefinitionBySchema} = require('./createColumnDefinition')(app); - const ddlProvider = require('../../ddlProvider')(null, null, app); - const {getDefinitionByReference} = app.require('@hackolade/ddl-fe-utils'); - - const collectionSchema = {...collection, ...(_.omit(collection?.role, 'properties') || {})}; - const tableName = getEntityName(collectionSchema); - const schemaName = collectionSchema.compMod?.keyspaceName; - const fullName = getNamePrefixedWithSchemaName(tableName, schemaName); - const schemaData = {schemaName, dbVersion}; - - return _.toPairs(collection.properties) - .filter(([name, jsonSchema]) => !jsonSchema.compMod) - .map(([name, jsonSchema]) => { - const definitionJsonSchema = getDefinitionByReference({ - propertySchema: jsonSchema, - modelDefinitions, - internalDefinitions, - externalDefinitions, - }); - - return createColumnDefinitionBySchema({ - name, - jsonSchema, - parentJsonSchema: collectionSchema, - ddlProvider, - schemaData, - definitionJsonSchema, - }); - }) - .map(ddlProvider.convertColumnDefinition) - .map(script => `ALTER TABLE IF EXISTS ${fullName} ADD COLUMN IF NOT EXISTS ${script};`); - }; - -const getDeleteColumnScript = app => collection => { - const _ = app.require('lodash'); - const {getEntityName} = require('../../utils/general')(_); - const {getNamePrefixedWithSchemaName, wrapInQuotes} = require('../general')({_}); - - const collectionSchema = {...collection, ...(_.omit(collection?.role, 'properties') || {})}; - const tableName = getEntityName(collectionSchema); - const schemaName = collectionSchema.compMod?.keyspaceName; - const fullName = getNamePrefixedWithSchemaName(tableName, schemaName); - - return _.toPairs(collection.properties) - .filter(([name, jsonSchema]) => !jsonSchema.compMod) - .map(([name]) => `ALTER TABLE IF EXISTS ${fullName} DROP COLUMN IF EXISTS ${wrapInQuotes(name)};`); -}; - -const getModifyColumnScript = app => collection => { - const _ = app.require('lodash'); - const ddlProvider = require('../../ddlProvider')(null, null, app); - - const renameColumnScripts = getRenameColumnScripts(_, ddlProvider)(collection); - const updateTypeScripts = getUpdateTypesScripts(_, ddlProvider)(collection); - const modifyNotNullScripts = getModifyNonNullColumnsScripts(_, ddlProvider)(collection); - const modifyCommentScripts = getModifiedCommentOnColumnScripts(_, ddlProvider)(collection); - - return [ - ...renameColumnScripts, - ...updateTypeScripts, - ...modifyNotNullScripts, - ...modifyCommentScripts, - ]; -}; - -module.exports = { - getAddCollectionScript, - getDeleteCollectionScript, - getModifyCollectionScript, - getAddColumnScript, - getDeleteColumnScript, - getModifyColumnScript, -}; diff --git a/forward_engineering/helpers/alterScriptHelpers/alterUdtHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterUdtHelper.js deleted file mode 100644 index 67a6450..0000000 --- a/forward_engineering/helpers/alterScriptHelpers/alterUdtHelper.js +++ /dev/null @@ -1,135 +0,0 @@ -const { checkFieldPropertiesChanged } = require('./common'); - -const getCreateUdtScript = - ({ app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions }) => - jsonSchema => { - const _ = app.require('lodash'); - const { createColumnDefinitionBySchema } = require('./createColumnDefinition')(app); - const ddlProvider = require('../../ddlProvider')(null, null, app); - const { getDefinitionByReference } = app.require('@hackolade/ddl-fe-utils'); - - const schemaData = { dbVersion }; - - const columnDefinitions = _.toPairs(jsonSchema.properties || {}).map(([name, column]) => { - const definitionJsonSchema = getDefinitionByReference({ - propertySchema: column, - modelDefinitions, - internalDefinitions, - externalDefinitions, - }); - - return createColumnDefinitionBySchema({ - name, - jsonSchema: column, - parentJsonSchema: jsonSchema, - ddlProvider, - schemaData, - definitionJsonSchema, - }); - }); - - const updatedUdt = createColumnDefinitionBySchema({ - name: jsonSchema.code || jsonSchema.name, - jsonSchema: jsonSchema, - parentJsonSchema: { required: [] }, - definitionJsonSchema: {}, - ddlProvider, - schemaData, - }); - - const udt = { ...updatedUdt, properties: columnDefinitions }; - - return ddlProvider.createUdt(udt); - }; - -const getDeleteUdtScript = app => udt => { - const _ = app.require('lodash'); - const { wrapInQuotes } = require('../general')({ _ }); - - if (udt.type === 'domain') { - return `DROP DOMAIN IF EXISTS ${wrapInQuotes(udt.code || udt.name)};`; - } else { - return `DROP TYPE IF EXISTS ${wrapInQuotes(udt.code || udt.name)};`; - } -}; - -const getAddColumnToTypeScript = - ({ app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions }) => - udt => { - const _ = app.require('lodash'); - const { createColumnDefinitionBySchema } = require('./createColumnDefinition')(app); - const { wrapInQuotes } = require('../general')({ _ }); - const ddlProvider = require('../../ddlProvider')(null, null, app); - const { getDefinitionByReference } = app.require('@hackolade/ddl-fe-utils'); - - const fullName = wrapInQuotes(udt.code || udt.name); - const schemaData = { dbVersion }; - - return _.toPairs(udt.properties) - .filter(([name, jsonSchema]) => !jsonSchema.compMod) - .map(([name, jsonSchema]) => { - const definitionJsonSchema = getDefinitionByReference({ - propertySchema: jsonSchema, - modelDefinitions, - internalDefinitions, - externalDefinitions, - }); - - return createColumnDefinitionBySchema({ - name, - jsonSchema, - parentJsonSchema: { required: [] }, - ddlProvider, - schemaData, - definitionJsonSchema, - }); - }) - .map(ddlProvider.convertColumnDefinition) - .map(script => `ALTER TYPE ${fullName} ADD ATTRIBUTE ${script};`); - }; - -const getDeleteColumnFromTypeScript = app => udt => { - const _ = app.require('lodash'); - const { wrapInQuotes } = require('../general')({ _ }); - - const fullName = wrapInQuotes(udt.code || udt.name); - - return _.toPairs(udt.properties) - .filter(([name, jsonSchema]) => !jsonSchema.compMod) - .map(([name]) => `ALTER TYPE ${fullName} DROP ATTRIBUTE IF EXISTS ${wrapInQuotes(name)};`); -}; - -const getModifyColumnOfTypeScript = app => udt => { - const _ = app.require('lodash'); - const { wrapInQuotes } = require('../general')({ _ }); - - const fullName = wrapInQuotes(udt.code || udt.name); - - const renameColumnScripts = _.values(udt.properties) - .filter(jsonSchema => checkFieldPropertiesChanged(jsonSchema.compMod, ['name'])) - .map( - jsonSchema => - `ALTER TYPE ${fullName} RENAME ATTRIBUTE ${wrapInQuotes( - jsonSchema.compMod.oldField.name, - )} TO ${wrapInQuotes(jsonSchema.compMod.newField.name)};`, - ); - - const changeTypeScripts = _.toPairs(udt.properties) - .filter(([name, jsonSchema]) => checkFieldPropertiesChanged(jsonSchema.compMod, ['type', 'mode'])) - .map( - ([name, jsonSchema]) => - `ALTER TYPE ${fullName} ALTER ATTRIBUTE ${wrapInQuotes(name)} SET DATA TYPE ${ - jsonSchema.compMod.newField.mode || jsonSchema.compMod.newField.type - };`, - ); - - return [...renameColumnScripts, ...changeTypeScripts]; -}; - -module.exports = { - getCreateUdtScript, - getDeleteUdtScript, - getAddColumnToTypeScript, - getDeleteColumnFromTypeScript, - getModifyColumnOfTypeScript, -}; diff --git a/forward_engineering/helpers/alterScriptHelpers/alterViewHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterViewHelper.js deleted file mode 100644 index a2379ef..0000000 --- a/forward_engineering/helpers/alterScriptHelpers/alterViewHelper.js +++ /dev/null @@ -1,48 +0,0 @@ -const {getModifyViewCommentsScripts} = require("./viewHelpers/commentsHelper"); -/** - * @return (view: Object) => string - * */ -const getAddViewScript = app => view => { - const ddlProvider = require('../../ddlProvider')(null, null, app); - - const viewData = { - name: view.code || view.name, - keys: [], - schemaData: { schemaName: '' }, - }; - const hydratedView = ddlProvider.hydrateView({ viewData, entityData: [view] }); - - return ddlProvider.createView(hydratedView, {}, view.isActivated); -}; - -/** - * @return (view: Object) => string - * */ -const getDeleteViewScript = app => view => { - const _ = app.require('lodash'); - const ddlProvider = require('../../ddlProvider')(null, null, app); - const { wrapInQuotes } = require('../general')({ _ }); - const viewName = wrapInQuotes(view.code || view.name); - - return ddlProvider.dropView(viewName); -}; - -/** - * @return (view: Object) => Array - * */ -const getModifyViewScript = (app) => (view) => { - const _ = app.require('lodash'); - const ddlProvider = require('../../ddlProvider')(null, null, app); - - const modifyCommentsScripts = getModifyViewCommentsScripts(_, ddlProvider)(view); - - return [ - ...modifyCommentsScripts, - ]; -} - -module.exports = { - getAddViewScript, - getDeleteViewScript, - getModifyViewScript, -}; diff --git a/forward_engineering/helpers/alterScriptHelpers/columnHelpers/renameColumnHelper.js b/forward_engineering/helpers/alterScriptHelpers/columnHelpers/renameColumnHelper.js deleted file mode 100644 index ff2e0e3..0000000 --- a/forward_engineering/helpers/alterScriptHelpers/columnHelpers/renameColumnHelper.js +++ /dev/null @@ -1,21 +0,0 @@ -const {getFullTableName} = require("../ddlHelper"); -const {checkFieldPropertiesChanged} = require("../common"); - -const getRenameColumnScripts = (_, ddlProvider) => (collection) => { - const fullTableName = getFullTableName(_)(collection); - const {wrapInQuotes} = require('../../general')({_}); - - return _.values(collection.properties) - .filter(jsonSchema => checkFieldPropertiesChanged(jsonSchema.compMod, ['name'])) - .map( - jsonSchema => { - const oldColumnName = wrapInQuotes(jsonSchema.compMod.oldField.name); - const newColumnName = wrapInQuotes(jsonSchema.compMod.newField.name); - return ddlProvider.renameColumn(fullTableName, oldColumnName, newColumnName); - } - ); -} - -module.exports = { - getRenameColumnScripts -} diff --git a/forward_engineering/helpers/alterScriptHelpers/common.js b/forward_engineering/helpers/alterScriptHelpers/common.js deleted file mode 100644 index 64ae513..0000000 --- a/forward_engineering/helpers/alterScriptHelpers/common.js +++ /dev/null @@ -1,7 +0,0 @@ -const checkFieldPropertiesChanged = (compMod, propertiesToCheck) => { - return propertiesToCheck.some(prop => compMod?.oldField[prop] !== compMod?.newField[prop]); -}; - -module.exports = { - checkFieldPropertiesChanged, -}; diff --git a/forward_engineering/helpers/alterScriptHelpers/containerHelpers/commentsHelper.js b/forward_engineering/helpers/alterScriptHelpers/containerHelpers/commentsHelper.js deleted file mode 100644 index 2435c91..0000000 --- a/forward_engineering/helpers/alterScriptHelpers/containerHelpers/commentsHelper.js +++ /dev/null @@ -1,49 +0,0 @@ - -const extractDescription = (container) => { - return container?.role?.compMod?.description || {}; -} - -/** - * @return (container: Object) => string - * */ -const getUpsertCommentsScript = (_, ddlProvider) => (container) => { - const {wrapComment, wrapInQuotes} = require('../../general')({_}); - - const description = extractDescription(container); - if (description.new && description.new !== description.old) { - const wrappedComment = wrapComment(description.new); - const wrappedSchemaName = wrapInQuotes(container.role.name); - return ddlProvider.updateSchemaComment(wrappedSchemaName, wrappedComment); - } - return ''; -} - -/** - * @return (container: Object) => string - * */ -const getDropCommentsScript = (_, ddlProvider) => (container) => { - const {wrapInQuotes} = require('../../general')({_}); - - const description = extractDescription(container); - if (description.old && !description.new) { - const wrappedSchemaName = wrapInQuotes(container.role.name); - return ddlProvider.dropSchemaComment(wrappedSchemaName); - } - return ''; -} - -/** - * @return (container: Object) => Array - * */ -const getModifySchemaCommentsScripts = (_, ddlProvider) => (container) => { - const upsertCommentScript = getUpsertCommentsScript(_, ddlProvider)(container); - const dropCommentScript = getDropCommentsScript(_, ddlProvider)(container); - return [ - upsertCommentScript, - dropCommentScript - ].filter(Boolean); -} - -module.exports = { - getModifySchemaCommentsScripts -} diff --git a/forward_engineering/helpers/alterScriptHelpers/ddlHelper.js b/forward_engineering/helpers/alterScriptHelpers/ddlHelper.js deleted file mode 100644 index 9bc59e3..0000000 --- a/forward_engineering/helpers/alterScriptHelpers/ddlHelper.js +++ /dev/null @@ -1,32 +0,0 @@ -const getFullTableName = (_) => (collection) => { - const {getEntityName} = require('../../utils/general')(_); - const {getNamePrefixedWithSchemaName} = require('../general')({_}); - - const collectionSchema = {...collection, ...(_.omit(collection?.role, 'properties') || {})}; - const tableName = getEntityName(collectionSchema); - const schemaName = collectionSchema.compMod?.keyspaceName; - return getNamePrefixedWithSchemaName(tableName, schemaName); -} - -const getFullColumnName = (_) => (collection, columnName) => { - const {wrapInQuotes} = require('../general')({_}); - - const fullTableName = getFullTableName(_)(collection); - return `${fullTableName}.${wrapInQuotes(columnName)}`; -} - -const getFullViewName = (_) => (view) => { - const {getViewName} = require('../../utils/general')(_); - const {getNamePrefixedWithSchemaName} = require('../general')({_}); - - const viewSchema = {...view, ...(_.omit(view?.role, 'properties') || {})}; - const viewName = getViewName(viewSchema); - const schemaName = viewSchema.compMod?.keyspaceName; - return getNamePrefixedWithSchemaName(viewName, schemaName); -} - -module.exports = { - getFullTableName, - getFullColumnName, - getFullViewName, -} diff --git a/forward_engineering/helpers/alterScriptHelpers/entityHelpers/commentsHelper.js b/forward_engineering/helpers/alterScriptHelpers/entityHelpers/commentsHelper.js deleted file mode 100644 index d2b067c..0000000 --- a/forward_engineering/helpers/alterScriptHelpers/entityHelpers/commentsHelper.js +++ /dev/null @@ -1,59 +0,0 @@ -const {getFullTableName} = require("../ddlHelper"); - -/** - * @return (collection: Object) => string - */ -const getUpdatedCommentOnCollectionScript = (_, ddlProvider) => (collection) => { - const {wrapComment} = require('../../general')({_}); - - const descriptionInfo = collection?.role.compMod?.description; - if (!descriptionInfo) { - return ''; - } - - const {old: oldComment, new: newComment} = descriptionInfo; - if (!newComment || newComment === oldComment) { - return ''; - } - - const tableName = getFullTableName(_)(collection); - const comment = wrapComment(newComment); - - return ddlProvider.updateTableComment(tableName, comment); -} - -/** - * @return (collection: Object) => string - */ -const getDeletedCommentOnCollectionScript = (_, ddlProvider) => (collection) => { - const descriptionInfo = collection?.role.compMod?.description; - if (!descriptionInfo) { - return ''; - } - - const {old: oldComment, new: newComment} = descriptionInfo; - if (!oldComment || newComment) { - return ''; - } - - const tableName = getFullTableName(_)(collection); - - return ddlProvider.dropTableComment(tableName); -} - -/** - * @return {(collection: Object) => Array} - * */ -const getModifyEntityCommentsScripts = (_, ddlProvider) => collection => { - const updatedCommentScript = getUpdatedCommentOnCollectionScript(_, ddlProvider)(collection); - const deletedCommentScript = getDeletedCommentOnCollectionScript(_, ddlProvider)(collection); - - return [ - updatedCommentScript, - deletedCommentScript - ].filter(Boolean); -}; - -module.exports = { - getModifyEntityCommentsScripts -} diff --git a/forward_engineering/helpers/alterScriptHelpers/viewHelpers/commentsHelper.js b/forward_engineering/helpers/alterScriptHelpers/viewHelpers/commentsHelper.js deleted file mode 100644 index 6043495..0000000 --- a/forward_engineering/helpers/alterScriptHelpers/viewHelpers/commentsHelper.js +++ /dev/null @@ -1,48 +0,0 @@ -const {getFullViewName} = require("../ddlHelper"); - -const extractDescription = (view) => { - return view?.role?.compMod?.description || {}; -} - -/** - * @return (view: Object) => string - * */ -const getUpsertCommentsScript = (_, ddlProvider) => (view) => { - const {wrapComment} = require('../../general')({_}); - - const description = extractDescription(view); - if (description.new && description.new !== description.old) { - const wrappedComment = wrapComment(description.new); - const viewName = getFullViewName(_)(view); - return ddlProvider.updateViewComment(viewName, wrappedComment); - } - return ''; -} - -/** - * @return (view: Object) => string - * */ -const getDropCommentsScript = (_, ddlProvider) => (view) => { - const description = extractDescription(view); - if (description.old && !description.new) { - const viewName = getFullViewName(_)(view); - return ddlProvider.dropViewComment(viewName); - } - return ''; -} - -/** - * @return (view: Object) => Array - * */ -const getModifyViewCommentsScripts = (_, ddlProvider) => (view) => { - const upsertCommentScript = getUpsertCommentsScript(_, ddlProvider)(view); - const dropCommentScript = getDropCommentsScript(_, ddlProvider)(view); - return [ - upsertCommentScript, - dropCommentScript - ].filter(Boolean); -} - -module.exports = { - getModifyViewCommentsScripts -} diff --git a/forward_engineering/helpers/commentDropStatements.js b/forward_engineering/helpers/commentDropStatements.js deleted file mode 100644 index e37e97d..0000000 --- a/forward_engineering/helpers/commentDropStatements.js +++ /dev/null @@ -1,50 +0,0 @@ -const { DROP_STATEMENTS } = require('./constants'); - -const isDropNotNullStatementRegex = /ALTER TABLE IF EXISTS .+ ALTER COLUMN .+ DROP NOT NULL;/; - -const isDropConstraintStatementRegex = /ALTER TABLE IF EXISTS .+ DROP CONSTRAINT IF EXISTS .+;/; - -const dropCommentRegex = /COMMENT ON (TABLE|SCHEMA|VIEW|COLUMN) .+ IS NULL;/; - -/** - * @param scriptLine {string} - * @return {boolean} - * */ -const shouldStatementBeCommentedOut = (scriptLine) => { - const doesContainDropStatements = DROP_STATEMENTS.some(statement => scriptLine.includes(statement)); - if (doesContainDropStatements) { - return true; - } - - return [ - isDropNotNullStatementRegex, - isDropConstraintStatementRegex, - dropCommentRegex, - ].some(regex => regex.test(scriptLine)); -} - -/** - * @param script {string} - * @return {boolean} - * */ -const doesScriptContainDropStatements = (script) => { - return script.split('\n') - .some(shouldStatementBeCommentedOut); -} - - -const commentDropStatements = (script = '') => - script - .split('\n') - .map(line => { - if (shouldStatementBeCommentedOut(line)) { - return `-- ${line}`; - } - return line; - }) - .join('\n'); - -module.exports = { - commentDropStatements, - doesScriptContainDropStatements, -}; diff --git a/forward_engineering/helpers/constants.js b/forward_engineering/helpers/constants.js deleted file mode 100644 index 5c9cba7..0000000 --- a/forward_engineering/helpers/constants.js +++ /dev/null @@ -1,13 +0,0 @@ -const DROP_STATEMENTS = [ - 'DROP SCHEMA', - 'DROP TABLE', - 'DROP COLUMN', - 'DROP DOMAIN', - 'DROP TYPE', - 'DROP ATTRIBUTE', - 'DROP VIEW', -]; - -module.exports = { - DROP_STATEMENTS, -}; diff --git a/forward_engineering/helpers/constraintsHelper.js b/forward_engineering/helpers/constraintsHelper.js deleted file mode 100644 index 202e755..0000000 --- a/forward_engineering/helpers/constraintsHelper.js +++ /dev/null @@ -1,106 +0,0 @@ -module.exports = ({ - _, - commentIfDeactivated, - checkAllKeysDeactivated, - assignTemplates, - wrapInQuotes, - getColumnsList, -}) => { - const generateConstraintsString = (dividedConstraints, isParentActivated) => { - const deactivatedItemsAsString = commentIfDeactivated( - (dividedConstraints?.deactivatedItems || []).join(',\n\t'), - { - isActivated: !isParentActivated, - isPartOfLine: true, - }, - ); - const activatedConstraints = dividedConstraints?.activatedItems?.length - ? ',\n\t' + dividedConstraints.activatedItems.join(',\n\t') - : ''; - - const deactivatedConstraints = dividedConstraints?.deactivatedItems?.length - ? '\n\t' + deactivatedItemsAsString - : ''; - - return activatedConstraints + deactivatedConstraints; - }; - - const foreignKeysToString = keys => { - if (Array.isArray(keys)) { - const activatedKeys = keys - .filter(key => _.get(key, 'isActivated', true)) - .map(key => wrapInQuotes(_.trim(key.name))); - const deactivatedKeys = keys - .filter(key => !_.get(key, 'isActivated', true)) - .map(key => wrapInQuotes(_.trim(key.name))); - const deactivatedKeysAsString = deactivatedKeys.length - ? commentIfDeactivated(deactivatedKeys, { isActivated: false, isPartOfLine: true }) - : ''; - - return activatedKeys.join(', ') + deactivatedKeysAsString; - } - return keys; - }; - - const foreignActiveKeysToString = keys => { - return keys.map(key => _.trim(key.name)).join(', '); - }; - - const createKeyConstraint = (templates, isParentActivated) => keyData => { - const constraintName = wrapInQuotes(_.trim(keyData.name)); - const isAllColumnsDeactivated = checkAllKeysDeactivated(keyData.columns || []); - const columns = !_.isEmpty(keyData.columns) - ? getColumnsList(keyData.columns, isAllColumnsDeactivated, isParentActivated) - : ''; - const includeNonKey = keyData.include.length - ? ` INCLUDE${getColumnsList(keyData.include, isAllColumnsDeactivated, isParentActivated)}` - : ''; - const storageParameters = keyData.storageParameters ? ` WITH (${keyData.storageParameters})` : ''; - const tablespace = keyData.tablespace ? ` USING INDEX TABLESPACE ${wrapInQuotes(keyData.tablespace)}` : ''; - - return { - statement: assignTemplates(templates.createKeyConstraint, { - constraintName: keyData.name ? `CONSTRAINT ${wrapInQuotes(constraintName)} ` : '', - keyType: keyData.keyType, - columns, - includeNonKey, - storageParameters, - tablespace, - }), - isActivated: !isAllColumnsDeactivated, - }; - }; - - const getConstraintsWarnings = (invalidConstraints = []) => { - if (_.isEmpty(invalidConstraints)) { - return ''; - } - - return ( - '\n\t' + - invalidConstraints - .map(keyData => { - const constraintName = keyData.name ? ` [constraint name: ${keyData.name}]` : ''; - - return `-- ${keyData.errorMessage}${constraintName}`; - }) - .join('\n\t') - ); - }; - - const additionalPropertiesForForeignKey = relationship => { - const foreignOnDelete = _.get(relationship, 'relationshipOnDelete', ''); - const foreignOnUpdate = _.get(relationship, 'relationshipOnUpdate', ''); - const foreignMatch = _.get(relationship, 'relationshipMatch', ''); - return { foreignOnDelete, foreignOnUpdate, foreignMatch }; - }; - - return { - generateConstraintsString, - foreignKeysToString, - foreignActiveKeysToString, - createKeyConstraint, - getConstraintsWarnings, - additionalPropertiesForForeignKey, - }; -}; diff --git a/forward_engineering/helpers/general.js b/forward_engineering/helpers/general.js deleted file mode 100644 index d110fd1..0000000 --- a/forward_engineering/helpers/general.js +++ /dev/null @@ -1,203 +0,0 @@ -const POSTGRES_RESERVED_WORDS = [ - 'ALL', - 'ANALYSE', - 'ANALYZE', - 'AND', - 'ANY', - 'ARRAY', - 'ASC', - 'ASYMMETRIC', - 'AUTHORIZATION', - 'BINARY', - 'BOTH', - 'CASE', - 'CAST', - 'CHECK', - 'COLLATE', - 'COLUMN', - 'CONCURRENTLY', - 'CONSTRAINT', - 'CREATE', - 'CROSS', - 'CURRENT_CATALOG', - 'CURRENT_DATE', - 'CURRENT_ROLE', - 'CURRENT_SCHEMA', - 'CURRENT_TIME', - 'CURRENT_TIMESTAMP', - 'CURRENT_USER', - 'DEFAULT', - 'DEFERRABLE', - 'DESC', - 'DISTINCT', - 'DO', - 'ELSE', - 'END', - 'EXCEPT', - 'FALSE', - 'FOR', - 'FOREIGN', - 'FREEZE', - 'FROM', - 'FULL', - 'GRANT', - 'GROUP', - 'HAVING', - 'ILIKE', - 'IN', - 'INITIALLY', - 'INTERSECT', - 'INTO', - 'IS', - 'ISNULL', - 'JOIN', - 'LATERAL', - 'LEADING', - 'LEFT', - 'LIKE', - 'LIMIT', - 'LOCALTIME', - 'LOCALTIMESTAMP', - 'NATURAL', - 'NOT', - 'NULL', - 'OFFSET', - 'ON', - 'ONLY', - 'OR', - 'ORDER', - 'OUTER', - 'OVERLAPS', - 'PLACING', - 'PRIMARY', - 'REFERENCES', - 'RETURNING', - 'RIGHT', - 'SELECT', - 'SESSION_USER', - 'SIMILAR', - 'SOME', - 'SYMMETRIC', - 'TABLE', - 'TABLESAMPLE', - 'THEN', - 'TO', - 'TRAILING', - 'TRUE', - 'UNION', - 'UNIQUE', - 'USER', - 'USING', - 'VARIADIC', - 'VERBOSE', - 'WHEN', - 'WHERE', - 'WINDOW', - 'WITH', -]; - -const MUST_BE_ESCAPED = /\t|\n|'|\f|\r/gm; - -module.exports = ({ _, divideIntoActivatedAndDeactivated, commentIfDeactivated }) => { - const getFunctionArguments = functionArguments => { - return _.map(functionArguments, arg => { - const defaultExpression = arg.defaultExpression ? `DEFAULT ${arg.defaultExpression}` : ''; - - return _.trim(`${arg.argumentMode} ${arg.argumentName || ''} ${arg.argumentType} ${defaultExpression}`); - }).join(', '); - }; - - const getNamePrefixedWithSchemaName = (name, schemaName) => { - if (schemaName) { - return `${wrapInQuotes(schemaName)}.${wrapInQuotes(name)}`; - } - - return wrapInQuotes(name); - }; - - const wrapInQuotes = name => - /\s|\W/.test(name) || _.includes(POSTGRES_RESERVED_WORDS, _.toUpper(name)) ? `"${name}"` : name; - - const columnMapToString = ({ name }) => wrapInQuotes(name); - - const getColumnsList = (columns, isAllColumnsDeactivated, isParentActivated, mapColumn = columnMapToString) => { - const dividedColumns = divideIntoActivatedAndDeactivated(columns, mapColumn); - const deactivatedColumnsAsString = dividedColumns?.deactivatedItems?.length - ? commentIfDeactivated(dividedColumns.deactivatedItems.join(', '), { - isActivated: false, - isPartOfLine: true, - }) - : ''; - - return !isAllColumnsDeactivated && isParentActivated - ? ' (' + dividedColumns.activatedItems.join(', ') + deactivatedColumnsAsString + ')' - : ' (' + columns.map(mapColumn).join(', ') + ')'; - }; - - const getKeyWithAlias = key => { - if (!key) { - return ''; - } - - if (key.alias) { - return `${wrapInQuotes(key.name)} as ${wrapInQuotes(key.alias)}`; - } else { - return wrapInQuotes(key.name); - } - }; - - const getViewData = keys => { - if (!Array.isArray(keys)) { - return { tables: [], columns: [] }; - } - - return keys.reduce( - (result, key) => { - if (!key.tableName) { - result.columns.push(getKeyWithAlias(key)); - - return result; - } - - let tableName = wrapInQuotes(key.tableName); - - if (!result.tables.includes(tableName)) { - result.tables.push(tableName); - } - - result.columns.push({ - statement: `${tableName}.${getKeyWithAlias(key)}`, - isActivated: key.isActivated, - }); - - return result; - }, - { - tables: [], - columns: [], - }, - ); - }; - - const prepareComment = (comment = '') => - comment.replace(MUST_BE_ESCAPED, character => `${'\\'}${character}`); - - - const wrapComment = comment => `E'${prepareComment(JSON.stringify(comment)).slice(1, -1)}'`; - - const getDbVersion = (dbVersion = '') => { - const version = dbVersion.match(/\d+/); - - return Number(_.get(version, [0], 0)); - }; - - return { - getFunctionArguments, - getNamePrefixedWithSchemaName, - wrapInQuotes, - getColumnsList, - getViewData, - wrapComment, - getDbVersion, - }; -}; diff --git a/forward_engineering/types/coreApplicationDataTypes.js b/forward_engineering/types/coreApplicationDataTypes.js new file mode 100644 index 0000000..9f248bd --- /dev/null +++ b/forward_engineering/types/coreApplicationDataTypes.js @@ -0,0 +1,215 @@ + +class ContainerJsonSchema { + /** + * @type {string} + */ + name + + /** + * @type {boolean} + */ + isActivated +} + +class ContainerStyles { + /** + * @type {Object} + * */ + backgroundColor +} + +class EntityData { + + /** + * @type {string | undefined} + */ + collectionName + + /** + * @type {boolean | undefined} + */ + isActivated + + /** + * @type {string | undefined} + */ + bucketId + + /** + * @type {any | undefined} + */ + additionalProperties + + /** + * @type {boolean | undefined} + */ + tableIfNotExists +} + +class InternalDefinitions { + + /** + * @type {string} + */ + $schema + + /** + * @type {"definitions"} + */ + type + + /** + * @type {string} + */ + GUID +} + +class ModelDefinitions { + + /** + * @type {string} + */ + $schema + + /** + * @type {"definitions"} + */ + type + + /** + * @type {string} + */ + GUID +} + +class ExternalDefinitions { + + /** + * @type {string} + */ + $schema + + /** + * @type {"externalDefinitions"} + */ + type + + /** + * @type {string} + */ + GUID +} + +class FieldJsonSchema { + + /** + * @type {string} + */ + type + + /** + * @type {boolean} + */ + isActivated + + /** + * @type {string} + */ + mode + + /** + * @type {string} + */ + subtype + + /** + * @type {[ + * "compositePartitionKey", + * "compositeClusteringKey", + * "compositePrimaryKey", + * "compositeUniqueKey", + * ]} + */ + compositeKey + + /** + * @type {boolean} + */ + compositePartitionKey + + /** + * @type {boolean} + */ + compositeClusteringKey + + /** + * @type {boolean} + */ + compositePrimaryKey + + /** + * @type {boolean} + */ + compositeUniqueKey + + /** + * @type {string} + */ + GUID +} + +class EntityJsonSchema { + + /** + * @type {string} + */ + $schema + + /** + * @type {"object"} + */ + type + + /** + * @type {string} + */ + title + + /** + * @type {{ + * [fieldName: string]: FieldJsonSchema + * }} + */ + properties + + /** + * @type {boolean} + */ + isActivated + + /** + * @type {boolean} + */ + additionalProperties + + /** + * @type {boolean} + */ + tableIfNotExists + + /** + * @type {string} + */ + GUID +} + +module.exports = { + ContainerJsonSchema, + ContainerStyles, + EntityData, + InternalDefinitions, + ModelDefinitions, + ExternalDefinitions, + FieldJsonSchema, + EntityJsonSchema, +} diff --git a/forward_engineering/types/coreApplicationTypes.js b/forward_engineering/types/coreApplicationTypes.js new file mode 100644 index 0000000..d5a0b8a --- /dev/null +++ b/forward_engineering/types/coreApplicationTypes.js @@ -0,0 +1,158 @@ +class PluginError { + /** + * @type string + */ + message + + /** + * @type {string | undefined} + */ + stack +} + +class App { + + /** + * @type {(library: string) => any} + * */ + require +} + +class Logger { + + /** + * @type {(level: string, additionalInfoDto: Object, message: string, hiddenKeys?: any) => void} + * */ + log + + /** + * @type {() => void} + * */ + clear +} + +class CoreData { + /** + * @type {string} + */ + jsonSchema + + /** + * @type {string} + */ + modelDefinitions + + /** + * @type {string} + */ + internalDefinitions + + /** + * @type {string} + */ + externalDefinitions + + /** + * @type {any} + */ + containerData + + /** + * @type {any} + */ + entityData + + /** + * @type {any} + */ + entities + + /** + * @type {Array} + */ + views + + /** + * @type {Object | undefined} + */ + viewData + + /** + * @type {Array} + */ + relationships + + /** + * @type {Object | undefined} + */ + collectionRefsDefinitionsMap + + /** + * @type {boolean} + */ + isUpdateScript + + /** + * @type {'container' | 'entity'} + */ + level + + /** + * @type {string | undefined} + */ + host + + /** + * @type {string | undefined} + */ + clusterId + + /** + * @type {string | undefined} + */ + accessToken + + /** + * @type {string | number | undefined} + */ + applyToInstanceQueryRequestTimeout + + /** + * @type {string | undefined} + */ + script + + /** + * @type {any | undefined} + */ + hiddenKeys + + /** + * @type {Array<{ + * id: string, + * value: any, + * }> | {separateBucket: boolean}} + */ + options + + /** + * @type {[ + * { + * modelName: string, + * dbVendor: string, + * dbVersion: string, + * isLineageEnabled: boolean + * }, + * { relationships: [] }, + * { sources: [] } + * ]} + * */ + modelData +} + +module.exports = { + App, + CoreData, + Logger, + PluginError, +} diff --git a/forward_engineering/utils/general.js b/forward_engineering/utils/general.js index 5432b00..1438f59 100644 --- a/forward_engineering/utils/general.js +++ b/forward_engineering/utils/general.js @@ -7,6 +7,11 @@ * the agreement/contract under which the software has been supplied. */ +const {AlterCollectionDto, AlterCollectionRoleDto} = require('../alterScript/types/AlterCollectionDto'); + +const {ReservedWordsAsArray} = require("../enums/reservedWords"); +const MUST_BE_ESCAPED = /\t|\n|'|\f|\r/gm; + module.exports = _ => { const getDbName = containerData => { return _.get(containerData, '[0].code') || _.get(containerData, '[0].name', ''); @@ -26,48 +31,6 @@ module.exports = _ => { const getViewOn = viewData => _.get(viewData, '[0].viewOn'); - const rejectRecursiveRelationships = foreignTableToRelationshipData => { - return Object.keys(foreignTableToRelationshipData).reduce((result, foreignTableId) => { - const tables = foreignTableToRelationshipData[foreignTableId].filter(item => { - const tables = foreignTableToRelationshipData[item.primaryTableId]; - - if (!Array.isArray(tables)) { - return true; - } - - return !tables.some( - item => item.primaryTableId === foreignTableId && item.primaryTableId !== item.foreignTableId, - ); - }); - - if (_.isEmpty(tables)) { - return result; - } - - return Object.assign({}, result, { - [foreignTableId]: tables, - }); - }, {}); - }; - - const filterRecursiveRelationships = foreignTableToRelationshipData => { - return Object.keys(foreignTableToRelationshipData).reduce((result, foreignTableId) => { - const tables = foreignTableToRelationshipData[foreignTableId].filter(item => { - const tables = foreignTableToRelationshipData[item.primaryTableId]; - - if (!Array.isArray(tables)) { - return false; - } - - return tables.some( - item => item.primaryTableId === foreignTableId && item.primaryTableId !== item.foreignTableId, - ); - }); - - return result.concat(tables); - }, []); - }; - const tab = (text, tab = '\t') => { return text .split('\n') @@ -79,6 +42,24 @@ module.exports = _ => { return Object.keys(types).map(_.toLower).includes(_.toLower(type)); }; + /** + * @param collection {AlterCollectionDto} + * @return {AlterCollectionDto & AlterCollectionRoleDto} + * */ + const getSchemaOfAlterCollection = (collection) => { + return {...collection, ...(_.omit(collection?.role, 'properties') || {})}; + } + + /** + * @param collectionSchema {AlterCollectionDto & AlterCollectionRoleDto} + * @return {string} + * */ + const getFullCollectionName = (collectionSchema) => { + const collectionName = getEntityName(collectionSchema); + const bucketName = collectionSchema.compMod?.keyspaceName; + return getNamePrefixedWithSchemaName(collectionName, bucketName); + } + const clean = obj => Object.entries(obj) .filter(([name, value]) => !_.isNil(value)) @@ -94,6 +75,11 @@ module.exports = _ => { return keys.every(key => _.get(key, 'isActivated', true)); }; + /** + * @param keys {Array<{ + * isActivated: boolean, + * }>} + * */ const checkAllKeysDeactivated = keys => { return keys.length ? keys.every(key => !_.get(key, 'isActivated', true)) : false; }; @@ -129,14 +115,136 @@ module.exports = _ => { } }; + const checkFieldPropertiesChanged = (compMod, propertiesToCheck) => { + return propertiesToCheck.some(prop => compMod?.oldField[prop] !== compMod?.newField[prop]); + }; + + const getFullTableName = (collection) => { + const collectionSchema = {...collection, ...(_.omit(collection?.role, 'properties') || {})}; + const tableName = getEntityName(collectionSchema); + const schemaName = collectionSchema.compMod?.keyspaceName; + return getNamePrefixedWithSchemaName(tableName, schemaName); + } + + const getFullColumnName = (collection, columnName) => { + const {wrapInQuotes} = require('../utils/general')(_); + + const fullTableName = getFullTableName(collection); + return `${fullTableName}.${wrapInQuotes(columnName)}`; + } + + const getFullViewName = (view) => { + const viewSchema = {...view, ...(_.omit(view?.role, 'properties') || {})}; + const viewName = getViewName(viewSchema); + const schemaName = viewSchema.compMod?.keyspaceName; + return getNamePrefixedWithSchemaName(viewName, schemaName); + } + + /** + * @param udt {Object} + * @return {string} + * */ + const getUdtName = (udt) => { + return udt.code || udt.name; + } + + const getDbVersion = (dbVersion = '') => { + const version = dbVersion.match(/\d+/); + + return Number(_.get(version, [0], 0)); + }; + + const prepareComment = (comment = '') => + comment.replace(MUST_BE_ESCAPED, character => `\\${character}`); + + const wrapComment = comment => `E'${prepareComment(JSON.stringify(comment)).slice(1, -1)}'`; + + const getFunctionArguments = functionArguments => { + return _.map(functionArguments, arg => { + const defaultExpression = arg.defaultExpression ? `DEFAULT ${arg.defaultExpression}` : ''; + + return _.trim(`${arg.argumentMode} ${arg.argumentName || ''} ${arg.argumentType} ${defaultExpression}`); + }).join(', '); + }; + + const getNamePrefixedWithSchemaName = (name, schemaName) => { + if (schemaName) { + return `${wrapInQuotes(schemaName)}.${wrapInQuotes(name)}`; + } + + return wrapInQuotes(name); + }; + + const wrapInQuotes = name => + /\s|\W/.test(name) || _.includes(ReservedWordsAsArray, _.toUpper(name)) ? `"${name}"` : name; + + const columnMapToString = ({ name }) => wrapInQuotes(name); + + const getColumnsList = (columns, isAllColumnsDeactivated, isParentActivated, mapColumn = columnMapToString) => { + const dividedColumns = divideIntoActivatedAndDeactivated(columns, mapColumn); + const deactivatedColumnsAsString = dividedColumns?.deactivatedItems?.length + ? commentIfDeactivated(dividedColumns.deactivatedItems.join(', '), { + isActivated: false, + isPartOfLine: true, + }) + : ''; + + return !isAllColumnsDeactivated && isParentActivated + ? ' (' + dividedColumns.activatedItems.join(', ') + deactivatedColumnsAsString + ')' + : ' (' + columns.map(mapColumn).join(', ') + ')'; + }; + + const getKeyWithAlias = key => { + if (!key) { + return ''; + } + + if (key.alias) { + return `${wrapInQuotes(key.name)} as ${wrapInQuotes(key.alias)}`; + } else { + return wrapInQuotes(key.name); + } + }; + + const getViewData = keys => { + if (!Array.isArray(keys)) { + return { tables: [], columns: [] }; + } + + return keys.reduce( + (result, key) => { + if (!key.tableName) { + result.columns.push(getKeyWithAlias(key)); + + return result; + } + + let tableName = wrapInQuotes(key.tableName); + + if (!result.tables.includes(tableName)) { + result.tables.push(tableName); + } + + result.columns.push({ + statement: `${tableName}.${getKeyWithAlias(key)}`, + isActivated: key.isActivated, + }); + + return result; + }, + { + tables: [], + columns: [], + }, + ); + }; + return { getDbName, getDbData, getEntityName, getViewName, getViewOn, - rejectRecursiveRelationships, - filterRecursiveRelationships, tab, hasType, clean, @@ -145,5 +253,19 @@ module.exports = _ => { divideIntoActivatedAndDeactivated, commentIfDeactivated, wrap, + checkFieldPropertiesChanged, + getFullTableName, + getFullColumnName, + getFullViewName, + getUdtName, + getDbVersion, + wrapComment, + getFunctionArguments, + getNamePrefixedWithSchemaName, + wrapInQuotes, + getColumnsList, + getViewData, + getSchemaOfAlterCollection, + getFullCollectionName }; };