dbConn.quit();
dbConn = null;
}
cb(null);
},
save: function(args, cb) {
assert(args);
assert(cb);
assert(args.ent);
var ent = args.ent;
var q = args.q;
var table = tablename(ent);
var entp = {};
if (!ent.id) {
if( ent.id$ ) {
ent.id = ent.id$;
}
else {
ent.id = uuid();
}
}
entp = makeentp(ent);
var objectMap = determineObjectMap(ent);
dbConn.hset(table, ent.id, entp, function(err, result) {
if (!error(args, err, cb)) {
saveMap(dbConn, objectMap, function(err, result) {
if (!error(args, err, cb)) {
seneca.log(args.tag$,'save', result);
cb(null, ent);
}
});
}
});
},
load: function(args, cb) {
assert(args);
assert(cb);
assert(args.qent);
assert(args.q);
var qent = args.qent;
var q = _.clone(args.q);
var table = tablename(qent);
q.limit$ = 1;
if (!q.id) {
store.list(args, function(err, list) {
if (!error(args, err, cb)) {
var ent = list[0] || null;
seneca.log(args.tag$, 'load', ent);
cb(err, ent ? ent : null );
}
});
}
else {
loadMap(dbConn, table, function(err, objMap) {
if (!error(args, err, cb)) {
dbConn.hget(table, q.id, function(err, row) {
if (!error(args, err, cb)) {
if (!row) {
cb(null, null);
}
else {
var ent = makeent(qent, row, objMap);
seneca.log(args.tag$, 'load', ent);
cb(null, ent);
}
}
});
}
});
}
},
list: function(args, cb) {
assert(args);
assert(cb);
assert(args.qent);
assert(args.q);
var qent = args.qent;
var q = args.q;
var table = tablename(qent);
loadMap(dbConn, table, function(err, objMap) {
if (!error(args, err, cb)) {
dbConn.hgetall(table, function(err, results) {
if (!error(args, err, cb)) {
var list = [];
_.each(results, function(value, key) {
var ent = makeent(qent, value, objMap);
list.push(ent);
});
if (!_.isEmpty(q)) {
list = _.filter(list, function(elem, b, c) {
var match = true;
_.each(q, function(value, key) {
var computed = (elem[key] === value);
match = match && computed;
});
return match;
});
}
cb(null, list);
}
});
}
});
},
remove: function(args, cb) {
assert(args);
assert(cb);
assert(args.qent);
assert(args.q);
var qent = args.qent;
var q = args.q;
var table = tablename(qent);
if (q.all$) {
dbConn.del(table, function(err, result) {
if (!error(args, err, cb)) {
cb(null, [result]);
}
});
}
else if(!_.isEmpty(q)) {
store.list(args, function(err, elements) {
var redisArgs = _.map(elements, 'id');
redisArgs.unshift(table);
dbConn.hdel(redisArgs, function(err, result) {
if (!error(args, err, cb)) {
cb(null, [result]);
}
});
});
}
else {
cb(null, null);
}
},
native: function(args, cb) {
assert(args);
assert(cb);
assert(args.ent);
var ent = args.ent;
cb(null, dbConn);
}
};
var meta = seneca.store.init(seneca, opts, store);
desc = meta.desc;
seneca.add({init:store.name,tag:meta.tag}, function(args,done) {
configure(opts, function(err) {
if (err) {
return seneca.fail({code:'entity/configure', store:store.name, error:err, desc:desc}, done);
}
else done();
});
});
return { name:store.name, tag:meta.tag };
};
var tablename = function (entity) {
var canon = entity.canon$({object:true});
return (canon.base?canon.base+'_':'')+canon.name;
};
var makeentp = function(ent) {
var entp = {};
var fields = ent.fields$();
fields.forEach(function(field){
if(_.isDate(ent[field]) || _.isObject(ent[field])) {
entp[field] = JSON.stringify(ent[field]);
}
else {
entp[field] = ent[field];
}
});
return JSON.stringify(entp);
};
var makeent = function(ent, row, objMap) {
var entp;
var fields;
row = JSON.parse(row);
fields = _.keys(row);
if (!_.isUndefined(ent) && !_.isUndefined(row)) {
entp = {};
fields.forEach(function(field) {
if (!_.isUndefined(row[field]) && !_.isUndefined(objMap.map[field])) {
if (objMap.map[field] === OBJECT_TYPE_STATIC) {
entp[field] = row[field];
}
else if (objMap.map[field] === OBJECT_TYPE_OBJECT) {
entp[field] = JSON.parse(row[field]);
}
else if (objMap.map[field] === OBJECT_TYPE_DATE) {
entp[field] = new Date(JSON.parse(row[field]));
}
}
});
}
return ent.make$(entp);
};
var determineObjectMap = function(ent){
var fields = ent.fields$();
var objectName = tablename(ent);
var objectMap = {};
var map = {};
fields.forEach(function(field){
if (_.isDate(ent[field])) {
map[field] = OBJECT_TYPE_DATE;
}
else if (_.isObject(ent[field])) {
map[field] = OBJECT_TYPE_OBJECT;
}
else {
map[field] = OBJECT_TYPE_STATIC;
}
});
objectMap = {id:objectName, map:map};
if(!_.isUndefined(globalObjectMap[objectName]) && _.size(objectMap.map) < _.size(globalObjectMap[objectName].map)) {
objectMap = globalObjectMap[objectName];
}
else {
globalObjectMap[objectName] = objectMap;
}
return objectMap;
};
var loadMap = function(dbConn, key, cb){
var table = 'seneca_object_map';
dbConn.hget(table, key, function(err, result){
if (!err) {
var objectMap = JSON.parse(result);
cb(null, objectMap);
}
else {
cb(err, null);
}
});
};
var saveMap = function(dbConn, newObjectMap, cb) {
var table = 'seneca_object_map';
var key = newObjectMap.id;
loadMap(dbConn, key, function(err, existingObjMap) {
if(err) { return cb(err, undefined); }
var mergedObjectMap = newObjectMap;
if(existingObjMap && existingObjMap.map) {
mergedObjectMap = existingObjMap;
for(var attr in newObjectMap.map) {
if(newObjectMap.map.hasOwnProperty(attr)) {
mergedObjectMap.map[attr] = newObjectMap.map[attr];
}
}
}
var savedObject = JSON.stringify(mergedObjectMap);
dbConn.hset(table, key, savedObject, cb);
});
};