This commit is contained in:
Nikita Sivukhin
2025-09-17 10:38:05 +04:00
parent 1185298670
commit 66de28d84b
30 changed files with 4175 additions and 190 deletions

View File

@@ -1,3 +1,4 @@
import { AsyncLock } from "./async-lock.js";
import { bindParams } from "./bind.js";
import { SqliteError } from "./sqlite-error.js";
import { NativeDatabase, NativeStatement, STEP_IO, STEP_ROW, STEP_DONE, DatabaseOpts } from "./types.js";
@@ -32,6 +33,7 @@ class Database {
db: NativeDatabase;
memory: boolean;
open: boolean;
execLock: AsyncLock;
private _inTransaction: boolean = false;
/**
* Creates a new database connection. If the database file pointed to by `path` does not exists, it will be created.
@@ -57,6 +59,7 @@ class Database {
initialize(db: NativeDatabase, name, readonly) {
this.db = db;
this.memory = db.memory;
this.execLock = new AsyncLock();
Object.defineProperties(this, {
inTransaction: {
get: () => this._inTransaction,
@@ -112,17 +115,22 @@ class Database {
const db = this;
const wrapTxn = (mode) => {
return async (...bindParameters) => {
await db.exec("BEGIN " + mode);
db._inTransaction = true;
await this.execLock.acquire();
try {
const result = await fn(...bindParameters);
await db.exec("COMMIT");
db._inTransaction = false;
return result;
} catch (err) {
await db.exec("ROLLBACK");
db._inTransaction = false;
throw err;
await db.exec("BEGIN " + mode);
db._inTransaction = true;
try {
const result = await fn(...bindParameters);
await db.exec("COMMIT");
db._inTransaction = false;
return result;
} catch (err) {
await db.exec("ROLLBACK");
db._inTransaction = false;
throw err;
}
} finally {
this.execLock.release();
}
};
};
@@ -195,6 +203,7 @@ class Database {
throw new TypeError("The database connection is not open");
}
await this.execLock.acquire();
try {
const stmt = this.prepare(sql);
try {
@@ -204,6 +213,8 @@ class Database {
}
} catch (err) {
throw convertError(err);
} finally {
this.execLock.release();
}
}
@@ -302,25 +313,30 @@ class Statement {
this.stmt.reset();
bindParams(this.stmt, bindParameters);
while (true) {
const stepResult = this.stmt.stepSync();
if (stepResult === STEP_IO) {
await this.db.db.ioLoopAsync();
continue;
}
if (stepResult === STEP_DONE) {
break;
}
if (stepResult === STEP_ROW) {
// For run(), we don't need the row data, just continue
continue;
await this.db.execLock.acquire();
try {
while (true) {
const stepResult = await this.stmt.stepSync();
if (stepResult === STEP_IO) {
await this.db.db.ioLoopAsync();
continue;
}
if (stepResult === STEP_DONE) {
break;
}
if (stepResult === STEP_ROW) {
// For run(), we don't need the row data, just continue
continue;
}
}
const lastInsertRowid = this.db.db.lastInsertRowid();
const changes = this.db.db.totalChanges() === totalChangesBefore ? 0 : this.db.db.changes();
return { changes, lastInsertRowid };
} finally {
this.db.execLock.release();
}
const lastInsertRowid = this.db.db.lastInsertRowid();
const changes = this.db.db.totalChanges() === totalChangesBefore ? 0 : this.db.db.changes();
return { changes, lastInsertRowid };
}
/**
@@ -332,18 +348,23 @@ class Statement {
this.stmt.reset();
bindParams(this.stmt, bindParameters);
while (true) {
const stepResult = this.stmt.stepSync();
if (stepResult === STEP_IO) {
await this.db.db.ioLoopAsync();
continue;
}
if (stepResult === STEP_DONE) {
return undefined;
}
if (stepResult === STEP_ROW) {
return this.stmt.row();
await this.db.execLock.acquire();
try {
while (true) {
const stepResult = await this.stmt.stepSync();
if (stepResult === STEP_IO) {
await this.db.db.ioLoopAsync();
continue;
}
if (stepResult === STEP_DONE) {
return undefined;
}
if (stepResult === STEP_ROW) {
return this.stmt.row();
}
}
} finally {
}
}
@@ -356,18 +377,23 @@ class Statement {
this.stmt.reset();
bindParams(this.stmt, bindParameters);
while (true) {
const stepResult = this.stmt.stepSync();
if (stepResult === STEP_IO) {
await this.db.db.ioLoopAsync();
continue;
}
if (stepResult === STEP_DONE) {
break;
}
if (stepResult === STEP_ROW) {
yield this.stmt.row();
await this.db.execLock.acquire();
try {
while (true) {
const stepResult = await this.stmt.stepSync();
if (stepResult === STEP_IO) {
await this.db.db.ioLoopAsync();
continue;
}
if (stepResult === STEP_DONE) {
break;
}
if (stepResult === STEP_ROW) {
yield this.stmt.row();
}
}
} finally {
this.db.execLock.release();
}
}
@@ -381,20 +407,26 @@ class Statement {
bindParams(this.stmt, bindParameters);
const rows: any[] = [];
while (true) {
const stepResult = this.stmt.stepSync();
if (stepResult === STEP_IO) {
await this.db.db.ioLoopAsync();
continue;
}
if (stepResult === STEP_DONE) {
break;
}
if (stepResult === STEP_ROW) {
rows.push(this.stmt.row());
await this.db.execLock.acquire();
try {
while (true) {
const stepResult = await this.stmt.stepSync();
if (stepResult === STEP_IO) {
await this.db.db.ioLoopAsync();
continue;
}
if (stepResult === STEP_DONE) {
break;
}
if (stepResult === STEP_ROW) {
rows.push(this.stmt.row());
}
}
return rows;
}
finally {
this.db.execLock.release();
}
return rows;
}
/**