UNPKG

@sqb/connect

Version:

Multi-dialect database connection framework written with TypeScript

173 lines (172 loc) 6.66 kB
"use strict"; 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;