diff --git a/src/libs/SqlRunnerManager.ts b/src/libs/SqlRunnerManager.ts index a5e65d0..7e83a43 100644 --- a/src/libs/SqlRunnerManager.ts +++ b/src/libs/SqlRunnerManager.ts @@ -26,6 +26,7 @@ interface SqlExecuteOption { onStart?: () => void; skipProtection?: boolean; disableAnalyze?: boolean; + insideTransaction?: boolean; } export class SqlRunnerManager { @@ -44,6 +45,12 @@ export class SqlRunnerManager { const result: SqlStatementResult[] = []; const parser = new Parser(); + // We only wrap transaction if it is multiple statement and + // insideTransactin is specified. Single statement, by itself, is + // transactional already. + const shouldStartTransaction = + !!options?.insideTransaction && statements.length > 1; + const finalStatements: SqlStatementWithAnalyze[] = options?.disableAnalyze ? statements : statements.map((statement) => { @@ -65,33 +72,40 @@ export class SqlRunnerManager { } } - for (const statement of finalStatements) { - for (const cb of this.beforeEachCallbacks) { - if (!(await cb(statement, options?.skipProtection))) { - throw 'Cancel'; + try { + if (shouldStartTransaction) await this.executor('START TRANSACTION;'); + for (const statement of finalStatements) { + for (const cb of this.beforeEachCallbacks) { + if (!(await cb(statement, options?.skipProtection))) { + throw 'Cancel'; + } } - } - if (options?.onStart) options.onStart(); + if (options?.onStart) options.onStart(); - console.log(statement.sql); + console.log(statement.sql); - const returnedResult = await this.executor( - statement.sql, - statement.params - ); + const returnedResult = await this.executor( + statement.sql, + statement.params + ); - if (!returnedResult?.error) { - result.push({ - statement, - result: returnedResult, - }); - } else { - throw returnedResult.error; + if (!returnedResult?.error) { + result.push({ + statement, + result: returnedResult, + }); + } else { + throw returnedResult.error; + } } - } - return result; + if (shouldStartTransaction) await this.executor('COMMIT;'); + return result; + } catch (e) { + if (shouldStartTransaction) await this.executor('ROLLBACK;'); + throw e; + } } registerBeforeAll(cb: BeforeAllEventCallback) { diff --git a/src/renderer/screens/DatabaseScreen/QueryResultViewer/QueryResultAction.tsx b/src/renderer/screens/DatabaseScreen/QueryResultViewer/QueryResultAction.tsx index f68e8fd..d123d27 100644 --- a/src/renderer/screens/DatabaseScreen/QueryResultViewer/QueryResultAction.tsx +++ b/src/renderer/screens/DatabaseScreen/QueryResultViewer/QueryResultAction.tsx @@ -64,7 +64,7 @@ export default function QueryResultAction({ })); runner - .execute(rawSql) + .execute(rawSql, { insideTransaction: true }) .then(() => { const changes = collector.getChanges();