@bazilio-san/af-stream
Version:
Data stream from database table
108 lines (96 loc) • 3.13 kB
text/typescript
import * as sql from 'mssql';
import { IDbConstructorOptions, IMsSqlConfig } from '../interfaces';
import { DbBase } from './DbBase';
import { MILLIS_IN_HOUR } from '../constants';
const commonTimeout = MILLIS_IN_HOUR * 3; // 3 ч
const mssqlDefaults: IMsSqlConfig = {
options: { enableArithAbort: false },
pool: {
max: 10,
min: 1,
idleTimeoutMillis: commonTimeout,
acquireTimeoutMillis: commonTimeout,
createTimeoutMillis: commonTimeout,
destroyTimeoutMillis: commonTimeout,
reapIntervalMillis: commonTimeout,
createRetryIntervalMillis: commonTimeout,
},
trustServerCertificate: true,
stream: false,
parseJSON: false,
requestTimeout: commonTimeout,
connectionTimeout: commonTimeout,
server: '',
};
export class DbMsSql extends DbBase {
public pool: sql.ConnectionPool | null;
public cfg: IMsSqlConfig;
public request: sql.Request | null;
constructor (options: IDbConstructorOptions) {
super(options);
this.pool = null;
const { dbOptions, dbConfig } = options;
const mssqlDbOptions = { ...mssqlDefaults, ...(dbOptions || {}) };
['options', 'pool'].forEach((propName) => {
if (typeof dbOptions?.[propName] === 'object') {
Object.assign(mssqlDbOptions[propName], dbOptions[propName]);
}
});
this.cfg = { ...mssqlDbOptions, ...dbConfig, server: dbConfig.server || dbConfig.host } as IMsSqlConfig;
this.request = null;
}
async getPool () {
if (this.pool?.connected || this.pool?.connecting) {
return this.pool;
}
if (this.pool?.close) {
await this.pool.close();
}
this.pool = null;
const { logger } = this.options;
try {
this.pool = new sql.ConnectionPool(this.cfg as sql.config);
if (typeof this.pool !== 'object') {
logger.error(`Cant create mssql connection pool: ${this.dbInfo}`);
process.exit(0);
}
this.pool.on('close', () => {
this.pool = null;
});
this.pool.on('error', (err: Error | any) => {
logger.error('POOL-ERROR');
logger.error(err);
});
await this.pool.connect();
return this.pool;
} catch (err) {
logger.error('POOL-ERROR');
logger.error(`Cant connect to ${this.dbInfo}\n${err}\nEXIT PROCESS`);
process.exit(1);
}
}
async close (): Promise<boolean> {
if (this.pool?.close) {
await this.pool.close();
this.options.logger.info(`Mssql connection pool for "${this.dbInfo}" closed`);
return true;
}
return false;
}
async query (strSQL: string) {
if (!this.request) {
const pool = await this.getPool();
this.request = new sql.Request(pool);
}
return this.request.query(strSQL);
}
async _getColumnsNames (): Promise<string[]> {
const result = await this.query(`${'SELECT'} TOP (1) * FROM ${this.schemaAndTable}`);
const { columns } = result.recordset;
return Object.keys(columns);
}
// eslint-disable-next-line class-methods-use-this
limitIt (strSQL: string, limit: number): string {
return strSQL.replace('SELECT ', `SELECT TOP(${limit}) `);
}
}