UNPKG

sqlite3orm

Version:

ORM for sqlite3 and TypeScript/JavaScript

227 lines 8.01 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SqlConnectionPool = void 0; const tslib_1 = require("tslib"); const node_utils_1 = require("@homeofthings/node-utils"); const _dbg = tslib_1.__importStar(require("debug")); const SqlConnectionPoolDatabase_1 = require("./SqlConnectionPoolDatabase"); const SqlDatabase_1 = require("./SqlDatabase"); const debug = _dbg.default('sqlite3orm:pool'); /** * A simple connection pool * * @export * @class SqlConnectionPool */ class SqlConnectionPool { name; databaseFile; mode; min; max; inPool; inUse; settings; _opening; get poolSize() { return this.inPool.length; } get openSize() { return this.inUse.size; } /** * Creates an instance of SqlConnectionPool. */ constructor(name = '') { this.name = name; this.databaseFile = undefined; this.mode = SqlDatabase_1.SQL_OPEN_DEFAULT; this.inUse = new Set(); this.inPool = []; this.min = this.max = 0; } /** * Open a database connection pool * * @param databaseFile - The path to the database file or URI * @param [mode=SQL_OPEN_DEFAULT] - A bit flag combination of: SQL_OPEN_CREATE | * SQL_OPEN_READONLY | SQL_OPEN_READWRITE * @param [min=1] minimum connections which should be opened by this connection pool * @param [max=0] maximum connections which can be opened by this connection pool * @returns A promise */ async open(databaseFile, mode = SqlDatabase_1.SQL_OPEN_DEFAULT, min = 1, max = 0, settings) { if (this._opening) { try { await this._opening; if (this.databaseFile === databaseFile && (mode & ~SqlDatabase_1.SQL_OPEN_CREATE) === this.mode) { // already opened return; } } catch (err) { /* empty */ } } this._opening = this.openInternal(databaseFile, mode, min, max, settings); try { await this._opening; } catch (err) { return Promise.reject(err); } finally { this._opening = undefined; } return; } async openInternal(databaseFile, mode = SqlDatabase_1.SQL_OPEN_DEFAULT, min = 1, max = 0, settings) { try { await this.close(); } catch (err) { /* empty */ } try { this.databaseFile = databaseFile; this.mode = mode; this.min = min; this.max = max; this.settings = settings; this.inPool.length = 0; const promises = []; if (this.min < 1) { this.min = 1; } let sqldb = new SqlConnectionPoolDatabase_1.SqlConnectionPoolDatabase(); await sqldb.openByPool(this, this.databaseFile, this.mode, this.settings); this.inPool.push(sqldb); this.mode &= ~SqlDatabase_1.SQL_OPEN_CREATE; for (let i = 1; i < this.min; i++) { sqldb = new SqlConnectionPoolDatabase_1.SqlConnectionPoolDatabase(); promises.push(sqldb.openByPool(this, this.databaseFile, this.mode, this.settings)); this.inPool.push(sqldb); } await Promise.all(promises); if (this.name.length) { SqlConnectionPool.openNamedPools.set(this.name, this); } debug(`pool ${this.name}: opened: ${this.inUse.size} connections open (${this.inPool.length} in pool)`); } catch (err) { try { await this.close(); } catch (_ignore) { /* empty */ } debug(`pool ${this.name}: opening ${databaseFile} failed: ${err.message}`); return Promise.reject(err); } } /** * Close the database connection pool * * @returns A promise */ async close() { try { if (this.databaseFile) { if (this.inUse.size) { debug(`pool ${this.name}: closing: forcibly closing ${this.inUse.size} opened connections (${this.inPool.length} in pool)`); } else { debug(`pool ${this.name}: closing: ${this.inUse.size} connections open (${this.inPool.length} in pool)`); } } if (this.name.length) { SqlConnectionPool.openNamedPools.delete(this.name); } this.databaseFile = undefined; this.mode = SqlDatabase_1.SQL_OPEN_DEFAULT; const promises = []; this.inPool.forEach((value) => { promises.push(value.closeByPool()); }); this.inPool.length = 0; this.inUse.forEach((value) => { promises.push(value.closeByPool()); }); this.inUse.clear(); await Promise.all(promises); } catch (err) { /* istanbul ignore next */ debug(`pool ${this.name}: closing failed: ${err.message}`); return Promise.reject(err); } } /** * test if this connection pool is connected to a database file */ isOpen() { return !!this.databaseFile; } /** * get a connection from the pool * * @param [timeout=0] The timeout to wait for a connection ( 0 is infinite ) * @returns A promise of the db connection */ async get(timeout = 0) { try { let sqldb; const cond = () => this.inPool.length > 0; if (this.max > 0 && !cond() && this.inUse.size >= this.max) { await (0, node_utils_1.wait)(cond, timeout); } if (this.inPool.length > 0) { sqldb = this.inPool.shift(); this.inUse.add(sqldb); debug(`pool ${this.name}: ${this.inUse.size} connections open (${this.inPool.length} in pool)`); return sqldb; } if (!this.databaseFile) { throw new Error(`connection pool not opened`); } sqldb = new SqlConnectionPoolDatabase_1.SqlConnectionPoolDatabase(); await sqldb.openByPool(this, this.databaseFile, this.mode, this.settings); this.inUse.add(sqldb); debug(`pool ${this.name}: ${this.inUse.size} connections open (${this.inPool.length} in pool)`); return sqldb; } catch (err) { debug(`pool ${this.name}: getting connection from pool failed: ${err.message}`); return Promise.reject(err); } } /** * release a connection to the pool * * @param sqldb - The db connection */ async release(sqldb) { /* istanbul ignore if */ if (!(sqldb instanceof SqlConnectionPoolDatabase_1.SqlConnectionPoolDatabase) || this !== sqldb.pool) { // not opened by this pool return sqldb.close(); } this.inUse.delete(sqldb); /* istanbul ignore else */ if (sqldb.isOpen()) { if (sqldb.dirty || this.inPool.length >= this.min) { // close database connection await sqldb.closeByPool(); } else { // transfer database connection const newsqldb = new SqlConnectionPoolDatabase_1.SqlConnectionPoolDatabase(); await newsqldb.recycleByPool(this, sqldb, this.settings); this.inPool.push(newsqldb); } debug(`pool ${this.name}: ${this.inUse.size} connections open (${this.inPool.length} in pool)`); } } static openNamedPools = new Map(); } exports.SqlConnectionPool = SqlConnectionPool; //# sourceMappingURL=SqlConnectionPool.js.map