SYNC: restore table fixes & backup table tests

This commit is contained in:
SPRINX0\prochazka
2025-12-02 11:07:56 +01:00
committed by Diflow
parent ef23f0d18e
commit ec06a7d861
3 changed files with 143 additions and 42 deletions

View File

@@ -103,13 +103,70 @@ describe('Transactions', () => {
describe('Backup table', () => { describe('Backup table', () => {
multiTest({ skipMongo: true }, (connectionName, databaseName, engine, options = {}) => { multiTest({ skipMongo: true }, (connectionName, databaseName, engine, options = {}) => {
const implicitTransactions = options.implicitTransactions ?? false;
cy.contains(connectionName).click(); cy.contains(connectionName).click();
if (databaseName) cy.contains(databaseName).click(); if (databaseName) cy.contains(databaseName).click();
cy.contains('customers').rightclick(); cy.contains('addresses').rightclick();
cy.contains('Create table backup').click(); cy.contains('Create table backup').click();
cy.testid('ConfirmSqlModal_okButton').click(); cy.testid('ConfirmSqlModal_okButton').click();
cy.contains('customers (').click(); cy.testid('app-object-group-items-table-backups').contains('addresses').click();
cy.contains('Rows: 8').should('be.visible'); cy.contains('Rows: 12').should('be.visible');
cy.testid('app-object-group-items-tables').contains('addresses').click();
cy.contains('Ridgewood').click();
cy.testid('TableDataTab_deleteSelectedRows').click();
cy.contains('Rosewood').click();
cy.testid('TableDataTab_deleteSelectedRows').click();
cy.contains('Vermont').click();
cy.get('body').realType('Wermont{enter}');
cy.testid('TableDataTab_insertNewRow').click();
cy.get('body').realType('Modranska{enter}');
cy.realPress(['ArrowLeft']);
cy.realPress(['ArrowLeft']);
cy.get('body').realType('13{enter}');
cy.realPress(['ArrowRight']);
cy.get('body').realType('1{enter}');
cy.realPress(['ArrowRight']);
cy.realPress(['ArrowRight']);
cy.realPress(['ArrowRight']);
cy.get('body').realType('Prague{enter}');
cy.realPress(['ArrowRight']);
cy.get('body').realType('CZ{enter}');
cy.realPress(['ArrowRight']);
cy.get('body').realType('10000{enter}');
cy.realPress(['ArrowRight']);
cy.get('body').realType('111222333{enter}');
cy.testid('TableDataTab_save').click();
cy.testid('ConfirmSqlModal_okButton').click();
cy.contains('Rows: 11').should('be.visible'); // wait for save
cy.testid('app-object-group-items-table-backups').contains('addresses').rightclick();
cy.contains('restore script').click();
cy.contains('UPDATE'); // wait for query
cy.testid('QueryTab_executeButton').click();
cy.contains('Query execution finished');
if (implicitTransactions) {
cy.testid('QueryTab_commitTransactionButton').click();
cy.contains('Commit Transaction finished');
}
cy.realPress('F1');
cy.realType('Close all');
cy.realPress('Enter');
// cy.testid('CloseTabModal_buttonConfirm').click();
cy.wait(1000);
cy.testid('app-object-group-items-tables').contains('addresses').click();
// check whether data was successfully restored
cy.contains('Rows: 12').should('be.visible');
cy.contains('Ridgewood');
cy.contains('Vermont');
}); });
}); });

View File

@@ -44,6 +44,7 @@
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormSubmit <FormSubmit
value={_t('datagrid.closeTabs.close', { defaultMessage: 'Close tabs' })} value={_t('datagrid.closeTabs.close', { defaultMessage: 'Close tabs' })}
data-testid="CloseTabModal_buttonConfirm"
on:click={() => { on:click={() => {
closeCurrentModal(); closeCurrentModal();
onConfirm(); onConfirm();
@@ -52,6 +53,7 @@
<FormStyledButton <FormStyledButton
type="button" type="button"
value={_t('common.cancel', { defaultMessage: 'Cancel' })} value={_t('common.cancel', { defaultMessage: 'Cancel' })}
data-testid="CloseTabModal_buttonCancel"
on:click={() => { on:click={() => {
closeCurrentModal(); closeCurrentModal();
onCancel(); onCancel();

View File

@@ -13,6 +13,10 @@ export function createTableRestoreScript(backupTable: TableInfo, originalTable:
); );
const valueColumns = _.difference(bothColumns, keyColumns); const valueColumns = _.difference(bothColumns, keyColumns);
if (keyColumns.length === 0) {
throw new Error('Cannot create restore script: no key columns found');
}
function makeColumnCond(colName: string, operator: '=' | '<>' | '<' | '>' | '<=' | '>=' = '='): Condition { function makeColumnCond(colName: string, operator: '=' | '<>' | '<' | '>' | '<=' | '>=' = '='): Condition {
return { return {
conditionType: 'binary', conditionType: 'binary',
@@ -30,6 +34,30 @@ export function createTableRestoreScript(backupTable: TableInfo, originalTable:
}; };
} }
function makeNullNotNullCond(colName: string, isCond1: boolean): Condition {
return {
conditionType: 'and',
conditions: [
{
conditionType: 'isNull',
expr: {
exprType: 'column',
columnName: colName,
source: isCond1 ? { name: originalTable } : { alias: 'bak' },
},
},
{
conditionType: 'isNotNull',
expr: {
exprType: 'column',
columnName: colName,
source: isCond1 ? { alias: 'bak' } : { name: originalTable },
},
},
],
};
}
function putTitle(title: string) { function putTitle(title: string) {
dmp.putRaw('\n\n'); dmp.putRaw('\n\n');
dmp.comment(`******************** ${title} ********************`); dmp.comment(`******************** ${title} ********************`);
@@ -45,50 +73,56 @@ export function createTableRestoreScript(backupTable: TableInfo, originalTable:
dmp.comment(`Follows UPDATE, DELETE, INSERT statements to restore data`); dmp.comment(`Follows UPDATE, DELETE, INSERT statements to restore data`);
dmp.putRaw('\n'); dmp.putRaw('\n');
const update: Update = { if (valueColumns.length > 0) {
commandType: 'update', const update: Update = {
from: { name: originalTable }, commandType: 'update',
fields: valueColumns.map(colName => ({ from: { name: originalTable },
exprType: 'select', fields: valueColumns.map(colName => ({
select: { exprType: 'select',
commandType: 'select', select: {
from: { name: backupTable, alias: 'bak' }, commandType: 'select',
columns: [ from: { name: backupTable, alias: 'bak' },
{ columns: [
exprType: 'column',
columnName: colName,
source: { alias: 'bak' },
},
],
where: {
conditionType: 'and',
conditions: keyColumns.map(colName => makeColumnCond(colName)),
},
},
targetColumn: colName,
})),
where: {
conditionType: 'exists',
subQuery: {
commandType: 'select',
from: { name: backupTable, alias: 'bak' },
selectAll: true,
where: {
conditionType: 'and',
conditions: [
...keyColumns.map(keyColName => makeColumnCond(keyColName)),
{ {
conditionType: 'or', exprType: 'column',
conditions: valueColumns.map(colName => makeColumnCond(colName, '<>')), columnName: colName,
source: { alias: 'bak' },
}, },
], ],
where: {
conditionType: 'and',
conditions: keyColumns.map(colName => makeColumnCond(colName)),
},
},
targetColumn: colName,
})),
where: {
conditionType: 'exists',
subQuery: {
commandType: 'select',
from: { name: backupTable, alias: 'bak' },
selectAll: true,
where: {
conditionType: 'and',
conditions: [
...keyColumns.map(keyColName => makeColumnCond(keyColName)),
{
conditionType: 'or',
conditions: valueColumns.flatMap(colName => [
makeColumnCond(colName, '<>'),
makeNullNotNullCond(colName, true),
makeNullNotNullCond(colName, false),
]),
},
],
},
}, },
}, },
}, };
}; putTitle('UPDATE');
putTitle('UPDATE'); dumpSqlUpdate(dmp, update);
dumpSqlUpdate(dmp, update); dmp.endCommand();
dmp.endCommand(); }
const delcmd: Delete = { const delcmd: Delete = {
commandType: 'delete', commandType: 'delete',
@@ -127,6 +161,14 @@ export function createTableRestoreScript(backupTable: TableInfo, originalTable:
}; };
putTitle('INSERT'); putTitle('INSERT');
const autoinc = originalTable.columns.find(x => x.autoIncrement);
if (autoinc) {
dmp.allowIdentityInsert(originalTable, true);
}
dumpSqlInsert(dmp, insert); dumpSqlInsert(dmp, insert);
dmp.endCommand(); dmp.endCommand();
if (autoinc) {
dmp.allowIdentityInsert(originalTable, false);
}
} }