'use strict'; module.exports = function(Fireproof) { /** * Delegates Firebase#transaction. * @method Fireproof#transaction * @param {function} updateFunction * @param {function} onComplete * @param {boolean=} applyLocally * @returns {Promise} Resolves on success, rejects on failure. */ Fireproof.prototype.transaction = function(updateFunction, onComplete, applyLocally) { var deferred = Fireproof._checkQ().defer(), self = this; Fireproof.stats._addListener(self.toString()); self._ref.transaction(updateFunction, function(err, committed, snap) { Fireproof.stats._record('read', self.toString()); snap = new Fireproof.Snapshot(snap); Fireproof._nextTick(function() { if (onComplete) { onComplete(err, committed, snap); } if (err) { deferred.reject(err); } else { deferred.resolve({ committed: committed, snapshot: snap }); } }); }, applyLocally); return deferred.promise; }; /** * Delegates Firebase#on. * @method Fireproof#on * @param {string} eventType * @param {function} callback * @param {function=} cancelCallback * @param {object=} context * @returns {function} Your callback parameter wrapped in fireproofing. Use * this return value, not your own copy of callback, to call .off(). It also * functions as a promise that resolves on success and rejects on failure. */ Fireproof.prototype.on = function(eventType, callback, cancelCallback, context) { var deferred = Fireproof._checkQ().defer(), resolved = false, self = this; Fireproof.stats._addListener(self.toString()); if (typeof callback !== 'function') { callback = function() {}; } if (typeof cancelCallback !== 'function') { cancelCallback = function() {}; } var callbackHandler = function(snap, prev) { Fireproof.stats._record('read', self.toString()); snap = new Fireproof.Snapshot(snap); Fireproof._nextTick(function() { callback(snap, prev); if (!resolved) { resolved = true; deferred.resolve(snap, prev); } }); }; callbackHandler.then = deferred.promise.then.bind(deferred.promise); self._ref.on(eventType, callbackHandler, function(err) { Fireproof.stats._removeListener(self.toString()); Fireproof._nextTick(function() { cancelCallback(err); if (!resolved) { resolved = true; deferred.reject(err); } }); }, context); return callbackHandler; }; /** * Delegates Firebase#off. * @method Fireproof#off * @param {string} eventType * @param {function=} callback * @param {object=} context */ Fireproof.prototype.off = function(eventType, callback, context) { Fireproof.stats._removeListener(this.toString()); this._ref.off(eventType, callback, context); }; /** * Delegates Firebase#once. * @method Fireproof#once * @param {object} eventType * @param {function} successCallback * @param {function=} failureCallback * @param {object=} context * @returns {Promise} Resolves on success and rejects on failure. */ Fireproof.prototype.once = function(eventType, successCallback, failureCallback, context) { var deferred = Fireproof._checkQ().defer(), self = this; Fireproof.stats._addListener(self.toString()); if (typeof successCallback !== 'function') { successCallback = function() {}; } if (typeof failureCallback !== 'function') { failureCallback = function() {}; } self._ref.once(eventType, function(snap) { Fireproof.stats._removeListener(self.toString()); Fireproof.stats._record('read', self.toString()); snap = new Fireproof.Snapshot(snap); deferred.resolve(snap); Fireproof._nextTick(function() { successCallback(snap); }); }, function(err) { Fireproof.stats._removeListener(self.toString()); deferred.reject(err); Fireproof._nextTick(function() { failureCallback(err); }); }, context); return deferred.promise; }; };