diff --git a/packages/api/src/shell/deployDb.js b/packages/api/src/shell/deployDb.js index a0ab51614..3141bc077 100644 --- a/packages/api/src/shell/deployDb.js +++ b/packages/api/src/shell/deployDb.js @@ -11,6 +11,7 @@ async function deployDb({ modelTransforms, dbdiffOptionsExtra, ignoreNameRegex = '', + targetSchema = null, }) { const { sql } = await generateDeploySql({ connection, @@ -22,6 +23,7 @@ async function deployDb({ modelTransforms, dbdiffOptionsExtra, ignoreNameRegex, + targetSchema, }); // console.log('RUNNING DEPLOY SCRIPT:', sql); await executeQuery({ connection, systemConnection, driver, sql, logScriptItems: true }); diff --git a/packages/api/src/shell/generateDeploySql.js b/packages/api/src/shell/generateDeploySql.js index 615dfbaea..0d0901f03 100644 --- a/packages/api/src/shell/generateDeploySql.js +++ b/packages/api/src/shell/generateDeploySql.js @@ -7,6 +7,8 @@ const { modelCompareDbDiffOptions, enrichWithPreloadedRows, skipNamesInStructureByRegex, + replaceSchemaInStructure, + filterStructureBySchema, } = require('dbgate-tools'); const importDbModel = require('../utility/importDbModel'); const requireEngineDriver = require('../utility/requireEngineDriver'); @@ -22,6 +24,7 @@ async function generateDeploySql({ modelTransforms = undefined, dbdiffOptionsExtra = {}, ignoreNameRegex = '', + targetSchema = null, }) { if (!driver) driver = requireEngineDriver(connection); @@ -44,6 +47,11 @@ async function generateDeploySql({ deployedModelSource = transform(deployedModelSource); } + if (targetSchema) { + deployedModelSource = replaceSchemaInStructure(deployedModelSource, targetSchema); + analysedStructure = filterStructureBySchema(analysedStructure, targetSchema); + } + const deployedModel = generateDbPairingId(extendDatabaseInfo(deployedModelSource)); const currentModel = generateDbPairingId(extendDatabaseInfo(analysedStructure)); const opts = { diff --git a/packages/tools/src/SqlDumper.ts b/packages/tools/src/SqlDumper.ts index 85f369c91..a5f6ffca4 100644 --- a/packages/tools/src/SqlDumper.ts +++ b/packages/tools/src/SqlDumper.ts @@ -515,6 +515,9 @@ export class SqlDumper implements AlterProcessor { this.put('%i %k', col.columnName, col.isDescending == true ? 'DESC' : 'ASC'); }); this.put('&<&n)'); + if (ix.filterDefinition && this.dialect.filteredIndexes) { + this.put('&n^where %s', ix.filterDefinition); + } this.endCommand(); } diff --git a/packages/tools/src/alterPlan.ts b/packages/tools/src/alterPlan.ts index 0351df84a..44e6a23b1 100644 --- a/packages/tools/src/alterPlan.ts +++ b/packages/tools/src/alterPlan.ts @@ -81,6 +81,7 @@ interface AlterOperation_ChangeConstraint { interface AlterOperation_DropConstraint { operationType: 'dropConstraint'; oldObject: ConstraintInfo; + isRecreate?: boolean; } interface AlterOperation_RenameConstraint { @@ -337,15 +338,16 @@ export class AlterPlan { if (op.operationType == testedOperationType) { const constraints = this._getDependendColumnConstraints(testedObject as ColumnInfo, testedDependencies); - if (constraints.length > 0 && this.opts.noDropConstraint) { - return []; - } + // if (constraints.length > 0 && this.opts.noDropConstraint) { + // return []; + // } const res: AlterOperation[] = [ ...constraints.map(oldObject => { const opRes: AlterOperation = { operationType: 'dropConstraint', oldObject, + isRecreate: true, }; return opRes; }), @@ -382,15 +384,16 @@ export class AlterPlan { } if (op.operationType == 'changeConstraint') { - if (this.opts.noDropConstraint) { - // skip constraint recreate - return []; - } + // if (this.opts.noDropConstraint) { + // // skip constraint recreate + // return []; + // } this.recreates.constraints += 1; const opDrop: AlterOperation = { operationType: 'dropConstraint', oldObject: op.oldObject, + isRecreate: true, }; const opCreate: AlterOperation = { operationType: 'createConstraint', @@ -547,7 +550,7 @@ export class AlterPlan { if (this.opts.noDropColumn && op.operationType == 'dropColumn') return false; if (this.opts.noDropTable && op.operationType == 'dropTable') return false; if (this.opts.noDropTable && op.operationType == 'recreateTable') return false; - if (this.opts.noDropConstraint && op.operationType == 'dropConstraint') return false; + if (this.opts.noDropConstraint && op.operationType == 'dropConstraint' && !op.isRecreate) return false; // if ( // this.opts.noDropSqlObject && // op.operationType == 'dropSqlObject' && diff --git a/packages/tools/src/diffTools.ts b/packages/tools/src/diffTools.ts index acbb2db62..1f50f0a55 100644 --- a/packages/tools/src/diffTools.ts +++ b/packages/tools/src/diffTools.ts @@ -127,6 +127,13 @@ export function removeTablePairingId(table: TableInfo): TableInfo { }; } +function simplifySqlExpression(sql: string) { + return (sql || '') + .replace(/[\s\(\)\[\]\"]/g, '') + .toLowerCase() + .trim(); +} + function generateObjectPairingId(obj) { if (obj.objectTypeField) return { @@ -375,6 +382,7 @@ function testEqualForeignKeys(a: ForeignKeyInfo, b: ForeignKeyInfo, opts: DbDiff function testEqualIndex(a: IndexInfo, b: IndexInfo, opts: DbDiffOptions) { 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; @@ -456,7 +464,7 @@ export function testEqualTypes(a: ColumnInfo, b: ColumnInfo, opts: DbDiffOptions return true; } - if ((a.dataType || '').toLowerCase() != (b.dataType || '').toLowerCase()) { + 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}` ); diff --git a/packages/tools/src/yamlModelConv.ts b/packages/tools/src/yamlModelConv.ts index dc9b0b6e4..da4fe5219 100644 --- a/packages/tools/src/yamlModelConv.ts +++ b/packages/tools/src/yamlModelConv.ts @@ -159,6 +159,7 @@ export function tableInfoFromYaml(table: TableInfoYaml, allTables: TableInfoYaml pureName: table.name, isUnique: index.unique, constraintType: 'index', + filterDefinition: index.filter, columns: [ ...index.columns.map(columnName => ({ columnName })), ...(index.included || []).map(columnName => ({ columnName, isIncludedColumn: true })), diff --git a/packages/types/dialect.d.ts b/packages/types/dialect.d.ts index 6356827ec..f4d117f1c 100644 --- a/packages/types/dialect.d.ts +++ b/packages/types/dialect.d.ts @@ -36,6 +36,7 @@ export interface SqlDialect { dropCheck?: boolean; renameSqlObject?: boolean; multipleSchema?: boolean; + filteredIndexes?: boolean; specificNullabilityImplementation?: boolean; omitForeignKeys?: boolean; diff --git a/packages/web/src/tableeditor/IndexEditorModal.svelte b/packages/web/src/tableeditor/IndexEditorModal.svelte index 431e0bf5e..a86186ebc 100644 --- a/packages/web/src/tableeditor/IndexEditorModal.svelte +++ b/packages/web/src/tableeditor/IndexEditorModal.svelte @@ -2,21 +2,26 @@ import CheckboxField from '../forms/CheckboxField.svelte'; import FormCheckboxField from '../forms/FormCheckboxField.svelte'; import SelectField from '../forms/SelectField.svelte'; + import TextField from '../forms/TextField.svelte'; import ColumnsConstraintEditorModal from './ColumnsConstraintEditorModal.svelte'; export let constraintInfo; export let setTableInfo; export let tableInfo; + export let driver; let isUnique = constraintInfo?.isUnique; function getExtractConstraintProps() { return { isUnique, + filterDefinition, }; } + let filterDefinition = constraintInfo?.filterDefinition; + $: isReadOnly = !setTableInfo; @@ -60,6 +65,22 @@ index + +