const { isUndefined } = require('lodash'); const Bluebird = require('bluebird'); const Transaction = require('../../transaction'); const debugTx = require('debug')('knex:tx'); module.exports = class Oracle_Transaction extends Transaction { // disable autocommit to allow correct behavior (default is true) begin() { return Bluebird.resolve(); } commit(conn, value) { this._completed = true; return conn .commitAsync() .then(() => value) .then(this._resolver, this._rejecter); } release(conn, value) { return this._resolver(value); } rollback(conn, err) { const self = this; this._completed = true; debugTx('%s: rolling back', this.txid); return conn .rollbackAsync() .timeout(5000) .catch(Bluebird.TimeoutError, function(e) { self._rejecter(e); }) .then(function() { if (isUndefined(err)) { if (self.doNotRejectOnRollback) { self._resolver(); return; } err = new Error(`Transaction rejected with non-error: ${err}`); } self._rejecter(err); }); } savepoint(conn) { return this.query(conn, `SAVEPOINT ${this.txid}`); } acquireConnection(config, cb) { const configConnection = config && config.connection; const t = this; return new Bluebird((resolve, reject) => { try { this.client .acquireConnection() .then((cnx) => { cnx.__knexTxId = this.txid; cnx.isTransaction = true; resolve(cnx); }) .catch(reject); } catch (e) { reject(e); } }).then(async (connection) => { try { return await cb(connection); } finally { debugTx('%s: releasing connection', this.txid); connection.isTransaction = false; try { await connection.commitAsync(); } catch (err) { t._rejecter(err); } finally { if (!configConnection) { await t.client.releaseConnection(connection); } else { debugTx('%s: not releasing external connection', t.txid); } } } }); } };