kysely
Version:
Type safe SQL query builder
126 lines (125 loc) • 4.14 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RuntimeDriver = void 0;
const performance_now_js_1 = require("../util/performance-now.js");
/**
* A small wrapper around {@link Driver} that makes sure the driver is
* initialized before it is used, only initialized and destroyed
* once etc.
*/
class RuntimeDriver {
#driver;
#log;
#initPromise;
#initDone;
#destroyPromise;
#connections = new WeakSet();
constructor(driver, log) {
this.#initDone = false;
this.#driver = driver;
this.#log = log;
}
async init() {
if (this.#destroyPromise) {
throw new Error('driver has already been destroyed');
}
if (!this.#initPromise) {
this.#initPromise = this.#driver
.init()
.then(() => {
this.#initDone = true;
})
.catch((err) => {
this.#initPromise = undefined;
return Promise.reject(err);
});
}
await this.#initPromise;
}
async acquireConnection() {
if (this.#destroyPromise) {
throw new Error('driver has already been destroyed');
}
if (!this.#initDone) {
await this.init();
}
const connection = await this.#driver.acquireConnection();
if (!this.#connections.has(connection)) {
if (this.#needsLogging()) {
this.#addLogging(connection);
}
this.#connections.add(connection);
}
return connection;
}
async releaseConnection(connection) {
await this.#driver.releaseConnection(connection);
}
beginTransaction(connection, settings) {
return this.#driver.beginTransaction(connection, settings);
}
commitTransaction(connection) {
return this.#driver.commitTransaction(connection);
}
rollbackTransaction(connection) {
return this.#driver.rollbackTransaction(connection);
}
async destroy() {
if (!this.#initPromise) {
return;
}
await this.#initPromise;
if (!this.#destroyPromise) {
this.#destroyPromise = this.#driver.destroy().catch((err) => {
this.#destroyPromise = undefined;
return Promise.reject(err);
});
}
await this.#destroyPromise;
}
#needsLogging() {
return (this.#log.isLevelEnabled('query') || this.#log.isLevelEnabled('error'));
}
// This method monkey patches the database connection's executeQuery method
// by adding logging code around it. Monkey patching is not pretty, but it's
// the best option in this case.
#addLogging(connection) {
const executeQuery = connection.executeQuery;
connection.executeQuery = async (compiledQuery) => {
let caughtError;
const startTime = (0, performance_now_js_1.performanceNow)();
try {
return await executeQuery.call(connection, compiledQuery);
}
catch (error) {
caughtError = error;
await this.#logError(error, compiledQuery, startTime);
throw error;
}
finally {
if (!caughtError) {
await this.#logQuery(compiledQuery, startTime);
}
}
};
}
async #logError(error, compiledQuery, startTime) {
await this.#log.error(() => ({
level: 'error',
error,
query: compiledQuery,
queryDurationMillis: this.#calculateDurationMillis(startTime),
}));
}
async #logQuery(compiledQuery, startTime) {
await this.#log.query(() => ({
level: 'query',
query: compiledQuery,
queryDurationMillis: this.#calculateDurationMillis(startTime),
}));
}
#calculateDurationMillis(startTime) {
return (0, performance_now_js_1.performanceNow)() - startTime;
}
}
exports.RuntimeDriver = RuntimeDriver;