UNPKG

lupdo

Version:

Database Abstraction Layer for Node js

213 lines (212 loc) 8.65 kB
import { EventEmitter } from 'node:events'; import { v4 as uuidv4 } from 'uuid'; import { ATTR_CASE, ATTR_DEBUG, ATTR_DRIVER_NAME, ATTR_FETCH_DIRECTION, ATTR_NULLS, CASE_NATURAL, DEBUG_DISABLED, DEBUG_ENABLED, FETCH_FORWARD, NULL_NATURAL, } from '../constants'; import PdoError from '../errors/pdo-error'; import PdoPool from './pdo-pool'; import PdoPreparedStatement from './pdo-prepared-statement'; import PdoStatement from './pdo-statement'; import PdoTransaction from './pdo-transaction'; export class PdoDriver extends EventEmitter { constructor(driver, userPoolOptions, userAttributes) { super(); this.instances = { transaction: PdoTransaction, preparedStatement: PdoPreparedStatement, statement: PdoStatement, }; this.defaultAttributes = { [ATTR_FETCH_DIRECTION]: FETCH_FORWARD, [ATTR_CASE]: CASE_NATURAL, [ATTR_NULLS]: NULL_NATURAL, [ATTR_DEBUG]: DEBUG_DISABLED, }; this.driverAttributes = {}; this.processedAttributes = null; this.processedPoolOptions = null; this.poolEvents = {}; this.hasDebug = false; this.initializedPool = null; this.disconnected = false; this.forceReconnect = false; this.userAttributes = userAttributes; const { created, destroyed, acquired, released, killed, ...otherOptions } = userPoolOptions; this.userPoolOptions = otherOptions; this.poolEvents = { created, destroyed, acquired, released, killed }; Object.assign(this.defaultAttributes, { [ATTR_DRIVER_NAME]: driver, }); } reconnect() { if (this.disconnected) { this.initializedPool = new PdoPool(this.poolOptions); this.assignPoolEvents(); this.disconnected = false; } } async disconnect() { await this.pool.destroy(); this.pool.removeAllListeners('acquireSuccess'); this.pool.removeAllListeners('release'); this.disconnected = true; } get poolOptions() { if (this.processedPoolOptions === null) { this.processedPoolOptions = { min: 2, max: 10, acquireTimeoutMillis: 10000, createTimeoutMillis: 5000, ...this.userPoolOptions, propagateCreateError: false, validate: (connection) => { return this.validateRawConnection(connection); }, create: async () => { const connection = await this.createConnection(); const uuid = uuidv4(); if (this.version === undefined) { this.version = await this.getVersionFromConnection(connection); } if (typeof this.poolEvents.created === 'function') { const pdoConnection = this.createPdoConnection(connection); pdoConnection.version = this.version; await this.poolEvents.created(uuid, pdoConnection); } connection.__lupdo_uuid = uuid; connection.__lupdo_killed = false; if (this.hasDebug) { console.log(`Pdo Pool Resource Created: ${connection.__lupdo_uuid}`); } return connection; }, kill: async (connection) => { if (connection !== undefined) { await this.destroyConnection(connection); connection.__lupdo_killed = true; if (typeof this.poolEvents.killed === 'function') { this.poolEvents.killed(connection.__lupdo_uuid); } if (this.hasDebug) { console.log(`Pdo Pool Resource Killed: ${connection.__lupdo_uuid}`); } } }, destroy: async (connection) => { if (connection !== undefined && !connection.__lupdo_killed) { const uuid = connection.__lupdo_uuid; await this.closeConnection(connection); if (typeof this.poolEvents.destroyed === 'function') { await this.poolEvents.destroyed(uuid); } if (this.hasDebug) { console.log(`Pdo Pool Resource Destroyed: ${connection.__lupdo_uuid}`); } } }, log: (message) => { this.emit('log', 'warning', message); }, }; } return this.processedPoolOptions; } get attributes() { if (this.processedAttributes === null) { this.processedAttributes = Object.assign({}, { ...this.defaultAttributes }, { ...this.driverAttributes }); for (const key in this.userAttributes) { if (key in this.processedAttributes && key !== ATTR_DRIVER_NAME) { this.processedAttributes[key] = this.userAttributes[key]; } } } return this.processedAttributes; } get pool() { if (this.initializedPool === null) { this.hasDebug = this.getAttribute(ATTR_DEBUG) === DEBUG_ENABLED; this.initializedPool = new PdoPool(this.poolOptions); this.assignPoolEvents(); } return this.initializedPool; } async beginTransaction() { this.throwIfDisconnected(); const connection = this.getRawConnection(); connection.setAttributes(this.attributes); await connection.beginTransaction(); return new this.instances.transaction(connection); } async prepare(sql) { this.throwIfDisconnected(); const connection = this.getRawConnection(); connection.setAttributes(this.attributes); return new this.instances.preparedStatement(connection, sql, await connection.prepare(sql)); } async exec(sql) { this.throwIfDisconnected(); const connection = this.getRawConnection(); connection.setAttributes(this.attributes); return await connection.exec(sql); } async query(sql) { this.throwIfDisconnected(); const connection = this.getRawConnection(); connection.setAttributes(this.attributes); return new this.instances.statement(connection, sql, ...(await connection.query(sql))); } getAttribute(attribute) { return this.attributes[attribute]; } setAttribute(attribute, value) { if (attribute in this.attributes) { this.attributes[attribute] = value; return true; } return false; } async getVersion() { if (this.version === undefined) { const connection = await this.createConnection(); this.version = await this.getVersionFromConnection(connection); await this.closeConnection(connection); } return this.version; } async getRawPoolConnection() { this.throwIfDisconnected(); const connection = await this.pool.acquire().promise; return { connection, release: async () => { await this.pool.release(connection); }, }; } async getRawDriverConnection() { return (await this.createConnection(true)); } assignPoolEvents() { this.pool.on('acquireSuccess', (eventId, connection) => { if (typeof this.poolEvents.acquired === 'function') { this.poolEvents.acquired(connection.__lupdo_uuid, eventId); } if (this.hasDebug) { console.log(`Pdo Pool Resource Acquired: ${connection.__lupdo_uuid}`); } }); this.pool.on('release', (connection) => { if (typeof this.poolEvents.released === 'function') { this.poolEvents.released(connection.__lupdo_uuid); } if (this.hasDebug) { console.log(`Pdo Pool Resource Released: ${connection.__lupdo_uuid}`); } }); } throwIfDisconnected() { if (this.disconnected) { throw new PdoError('Pdo is Disconnected from pool, please reconnect.'); } } } export default PdoDriver;