providerrefactor part1

This commit is contained in:
seb
2026-09-21 03:33:55 +02:00
parent 53a20c4353
commit 4ed6260e91
57 changed files with 1662 additions and 145 deletions

View File

@@ -4,6 +4,8 @@
* { rows, rowsAffected, insertId }
*/
import sql from 'mssql';
function normalizeRows(result) {
const recordset = result?.recordset ?? [];
const affected = Array.isArray(result?.rowsAffected)
@@ -55,24 +57,67 @@ export class MssqlExecutor {
}
export class MssqlProvider {
/** @param {import('mssql').ConnectionPool} pool */
constructor(pool) {
if (!pool || typeof pool.request !== 'function') {
throw new TypeError('MssqlProvider requires an mssql ConnectionPool');
/**
* @param {import('mssql').ConnectionPool | import('mssql').config} poolOrConfig
* Either an already-connected mssql ConnectionPool, or a plain mssql
* config object — in which case the pool is created lazily on first use
* (and closed by {@link MssqlProvider#close}).
*/
constructor(poolOrConfig) {
const isPool =
poolOrConfig && typeof poolOrConfig.request === 'function';
if (!poolOrConfig || (!isPool && !poolOrConfig.server)) {
throw new TypeError(
'MssqlProvider requires an mssql ConnectionPool or a config object with `server`',
);
}
this.pool = pool;
// Keep a stable pool object available immediately. Transitional store
// modules capture `provider.pool` in their factory closures, so assigning
// a different object after a lazy connection would leave them with null.
this.pool = isPool ? poolOrConfig : new sql.ConnectionPool(poolOrConfig);
this.#config = isPool ? null : poolOrConfig;
this.dialect = 'mssql';
}
#config;
#connecting;
/**
* Returns the underlying pool, creating and connecting it on first use
* when the provider was constructed from a config object.
* @returns {Promise<import('mssql').ConnectionPool>}
*/
ensurePool() {
if (this.pool.connected) return Promise.resolve(this.pool);
if (!this.#connecting) {
this.#connecting = this.pool
.connect()
.then((pool) => {
return pool;
})
.catch((err) => {
this.#connecting = undefined;
throw err;
});
}
return this.#connecting;
}
makeExecutor(requestFactory = () => this.pool.request()) {
return new MssqlExecutor(requestFactory);
}
async #withPool(fn) {
const pool = await this.ensurePool();
return fn(new MssqlExecutor(() => pool.request()));
}
async query(sql, params = {}) {
return this.makeExecutor().query(sql, params);
return this.#withPool((executor) => executor.query(sql, params));
}
async exec(procName, options) {
return this.makeExecutor().exec(procName, options);
return this.#withPool((executor) => executor.exec(procName, options));
}
/**
@@ -84,7 +129,8 @@ export class MssqlProvider {
* @returns {Promise<T>}
*/
async transaction(fn) {
const tx = this.pool.transaction();
const pool = await this.ensurePool();
const tx = pool.transaction();
await tx.begin();
try {
const runner = this.makeExecutor(() => tx.request());
@@ -111,7 +157,7 @@ export class MssqlProvider {
}
close() {
return this.pool.close();
return this.pool ? this.pool.close() : Promise.resolve();
}
}