1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | 1 1 1 1 1 1 1 42 42 42 42 66 66 66 66 66 66 56 139 139 139 139 139 139 63 63 69 63 72 72 72 72 72 72 72 72 112 72 72 72 19 19 19 19 19 19 19 19 19 22 22 22 22 22 22 22 22 22 22 22 1 113 1 | /** MongoDB Backend. Implementation of the storage backend using MongoDB */ "use strict"; var contract = require('./contract'); var async = require('async'); var _ = require('lodash'); function MongoDBBackend(db, prefix){ this.db = db; this.prefix = typeof prefix !== 'undefined' ? prefix : ''; } MongoDBBackend.prototype = { /** Begins a transaction. */ begin : function(){ // returns a transaction object(just an array of functions will do here.) return []; }, /** Ends a transaction (and executes it) */ end : function(transaction, cb){ contract(arguments).params('array', 'function').end(); async.series(transaction,function(err){ cb(err instanceof Error? err : undefined); }); }, /** Cleans the whole storage. */ clean : function(cb){ contract(arguments).params('function').end(); this.db.collections(function(err, collections) { if (err instanceof Error) return cb(err); async.forEach(collections,function(coll,innercb){ coll.drop(function(){innercb()}); // ignores errors },cb); }); }, /** Gets the contents at the bucket's key. */ get : function(bucket, key, cb){ contract(arguments) .params('string', 'string', 'function') .end(); this.db.collection(this.prefix + bucket,function(err,collection){ Iif(err instanceof Error) return cb(err); collection.findOne({key:key},function(err, doc){ Iif(err) return cb(err); if(! _.isObject(doc) ) return cb(undefined,[]); cb(undefined,_.without(_.keys(doc),"key","_id")); }); }); }, /** Returns the union of the values in the given keys. */ union : function(bucket, keys, cb){ contract(arguments) .params('string', 'array', 'function') .end(); this.db.collection(this.prefix + bucket,function(err,collection){ Iif(err instanceof Error) return cb(err); collection.find({key: { $in: keys }}).toArray(function(err,docs){ Iif(err instanceof Error) return cb(err); if( ! docs.length ) return cb(undefined, []); var keyArrays = []; docs.forEach(function(doc){ keyArrays.push.apply(keyArrays, _.keys(doc)); }); cb(undefined, _.without(_.union(keyArrays),"key","_id")); }); }); }, /** Adds values to a given key inside a bucket. */ add : function(transaction, bucket, key, values){ contract(arguments) .params('array', 'string', 'string','string|array') .end(); Iif(key=="key") throw new Error("Key name 'key' is not allowed."); var self=this; transaction.push(function(cb){ values = makeArray(values); self.db.collection(self.prefix + bucket, function(err,collection){ Iif(err instanceof Error) return cb(err); // build doc from array values var doc = {}; values.forEach(function(value){doc[value]=true;}); // update document collection.update({key:key},{$set:doc},{safe:true,upsert:true},function(err){ Iif(err instanceof Error) return cb(err); cb(undefined); }); }); }); }, /** Delete the given key(s) at the bucket */ del : function(transaction, bucket, keys){ contract(arguments) .params('array', 'string', 'string|array') .end(); keys = makeArray(keys); var self= this; transaction.push(function(cb){ self.db.collection(self.prefix + bucket,function(err,collection){ Iif(err instanceof Error) return cb(err); collection.remove({key:{$in:keys}},{safe:true},function(err){ Iif(err instanceof Error) return cb(err); cb(undefined); }); }); }); }, /** Removes values from a given key inside a bucket. */ remove : function(transaction, bucket, key, values){ contract(arguments) .params('array', 'string', 'string','string|array') .end(); var self=this; values = makeArray(values); transaction.push(function(cb){ self.db.collection(self.prefix + bucket,function(err,collection){ Iif(err instanceof Error) return cb(err); // build doc from array values var doc = {}; values.forEach(function(value){doc[value]=true;}); // update document collection.update({key:key},{$unset:doc},{safe:true,upsert:true},function(err){ Iif(err instanceof Error) return cb(err); cb(undefined); }); }); }); } } function makeArray(arr){ return Array.isArray(arr) ? arr : [arr]; } exports = module.exports = MongoDBBackend; |