UNPKG

mongoose-transaction

Version:

A small library to provide an transaction-like process for mongoose

192 lines (176 loc) 5.04 kB
var $ = require('jquery-deferred'); function Transaction (mongoose) { var transacts = []; var updateOrRemoveObjects = []; this.insert = function(collectionName, data){ var Model = mongoose.model(collectionName); if(!Model) throw new Error('Collection not found'); transacts.push(constructInsertTask({ Model: Model, data:data, type: 'insert' })); }; this.update = function(collectionName, objectId, data){ var Model = mongoose.model(collectionName); if(!Model) throw new Error('Collection not found'); updateOrRemoveObjects.push({objectId: objectId, data:data, Model:Model, type:'update'}); // var doc = Model(data); // var transact = { type: 'update', doc: doc }; // storeOldDoc(objectId, transact); }; this.remove = function(collectionName, objectId){ var Model = mongoose.model(collectionName); if(!Model) throw new Error('Collection not found'); updateOrRemoveObjects.push({objectId: objectId, Model:Model, type:'remove'}); // var transact = {type: 'remove'}; // storeOldDoc(objectId, transact); }; this.run = function(callback){ var updateOrRemoveDeferredArray = []; updateOrRemoveObjects.forEach(function(docData){ updateOrRemoveDeferredArray.push(getTask(docData)); }); $.when.apply($, updateOrRemoveDeferredArray).done(function(){ var tasks = Array.prototype.slice.call(arguments); if(tasks && tasks.length > 0) transacts = transacts.concat(tasks); var transactsDeffered = []; transacts.forEach(function(transact){ transactsDeffered.push(transact.call()); }); $.when.apply($, transactsDeffered).done(function(){ results = Array.prototype.slice.call(arguments); var errs = [], successDocData = [], docs = []; results.forEach(function(result){ if (!result) return; if (result[0]) errs.push(result[0]); if (result[1]) successDocData.push(result[1]); if (result[2]) docs.push(result[2]); }); if(errs.length !== 0){ var rollbacksDeffered = []; if (successDocData.length !== 0){ successDocData.forEach(function(docData){ rollbacksDeffered.push(rollback(docData)); }); $.when.apply($, rollbacksDeffered).done(function(docs){ callback(docs); }); } } else { callback(null, docs); } }); }).fail(function(err){ callback(err); }); }; function getTask (docData) { var deferred = $.Deferred(); docData.Model.findById(docData.objectId, function(err, oldDoc){ if(err) deferred.reject(err); else{ var task; docData.oldDoc = oldDoc; if (docData.type === 'update') { task = constructUpdateTask(docData); } else if (docData.type === 'remove') { task = constructRemoveTask(docData); } deferred.resolve(task); } }); return deferred.promise(); } function rollback (docData) { var deferred = $.Deferred(); if (!docData || !docData.doc && !docData.oldDoc) { deferred.resolve(); } else { if(docData.type === 'insert') docData.doc.remove(function (err, doc) { if(err) deferred.reject(err); else deferred.resolve(); }); else if (docData.type === 'update') { for (var key in docData.oldDoc) { docData.doc[key] = docData.oldDoc[key]; } docData.doc.save(function (err, doc){ if(err) deferred.reject(err); else deferred.resolve(); }); } else if (docData.type === 'remove'){ var oldDocData = JSON.parse(JSON.stringify(docData.oldDoc)); var oldDoc = new docData.Model(oldDocData); oldDoc.save(function (err, doc){ if(err) deferred.reject(err); else deferred.resolve(); }); } } return deferred.promise(); } function constructUpdateTask (docData) { return function () { var deferred = $.Deferred(); var oldDocData = JSON.parse(JSON.stringify(docData.oldDoc)); docData.doc = docData.oldDoc; for (var key in docData.data) { docData.doc[key] = docData.data[key]; } docData.doc.save(function(err, doc){ if(err) deferred.resolve(err, null, null); else { docData.oldDoc = oldDocData; deferred.resolve(null, docData, doc); } }); return deferred.promise(); }; } function constructRemoveTask (docData) { return function () { var deferred = $.Deferred(); docData.oldDoc.remove(function(err, doc){ if(err){ deferred.resolve(err, null, null); } else { deferred.resolve(null, docData, doc); } }); return deferred.promise(); }; } function constructInsertTask (docData) { return function () { var deferred = $.Deferred(); var model = new docData.Model(docData.data); model.save(function(err, doc){ if(err){ deferred.resolve(err, null, null); } else { docData.doc = doc; deferred.resolve(null, docData, doc); } }); return deferred.promise(); }; } } module.exports = function(mongoose) { return function (){ return new Transaction(mongoose); }; };