@sqb/connect
Version:
Multi-dialect database connection framework written with TypeScript
173 lines (172 loc) • 6.66 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SqbClient = void 0;
const tslib_1 = require("tslib");
const debug_1 = tslib_1.__importDefault(require("debug"));
const lightning_pool_1 = require("lightning-pool");
const putil_varhelpers_1 = require("putil-varhelpers");
const strict_typed_events_1 = require("strict-typed-events");
const entity_metadata_js_1 = require("../orm/model/entity-metadata.js");
const repository_class_js_1 = require("../orm/repository.class.js");
const extensions_js_1 = require("./extensions.js");
const sqb_connection_js_1 = require("./sqb-connection.js");
const debug = (0, debug_1.default)('sqb:client');
const inspect = Symbol.for('nodejs.util.inspect.custom');
class SqbClient extends (0, strict_typed_events_1.TypedEventEmitterClass)(strict_typed_events_1.AsyncEventEmitter) {
constructor(config) {
super();
this._entities = {};
if (!(config && typeof config === 'object'))
throw new TypeError('Configuration object required');
let adapter;
if (config.driver) {
adapter = extensions_js_1.AdapterRegistry.findDriver(config.driver);
if (!adapter)
throw new Error(`No database adapter registered for "${config.driver}" driver`);
}
else if (config.dialect) {
adapter = extensions_js_1.AdapterRegistry.findDialect(config.dialect);
if (!adapter)
throw new Error(`No database adapter registered for "${config.dialect}" dialect`);
}
if (!adapter)
throw new Error(`You must provide one of "driver" or "dialect" properties`);
this._adapter = adapter;
this._defaults = config.defaults || {};
const poolOptions = {};
const popts = config.pool || {};
poolOptions.acquireMaxRetries = (0, putil_varhelpers_1.coerceToInt)(popts.acquireMaxRetries, 0);
poolOptions.acquireRetryWait = (0, putil_varhelpers_1.coerceToInt)(popts.acquireRetryWait, 2000);
poolOptions.acquireTimeoutMillis = (0, putil_varhelpers_1.coerceToInt)(popts.acquireTimeoutMillis, 0);
poolOptions.idleTimeoutMillis = (0, putil_varhelpers_1.coerceToInt)(popts.idleTimeoutMillis, 30000);
poolOptions.max = (0, putil_varhelpers_1.coerceToInt)(popts.max, 10);
poolOptions.maxQueue = (0, putil_varhelpers_1.coerceToInt)(popts.maxQueue, 1000);
poolOptions.max = (0, putil_varhelpers_1.coerceToInt)(popts.max, 10);
poolOptions.min = (0, putil_varhelpers_1.coerceToInt)(popts.min, 0);
poolOptions.minIdle = (0, putil_varhelpers_1.coerceToInt)(popts.minIdle, 0);
poolOptions.validation = (0, putil_varhelpers_1.coerceToBoolean)(popts.validation, false);
const cfg = { ...config };
const poolFactory = {
create: () => adapter.connect(cfg),
destroy: instance => instance.close(),
reset: async (instance) => instance.reset(),
validate: instance => instance.test(),
};
this._pool = (0, lightning_pool_1.createPool)(poolFactory, poolOptions);
this._pool.on('closing', () => this.emit('closing'));
this._pool.on('close', () => this.emit('close'));
this._pool.on('terminate', () => this.emit('terminate'));
// @ts-ignore
this._pool.on('error', (...args) => this.emit('error', ...args));
}
get defaults() {
return this._defaults;
}
/**
* Returns dialect
*/
get dialect() {
return this._adapter.dialect;
}
/**
* Returns database driver name
*/
get driver() {
return this._adapter.driver;
}
/**
* Returns true if pool is closed
*/
get isClosed() {
return this._pool.state === lightning_pool_1.PoolState.CLOSED;
}
get pool() {
return this._pool;
}
async acquire(arg0, arg1) {
debug('acquire');
if (typeof arg0 === 'function') {
const connection = await this.acquire(arg1);
try {
return await arg0(connection);
}
finally {
connection.release();
}
}
const options = arg1;
const adapterConnection = await this._pool.acquire();
const opts = { autoCommit: this.defaults.autoCommit, ...options };
const connection = new sqb_connection_js_1.SqbConnection(this, adapterConnection, opts);
await this.emitAsyncSerial('acquire', connection);
connection.on('execute', (request) => this.emit('execute', request));
connection.on('error', (error) => this.emit('error', error));
connection.on('close', () => this.emitAsyncSerial('connection-return', connection));
return connection;
}
/**
* Shuts down the pool and destroys all resources.
*/
async close(terminateWait) {
const ms = terminateWait == null ? Infinity : 0;
return this._pool.close(ms);
}
/**
* Executes a query or callback with a new acquired connection.
*/
async execute(query, options) {
debug('execute');
const connection = await this.acquire();
try {
const qr = await connection.execute(query, options);
if (qr && qr.cursor) {
connection.retain();
qr.cursor.once('close', () => connection.release());
}
return qr;
}
finally {
connection.release();
}
}
/**
* Tests the pool
*/
async test() {
const connection = await this.acquire();
try {
await connection.test();
}
finally {
connection.release();
}
}
getRepository(entity, opts) {
let ctor;
if (typeof entity === 'string') {
ctor = this.getEntity(entity);
if (!ctor)
throw new Error(`Repository "${entity}" is not registered`);
}
else
ctor = entity;
const entityDef = entity_metadata_js_1.EntityMetadata.get(ctor);
if (!entityDef)
throw new Error(`You must provide an @Entity annotated constructor`);
return new repository_class_js_1.Repository(entityDef, this, opts?.schema);
}
getEntity(name) {
return this._entities[name];
}
toString() {
return ('[object ' +
Object.getPrototypeOf(this).constructor.name +
'(' +
this.dialect +
')]');
}
[inspect]() {
return this.toString();
}
}
exports.SqbClient = SqbClient;