import { Result } from "./result.mjs"; import { PawSQLiteError } from "./pawsqlite_error.mjs"; import { query } from "./query.mjs"; export class Transaction { constructor(dbName, adapter, enqueue, rollbackOnError=false) { this.dbName = dbName; this.adapter = adapter; this._rollbackOnError = rollbackOnError; this._enqueue = enqueue; this._completeCb = null; this._readyWait = null; this._ready = false; this._finalized = false; } async sql(sql, ...args) { if (this._finalized) { throw new PawSQLiteError("Transaction has already completed"); } if (!this._ready) { await this._waitUntilReady(); } let result; try { result = await this.adapter.sql(this.dbName, ...query(sql, ...args)); } catch (e) { if (this._rollbackOnError) { await this.rollback(); } throw e; } return new Result(result); } commit() { return this._complete("COMMIT"); } rollback() { return this._complete("ROLLBACK"); } async _waitUntilReady() { if (!this._readyWait) { this._readyWait = (async () => { this._completeCb = await this._enqueue(); await this._begin(); this._ready = true; })(); } await this._readyWait; } async _begin() { const result = await this.adapter.sql(this.dbName, "BEGIN"); } async _complete(sql) { if (this._finalized) { throw new PawSQLiteError("Transaction has already completed"); } this._finalized = true; if (!this._readyWait) { // Transaction was unused return; } else if (!this._ready) { await this._waitUntilReady(); } let result; let error; try { result = await this.adapter.sql(this.dbName, sql); } catch (e) { error = e; } this._completeCb(); if (error) { throw error; } return new Result(result); } }