preloaded data works

This commit is contained in:
Jan Prochazka
2021-11-27 17:49:02 +01:00
parent d4f4211ee4
commit 40d53275e3
12 changed files with 177 additions and 5 deletions

View File

@@ -1,3 +1,4 @@
import _ from 'lodash';
import {
ColumnInfo,
ConstraintInfo,
@@ -604,4 +605,40 @@ export class SqlDumper implements AlterProcessor {
dropSqlObject(obj: SqlObjectInfo) {
this.putCmd('^drop %s %f', this.getSqlObjectSqlName(obj.objectTypeField), obj);
}
fillPreloadedRows(table: NamedObjectInfo, oldRows: any[], newRows: any[], key: string[]) {
let was = false;
for (const row of newRows) {
const old = oldRows?.find(r => key.every(col => r[col] == row[col]));
const rowKeys = _.keys(row);
if (old) {
const updated = [];
for (const col of rowKeys) {
if (row[col] != old[col]) {
updated.push(col);
}
}
if (updated.length > 0) {
if (was) this.put(';\n');
was = true;
this.put('^update %f ^set ', table);
this.putCollection(', ', updated, col => this.put('%i=%v', col, row[col]));
this.put(' ^ where ');
this.putCollection(' ^and ', key, col => this.put('%i=%v', col, row[col]));
}
} else {
if (was) this.put(';\n');
was = true;
this.put(
'^insert ^into %f (%,i) ^values (%,v)',
table,
rowKeys,
rowKeys.map(x => row[x])
);
}
}
if (was) {
this.endCommand();
}
}
}

View File

@@ -8,6 +8,7 @@ import {
SqlObjectInfo,
SqlDialect,
TableInfo,
NamedObjectInfo,
} from '../../types';
import { DatabaseInfoAlterProcessor } from './database-info-alter-processor';
import { DatabaseAnalyser } from './DatabaseAnalyser';
@@ -86,6 +87,13 @@ interface AlterOperation_RecreateTable {
table: TableInfo;
operations: AlterOperation[];
}
interface AlterOperation_FillPreloadedRows {
operationType: 'fillPreloadedRows';
table: NamedObjectInfo;
oldRows: any[];
newRows: any[];
key: string[];
}
type AlterOperation =
| AlterOperation_CreateColumn
@@ -101,7 +109,8 @@ type AlterOperation =
| AlterOperation_RenameConstraint
| AlterOperation_CreateSqlObject
| AlterOperation_DropSqlObject
| AlterOperation_RecreateTable;
| AlterOperation_RecreateTable
| AlterOperation_FillPreloadedRows;
export class AlterPlan {
recreates = {
@@ -223,6 +232,16 @@ export class AlterPlan {
this.recreates.tables += 1;
}
fillPreloadedRows(table: NamedObjectInfo, oldRows: any[], newRows: any[], key: string[]) {
this.operations.push({
operationType: 'fillPreloadedRows',
table,
oldRows,
newRows,
key,
});
}
run(processor: AlterProcessor) {
for (const op of this.operations) {
runAlterOperation(op, processor);
@@ -545,6 +564,9 @@ export function runAlterOperation(op: AlterOperation, processor: AlterProcessor)
case 'dropSqlObject':
processor.dropSqlObject(op.oldObject);
break;
case 'fillPreloadedRows':
processor.fillPreloadedRows(op.table, op.oldRows, op.newRows, op.key);
break;
case 'recreateTable':
{
const oldTable = generateTablePairingId(op.table);

View File

@@ -10,6 +10,7 @@ import {
CheckInfo,
UniqueInfo,
SqlObjectInfo,
NamedObjectInfo,
} from '../../types';
export class DatabaseInfoAlterProcessor {
@@ -114,4 +115,10 @@ export class DatabaseInfoAlterProcessor {
recreateTable(oldTable: TableInfo, newTable: TableInfo) {
throw new Error('recreateTable not implemented for DatabaseInfoAlterProcessor');
}
fillPreloadedRows(table: NamedObjectInfo, oldRows: any[], newRows: any[], key: string[]) {
const tableInfo = this.db.tables.find(x => x.pureName == table.pureName && x.schemaName == table.schemaName);
tableInfo.preloadedRows = newRows;
tableInfo.preloadedRowsKey = key;
}
}

View File

@@ -325,6 +325,13 @@ function createPairs(oldList, newList, additionalCondition = null) {
return res;
}
function planTablePreload(plan: AlterPlan, oldTable: TableInfo, newTable: TableInfo) {
const key = newTable.preloadedRowsKey || newTable.primaryKey?.columns?.map(x => x.columnName);
if (newTable.preloadedRows?.length > 0 && key?.length > 0) {
plan.fillPreloadedRows(newTable, oldTable?.preloadedRows, newTable.preloadedRows, key);
}
}
function planAlterTable(plan: AlterPlan, oldTable: TableInfo, newTable: TableInfo, opts: DbDiffOptions) {
// if (oldTable.primaryKey)
@@ -374,6 +381,8 @@ function planAlterTable(plan: AlterPlan, oldTable: TableInfo, newTable: TableInf
});
constraintPairs.filter(x => x[0] == null).forEach(x => plan.createConstraint(x[1]));
planTablePreload(plan, oldTable, newTable);
}
export function testEqualTables(
@@ -405,6 +414,7 @@ export function createAlterTablePlan(
const plan = new AlterPlan(wholeOldDb, wholeNewDb, driver.dialect, opts);
if (oldTable == null) {
plan.createTable(newTable);
planTablePreload(plan, null, newTable);
} else if (newTable == null) {
plan.dropTable(oldTable);
} else {
@@ -452,7 +462,10 @@ export function createAlterDatabasePlan(
for (const newobj of newDb[objectTypeField] || []) {
const oldobj = (oldDb[objectTypeField] || []).find(x => x.pairingId == newobj.pairingId);
if (objectTypeField == 'tables') {
if (oldobj == null) plan.createTable(newobj);
if (oldobj == null) {
plan.createTable(newobj);
planTablePreload(plan, null, newobj);
}
} else {
if (oldobj == null) plan.createSqlObject(newobj);
}

View File

@@ -16,3 +16,4 @@ export * from './schemaEditorTools';
export * from './yamlModelConv';
export * from './stringTools';
export * from './computeDiffRows';
export * from './preloadedRowsTools';

View File

@@ -0,0 +1,47 @@
import _ from 'lodash';
import { DatabaseInfo, EngineDriver } from 'dbgate-types';
export async function enrichWithPreloadedRows(
dbModel: DatabaseInfo,
dbTarget: DatabaseInfo,
conn,
driver: EngineDriver
): Promise<DatabaseInfo> {
// const res = { ...dbTarget, tables: [...(dbTarget.tables || [])] };
const repl = {};
for (const tableTarget of dbTarget.tables) {
const tableModel = dbModel.tables.find(x => x.pairingId == tableTarget.pairingId);
if (tableModel.preloadedRows?.length || 0 == 0) continue;
const keyColumns = tableModel.preloadedRowsKey || tableModel.primaryKey?.columns?.map(x => x.columnName);
if (keyColumns?.length || 0 == 0) continue;
const dmp = driver.createDumper();
if (keyColumns.length == 1) {
dmp.putCmd(
'^select * ^from %f ^where %i ^in (%,v)',
tableTarget,
keyColumns[0],
tableModel.preloadedRows.map(x => x[keyColumns[0]])
);
} else {
dmp.put('^select * ^from %f ^where', tableTarget);
dmp.putCollection(' ^or ', tableTarget.preloadedRows, row => {
dmp.put('(');
dmp.putCollection(' ^and ', keyColumns, col => dmp.put('%i=%v', col, row[col]));
dmp.put(')');
});
dmp.endCommand();
}
const resp = await driver.query(conn, dmp.s);
repl[tableTarget.pairingId] = {
...tableTarget,
preloadedRows: resp.rows,
preloadedRowsKey: keyColumns,
};
}
if (_.isEmpty(repl)) return dbTarget;
return {
...dbTarget,
tables: dbTarget.tables.map(x => repl[x.pairingId] || x),
};
}

View File

@@ -22,6 +22,9 @@ export interface TableInfoYaml {
// schema?: string;
columns: ColumnInfoYaml[];
primaryKey?: string[];
insertKey?: string[];
data?: any[];
}
export interface ForeignKeyInfoYaml {
@@ -119,6 +122,8 @@ export function tableInfoFromYaml(table: TableInfoYaml, allTables: TableInfoYaml
columns: table.primaryKey.map(columnName => ({ columnName })),
};
}
res.preloadedRows = table.data;
res.preloadedRowsKey = table.insertKey;
return res;
}