Skip to content

Instantly share code, notes, and snippets.

@tmathmeyer
Created June 30, 2016 21:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tmathmeyer/6cfd7866d5986d438e5d76c1c7ae1334 to your computer and use it in GitHub Desktop.
Save tmathmeyer/6cfd7866d5986d438e5d76c1c7ae1334 to your computer and use it in GitHub Desktop.
var uuid_gen = require('node-uuid');
var redis = require('redis').createClient();
var isotope = require('isotope').create(7088);
inarr = function(arr, f) {
for(var i=0; i<arr.length; i++) {
if (arr[i] === f) {
return true;
}
}
return false;
}
var redisHAL = 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();
resp.writeHead(201, {
"Location": prefix+name+'/'+res._self
});
resp.end(JSON.stringify({map: res._self}));
});
Object.keys(links).forEach(function(each_link) {
isotope.put(prefix+name+'/_var/_var', function(resp, req, id, field) {
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(each_field) {
isotope.put(prefix+name+'/_var/_var', function(resp, req, id, field) {
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+"/_var", function(resp, req, uuid) {
resp.writeHead(200, {
"Content-Type": "text/json",
});
var ret = {_links:{
self: {
href: prefix+name+'/'+uuid
}
}};
var obj = result[name](uuid);
chain(Object.keys(each.fields), function(kes, done) {
obj[kes](function(res) {
ret[kes] = res;
done();
});
}, function() {
chain(Object.keys(each.links), function(kes, done) {
obj[kes](function(res) {
if (typeof res === "string") {
ret._links[kes] = {
href: prefix+each.links[kes]+'/'+res
}
} else if (res instanceof Array) {
ret._links[kes] = res.map(function(A) {
return {
self: {
href: prefix+kes+'/'+A
}
}
});
} else {
ret._links[kes] = null;
}
done();
});
}, function() {
resp.end(JSON.stringify(ret));
});
});
});
});
}
result.api = api;
return result;
}
var chain = function(list, each, done) {
if (list.length === 0) {
done();
} else {
each(list[0], function() {
list.shift();
chain(list, each, done);
});
}
}
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 apiSchema = [
{
"table": "users",
"key": "username",
"fields": {
"hash": {
"type": "string"
},
"real_name": {
"type": "string"
}
},
"links": {
"maps": "[maps]",
"profile": "images"
}
},
{
"table": "maps",
"fields": {
"name": {
"type": "string",
},
"frame_north": {
"type": "string",
},
"frame_east": {
"type": "string",
},
"frame_south": {
"type": "string",
},
"frame_west": {
"type": "string",
},
"public": {
"type": "boolean"
}
},
"links": {
"owner": "users",
"shared_with": "[users]",
"points": "[points]",
}
},
{
"table": "points",
"fields": {
"name": {
"type": "string"
},
"lat": {
"type": "string"
},
"long": {
"type": "string"
}
},
"links": {
"photos": "images"
}
},
{
"table": "images",
"fields": {
"url": {
"type": "string"
}
},
"links": {}
}
]
var schema = redisHAL(redis, apiSchema);
schema.api(isotope, 'api/', schema);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment