Skip to content

Instantly share code, notes, and snippets.

@tmathmeyer
Created July 3, 2016 04:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tmathmeyer/401cb4a91b5b2abf30bf0365cfab52ca to your computer and use it in GitHub Desktop.
Save tmathmeyer/401cb4a91b5b2abf30bf0365cfab52ca to your computer and use it in GitHub Desktop.
var uuid_gen = require('node-uuid');
inarr = function(arr, f) {
for(var i=0; i<arr.length; i++) {
if (arr[i] === f) {
return true;
}
}
return false;
}
module.exports = function(redis, tables) {
var result = {};
tables.forEach(function(each) {
var table = each.table;
var key = each.key;
result[table] = function(uuid) {
var fields = each.fields;
var links = each.links;
if (typeof uuid === "undefined") {
// didnt provide UUID, must be creating one
return {
"create": function(_key) {
uuid = uuid_gen.v4();
if (typeof _key === typeof key) {
Object.keys(links).forEach(function(link) {
var lt = tables.map(A => '['+A.table+']');
if (inarr(lt, links[link])) {
redis.hset(uuid, link, uuid_gen.v4());
}
});
if (!(typeof _key === "undefined")) {
redis.hexists(table, uuid, function(uid_exists){
if (!uid_exists) {
redis.hset(table, _key, uuid);
} else {
return null;
}
});
return result[table](uuid);
}
return result[table](uuid);
} else {
return "ERROR, type: "+table+" was either erroneously provided a key value, or a key value was missing";
}
}
};
} else {
//provided a UUID, must be looking one up
var ret = {
"_self": uuid,
"_collect": function(cb) {
collapse(Object.keys(ret),
Object.keys(ret).map(A => ret[A]),
cb,
{})
}
};
Object.keys(fields).forEach(function(each) {
ret[each] = function(cb) {
if (typeof cb === "function") {
redis.hget(uuid, each, function(err, res) {
cb(res);
});
} else {
redis.hset(uuid, each, cb);
}
}
});
Object.keys(links).forEach(function(each) {
ret[each] = function(cb) {
if (typeof cb == "function") {
var lt = tables.map(A => '['+A.table+']');
if (inarr(lt, links[each])) {
redis.hget(uuid, each, function(err, map) {
if (map) {
redis.smembers(map, function(err, entries) {
cb(entries);
});
}
});
} else {
redis.hget(uuid, each, function(err, map) {
cb(map);
});
}
} else {
var lt = tables.map(A => '['+A.table+']');
if (inarr(lt, links[each])) {
redis.hget(uuid, each, function(err, map) {
if (cb.op === "add") {
redis.sadd(map, cb.value);
} else if (cb.op === "del") {
redis.srem(map, cb.value);
}
});
} else {
redis.hset(uuid, each, cb.value);
console.log("TODO, ALLOW REMOVING FROM SINGLE ELEMENT LINK");
}
}
}
});
return ret;
}
return ret;
}
});
api = function(isotope, prefix, result) {
tables.forEach(function(each) {
var name = each.table;
var key = each.key;
var links = each.links;
var fields = each.fields;
if (!(typeof key === "undefined")) {
isotope.get(prefix+name, function(resp, req) {
resp.writeHead(200, {
"Content-Type": "text/json",
});
redis.hvals(name, function(err, res) {
ret = {_links:{}};
res.forEach(function(each) {
ret._links[each] = {
href: "/api/"+name+"/"+each
};
});
resp.end(JSON.stringify(ret));
});
});
}
isotope.post(prefix+name, function(resp, req) {
var res = result[name]().create();
isotope.extract_data(req, function(data) {
if (data) {
Object.keys(data).forEach(function(field) {
if (inarr(Object.keys(links), field)) {
res[field]({
op: 'add',
value: data[field]
});
} else {
res[field](data[field]);
}
});
}
});
resp.writeHead(201, {
"Location": prefix+name+'/'+res._self
});
resp.end(JSON.stringify({uuid: res._self}));
});
Object.keys(links).forEach(function(field) {
isotope.put(prefix+name+'/_var/'+field, function(resp, req, id) {
isotope.extract_data(req, function(data){
data = data.data;
result[name](id)[field]({
op: 'add',
value: data
});
resp.writeHead(200, {
"Content-Type": "text/plain"
});
resp.end("");
});
});
});
Object.keys(fields).forEach(function(field) {
isotope.put(prefix+name+'/_var/'+field, function(resp, req, id) {
isotope.extract_data(req, function(data){
data = data.data;
result[name](id)[field](data);
resp.writeHead(200, {
"Content-Type": "text/plain"
});
resp.end("");
});
});
});
isotope.get(prefix+name+"/_csv", function(resp, req, uuids) {
supercollapse(uuids, [], function(uuid, resp_array, continuation) {
var self_obj = result[name](uuid);
supercollapse(Object.keys(each.fields), {
_links: {
self: {
href: prefix+name+'/'+uuid
},
},
_self: uuid
}, function(field, arr_it, cont) {
self_obj[field](function(field_value) {
arr_it[field] = field_value;
cont(arr_it);
});
}, function(done) {
supercollapse(Object.keys(each.links), done, function(link, arr_it, cont) {
self_obj[link](function(link_value) {
if (typeof link_value === "string") {
arr_it._links[link] = {
href: prefix+each.links[link]+'/'+link_value
}
} else if (link_value instanceof Array) {
arr_it._links[link] = link_value.map(function(A) {
return {
self: {
href: prefix+link+'/'+A,
uuid: A
},
}
});
} else {
arr_it._links[link] = null;
}
cont(arr_it);
});
}, function(done) {
resp_array.push(done);
continuation(resp_array);
});
});
}, function(done) {
resp.writeHead(200, {
"Content-Type": "text/json",
});
if (done.length === 1) {
resp.end(JSON.stringify(done[0]));
} else {
resp.end(JSON.stringify(done));
}
});
});
});
}
result.api = api;
return result;
}
var collapse = function(names, fns, done, _collect) {
if (!_collect) _collect = {};
if (names.length != 0) {
var f_name = names.shift();
var f_fn = fns.shift();
if (f_name.startsWith('_')) {
collapse(names, fns, done, _collect);
} else {
f_fn(function(data) {
_collect[f_name] = data;
collapse(names, fns, done, _collect);
});
}
} else {
done(_collect);
}
}
var supercollapse = function(list, start, each, finished) {
if (list.length === 0) {
finished(start);
return;
}
var first = list.shift();
each(first, start, function(new_start) {
supercollapse(list, new_start, each, finished);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment