mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-02 17:13:58 +00:00
postgre, mysql uniques, recreate table WIP, drop index works
This commit is contained in:
@@ -56,8 +56,8 @@ async function testTableDiff(conn, driver, mangle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// const TESTED_COLUMNS = ['col_pk', 'col_std', 'col_def', 'col_fk', 'col_ref', 'col_idx', 'col_uq'];
|
// const TESTED_COLUMNS = ['col_pk', 'col_std', 'col_def', 'col_fk', 'col_ref', 'col_idx', 'col_uq'];
|
||||||
const TESTED_COLUMNS = ['col_pk'];
|
// const TESTED_COLUMNS = ['col_pk'];
|
||||||
// const TESTED_COLUMNS = ['col_idx'];
|
const TESTED_COLUMNS = ['col_idx'];
|
||||||
// const TESTED_COLUMNS = ['col_fk'];
|
// const TESTED_COLUMNS = ['col_fk'];
|
||||||
// const TESTED_COLUMNS = ['col_std'];
|
// const TESTED_COLUMNS = ['col_std'];
|
||||||
|
|
||||||
@@ -69,15 +69,15 @@ describe('Alter processor', () => {
|
|||||||
test.each(engines.map(engine => [engine.label, engine]))(
|
test.each(engines.map(engine => [engine.label, engine]))(
|
||||||
'Add column - %s',
|
'Add column - %s',
|
||||||
testWrapper(async (conn, driver, engine) => {
|
testWrapper(async (conn, driver, engine) => {
|
||||||
await testTableDiff(conn, driver, tbl =>
|
await testTableDiff(conn, driver, tbl => {
|
||||||
tbl.columns.push({
|
tbl.columns.push({
|
||||||
columnName: 'added',
|
columnName: 'added',
|
||||||
dataType: 'int',
|
dataType: 'int',
|
||||||
pairingId: uuidv1(),
|
pairingId: uuidv1(),
|
||||||
notNull: false,
|
notNull: false,
|
||||||
autoIncrement: false,
|
autoIncrement: false,
|
||||||
})
|
});
|
||||||
);
|
});
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -109,4 +109,13 @@ describe('Alter processor', () => {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test.each(engines.map(engine => [engine.label, engine]))(
|
||||||
|
'Drop index - %s',
|
||||||
|
testWrapper(async (conn, driver, engine) => {
|
||||||
|
await testTableDiff(conn, driver, tbl => {
|
||||||
|
tbl.indexes = [];
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -133,10 +133,10 @@ describe('Table analyse', () => {
|
|||||||
const structure = await driver.analyseFull(conn);
|
const structure = await driver.analyseFull(conn);
|
||||||
|
|
||||||
const t2 = structure.tables.find(x => x.pureName == 't2');
|
const t2 = structure.tables.find(x => x.pureName == 't2');
|
||||||
const indexesAndUniques = [...t2.uniques, ...t2.indexes];
|
// const indexesAndUniques = [...t2.uniques, ...t2.indexes];
|
||||||
expect(indexesAndUniques.length).toEqual(1);
|
expect(t2.uniques.length).toEqual(1);
|
||||||
expect(indexesAndUniques[0].columns.length).toEqual(1);
|
expect(t2.uniques[0].columns.length).toEqual(1);
|
||||||
expect(indexesAndUniques[0].columns[0]).toEqual(expect.objectContaining({ columnName: 'val2' }));
|
expect(t2.uniques[0].columns[0]).toEqual(expect.objectContaining({ columnName: 'val2' }));
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -420,8 +420,24 @@ export class SqlDumper implements AlterProcessor {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
dropIndex(ix: IndexInfo) {}
|
dropIndex(ix: IndexInfo) {
|
||||||
createIndex(ix: IndexInfo) {}
|
this.put('^drop ^index %i', ix.constraintName);
|
||||||
|
if (this.dialect.dropIndexContainsTableSpec) {
|
||||||
|
this.put(' ^on %f', ix);
|
||||||
|
}
|
||||||
|
this.endCommand();
|
||||||
|
}
|
||||||
|
createIndex(ix: IndexInfo) {
|
||||||
|
this.put('^create');
|
||||||
|
if (ix.indexType) this.put(' %k', ix.indexType);
|
||||||
|
if (ix.isUnique) this.put(' ^unique');
|
||||||
|
this.put(' ^index %i &n^on %f (&>&n', ix.constraintName, ix);
|
||||||
|
this.putCollection(',&n', ix.columns, col => {
|
||||||
|
this.put('%i %k', col.columnName, col.isDescending == true ? 'DESC' : 'ASC');
|
||||||
|
});
|
||||||
|
this.put('&<&n)');
|
||||||
|
this.endCommand();
|
||||||
|
}
|
||||||
|
|
||||||
dropUnique(uq: UniqueInfo) {
|
dropUnique(uq: UniqueInfo) {
|
||||||
this.dropConstraintCore(uq);
|
this.dropConstraintCore(uq);
|
||||||
|
|||||||
@@ -207,6 +207,8 @@ export class AlterPlan {
|
|||||||
...(this.dialect.dropColumnDependencies?.includes('uniques') ? table.uniques : []),
|
...(this.dialect.dropColumnDependencies?.includes('uniques') ? table.uniques : []),
|
||||||
]).filter(cnt => cnt.columns.find(col => col.columnName == op.oldObject.columnName));
|
]).filter(cnt => cnt.columns.find(col => col.columnName == op.oldObject.columnName));
|
||||||
|
|
||||||
|
console.log('deletedConstraints', deletedConstraints);
|
||||||
|
|
||||||
const res: AlterOperation[] = [
|
const res: AlterOperation[] = [
|
||||||
...[...deletedFks, ...deletedConstraints].map(oldObject => {
|
...[...deletedFks, ...deletedConstraints].map(oldObject => {
|
||||||
const opRes: AlterOperation = {
|
const opRes: AlterOperation = {
|
||||||
@@ -260,11 +262,13 @@ export class AlterPlan {
|
|||||||
): AlterOperation[] | null {
|
): AlterOperation[] | null {
|
||||||
if (op.operationType == operationType) {
|
if (op.operationType == operationType) {
|
||||||
if (_.isFunction(isAllowed)) {
|
if (_.isFunction(isAllowed)) {
|
||||||
if (!isAllowed(op[objectField])) return null;
|
if (isAllowed(op[objectField])) return null;
|
||||||
} else {
|
} else {
|
||||||
if (!isAllowed) return null;
|
if (isAllowed) return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// console.log('*****************RECREATED NEEDED', op, operationType, isAllowed);
|
||||||
|
// console.log(this.dialect);
|
||||||
const table = this.db.tables.find(
|
const table = this.db.tables.find(
|
||||||
x => x.pureName == op[objectField].pureName && x.schemaName == op[objectField].schemaName
|
x => x.pureName == op[objectField].pureName && x.schemaName == op[objectField].schemaName
|
||||||
);
|
);
|
||||||
|
|||||||
2
packages/types/dialect.d.ts
vendored
2
packages/types/dialect.d.ts
vendored
@@ -15,6 +15,8 @@ export interface SqlDialect {
|
|||||||
dropColumnDependencies?: string[];
|
dropColumnDependencies?: string[];
|
||||||
changeColumnDependencies?: string[];
|
changeColumnDependencies?: string[];
|
||||||
|
|
||||||
|
dropIndexContainsTableSpec?: boolean;
|
||||||
|
|
||||||
createColumn?: boolean;
|
createColumn?: boolean;
|
||||||
dropColumn?: boolean;
|
dropColumn?: boolean;
|
||||||
createIndex?: boolean;
|
createIndex?: boolean;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const dialect = {
|
|||||||
dropColumnDependencies: ['default', 'dependencies', 'indexes', 'primaryKey'],
|
dropColumnDependencies: ['default', 'dependencies', 'indexes', 'primaryKey'],
|
||||||
changeColumnDependencies: ['indexes'],
|
changeColumnDependencies: ['indexes'],
|
||||||
anonymousPrimaryKey: false,
|
anonymousPrimaryKey: false,
|
||||||
|
dropIndexContainsTableSpec: true,
|
||||||
quoteIdentifier(s) {
|
quoteIdentifier(s) {
|
||||||
return `[${s}]`;
|
return `[${s}]`;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
|
|
||||||
const viewTexts = await this.getViewTexts(views.rows.map(x => x.pureName));
|
const viewTexts = await this.getViewTexts(views.rows.map(x => x.pureName));
|
||||||
const indexes = await this.driver.query(this.pool, this.createQuery('indexes', ['tables']));
|
const indexes = await this.driver.query(this.pool, this.createQuery('indexes', ['tables']));
|
||||||
|
const uniqueNames = await this.driver.query(this.pool, this.createQuery('uniqueNames', ['tables']));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tables: tables.rows.map(table => ({
|
tables: tables.rows.map(table => ({
|
||||||
@@ -84,9 +85,11 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
columns: columns.rows.filter(col => col.pureName == table.pureName).map(getColumnInfo),
|
columns: columns.rows.filter(col => col.pureName == table.pureName).map(getColumnInfo),
|
||||||
primaryKey: DatabaseAnalyser.extractPrimaryKeys(table, pkColumns.rows),
|
primaryKey: DatabaseAnalyser.extractPrimaryKeys(table, pkColumns.rows),
|
||||||
foreignKeys: DatabaseAnalyser.extractForeignKeys(table, fkColumns.rows),
|
foreignKeys: DatabaseAnalyser.extractForeignKeys(table, fkColumns.rows),
|
||||||
uniques: [],
|
|
||||||
indexes: _.uniqBy(
|
indexes: _.uniqBy(
|
||||||
indexes.rows.filter(idx => idx.tableName == table.pureName),
|
indexes.rows.filter(
|
||||||
|
idx =>
|
||||||
|
idx.tableName == table.pureName && !uniqueNames.rows.find(x => x.constraintName == idx.constraintName)
|
||||||
|
),
|
||||||
'constraintName'
|
'constraintName'
|
||||||
).map(idx => ({
|
).map(idx => ({
|
||||||
..._.pick(idx, ['constraintName', 'indexType']),
|
..._.pick(idx, ['constraintName', 'indexType']),
|
||||||
@@ -97,6 +100,21 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
..._.pick(col, ['columnName']),
|
..._.pick(col, ['columnName']),
|
||||||
})),
|
})),
|
||||||
})),
|
})),
|
||||||
|
|
||||||
|
uniques: _.uniqBy(
|
||||||
|
indexes.rows.filter(
|
||||||
|
idx =>
|
||||||
|
idx.tableName == table.pureName && uniqueNames.rows.find(x => x.constraintName == idx.constraintName)
|
||||||
|
),
|
||||||
|
'constraintName'
|
||||||
|
).map(idx => ({
|
||||||
|
..._.pick(idx, ['constraintName']),
|
||||||
|
columns: indexes.rows
|
||||||
|
.filter(col => col.tableName == idx.tableName && col.constraintName == idx.constraintName)
|
||||||
|
.map(col => ({
|
||||||
|
..._.pick(col, ['columnName']),
|
||||||
|
})),
|
||||||
|
})),
|
||||||
})),
|
})),
|
||||||
views: views.rows.map(view => ({
|
views: views.rows.map(view => ({
|
||||||
...view,
|
...view,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const indexes = require('./indexes');
|
|||||||
const programmables = require('./programmables');
|
const programmables = require('./programmables');
|
||||||
const procedureModifications = require('./procedureModifications');
|
const procedureModifications = require('./procedureModifications');
|
||||||
const functionModifications = require('./functionModifications');
|
const functionModifications = require('./functionModifications');
|
||||||
|
const uniqueNames = require('./uniqueNames');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
columns,
|
columns,
|
||||||
@@ -20,4 +21,5 @@ module.exports = {
|
|||||||
procedureModifications,
|
procedureModifications,
|
||||||
functionModifications,
|
functionModifications,
|
||||||
indexes,
|
indexes,
|
||||||
|
uniqueNames,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
module.exports = `
|
||||||
|
select CONSTRAINT_NAME as constraintName
|
||||||
|
from information_schema.TABLE_CONSTRAINTS
|
||||||
|
where CONSTRAINT_SCHEMA = '#DATABASE#' and constraint_type = 'UNIQUE'
|
||||||
|
`;
|
||||||
@@ -22,6 +22,7 @@ const dialect = {
|
|||||||
dropForeignKey: true,
|
dropForeignKey: true,
|
||||||
createPrimaryKey: true,
|
createPrimaryKey: true,
|
||||||
dropPrimaryKey: true,
|
dropPrimaryKey: true,
|
||||||
|
dropIndexContainsTableSpec: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mysqlDriverBase = {
|
const mysqlDriverBase = {
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
const routines = await this.driver.query(this.pool, this.createQuery('routines', ['procedures', 'functions']));
|
const routines = await this.driver.query(this.pool, this.createQuery('routines', ['procedures', 'functions']));
|
||||||
const indexes = await this.driver.query(this.pool, this.createQuery('indexes', ['tables']));
|
const indexes = await this.driver.query(this.pool, this.createQuery('indexes', ['tables']));
|
||||||
const indexcols = await this.driver.query(this.pool, this.createQuery('indexcols', ['tables']));
|
const indexcols = await this.driver.query(this.pool, this.createQuery('indexcols', ['tables']));
|
||||||
|
const uniqueNames = await this.driver.query(this.pool, this.createQuery('uniqueNames', ['tables']));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tables: tables.rows.map(table => {
|
tables: tables.rows.map(table => {
|
||||||
@@ -107,7 +108,12 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
}))
|
}))
|
||||||
),
|
),
|
||||||
indexes: indexes.rows
|
indexes: indexes.rows
|
||||||
.filter(x => x.table_name == table.pure_name && x.schema_name == table.schema_name)
|
.filter(
|
||||||
|
x =>
|
||||||
|
x.table_name == table.pure_name &&
|
||||||
|
x.schema_name == table.schema_name &&
|
||||||
|
!uniqueNames.rows.find(y => y.constraint_name == x.index_name)
|
||||||
|
)
|
||||||
.map(idx => ({
|
.map(idx => ({
|
||||||
constraintName: idx.index_name,
|
constraintName: idx.index_name,
|
||||||
isUnique: idx.is_unique,
|
isUnique: idx.is_unique,
|
||||||
@@ -120,7 +126,24 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
}))
|
}))
|
||||||
),
|
),
|
||||||
})),
|
})),
|
||||||
uniques: [],
|
uniques: indexes.rows
|
||||||
|
.filter(
|
||||||
|
x =>
|
||||||
|
x.table_name == table.pure_name &&
|
||||||
|
x.schema_name == table.schema_name &&
|
||||||
|
uniqueNames.rows.find(y => y.constraint_name == x.index_name)
|
||||||
|
)
|
||||||
|
.map(idx => ({
|
||||||
|
constraintName: idx.index_name,
|
||||||
|
columns: _.compact(
|
||||||
|
idx.indkey
|
||||||
|
.split(' ')
|
||||||
|
.map(colid => indexcols.rows.find(col => col.oid == idx.oid && col.attnum == colid))
|
||||||
|
.map(col => ({
|
||||||
|
columnName: col.column_name,
|
||||||
|
}))
|
||||||
|
),
|
||||||
|
})),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
views: views.rows.map(view => ({
|
views: views.rows.map(view => ({
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const routineModifications = require('./routineModifications');
|
|||||||
const matviewColumns = require('./matviewColumns');
|
const matviewColumns = require('./matviewColumns');
|
||||||
const indexes = require('./indexes');
|
const indexes = require('./indexes');
|
||||||
const indexcols = require('./indexcols');
|
const indexcols = require('./indexcols');
|
||||||
|
const uniqueNames = require('./uniqueNames');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
columns,
|
columns,
|
||||||
@@ -28,4 +29,5 @@ module.exports = {
|
|||||||
matviewColumns,
|
matviewColumns,
|
||||||
indexes,
|
indexes,
|
||||||
indexcols,
|
indexcols,
|
||||||
|
uniqueNames,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
module.exports = `
|
||||||
|
select conname as "constraint_name" from pg_constraint where contype = 'u'
|
||||||
|
`;
|
||||||
@@ -15,6 +15,15 @@ const dialect = {
|
|||||||
return '"' + s + '"';
|
return '"' + s + '"';
|
||||||
},
|
},
|
||||||
stringAgg: true,
|
stringAgg: true,
|
||||||
|
|
||||||
|
createColumn: true,
|
||||||
|
dropColumn: true,
|
||||||
|
createIndex: true,
|
||||||
|
dropIndex: true,
|
||||||
|
createForeignKey: true,
|
||||||
|
dropForeignKey: true,
|
||||||
|
createPrimaryKey: true,
|
||||||
|
dropPrimaryKey: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const postgresDriverBase = {
|
const postgresDriverBase = {
|
||||||
@@ -35,15 +44,6 @@ const postgresDriver = {
|
|||||||
dialect: {
|
dialect: {
|
||||||
...dialect,
|
...dialect,
|
||||||
materializedViews: true,
|
materializedViews: true,
|
||||||
|
|
||||||
createColumn: true,
|
|
||||||
dropColumn: true,
|
|
||||||
createIndex: true,
|
|
||||||
dropIndex: true,
|
|
||||||
createForeignKey: true,
|
|
||||||
dropForeignKey: true,
|
|
||||||
createPrimaryKey: true,
|
|
||||||
dropPrimaryKey: true,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const dialect = {
|
|||||||
explicitDropConstraint: true,
|
explicitDropConstraint: true,
|
||||||
stringEscapeChar: "'",
|
stringEscapeChar: "'",
|
||||||
fallbackDataType: 'nvarchar(max)',
|
fallbackDataType: 'nvarchar(max)',
|
||||||
dropColumnDependencies: ['index', 'primaryKey'],
|
dropColumnDependencies: ['indexes', 'primaryKey'],
|
||||||
quoteIdentifier(s) {
|
quoteIdentifier(s) {
|
||||||
return `[${s}]`;
|
return `[${s}]`;
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user