knex/lib/transaction.js
2014-09-01 17:19:34 +02:00

95 lines
3.1 KiB
JavaScript

'use strict';
// Transaction
// -------
var Promise = require('./promise');
var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;
// Creates a new wrapper object for constructing a transaction.
// Called by the `knex.transaction`, which sets the correct client
// and handles the `container` object, passing along the correct
// `connection` to keep all of the transactions on the correct connection.
function Transaction(container) {
this.container = container;
}
inherits(Transaction, EventEmitter);
// Build the knex instance passed around inside the transaction container.
// It can be used both as a fully functional knex instance, or assimilated
// into existing knex chains via the ".transacting" method call.
Transaction.prototype.containerObject = function(runner) {
var Knex = require('../knex');
// Create an entirely new knex instance just for this transaction
var transactor = Knex.initialize({
__client__ : this.client,
__transactor__ : {_runner: runner}
});
// Remove the ability to start a transaction or destroy
// the entire pool within a transaction.
transactor.destroy = transactor.transaction = void 0;
// Commits the transaction:
transactor.commit = function(message) {
runner.finishTransaction(0, transactor, message);
};
// Rolls back the transaction.
transactor.rollback = function(error) {
runner.finishTransaction(1, transactor, error);
};
transactor._runner = runner;
return transactor;
};
Transaction.prototype.initiateDeferred = function(transactor) {
// Initiate a deferred object, bound to the container object,
// so we know when the transaction completes or fails
// and can continue from there.
var dfd = transactor.__dfd__ = Promise.pending();
// Call the container with the transaction
// commit & rollback objects.
var result = this.container(transactor);
// If we've returned a "thenable" from the transaction container,
// and it's got the transaction object we're running for this, assume
// the rollback and commit are chained to this object's success / failure.
if (result && result.then && typeof result.then === 'function') {
result.then(function(val) { transactor.commit(val); }).catch(function(err) { transactor.rollback(err); });
}
// Return the promise for the entire transaction.
return dfd.promise;
};
// Allow the `Transaction` object to be utilized with full access to the relevant
// promise API.
require('./interface')(Transaction);
// Passed a `container` function, this method runs the current
// transaction, returning a promise.
Transaction.prototype.then = function(onFulfilled, onRejected) {
var Runner = this.client.Runner;
var promise = this;
// Create a new "runner" object, passing the "runner"
// object along, so we can easily keep track of every
// query run on the current connection.
return new Runner(this)
.startTransaction()
.then(function(obj) {
return promise.containerObject(obj);
})
.then(function(obj) {
return promise.initiateDeferred(obj);
})
.then(onFulfilled, onRejected);
};
module.exports = Transaction;