tomahawk-plugin-mongo
Version:
A Tomahawk plugin to impletem a Key Value Pair Store backed by MongoDB
197 lines (179 loc) • 7.55 kB
JavaScript
module.exports = function () {
var mongoose = require('mongoose');
function isUndefined(object) { return typeof(object) === 'undefined'; }
function create(app, config, io) {
config = config || {};
var connected = false,
schema = null,
Tuple = null,
version = config.version || '0.0.0',
logger = config.logger || {log:function(){}},
meta = config.meta || {$_id:'mongo'};
function status(next) {
process.nextTick(function () {
if (next) next(null, {
connected : connected,
status : 'OK'
});
});
}
function connect(url, next) {
mongoose.connect(url);
hashMapSchema = new mongoose.Schema({
key : { type : String, index: true },
value : String
}, { autoIndex: true }
);
Tuple = mongoose.model('Tuples', hashMapSchema);
hashSetSchema = new mongoose.Schema({
key : { type : String, index: true },
members : [String]
}, { autoIndex: true }
);
HashSet = mongoose.model('HashSet', hashSetSchema);
connected = true;
}
function close(next) {
mongoose.disconnect(function () {
connected = false;
});
}
function get(key, next) {
if (key.indexOf('*') !== -1) {
var regex = '^' + key.replace(/\*/g, '.*') + '$',
promise = Tuple.find({ key : new RegExp(regex) }).exec();
promise.then(function (documents) {
var tuples = documents.map(function (document) {
return {key: document.key, value: document.value};
});
next(null, tuples, meta);
}, function (err) {
next(err, null, meta);
}).end();
} else {
var promise = Tuple.findOne({ key : key }).exec();
promise.then(function (document) {
next(null, document && document.value ? document.value : null, meta);
}, function (err) {
next(err, null, meta);
}).end();
}
}
function set(tuples, next) {
var count = 0;
function update(vector, error) {
if (vector.length === 0)
return next(error, count);
var tuple = vector.shift();
Tuple.update(
{key:tuple.key},
{key:tuple.key, value:tuple.value},
{upsert:true}, function (err, document) {
if (!err)
++count;
update(vector, err ? err : error);
});
}
update(tuples.slice(0));
}
function del(key, next) {
var tuples = [];
if (key instanceof Array)
tuples = key.map(function (oneKey) {return {key:oneKey}});
else if (key.indexOf('*') !== -1)
tuples = [{key:new RegExp('^' + key.replace(/\*/g, '.*') + '$')}];
else
tuples = [{key:key}];
var count = 0;
function del(vector, error) {
if (vector.length === 0)
return next(error, count);
var tuple = vector.shift();
Tuple.find().remove(tuple, function (err, document) {
if (!err)
++count;
del(vector, err ? err : error);
});
}
del(tuples.slice(0));
}
function sget(setName, member, next) {
if (member === '*') {
var promise = HashSet.findOne({ key : setName }).exec();
promise.then(function (document) {
next(null, document && document.members ? document.members : [], meta);
}, function (err) {
next(err, null, meta);
}).end();
} else {
var promise = HashSet.findOne({ key : setName, members : member }).exec();
promise.then(function (document) {
logger.log('debug', 'mongo::sget(setName: %s, member:%s) >>> document:%j', setName, member, document, meta);
next(null, document ? 1 : 0, meta);
}, function (err) {
next(err, null, meta);
}).end();
}
}
function sadd(tuples, next) {
var count = 0;
logger.log('debug', 'mongo::sadd(tuples: %j)', tuples, meta);
function update(vector, error) {
if (vector.length === 0)
return next(error, count);
var tuple = vector.shift();
logger.log('debug', 'mongo::sadd(setName:%s, member:%s)', tuple.key, tuple.value, meta);
HashSet.update(
{key:tuple.key},
{$addToSet:{members:tuple.value}},
{upsert:true}, function (err, document) {
logger.log('debug', 'mongo::sadd(setName:%s, member:%s) >>> document:%j', tuple.key, tuple.value, document, meta);
if (!err)
++count;
update(vector, err ? err : error);
});
}
update(tuples.slice(0));
}
function sdel(setName, member, next) {
var count = 0;
// delete the whole set
if (member === '*') {
var promise = HashSet.remove({ key : setName }).exec();
promise.then(function (document) {
next(null, 1, meta);
}, function (err) {
next(err, null, meta);
}).end();
}
else {
var promise = HashSet.update({ key : setName }, { $pull : { members : member } }).exec();
promise.then(function (document) {
logger.log('debug', 'mongo::sdel(setName:%s, member:%s) >>> document:%j', setName, member, document, meta);
next(null, 1, meta);
}, function (err) {
next(err, null, meta);
}).end();
}
}
////////////////////////////////////////////////////////////////////////
return {
constructor : function (next) {
connect(process.env.MONGODB_URL || process.env.MONGOLAB_URI || config.plugins.store.url, next);
},
shutdown : function (next) {
close(next);
},
status : status,
connect : connect,
close : close,
get : get,
set : set,
del : del,
sadd : sadd,
sget : sget,
sdel : sdel
};
}
return create;
}();