sorting key support, clickhouse recreate table support

This commit is contained in:
Jan Prochazka 2024-09-12 11:59:03 +02:00
parent 670cfb9dc0
commit 2f1cbbd75e
8 changed files with 116 additions and 32 deletions

View File

@ -622,10 +622,8 @@ export class SqlDumper implements AlterProcessor {
if (!oldTable.pairingId || !newTable.pairingId || oldTable.pairingId != newTable.pairingId) {
throw new Error('Recreate is not possible: oldTable.paringId != newTable.paringId');
}
const tmpTable = `temp_${uuidv1()}`;
// console.log('oldTable', oldTable);
// console.log('newTable', newTable);
const tmpTable = `temp_${uuidv1()}`;
const columnPairs = oldTable.columns
.map(oldcol => ({
@ -634,6 +632,7 @@ export class SqlDumper implements AlterProcessor {
}))
.filter(x => x.newcol);
if (this.driver.supportsTransactions) {
this.dropConstraints(oldTable, true);
this.renameTable(oldTable, tmpTable);
@ -661,6 +660,21 @@ export class SqlDumper implements AlterProcessor {
}
this.dropTable({ ...oldTable, pureName: tmpTable });
} else {
// we have to preserve old table as long as possible
this.createTable({ ...newTable, pureName: tmpTable });
this.putCmd(
'^insert ^into %f (%,i) select %,s ^from %f',
{ ...newTable, pureName: tmpTable },
columnPairs.map(x => x.newcol.columnName),
columnPairs.map(x => x.oldcol.columnName),
oldTable
);
this.dropTable(oldTable);
this.renameTable({ ...newTable, pureName: tmpTable }, newTable.pureName);
}
}
createSqlObject(obj: SqlObjectInfo) {

View File

@ -284,6 +284,7 @@ export class AlterPlan {
: [];
const constraints = _.compact([
dependencyDefinition?.includes('primaryKey') ? table.primaryKey : null,
dependencyDefinition?.includes('sortingKey') ? table.sortingKey : null,
...(dependencyDefinition?.includes('foreignKeys') ? table.foreignKeys : []),
...(dependencyDefinition?.includes('indexes') ? table.indexes : []),
...(dependencyDefinition?.includes('uniques') ? table.uniques : []),
@ -400,6 +401,7 @@ export class AlterPlan {
_canCreateConstraint(cnt: ConstraintInfo) {
if (cnt.constraintType == 'primaryKey') return this.dialect.createPrimaryKey;
if (cnt.constraintType == 'sortingKey') return this.dialect.createPrimaryKey;
if (cnt.constraintType == 'foreignKey') return this.dialect.createForeignKey;
if (cnt.constraintType == 'index') return this.dialect.createIndex;
if (cnt.constraintType == 'unique') return this.dialect.createUnique;
@ -409,6 +411,7 @@ export class AlterPlan {
_canDropConstraint(cnt: ConstraintInfo) {
if (cnt.constraintType == 'primaryKey') return this.dialect.dropPrimaryKey;
if (cnt.constraintType == 'sortingKey') return this.dialect.dropPrimaryKey;
if (cnt.constraintType == 'foreignKey') return this.dialect.dropForeignKey;
if (cnt.constraintType == 'index') return this.dialect.dropIndex;
if (cnt.constraintType == 'unique') return this.dialect.dropUnique;

View File

@ -11,6 +11,7 @@ import {
UniqueInfo,
SqlObjectInfo,
NamedObjectInfo,
ColumnsConstraintInfo,
} from '../../types';
export class DatabaseInfoAlterProcessor {
@ -59,6 +60,9 @@ export class DatabaseInfoAlterProcessor {
case 'primaryKey':
table.primaryKey = constraint as PrimaryKeyInfo;
break;
case 'sortingKey':
table.sortingKey = constraint as ColumnsConstraintInfo;
break;
case 'foreignKey':
table.foreignKeys.push(constraint as ForeignKeyInfo);
break;
@ -86,6 +90,9 @@ export class DatabaseInfoAlterProcessor {
case 'primaryKey':
table.primaryKey = null;
break;
case 'sortingKey':
table.sortingKey = null;
break;
case 'foreignKey':
table.foreignKeys = table.foreignKeys.filter(x => x.constraintName != constraint.constraintName);
break;

View File

@ -46,6 +46,14 @@ export function generateTablePairingId(table: TableInfo): TableInfo {
if (!table.pairingId) {
return {
...table,
primaryKey: table.primaryKey && {
...table.primaryKey,
pairingId: table.primaryKey.pairingId || uuidv1(),
},
sortingKey: table.sortingKey && {
...table.sortingKey,
pairingId: table.sortingKey.pairingId || uuidv1(),
},
columns: table.columns?.map(col => ({
...col,
pairingId: col.pairingId || uuidv1(),
@ -335,6 +343,7 @@ export function testEqualTypes(a: ColumnInfo, b: ColumnInfo, opts: DbDiffOptions
function getTableConstraints(table: TableInfo) {
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);
@ -345,7 +354,9 @@ function getTableConstraints(table: TableInfo) {
function createPairs(oldList, newList, additionalCondition = null) {
const res = [];
for (const a of oldList) {
const b = newList.find(x => x.pairingId == a.pairingId || (additionalCondition && additionalCondition(a, x)));
const b = newList.find(
x => (a.pairingId && x.pairingId == a.pairingId) || (additionalCondition && additionalCondition(a, x))
);
if (b) {
res.push([a, b]);
} else {
@ -381,9 +392,14 @@ function planAlterTable(plan: AlterPlan, oldTable: TableInfo, newTable: TableInf
const constraintPairs = createPairs(
getTableConstraints(oldTable),
getTableConstraints(newTable),
(a, b) => a.constraintType == 'primaryKey' && b.constraintType == 'primaryKey'
(a, b) =>
(a.constraintType == 'primaryKey' && b.constraintType == 'primaryKey') ||
(a.constraintType == 'sortingKey' && b.constraintType == 'sortingKey')
);
// console.log('constraintPairs SOURCE', getTableConstraints(oldTable), getTableConstraints(newTable));
// 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) {
@ -427,6 +443,10 @@ function planAlterTable(plan: AlterPlan, oldTable: TableInfo, newTable: TableInf
planTablePreload(plan, oldTable, newTable);
planChangeTableOptions(plan, oldTable, newTable, opts);
// console.log('oldTable', oldTable);
// console.log('newTable', newTable);
// console.log('plan.operations', plan.operations);
}
function planChangeTableOptions(plan: AlterPlan, oldTable: TableInfo, newTable: TableInfo, opts: DbDiffOptions) {

View File

@ -2,6 +2,7 @@ import uuidv1 from 'uuid/v1';
import _omit from 'lodash/omit';
import type {
ColumnInfo,
ColumnsConstraintInfo,
ConstraintInfo,
ForeignKeyInfo,
IndexInfo,
@ -195,6 +196,13 @@ export function editorAddConstraint(table: TableInfo, constraint: ConstraintInfo
} as PrimaryKeyInfo;
}
if (constraint.constraintType == 'sortingKey') {
res.sortingKey = {
pairingId: uuidv1(),
...constraint,
} as ColumnsConstraintInfo;
}
if (constraint.constraintType == 'foreignKey') {
res.foreignKeys = [
...(res.foreignKeys || []),
@ -240,6 +248,13 @@ export function editorModifyConstraint(table: TableInfo, constraint: ConstraintI
};
}
if (constraint.constraintType == 'sortingKey') {
res.sortingKey = {
...res.sortingKey,
...constraint,
};
}
if (constraint.constraintType == 'foreignKey') {
res.foreignKeys = table.foreignKeys.map(fk =>
fk.pairingId == constraint.pairingId ? { ...fk, ...constraint } : fk

View File

@ -27,6 +27,7 @@ export interface TableInfoYaml {
// schema?: string;
columns: ColumnInfoYaml[];
primaryKey?: string[];
sortingKey?: string[];
insertKey?: string[];
insertOnly?: string[];
@ -91,6 +92,9 @@ export function tableInfoToYaml(table: TableInfo): TableInfoYaml {
if (tableCopy.primaryKey && !tableCopy.primaryKey['_dumped']) {
res.primaryKey = tableCopy.primaryKey.columns.map(x => x.columnName);
}
if (tableCopy.sortingKey && !tableCopy.sortingKey['_dumped']) {
res.sortingKey = tableCopy.sortingKey.columns.map(x => x.columnName);
}
// const foreignKeys = (tableCopy.foreignKeys || []).filter(x => !x['_dumped']).map(foreignKeyInfoToYaml);
return res;
}
@ -132,6 +136,13 @@ export function tableInfoFromYaml(table: TableInfoYaml, allTables: TableInfoYaml
columns: table.primaryKey.map(columnName => ({ columnName })),
};
}
if (table.sortingKey) {
res.sortingKey = {
pureName: table.name,
constraintType: 'sortingKey',
columns: table.sortingKey.map(columnName => ({ columnName })),
};
}
res.preloadedRows = table.data;
res.preloadedRowsKey = table.insertKey;
res.preloadedRowsInsertOnly = table.insertOnly;

View File

@ -46,10 +46,10 @@ class Analyser extends DatabaseAnalyser {
...extractDataType(col.dataType),
})),
primaryKey: table.primaryKeyColumns
? { columns: (table.primaryKeyColumns || '').split(',').map((columnName) => ({ columnName })) }
? { columns: (table.primaryKeyColumns || '').split(',').map((x) => ({ columnName: x.trim() })) }
: null,
sortingKey: table.sortingKeyColumns
? { columns: (table.sortingKeyColumns || '').split(',').map((columnName) => ({ columnName })) }
? { columns: (table.sortingKeyColumns || '').split(',').map((x) => ({ columnName: x.trim() })) }
: null,
foreignKeys: [],
})),

View File

@ -23,6 +23,20 @@ class Dumper extends SqlDumper {
renameColumn(column, newcol) {
this.putCmd('^alter ^table %f ^rename ^column %i ^to %i', column, column.columnName, newcol);
}
renameTable(obj, newName) {
this.putCmd('^rename ^table %f ^to %i', obj, newName);
}
tableOptions(table) {
super.tableOptions(table);
if (table.sortingKey) {
this.put(
'&n^order ^by (%,i)',
table.sortingKey.columns.map((x) => x.columnName)
);
}
}
}
module.exports = Dumper;