UNPKG

dbgate-tools

Version:

Auxiliary tools for other DbGate packages.

742 lines (741 loc) 31.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.modelCompareDbDiffOptions = exports.matchPairedObjects = exports.getAlterDatabaseScript = exports.getAlterTableScript = exports.createAlterDatabasePlan = exports.createAlterTablePlan = exports.testEqualSqlObjects = exports.testEqualTables = exports.testEqualTypes = exports.testEqualColumns = exports.hasDeletedPrefix = exports.generateDbPairingId = exports.removeTablePairingId = exports.generateTablePairingId = void 0; const v1_1 = __importDefault(require("uuid/v1")); const alterPlan_1 = require("./alterPlan"); const toposort_1 = __importDefault(require("toposort")); const cloneDeep_1 = __importDefault(require("lodash/cloneDeep")); const isEqual_1 = __importDefault(require("lodash/isEqual")); const pick_1 = __importDefault(require("lodash/pick")); const compact_1 = __importDefault(require("lodash/compact")); const isString_1 = __importDefault(require("lodash/isString")); const structureTools_1 = require("./structureTools"); function generateTablePairingId(table) { var _a, _b, _c, _d, _e; if (!table) return table; if (!table.pairingId) { return { ...table, primaryKey: table.primaryKey && { ...table.primaryKey, pairingId: table.primaryKey.pairingId || (0, v1_1.default)(), }, sortingKey: table.sortingKey && { ...table.sortingKey, pairingId: table.sortingKey.pairingId || (0, v1_1.default)(), }, columns: (_a = table.columns) === null || _a === void 0 ? void 0 : _a.map(col => ({ ...col, pairingId: col.pairingId || (0, v1_1.default)(), })), foreignKeys: (_b = table.foreignKeys) === null || _b === void 0 ? void 0 : _b.map(cnt => ({ ...cnt, pairingId: cnt.pairingId || (0, v1_1.default)(), })), checks: (_c = table.checks) === null || _c === void 0 ? void 0 : _c.map(cnt => ({ ...cnt, pairingId: cnt.pairingId || (0, v1_1.default)(), })), indexes: (_d = table.indexes) === null || _d === void 0 ? void 0 : _d.map(cnt => ({ ...cnt, pairingId: cnt.pairingId || (0, v1_1.default)(), })), uniques: (_e = table.uniques) === null || _e === void 0 ? void 0 : _e.map(cnt => ({ ...cnt, pairingId: cnt.pairingId || (0, v1_1.default)(), })), pairingId: table.pairingId || (0, v1_1.default)(), }; } return table; } exports.generateTablePairingId = generateTablePairingId; function removeTablePairingId(table) { var _a, _b, _c, _d, _e; if (!table) return table; return { ...table, columns: (_a = table.columns) === null || _a === void 0 ? void 0 : _a.map(col => ({ ...col, pairingId: undefined, })), foreignKeys: (_b = table.foreignKeys) === null || _b === void 0 ? void 0 : _b.map(cnt => ({ ...cnt, pairingId: undefined, })), checks: (_c = table.checks) === null || _c === void 0 ? void 0 : _c.map(cnt => ({ ...cnt, pairingId: undefined, })), indexes: (_d = table.indexes) === null || _d === void 0 ? void 0 : _d.map(cnt => ({ ...cnt, pairingId: undefined, })), uniques: (_e = table.uniques) === null || _e === void 0 ? void 0 : _e.map(cnt => ({ ...cnt, pairingId: undefined, })), pairingId: undefined, }; } exports.removeTablePairingId = removeTablePairingId; function simplifySqlExpression(sql) { return (sql || '') .replace(/[\s\(\)\[\]\"]/g, '') .toLowerCase() .trim(); } function generateObjectPairingId(obj) { if (obj.objectTypeField) return { ...obj, pairingId: obj.pairingId || (0, v1_1.default)(), }; return obj; } function generateDbPairingId(db) { var _a, _b, _c, _d, _e, _f, _g; if (!db) return db; return { ...db, // ..._.mapValues(db, v => (_.isArray(v) ? v.map(generateObjectPairingId) : v)), tables: (_a = db.tables) === null || _a === void 0 ? void 0 : _a.map(generateTablePairingId), views: (_b = db.views) === null || _b === void 0 ? void 0 : _b.map(generateObjectPairingId), procedures: (_c = db.procedures) === null || _c === void 0 ? void 0 : _c.map(generateObjectPairingId), functions: (_d = db.functions) === null || _d === void 0 ? void 0 : _d.map(generateObjectPairingId), triggers: (_e = db.triggers) === null || _e === void 0 ? void 0 : _e.map(generateObjectPairingId), schedulerEvents: (_f = db.schedulerEvents) === null || _f === void 0 ? void 0 : _f.map(generateObjectPairingId), matviews: (_g = db.matviews) === null || _g === void 0 ? void 0 : _g.map(generateObjectPairingId), }; } exports.generateDbPairingId = generateDbPairingId; function getNameWithoutDeletedPrefix(name, opts, deletedPrefix) { if (deletedPrefix) { if (opts.ignoreCase) { if ((name || '').toLowerCase().startsWith(deletedPrefix.toLowerCase())) { return name.slice(deletedPrefix.length); } } else { if ((name || '').startsWith(deletedPrefix)) { return name.slice(deletedPrefix.length); } } } return name; } function hasDeletedPrefix(name, opts, deletedPrefix) { if (deletedPrefix) { if (opts.ignoreCase) { return (name || '').toLowerCase().startsWith(deletedPrefix.toLowerCase()); } else { return (name || '').startsWith(deletedPrefix); } } return false; } exports.hasDeletedPrefix = hasDeletedPrefix; function testEqualNames(a, b, opts, deletedPrefix) { a = getNameWithoutDeletedPrefix(a, opts, deletedPrefix); b = getNameWithoutDeletedPrefix(b, opts, deletedPrefix); if (opts.ignoreCase) return (a || '').toLowerCase() == (b || '').toLowerCase(); return a == b; } function testEqualSchemas(lschema, rschema, opts) { if (opts.schemaMode == 'ignore') lschema = null; if (opts.schemaMode == 'ignoreImplicit' && lschema == opts.leftImplicitSchema) lschema = null; if (opts.schemaMode == 'ignore') rschema = null; if (opts.schemaMode == 'ignoreImplicit' && rschema == opts.rightImplicitSchema) rschema = null; return testEqualNames(lschema, rschema, opts); } function testEqualFullNames(lft, rgt, opts, deletedPrefix) { if (lft == null || rgt == null) return lft == rgt; return (testEqualSchemas(lft.schemaName, rgt.schemaName, opts) && testEqualNames(lft.pureName, rgt.pureName, opts, deletedPrefix)); } function testEqualDefaultValues(value1, value2) { if (value1 == null) return value2 == null || value2 == 'NULL'; if (value2 == null) return value1 == null || value1 == 'NULL'; if ((0, isString_1.default)(value1) && (0, isString_1.default)(value2)) { value1 = value1.trim(); value2 = value2.trim(); if (value1.startsWith("'") && value1.endsWith("'") && value2.startsWith("'") && value2.endsWith("'")) { return value1 == value2; } return value1.toLowerCase() == value2.toLowerCase(); } return value1 == value2; } function testEqualColumns(a, b, checkName, checkDefault, opts = {}) { if (checkName && !testEqualNames(a.columnName, b.columnName, opts)) { // opts.DiffLogger.Trace("Column, different name: {0}; {1}", a, b); return false; } //if (!DbDiffTool.EqualFullNames(a.Domain, b.Domain, opts)) //{ // opts.DiffLogger.Trace("Column {0}, {1}: different domain: {2}; {3}", a, b, a.Domain, b.Domain); // return false; //} if (a.computedExpression != b.computedExpression) { console.debug(`Column ${a.pureName}.${a.columnName}, ${b.pureName}.${b.columnName}: different computed expression: ${a.computedExpression}, ${b.computedExpression}`); // opts.DiffLogger.Trace( // 'Column {0}, {1}: different computed expression: {2}; {3}', // a, // b, // a.ComputedExpression, // b.ComputedExpression // ); return false; } if (a.computedExpression != null) { return true; } if (checkDefault) { if (!testEqualDefaultValues(a.defaultValue, b.defaultValue)) { console.debug(`Column ${a.pureName}.${a.columnName}, ${b.pureName}.${b.columnName}: different default value: ${a.defaultValue}, ${b.defaultValue}`); // opts.DiffLogger.Trace( // 'Column {0}, {1}: different default values: {2}; {3}', // a, // b, // a.DefaultValue, // b.DefaultValue // ); return false; } if (a.defaultConstraint != b.defaultConstraint) { console.debug(`Column ${a.pureName}.${a.columnName}, ${b.pureName}.${b.columnName}: different default constraint: ${a.defaultConstraint}, ${b.defaultConstraint}`); // opts.DiffLogger.Trace( // 'Column {0}, {1}: different default constraint names: {2}; {3}', // a, // b, // a.DefaultConstraint, // b.DefaultConstraint // ); return false; } } if ((a.notNull || false) != (b.notNull || false)) { console.debug(`Column ${a.pureName}.${a.columnName}, ${b.pureName}.${b.columnName}: different nullability: ${a.notNull}, ${b.notNull}`); // opts.DiffLogger.Trace('Column {0}, {1}: different nullable: {2}; {3}', a, b, a.NotNull, b.NotNull); return false; } if ((a.autoIncrement || false) != (b.autoIncrement || false)) { console.debug(`Column ${a.pureName}.${a.columnName}, ${b.pureName}.${b.columnName}: different autoincrement: ${a.autoIncrement}, ${b.autoIncrement}`); // opts.DiffLogger.Trace('Column {0}, {1}: different autoincrement: {2}; {3}', a, b, a.AutoIncrement, b.AutoIncrement); return false; } if ((a.isSparse || false) != (b.isSparse || false)) { console.debug(`Column ${a.pureName}.${a.columnName}, ${b.pureName}.${b.columnName}: different is_sparse: ${a.isSparse}, ${b.isSparse}`); // opts.DiffLogger.Trace('Column {0}, {1}: different is_sparse: {2}; {3}', a, b, a.IsSparse, b.IsSparse); return false; } if ((a.isUnsigned || false) != (b.isUnsigned || false)) { console.debug(`Column ${a.pureName}.${a.columnName}, ${b.pureName}.${b.columnName}: different unsigned: ${a.isUnsigned}, ${b.isUnsigned}`); return false; } if ((a.isZerofill || false) != (b.isZerofill || false)) { console.debug(`Column ${a.pureName}.${a.columnName}, ${b.pureName}.${b.columnName}: different zerofill: ${a.isZerofill}, ${b.isZerofill}`); return false; } if (!opts.ignoreComments) { if ((a.columnComment || '') != (b.columnComment || '')) { console.debug(`Column ${a.pureName}.${a.columnName}, ${b.pureName}.${b.columnName}: different comment: ${a.columnComment}, ${b.columnComment}`); return false; } } if (!testEqualTypes(a, b, opts)) { return false; } //var btype = b.DataType; //var atype = a.DataType; //if (pairing != null && pairing.Target != null && pairing.Source.Dialect != null) //{ // btype = pairing.Source.Dialect.MigrateDataType(b, btype, pairing.Source.Dialect.GetDefaultMigrationProfile(), null); // btype = pairing.Source.Dialect.GenericTypeToSpecific(btype).ToGenericType(); // // normalize type // atype = pairing.Source.Dialect.GenericTypeToSpecific(atype).ToGenericType(); //} //if (!EqualTypes(atype, btype, opts)) //{ // opts.DiffLogger.Trace("Column {0}, {1}: different types: {2}; {3}", a, b, a.DataType, b.DataType); // return false; //} //if (!opts.IgnoreColumnCollation && a.Collation != b.Collation) //{ // opts.DiffLogger.Trace("Column {0}, {1}: different collations: {2}; {3}", a, b, a.Collation, b.Collation); // return false; //} //if (!opts.IgnoreColumnCharacterSet && a.CharacterSet != b.CharacterSet) //{ // opts.DiffLogger.Trace("Column {0}, {1}: different character sets: {2}; {3}", a, b, a.CharacterSet, b.CharacterSet); // return false; //} return true; } exports.testEqualColumns = testEqualColumns; function testEqualColumnRefs(a, b, opts) { if (a.length != b.length) return false; for (let i = 0; i < a.length; i++) { if (!testEqualNames(a[i].columnName, b[i].columnName, opts)) return false; if (!testEqualNames(a[i].refColumnName, b[i].refColumnName, opts)) return false; } return true; } function testEqualPrimaryKeys(a, b, opts) { if (!testEqualColumnRefs(a.columns, b.columns, opts)) return false; return true; } function testEqualForeignKeys(a, b, opts) { if (!testEqualColumnRefs(a.columns, b.columns, opts)) return false; if (!opts.ignoreConstraintNames && !testEqualNames(a.constraintName, b.constraintName, opts)) return false; return true; } function testEqualIndex(a, b, opts) { if (!testEqualColumnRefs(a.columns, b.columns, opts)) return false; if (!!a.isUnique != !!b.isUnique) return false; if (simplifySqlExpression(a.filterDefinition) != simplifySqlExpression(b.filterDefinition)) return false; if (!opts.ignoreConstraintNames && !testEqualNames(a.constraintName, b.constraintName, opts)) return false; return true; } function testEqualUnique(a, b, opts) { if (!testEqualColumnRefs(a.columns, b.columns, opts)) return false; if (!opts.ignoreConstraintNames && !testEqualNames(a.constraintName, b.constraintName, opts)) return false; return true; } function testEqualCheck(a, b, opts) { if (a.definition != b.definition) return false; if (!opts.ignoreConstraintNames && !testEqualNames(a.constraintName, b.constraintName, opts)) return false; return true; } function testEqualConstraints(a, b, opts = {}) { if (a.constraintType != b.constraintType) { console.debug(`Constraint ${a.pureName}: different constraint type: ${a.constraintType}, ${b.constraintType}`); return false; } switch (a.constraintType) { case 'primaryKey': case 'sortingKey': return testEqualPrimaryKeys(a, b, opts); case 'foreignKey': return testEqualForeignKeys(a, b, opts); case 'index': return testEqualIndex(a, b, opts); case 'unique': return testEqualUnique(a, b, opts); case 'check': return testEqualCheck(a, b, opts); } console.debug(`Unknown constraint type: ${a.pureName}`); return false; // const omitList = ['pairingId']; // if (opts.ignoreForeignKeyActions) { // omitList.push('updateAction'); // omitList.push('deleteAction'); // } // if (opts.ignoreConstraintNames) { // omitList.push('constraintName'); // } // if (opts.schemaMode == 'ignore') { // omitList.push('schemaName'); // omitList.push('refSchemaName'); // } // if (a.constraintType == 'primaryKey' && b.constraintType == 'primaryKey') { // console.log('PK1', stableStringify(_.omit(a, omitList))); // console.log('PK2', stableStringify(_.omit(b, omitList))); // } // if (a.constraintType == 'foreignKey' && b.constraintType == 'foreignKey') { // console.log('FK1', stableStringify(_omit(a, omitList))); // console.log('FK2', stableStringify(_omit(b, omitList))); // } // if (a.constraintType == 'index' && b.constraintType == 'index') { // console.log('IX1', stableStringify(_omit(a, omitList))); // console.log('IX2', stableStringify(_omit(b, omitList))); // } // const aStringified = stableStringify(_omit(a, omitList)); // const bStringified = stableStringify(_omit(b, omitList)); // return aStringified == bStringified; } function testEqualTypes(a, b, opts = {}) { if (opts.ignoreDataTypes) { return true; } if (simplifySqlExpression(a.dataType) != simplifySqlExpression(b.dataType)) { console.debug(`Column ${a.pureName}.${a.columnName}, ${b.pureName}.${b.columnName}: different data type: ${a.dataType}, ${b.dataType}`); return false; } return true; } exports.testEqualTypes = testEqualTypes; function getTableConstraints(table) { const res = []; if (table.primaryKey) res.push(table.primaryKey); if (table.sortingKey) res.push(table.sortingKey); if (table.foreignKeys) res.push(...table.foreignKeys); if (table.indexes) res.push(...table.indexes); if (table.uniques) res.push(...table.uniques); if (table.checks) res.push(...table.checks); return res; } function createPairs(oldList, newList, additionalCondition = null) { const res = []; for (const a of oldList) { const b = newList.find(x => (a.pairingId && x.pairingId == a.pairingId) || (additionalCondition && additionalCondition(a, x))); if (b) { res.push([a, b]); } else { res.push([a, null]); } } for (const b of newList) { if (!res.find(x => x[1] == b)) { res.push([null, b]); } } return res; } function planTablePreload(plan, oldTable, newTable) { var _a, _b, _c, _d; const key = newTable.preloadedRowsKey || ((_b = (_a = newTable.primaryKey) === null || _a === void 0 ? void 0 : _a.columns) === null || _b === void 0 ? void 0 : _b.map(x => x.columnName)); if (((_c = newTable.preloadedRows) === null || _c === void 0 ? void 0 : _c.length) > 0 && (key === null || key === void 0 ? void 0 : key.length) > 0 && (0, structureTools_1.detectChangesInPreloadedRows)(oldTable, newTable)) { plan.fillPreloadedRows(newTable, oldTable === null || oldTable === void 0 ? void 0 : oldTable.preloadedRows, newTable.preloadedRows, key, newTable.preloadedRowsInsertOnly, (_d = newTable.columns.find(x => x.autoIncrement)) === null || _d === void 0 ? void 0 : _d.columnName); } } function planAlterTable(plan, oldTable, newTable, opts) { // if (oldTable.primaryKey) const columnPairs = createPairs(oldTable.columns, newTable.columns); const constraintPairs = createPairs(getTableConstraints(oldTable), getTableConstraints(newTable), (a, b) => (a.constraintType == 'primaryKey' && b.constraintType == 'primaryKey') || (a.constraintType == 'sortingKey' && b.constraintType == 'sortingKey')); // console.log('constraintPairs OLD TABLE', oldTable); // console.log('constraintPairs NEW TABLE', newTable); // console.log('constraintPairs SOURCE OLD', getTableConstraints(oldTable)); // console.log('constraintPairs SOURCE NEW', getTableConstraints(newTable)); // console.log('constraintPairs', constraintPairs); if (!opts.noDropConstraint) { constraintPairs.filter(x => x[1] == null).forEach(x => plan.dropConstraint(x[0])); } if (opts.deletedColumnPrefix) { columnPairs .filter(x => x[1] == null) .forEach(x => { if (!hasDeletedPrefix(x[0].columnName, opts, opts.deletedColumnPrefix)) { plan.renameColumn(x[0], opts.deletedColumnPrefix + x[0].columnName); } }); } else if (!opts.noDropColumn) { columnPairs.filter(x => x[1] == null).forEach(x => plan.dropColumn(x[0])); } if (!testEqualFullNames(oldTable, newTable, opts) && !opts.noRenameTable) { plan.renameTable(oldTable, newTable.pureName); } if (hasDeletedPrefix(oldTable.pureName, opts, opts.deletedTablePrefix)) { plan.renameTable(oldTable, newTable.pureName); } columnPairs.filter(x => x[0] == null).forEach(x => plan.createColumn(x[1])); columnPairs .filter(x => x[0] && x[1]) .forEach(x => { let srccol = x[0]; let dstcol = x[1]; if (hasDeletedPrefix(srccol.columnName, opts, opts.deletedColumnPrefix)) { plan.renameColumn(srccol, dstcol.columnName); // rename is already done srccol = { ...srccol, columnName: dstcol.columnName, }; } if (!testEqualColumns(srccol, dstcol, true, true, opts)) { if (testEqualColumns(srccol, dstcol, false, true, opts) && !opts.noRenameColumn) { // console.log('PLAN RENAME COLUMN') plan.renameColumn(srccol, dstcol.columnName); } else { // console.log('PLAN CHANGE COLUMN', x[0], x[1]); plan.changeColumn(srccol, dstcol); } } }); constraintPairs .filter(x => x[0] && x[1]) .forEach(x => { if (!testEqualConstraints(x[0], x[1], opts)) { // console.log('PLAN CHANGE CONSTRAINT', x[0], x[1]); plan.changeConstraint(x[0], x[1]); } }); constraintPairs.filter(x => x[0] == null).forEach(x => plan.createConstraint(x[1])); planChangeTableOptions(plan, oldTable, newTable, opts); // console.log('oldTable', oldTable); // console.log('newTable', newTable); // console.log('plan.operations', plan.operations); } function planChangeTableOptions(plan, oldTable, newTable, opts) { var _a, _b; for (const option of ((_b = (_a = plan.dialect) === null || _a === void 0 ? void 0 : _a.getTableFormOptions) === null || _b === void 0 ? void 0 : _b.call(_a, 'sqlAlterTable')) || []) { if (option.disabled) { continue; } const name = option.name; if (oldTable[name] != newTable[name] && (oldTable[name] || newTable[name]) && (newTable[name] || option.allowEmptyValue)) { plan.setTableOption(newTable, name, newTable[name]); } } } function testEqualTables(a, b, opts, wholeOldDb, wholeNewDb, driver) { const plan = new alterPlan_1.AlterPlan(wholeOldDb, wholeNewDb, driver.dialect, opts); planAlterTable(plan, a, b, opts); // if (plan.operations.length > 0) { // console.log('************** plan.operations', a, b, plan.operations); // } if (plan.operations.length > 0) { return false; } if ((0, structureTools_1.detectChangesInPreloadedRows)(a, b)) { return false; } return true; } exports.testEqualTables = testEqualTables; function testEqualSqlObjects(a, b, opts) { var _a, _b, _c, _d; return ((_b = (_a = a.createSql) === null || _a === void 0 ? void 0 : _a.trim()) === null || _b === void 0 ? void 0 : _b.toLowerCase()) == ((_d = (_c = b.createSql) === null || _c === void 0 ? void 0 : _c.trim()) === null || _d === void 0 ? void 0 : _d.toLowerCase()); } exports.testEqualSqlObjects = testEqualSqlObjects; function createAlterTablePlan(oldTable, newTable, opts, wholeOldDb, wholeNewDb, driver) { const plan = new alterPlan_1.AlterPlan(wholeOldDb, wholeNewDb, driver.dialect, opts); if (oldTable == null) { plan.createTable(newTable); planTablePreload(plan, null, newTable); } else if (newTable == null) { plan.dropTable(oldTable); } else { planAlterTable(plan, oldTable, newTable, opts); planTablePreload(plan, oldTable, newTable); } plan.transformPlan(); return plan; } exports.createAlterTablePlan = createAlterTablePlan; function sortViewsByDependency(views) { const viewNames = []; const viewDict = {}; for (const view of views) { if (!viewNames.includes(view.pureName)) { viewNames.push(view.pureName); } viewDict[view.pureName] = viewDict[view.pureName] ? `${viewDict[view.pureName]} ${view.createSql}}` : view.createSql; } const edges = []; for (const viewName of viewNames) { edges.push([viewName, null]); const viewText = viewDict[viewName]; for (const otherView of viewNames) { if (otherView === viewName) continue; if ((' ' + viewText + ' ').match('[\\W]' + otherView + '[\\W]')) { edges.push([otherView, viewName]); } } } const ordered = (0, compact_1.default)((0, toposort_1.default)(edges)); const res = []; for (const viewName of ordered) { res.push(...views.filter(x => x.pureName == viewName)); } return res; } function createAlterDatabasePlan(oldDb, newDb, opts, wholeOldDb, wholeNewDb, driver) { const plan = new alterPlan_1.AlterPlan(wholeOldDb, wholeNewDb, driver.dialect, opts); for (const objectTypeField of [ 'tables', 'views', 'procedures', 'matviews', 'functions', 'triggers', 'schedulerEvents', ]) { for (const oldobj of oldDb[objectTypeField] || []) { const newobj = (newDb[objectTypeField] || []).find(x => x.pairingId == oldobj.pairingId); if (objectTypeField == 'tables') { if (newobj == null) { if (opts.deletedTablePrefix && !hasDeletedPrefix(oldobj.pureName, opts, opts.deletedTablePrefix)) { plan.renameTable(oldobj, opts.deletedTablePrefix + oldobj.pureName); } else if (!opts.noDropTable) { plan.dropTable(oldobj); } } else { planAlterTable(plan, oldobj, newobj, opts); planTablePreload(plan, oldobj, newobj); } } else { if (newobj == null) { if (opts.deletedSqlObjectPrefix && driver.dialect.renameSqlObject && !hasDeletedPrefix(oldobj.pureName, opts, opts.deletedSqlObjectPrefix)) { plan.renameSqlObject(oldobj, opts.deletedSqlObjectPrefix + oldobj.pureName); } else if (!opts.noDropSqlObject) { plan.dropSqlObject(oldobj); } } else { if (opts.deletedSqlObjectPrefix && hasDeletedPrefix(oldobj.pureName, opts, opts.deletedSqlObjectPrefix)) { if (driver.dialect.renameSqlObject && testEqualSqlObjects(oldobj, newobj, opts)) { plan.renameSqlObject(oldobj, newobj.pureName); } else { plan.dropSqlObject(oldobj); plan.createSqlObject(newobj); } } else if (!testEqualSqlObjects(oldobj, newobj, opts)) { plan.recreates.sqlObjects += 1; plan.dropSqlObject(oldobj); plan.createSqlObject(newobj); } else if (!testEqualFullNames(oldobj, newobj, opts)) { plan.renameSqlObject(oldobj, newobj.pureName); } } } } let newList = newDb[objectTypeField] || []; if (objectTypeField == 'views') { newList = sortViewsByDependency(newList); } for (const newobj of newList) { const oldobj = (oldDb[objectTypeField] || []).find(x => x.pairingId == newobj.pairingId); if (objectTypeField == 'tables') { if (oldobj == null) { plan.createTable(newobj); planTablePreload(plan, null, newobj); } } else { if (oldobj == null) plan.createSqlObject(newobj); } } } plan.transformPlan(); return plan; } exports.createAlterDatabasePlan = createAlterDatabasePlan; function getAlterTableScript(oldTable, newTable, opts, wholeOldDb, wholeNewDb, driver) { if ((!oldTable && !newTable) || !driver) { return { sql: '', recreates: [] }; } const plan = createAlterTablePlan(oldTable, newTable, opts, wholeOldDb, wholeNewDb, driver); const dmp = driver.createDumper({ useHardSeparator: true }); plan.run(dmp); return { sql: dmp.s, recreates: plan.recreates, }; } exports.getAlterTableScript = getAlterTableScript; function getAlterDatabaseScript(oldDb, newDb, opts, wholeOldDb, wholeNewDb, driver, transformPlan = null) { const plan = createAlterDatabasePlan(oldDb, newDb, opts, wholeOldDb, wholeNewDb, driver); if (transformPlan) { transformPlan(plan); } const dmp = driver.createDumper({ useHardSeparator: true }); plan.run(dmp); return { sql: dmp.s, recreates: plan.recreates, isEmpty: plan.operations.length == 0, }; } exports.getAlterDatabaseScript = getAlterDatabaseScript; function matchPairedObjects(db1, db2, opts) { if (!db1 || !db2) return null; const res = (0, cloneDeep_1.default)(db2); for (const objectTypeField of ['tables', 'views', 'procedures', 'matviews', 'functions']) { for (const obj2 of res[objectTypeField] || []) { const obj1 = db1[objectTypeField].find(x => testEqualFullNames(x, obj2, opts, objectTypeField == 'tables' ? opts.deletedTablePrefix : opts.deletedSqlObjectPrefix)); if (obj1) { obj2.pairingId = obj1.pairingId; if (objectTypeField == 'tables') { for (const col2 of obj2.columns) { const col1 = obj1.columns.find(x => testEqualNames(x.columnName, col2.columnName, opts, opts.deletedColumnPrefix)); if (col1) col2.pairingId = col1.pairingId; } for (const fk2 of obj2.foreignKeys) { const fk1 = obj1.foreignKeys.find(x => testEqualNames(x.refTableName, fk2.refTableName, opts) && (0, isEqual_1.default)(x.columns.map(y => (0, pick_1.default)(y, ['columnName', 'refColumnName'])), fk2.columns.map(y => (0, pick_1.default)(y, ['columnName', 'refColumnName'])))); if (fk1) fk2.pairingId = fk1.pairingId; } for (const uq2 of obj2.uniques) { const uq1 = obj1.uniques.find(x => (0, isEqual_1.default)(x.columns.map(y => (0, pick_1.default)(y, ['columnName'])), uq2.columns.map(y => (0, pick_1.default)(y, ['columnName'])))); if (uq1) uq2.pairingId = uq1.pairingId; } for (const ix2 of obj2.indexes) { const ix1 = obj1.indexes.find(x => testEqualNames(x.constraintName, ix2.constraintName, opts)); if (ix1) ix2.pairingId = ix1.pairingId; } } } } } return res; } exports.matchPairedObjects = matchPairedObjects; exports.modelCompareDbDiffOptions = { ignoreCase: true, ignoreConstraintNames: true, ignoreForeignKeyActions: true, ignoreDataTypes: true, };