@n8n/typeorm
Version:
Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, MongoDB databases.
128 lines (126 loc) • 4.52 kB
JavaScript
import { captureException } from "@sentry/node";
import { Mutex, withTimeout, E_TIMEOUT } from "async-mutex";
import assert from "assert";
import { DriverAlreadyReleasedError } from "../../error/DriverAlreadyReleasedError";
import { LeasedDbConnection } from "./LeasedDbConnection";
import { TimeoutTimer } from "./Timer";
/**
* A single write connection to the database.
*/
export class SqliteWriteConnection {
constructor(sqliteLibray, options) {
this.sqliteLibray = sqliteLibray;
this.options = options;
this.writeConnectionPromise = null;
/**
* Should the connection be re-created after it has been released
*/
this.isConnectionValid = true;
this.isReleased = false;
const acquireTimeout = options.acquireTimeout;
this.writeConnectionMutex = withTimeout(new Mutex(), acquireTimeout);
}
async connect() {
this.assertNotReleased();
await this.writeConnectionMutex.runExclusive(async () => await this.createConnection());
}
async close() {
if (this.isReleased)
return;
this.isReleased = true;
// Cancel any pending acquires
this.writeConnectionMutex.cancel();
// If there is an existing lease, request it to be released
if (this.dbLease) {
this.dbLease.requestRelease();
}
const timeoutTimer = TimeoutTimer.start(this.options.destroyTimeout);
await Promise.race([
this.writeConnectionMutex.acquire(),
timeoutTimer.promise,
]).finally(() => {
timeoutTimer.clear();
});
if (this.writeConnectionPromise) {
const dbConnection = await this.writeConnectionPromise;
this.sqliteLibray.destroyDatabaseConnection(dbConnection);
}
}
async runExclusive(dbLeaseHolder, callback) {
this.assertNotReleased();
try {
return await this.writeConnectionMutex.runExclusive(async () => {
this.dbLease = await this.createAndGetConnection(dbLeaseHolder);
const result = await callback(this.dbLease);
return result;
});
}
catch (error) {
if (error === E_TIMEOUT) {
captureException(error);
}
throw error;
}
finally {
this.dbLease = undefined;
}
}
async leaseConnection(dbLeaseHolder) {
this.assertNotReleased();
try {
await this.writeConnectionMutex.acquire();
}
catch (error) {
captureException(error);
throw error;
}
this.dbLease = await this.createAndGetConnection(dbLeaseHolder);
return this.dbLease;
}
invalidateConnection(leasedDbConnection) {
assert(this.dbLease === leasedDbConnection);
assert(this.writeConnectionMutex.isLocked());
assert(this.writeConnectionPromise);
this.isConnectionValid = false;
}
async releaseConnection(leasedDbConnection) {
assert(this.dbLease === leasedDbConnection);
assert(this.writeConnectionMutex.isLocked());
assert(this.writeConnectionPromise);
try {
const connection = await this.writeConnectionPromise;
if (!this.isConnectionValid) {
this.sqliteLibray.destroyDatabaseConnection(connection);
this.writeConnectionPromise = null;
}
}
finally {
this.dbLease = undefined;
this.writeConnectionMutex.release();
}
}
async createAndGetConnection(dbLeaseHolder) {
if (!this.writeConnectionPromise) {
this.writeConnectionPromise =
this.sqliteLibray.createDatabaseConnection();
}
const dbConnection = await this.writeConnectionPromise;
assert(!this.dbLease);
return new LeasedDbConnection(dbConnection, this, dbLeaseHolder);
}
async createConnection() {
this.assertNotReleased();
if (this.writeConnectionPromise) {
throw new Error("Connection already created");
}
this.writeConnectionPromise =
this.sqliteLibray.createDatabaseConnection();
return this.writeConnectionPromise;
}
assertNotReleased() {
if (this.isReleased) {
throw new DriverAlreadyReleasedError();
}
}
}
//# sourceMappingURL=SqliteWriteConnection.js.map