inceptum
Version:
hipages take on the foundational library for enterprise-grade apps written in NodeJS
133 lines • 4.77 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DBTransaction = void 0;
const prom_client_1 = require("prom-client");
const TransactionManager_1 = require("../transaction/TransactionManager");
const LogManager_1 = require("../log/LogManager");
const LOGGER = LogManager_1.LogManager.getLogger(__filename);
const transactionExecutionDurationsHistogram = new prom_client_1.Histogram({
name: 'db_transaction_execute_time',
help: 'Time required to execute a transaction',
labelNames: ['clientName', 'readonly'],
buckets: [0.003, 0.005, 0.01, 0.05, 0.1, 0.3, 1, 5],
});
const rolledBackTransactionsCounter = new prom_client_1.Counter({
name: 'db_transaction_rollback_counter',
help: 'Number of times transactions have been rolled back',
labelNames: ['clientName', 'readonly'],
});
class DBTransaction {
/**
*
* @param transaction
*/
constructor(clientName, readonly, connectionPool) {
this.rolledBack = false;
this.transaction = new TransactionManager_1.Transaction();
this.clientName = clientName;
this.readonly = readonly;
this.connectionPool = connectionPool;
const labels = [clientName, readonly ? 'true' : 'false'];
this.transactionExecutionDurationsHistogram = transactionExecutionDurationsHistogram.labels(...labels);
this.rolledBackTransactionsCounter = rolledBackTransactionsCounter.labels(...labels);
}
async runQueryWithoutTransaction(sql, bindsArr) {
await this.obtainConnection();
try {
return await this.sanitizeAndRunQueryInConnection(sql, bindsArr);
}
finally {
this.releaseConnection();
}
}
getTransaction() {
return this.transaction;
}
async begin() {
this.timer = this.transactionExecutionDurationsHistogram.startTimer();
await this.obtainConnection();
await this.doTransactionBegin();
this.transaction.begin();
this.transaction.addCommitListener(() => this.doTransactionCommit());
this.transaction.addRollbackListener(() => this.doTransactionRollback());
this.transaction.addEndListener(() => this.releaseConnection());
}
async obtainConnection() {
this.connection = await this.connectionPool.getConnection();
}
query(sql, ...bindArrs) {
return this.sanitizeAndRunQueryInConnection(sql, bindArrs);
}
queryAssoc(sql, bindObj) {
return this.runQueryAssocPrivate(sql, bindObj);
}
markError(error) {
this.transaction.markError(error);
}
sanitizeAndRunQueryInConnection(sql, bindsArr) {
LOGGER.debug(`sql: ${sql} ${(bindsArr && (bindsArr.length > 0)) ? `| ${bindsArr}` : ''}`);
if (!Array.isArray(bindsArr)) {
bindsArr = [];
}
return this.runQueryInConnection(`/* Transaction Id ${this.transaction.id} */ ${sql}`, bindsArr);
}
runQueryAssocPrivate(sql, bindsObj) {
if (sql.indexOf('::') < 0 || !bindsObj) {
// tslint:disable-next-line:no-invalid-this
return this.sanitizeAndRunQueryInConnection.call(this, sql, []);
}
sql.replace(/::(\w)+::/g, (substr, key) => {
if (bindsObj.hasOwnProperty(key)) {
return bindsObj[key];
}
return substr;
});
}
doTransactionBegin() {
return this.sanitizeAndRunQueryInConnection(this.getTransactionBeginSQL());
}
// tslint:disable-next-line:prefer-function-over-method
getTransactionBeginSQL() {
return 'BEGIN';
}
doTransactionCommit() {
return this.sanitizeAndRunQueryInConnection(this.getTransactionCommitSQL());
}
// tslint:disable-next-line:prefer-function-over-method
getTransactionCommitSQL() {
return 'COMMIT';
}
doTransactionRollback() {
this.rolledBack = true;
this.rolledBackTransactionsCounter.inc();
return this.sanitizeAndRunQueryInConnection(this.getTransactionRollbackSQL());
}
// tslint:disable-next-line:prefer-function-over-method
getTransactionRollbackSQL() {
return 'ROLLBACK';
}
async releaseConnection() {
if (this.connection) {
this.connectionPool.release(this.connection);
this.connection = null;
}
}
async end() {
try {
await this.transaction.end();
}
finally {
if (this.timer) {
this.timer();
}
}
}
isRolledBack() {
return this.rolledBack;
}
isReadonly() {
return this.readonly;
}
}
exports.DBTransaction = DBTransaction;
//# sourceMappingURL=DBTransaction.js.map