260 lines
6.5 KiB
JavaScript
260 lines
6.5 KiB
JavaScript
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
// Copyright (c) 2015-2025 MariaDB Corporation Ab
|
|
|
|
'use strict';
|
|
|
|
import { EventEmitter } from 'node:events';
|
|
import Pool from './pool.js';
|
|
import ConnectionPromise, { paramSetter } from './connection-promise.js';
|
|
import * as Errors from './misc/errors.js';
|
|
|
|
const hasAsyncDispose = typeof Symbol.asyncDispose === 'symbol';
|
|
|
|
class PoolPromise extends EventEmitter {
|
|
#pool;
|
|
constructor(options) {
|
|
super();
|
|
this.#pool = new Pool(options);
|
|
const poolPromise = this;
|
|
this.#pool._onNewConnection = (conn) => {
|
|
try {
|
|
poolPromise.emit('connection', new ConnectionPromise(conn));
|
|
} catch (err) {
|
|
// ignore user errors in connection event handler
|
|
}
|
|
};
|
|
this.#pool.on('acquire', this.emit.bind(this, 'acquire'));
|
|
this.#pool.on('enqueue', this.emit.bind(this, 'enqueue'));
|
|
this.#pool.on('release', this.emit.bind(this, 'release'));
|
|
this.#pool.on('error', this.emit.bind(this, 'error'));
|
|
}
|
|
|
|
get closed() {
|
|
return this.#pool.closed;
|
|
}
|
|
|
|
/**
|
|
* Get the current total connection number.
|
|
* @return {number}
|
|
*/
|
|
totalConnections() {
|
|
return this.#pool.totalConnections();
|
|
}
|
|
|
|
/**
|
|
* Get current active connections.
|
|
* @return {number}
|
|
*/
|
|
activeConnections() {
|
|
return this.#pool.activeConnections();
|
|
}
|
|
|
|
/**
|
|
* Get the current idle connection number.
|
|
* @return {number}
|
|
*/
|
|
idleConnections() {
|
|
return this.#pool.idleConnections();
|
|
}
|
|
|
|
/**
|
|
* Get current stacked connection request.
|
|
* @return {number}
|
|
*/
|
|
taskQueueSize() {
|
|
return this.#pool.taskQueueSize();
|
|
}
|
|
|
|
escape(value) {
|
|
return this.#pool.escape(value);
|
|
}
|
|
|
|
escapeId(value) {
|
|
return this.#pool.escapeId(value);
|
|
}
|
|
|
|
/**
|
|
* End pool
|
|
*
|
|
* @return Promise
|
|
**/
|
|
end() {
|
|
return this.#pool.end();
|
|
}
|
|
|
|
/**
|
|
* Retrieve a connection from the pool.
|
|
* Create a new one if the limit is not reached.
|
|
* wait until acquireTimeout.
|
|
*
|
|
*/
|
|
async getConnection() {
|
|
const cmdParam = {};
|
|
if (this.#pool.opts.connOptions.trace) Error.captureStackTrace(cmdParam);
|
|
return new Promise((resolve, reject) => {
|
|
this.#pool.getConnection(cmdParam, (err, baseConn) => {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
const conn = new ConnectionPromise(baseConn);
|
|
conn.release = () => new Promise(baseConn.release);
|
|
conn.end = conn.release;
|
|
conn.close = conn.release;
|
|
if (hasAsyncDispose) {
|
|
conn[Symbol.asyncDispose] = () => conn.release();
|
|
}
|
|
resolve(conn);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Execute a query using text protocol with callback emit columns/data/end/error
|
|
* events to permit streaming big result-set
|
|
*
|
|
* @param sql sql parameter Object can be used to supersede the default option.
|
|
* Object must then have a `sql` property.
|
|
* @param values object / array of placeholder values (not mandatory)
|
|
*/
|
|
query(sql, values) {
|
|
const cmdParam = paramSetter(sql, values);
|
|
if (this.#pool.opts.connOptions.trace) Error.captureStackTrace(cmdParam);
|
|
return new Promise((resolve, reject) => {
|
|
return this.#pool.getConnection(cmdParam, (err, baseConn) => {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
baseConn.query(
|
|
cmdParam,
|
|
(res) => {
|
|
this.#pool.release(baseConn);
|
|
resolve(res);
|
|
},
|
|
(err) => {
|
|
this.#pool.release(baseConn);
|
|
reject(err);
|
|
}
|
|
);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Execute a query using binary protocol with callback emit columns/data/end/error
|
|
* events to permit streaming big result-set
|
|
*
|
|
* @param sql sql parameter Object can be used to supersede the default option.
|
|
* Object must then have a `sql` property.
|
|
* @param values object / array of placeholder values (not mandatory)
|
|
*/
|
|
execute(sql, values) {
|
|
const cmdParam = paramSetter(sql, values);
|
|
if (this.#pool.opts.connOptions.trace) Error.captureStackTrace(cmdParam);
|
|
return new Promise((resolve, reject) => {
|
|
return this.#pool.getConnection(cmdParam, (err, baseConn) => {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
baseConn.prepareExecute(
|
|
cmdParam,
|
|
(res) => {
|
|
this.#pool.release(baseConn);
|
|
resolve(res);
|
|
},
|
|
(err) => {
|
|
this.#pool.release(baseConn);
|
|
reject(err);
|
|
}
|
|
);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* execute a batch
|
|
*
|
|
* @param sql sql parameter Object can be used to supersede the default option.
|
|
* Object must then have a `sql` property.
|
|
* @param values array of placeholder values
|
|
*/
|
|
batch(sql, values) {
|
|
const cmdParam = paramSetter(sql, values);
|
|
if (this.#pool.opts.connOptions.trace) Error.captureStackTrace(cmdParam);
|
|
return new Promise((resolve, reject) => {
|
|
return this.#pool.getConnection(cmdParam, (err, baseConn) => {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
baseConn.batch(
|
|
cmdParam,
|
|
(res) => {
|
|
this.#pool.release(baseConn);
|
|
resolve(res);
|
|
},
|
|
(err) => {
|
|
this.#pool.release(baseConn);
|
|
reject(err);
|
|
}
|
|
);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Import SQL file.
|
|
*
|
|
* @param opts JSON array with 2 possible fields: file and database
|
|
*/
|
|
importFile(opts) {
|
|
if (!opts) {
|
|
return Promise.reject(
|
|
Errors.createError(
|
|
'SQL file parameter is mandatory',
|
|
Errors.client.ER_MISSING_SQL_PARAMETER,
|
|
null,
|
|
'HY000',
|
|
null,
|
|
false,
|
|
null
|
|
)
|
|
);
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
|
return this.#pool.getConnection({}, (err, baseConn) => {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
baseConn.importFile(
|
|
{ file: opts.file, database: opts.database },
|
|
(res) => {
|
|
this.#pool.release(baseConn);
|
|
resolve(res);
|
|
},
|
|
(err) => {
|
|
this.#pool.release(baseConn);
|
|
reject(err);
|
|
}
|
|
);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
toString() {
|
|
return 'poolPromise(' + this.#pool.toString() + ')';
|
|
}
|
|
}
|
|
|
|
if (hasAsyncDispose) {
|
|
PoolPromise.prototype[Symbol.asyncDispose] = function () {
|
|
return this.end();
|
|
};
|
|
}
|
|
|
|
export default PoolPromise;
|