1 line
32 KiB
JSON
1 line
32 KiB
JSON
|
{"ast":null,"code":"import * as hrana from \"@libsql/hrana-client\";\nimport { LibsqlError } from \"@libsql/core/api\";\nimport { transactionModeToBegin, ResultSetImpl } from \"@libsql/core/util\";\nexport class HranaTransaction {\n #mode;\n #version;\n // Promise that is resolved when the BEGIN statement completes, or `undefined` if we haven't executed the\n // BEGIN statement yet.\n #started;\n /** @private */\n constructor(mode, version) {\n this.#mode = mode;\n this.#version = version;\n this.#started = undefined;\n }\n execute(stmt) {\n return this.batch([stmt]).then(results => results[0]);\n }\n async batch(stmts) {\n const stream = this._getStream();\n if (stream.closed) {\n throw new LibsqlError(\"Cannot execute statements because the transaction is closed\", \"TRANSACTION_CLOSED\");\n }\n try {\n const hranaStmts = stmts.map(stmtToHrana);\n let rowsPromises;\n if (this.#started === undefined) {\n // The transaction hasn't started yet, so we need to send the BEGIN statement in a batch with\n // `hranaStmts`.\n this._getSqlCache().apply(hranaStmts);\n const batch = stream.batch(this.#version >= 3);\n const beginStep = batch.step();\n const beginPromise = beginStep.run(transactionModeToBegin(this.#mode));\n // Execute the `hranaStmts` only if the BEGIN succeeded, to make sure that we don't execute it\n // outside of a transaction.\n let lastStep = beginStep;\n rowsPromises = hranaStmts.map(hranaStmt => {\n const stmtStep = batch.step().condition(hrana.BatchCond.ok(lastStep));\n if (this.#version >= 3) {\n // If the Hrana version supports it, make sure that we are still in a transaction\n stmtStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));\n }\n const rowsPromise = stmtStep.query(hranaStmt);\n rowsPromise.catch(() => undefined); // silence Node warning\n lastStep = stmtStep;\n return rowsPromise;\n });\n // `this.#started` is resolved successfully only if the batch and the BEGIN statement inside\n // of the batch are both successful.\n this.#started = batch.execute().then(() => beginPromise).then(() => undefined);\n try {\n await this.#started;\n } catch (e) {\n // If the BEGIN failed, the transaction is unusable and we must close it. However, if the\n // BEGIN suceeds and `hranaStmts` fail, the transaction is _not_ closed.\n this.close();\n throw e;\n }\n } else {\n if (this.#version < 3) {\n // The transaction has started, so we must wait until the BEGIN statement completed to make\n // sure that we don't execute `hranaStmts` outside of a transaction.\n await this.#started;\n } else {\n // The transaction has started, but we will use `hrana.BatchCond.isAutocommit()` to make\n // sure that we don't execute `hranaStmts` outside of a transaction, so we don't have to\n // wait for `this.#started`\n }\n this._getSqlCache().apply(hranaStmts);\n const batch = stream.batch(this.#version >= 3);\n let lastStep = undefined;\n rowsPromises = hranaStmts.map(hranaStmt => {\n const stmtStep = batch.step();\n if (lastStep !== undefined) {\n stmtStep.condition(hrana.BatchCond.ok(lastStep));\n }\n if (this.#version >= 3) {\n stmtStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));\n }\n const rowsPromise = stmtStep.query(hranaStmt);\n rowsPromise.catch(() => undefined); // silence Node warning\n lastStep = stmtStep;\n return rowsPromise;\n });\n await batch.execute();\n }\n const resultSets = [];\n for (const rowsPromise of rowsPromises) {\n const rows = await rowsPromise;\n if (rows === undefined) {\n throw new LibsqlError(\"St
|