This commit is contained in:
Mark Nadal 2016-05-23 12:15:34 -07:00
parent 8c33ab1efb
commit 639203fdd2
3 changed files with 306 additions and 352 deletions

604
gun.js
View File

@ -32,18 +32,18 @@
if(Type.obj.has(o,'*')){ if(t.slice(0, o['*'].length) === o['*']){ r = true; t = t.slice(o['*'].length) } else { return false }}
if(Type.obj.has(o,'!')){ if(t.slice(-o['!'].length) === o['!']){ r = true } else { return false }}
if(Type.obj.has(o,'+')){
if(Type.list.map(Type.list.is(o['+'])? o['+'] : [o['+']], function(m){ // TODO: PERF! CACHE!
if(Type.list.map(Type.list.is(o['+'])? o['+'] : [o['+']], function(m){
if(t.indexOf(m) >= 0){ r = true } else { return true }
})){ return false }
}
if(Type.obj.has(o,'-')){
if(Type.list.map(Type.list.is(o['-'])? o['-'] : [o['-']], function(m){ // TODO: PERF! CACHE!
if(Type.list.map(Type.list.is(o['-'])? o['-'] : [o['-']], function(m){
if(t.indexOf(m) < 0){ r = true } else { return true }
})){ return false }
}
if(Type.obj.has(o,'>')){ if(t > o['>']){ r = true } else { return false }}
if(Type.obj.has(o,'<')){ if(t < o['<']){ r = true } else { return false }}
function fuzzy(t,f){ var n = -1, i = 0, c; for(;c = f[i++];){ if(!~(n = t.indexOf(c, n+1))){ return false }} return true } // via http://stackoverflow.com/questions/9206013/javascript-fuzzy-search // TODO: PERF! CACHE!
function fuzzy(t,f){ var n = -1, i = 0, c; for(;c = f[i++];){ if(!~(n = t.indexOf(c, n+1))){ return false }} return true } // via http://stackoverflow.com/questions/9206013/javascript-fuzzy-search
if(Type.obj.has(o,'?')){ if(fuzzy(t, o['?'])){ r = true } else { return false }} // change name!
return r;
}
@ -58,25 +58,36 @@
}
Type.list.map = function(l, c, _){ return Type.obj.map(l, c, _) }
Type.list.index = 1; // change this to 0 if you want non-logical, non-mathematical, non-matrix, non-convenient array notation
Type.obj = {is: function(o){ return o? (o instanceof Object && o.constructor === Object) || Object.prototype.toString.call(o).match(/^\[object (\w+)\]$/)[1] === 'Object' : false }} // TODO: PERF HIT! Fixed?
Type.obj = {is: function(o){ return o? (o instanceof Object && o.constructor === Object) || Object.prototype.toString.call(o).match(/^\[object (\w+)\]$/)[1] === 'Object' : false }}
Type.obj.put = function(o, f, v){ return (o||{})[f] = v, o }
Type.obj.has = function(o, t){ return o && Object.prototype.hasOwnProperty.call(o, t) }
Type.obj.del = function(o, k){
if(!o){ return }
o[k] = null;
delete o[k];
return o;
}
Type.obj.as = function(o, f, v){ return o[f] = o[f] || (arguments.length >= 3? v : {}) }
Type.obj.ify = function(o){
if(Type.obj.is(o)){ return o }
try{o = JSON.parse(o);
}catch(e){o={}};
return o;
}
;(function(){ var u;
function map(v,f){
if(obj_has(this,f) && u !== this[f]){ return }
this[f] = v;
}
Type.obj.to = function(from, to){
to = to || {};
obj_map(from, map, to);
return to;
}
}());
Type.obj.copy = function(o){ // because http://web.archive.org/web/20140328224025/http://jsperf.com/cloning-an-object/2
return !o? o : JSON.parse(JSON.stringify(o)); // is shockingly faster than anything else, and our data has to be a subset of JSON anyways!
}
Type.obj.as = function(o, f, v){ return o[f] = o[f] || (arguments.length >= 3? v : {}) }
Type.obj.has = function(o, t){ return o && Object.prototype.hasOwnProperty.call(o, t) }
;(function(){
function empty(v,i){ n = this.n;
if(n && (i === n || (Type.obj.is(n) && Type.obj.has(n, i)))){ return }
@ -143,6 +154,7 @@
}
Act.chain = Act.prototype;
Act.chain.stun = function(){
if(!this.tmp){ return }
if(!arguments.length){
return this.tmp.halt = true;
}
@ -185,7 +197,7 @@
if(!arr){
act.fn.call(act.at, arg, act);
} else {
act.fn.apply(act.at, arg);
act.fn.apply(act.at, arg.concat(act));
}
if(noop === act.fn){
off = true;
@ -212,20 +224,20 @@
return;
}
exports.on = Event;
}(Util, function(tag, act, on, at){ // Gun specific extensions
if(!at.gun || !at.lex){ return }
var mem = on.mem;
}(Util, function(tag, act, on, ctx){ // Gun specific extensions
var mem = on.mem, at;
if(mem){
if(mem instanceof Array){
act.fn.apply(act.at, mem);
act.fn.apply(act.at, mem.concat(act));
} else {
act.fn.call(act.at, mem, act);
}
return;
}
if(!Gun.obj.empty(at.lex)){
Gun.get(at);
}
at = act.at? act.at.gun? act.at : ctx : ctx;
//if(obj_empty(at.lex)){ return }
if(!at.lex || !at.lex.soul){ return } // TODO: What about lex cursors?
Gun.get(at);
}, function(tag, arg, on, at){
on.mem = arg;
}));
@ -364,11 +376,6 @@
Gun.is.rel.ify = function(s){ var r = {}; return obj_put(r, _soul, s), r } // convert a soul into a relation and return it.
;(function(){
function map(v, f){ // we invert this because the way we check for this is via a negation.
if(f === _meta){ return } // skip over the metadata.
if(!is_val(v)){ return true } // it is true that this is an invalid node.
if(this.cb){ this.cb.call(this.o, v, f, this.n) } // optionally callback each field/value.
}
Gun.is.node = function(n, cb, o){ var s; // checks to see if an object is a valid node.
if(!obj_is(n)){ return false } // must be an object.
if(s = is_node_soul(n)){ // must have a soul on it.
@ -376,6 +383,11 @@
}
return false; // nope! This was not a valid node.
}
function map(v, f){ // we invert this because the way we check for this is via a negation.
if(f === _meta){ return } // skip over the metadata.
if(!is_val(v)){ return true } // it is true that this is an invalid node.
if(this.cb){ this.cb.call(this.o, v, f, this.n) } // optionally callback each field/value.
}
}());
Gun.is.node.copy = function(g, s){
@ -419,19 +431,19 @@
return n;
}
;(function(){
Gun.is.graph = function(g, cb, fn, o){ // checks to see if an object is a valid graph.
if(!obj_is(g) || obj_empty(g)){ return false } // must be an object.
return !obj_map(g, map, {fn:fn,cb:cb,o:o}); // makes sure it wasn't an empty object.
}
function nf(fn){ // optional callback for each node.
if(fn){ Gun.is.node(nf.n, fn, nf.o) } // where we then have an optional callback for each field/value.
if(fn){ is_node(nf.n, fn, nf.o) } // where we then have an optional callback for each field/value.
}
function map(n, s){ // we invert this because the way we check for this is via a negation.
if(!n || s !== Gun.is.node.soul(n) || !Gun.is.node(n, this.fn)){ return true } // it is true that this is an invalid graph.
if(!Gun.fns.is(this.cb)){ return }
if(!n || s !== is_node_soul(n) || !is_node(n, this.fn)){ return true } // it is true that this is an invalid graph.
if(!fn_is(this.cb)){ return }
nf.n = n; nf.o = this.o;
this.cb.call(nf.o, n, s, nf);
}
Gun.is.graph = function(g, cb, fn, o){ // checks to see if an object is a valid graph.
if(!Gun.obj.is(g) || Gun.obj.empty(g)){ return false } // must be an object.
return !Gun.obj.map(g, map, {fn:fn,cb:cb,o:o}); // makes sure it wasn't an empty object.
}
}());
Gun.is.graph.ify = function(n){ var s; // wrap a node into a graph.
@ -487,7 +499,7 @@
root.console.log(".!HYPOTHETICAL AMNESIA MACHINE ERR!.", HAM.err); // this error should never happen.
return;
}
if(HAM.state || HAM.historical || HAM.current){
if(HAM.state || HAM.historical || HAM.current){ // TODO: BUG! Not implemented.
//opt.lower(vertex, {field: field, value: value, state: is});
return;
}
@ -495,7 +507,7 @@
is_node_state_ify(vertex, {field: field, value: value, state: is});
return;
}
if(HAM.defer){
if(HAM.defer){ // TODO: BUG! Not implemented.
/*upper.wait = true;
opt.upper.call(state, vertex, field, incoming, ctx.incoming.state); // signals that there are still future modifications.
Gun.schedule(ctx.incoming.state, function(){
@ -527,45 +539,13 @@
}
}());
Gun.HAM.graph = function(gun, graph){ var g = {};
if(!Gun.is.graph(graph, function(node, soul){ // TODO: PERF! CACHE!
g[soul] = Gun.HAM.node(gun, node);
})){ return }
return g;
}
;(function(){ var u;
function An(){ /*Gun.on.create(this)*/ }
An.chain = An.prototype;
An.chain.event = function(tag, fn, at){
var an = this.an || this;
if(fn){
if(an.mem){
an.on(tag, fn, at).fn(an.mem, at);
at.ran = true;
} else {
an.on(tag, fn, at);
}
}
an.tag = tag;
return an;
;(function(){
Gun.HAM.graph = function(gun, graph){ var g = {};
if(!Gun.is.graph(graph, map, {g:g,gun:gun})){ return }
return g;
}
An.chain.emit = function(a){
var an = this.an || this, tag = an.tag;
an.mem = a;
an.on(tag, a);
}
Gun.at = function(at){
at.on = (at.an = new An()).event;
};
function map(v,f){
if(obj_has(this,f) && u !== this[f]){ return }
this[f] = v;
}
Gun.at.copy = function(from, at){
at = at || {};
obj_map(from, map, at);
return at;
function map(node, soul){
this.g[soul] = Gun.HAM.node(this.gun, node);
}
}());
@ -583,44 +563,40 @@
at = gun;
at.opt = at.opt || {};
at.ack = at.cb;
at.cb = function(err, ok){ // TODO: PERF! CACHE!
if(err){ Gun.log(err) }
var cat = Gun.at.copy(at, {err: err, ok: ok});
Gun.on('ack', cat);
at.ack(cat.err, cat.ok, cat);
}
at.cb = put;
}
Gun.on('put', at);
if(2 >= Gun.ons.put.s.length){ // TODO: Try not to hardcode the default driver count?
if(!Gun.log.count('no-wire-put')){
Gun.log("Warning! You have no storage or persistence!");
}
at.cb(null);
}
return at.gun;
}
}());
;(function(){
function map(node, soul){
}
Gun.on('put', function(at){
if(!Gun.is.graph(at.graph, function(node, soul){ // TODO: PERF! CACHE!
Gun.HAM.node(at.gun, node);
})){ return at.cb({err: "Invalid graph!"}), this.stun() }
});
}());
Gun.on('put', function(at){ var to;
Gun.is.graph(at.graph, function(node, soul){ // TODO: PERF! CACHE!
if(!(to = at.gun.__.by[soul]) || !to._.get){ return }
to._.get(null, node);
});
});
;(function(){
function stream(at){
if(!at.get){ console.log("WARNING! No at.get", at); }
at.get(at.err, at.node);
}
function got(err, node){
function put(err, ok){
if(err){ Gun.log(err) }
Gun.on('stream', Gun.at.copy(this, {err: err, node: node}), stream);
var at = this, cat = Gun.obj.to(at, {err: err, ok: ok});
Gun.on('ack', cat);
at.ack(cat.err, cat.ok, cat);
}
Gun.on('put', function(at, ev){
if(is_graph(at.graph)){ return }
at.cb({err: "Invalid graph!"});
ev.stun();
});
}());
;(function(){
Gun.on('put', function(at, ev){
is_graph(at.graph, map, null, at);
});
function map(node, soul){
Gun.get.got.call(this.gun.__.gun.get(soul)._, null, node);
}
}());
;(function(){
Gun.get = function(at, lex, cb, opt){
if(at.lex){
at.cb = got;
@ -631,15 +607,24 @@
lex: Gun.is.lex(lex || {}),
opt: Gun.is.opt(opt || {}, gun.__.opt),
cb: got,
get: cb
stream: cb
}
}
Gun.on('get', at); // TODO: What is the cleanest way to reply if there is no responses, without assuming drivers do reply or not?
return at.gun;
}
Gun.get.got = got;
function got(err, node){
if(err){ Gun.log(err) }
Gun.on('stream', Gun.obj.to(this, {err: err, node: node}), stream);
}
function stream(at){
if(!at.stream){ console.log("WARNING! No at.get", at); }
at.stream(at.err, at.node);
}
}());
Gun.on('get', function(at, ev){
Gun.on('get', function(at, ev){ // TODO: BUG! What if field isn't in memory? Then we need to still pass the lex out to the peers.
var opt = at.opt;
if(opt.force){ return }
var lex = at.lex, gun = at.gun, graph = gun.__.graph, node = graph[lex.soul];
@ -658,9 +643,9 @@
Gun.on('stream', function(at){ var node;
if(!(node = at.node)){ return }
var __ = at.gun.__, by = __.by, soul = is_node_soul(node);
if(by[soul] && !by[soul]._.node){
by[soul]._.node = __.graph[soul];
var __ = at.gun.__, get = __.get, soul = is_node_soul(node);
if(get && get[soul] && !get[soul]._.node){
get[soul]._.node = __.graph[soul];
}
});
@ -671,6 +656,9 @@
if(soul !== is_node_soul(at.node)){
at.node = obj_copy(node);
}
if(is_node_soul(at.node, 'key')){
return;
}
}
if(at.node && field){ // TODO: Multiples?
var ignore = obj_put({}, _meta, 1);
@ -782,7 +770,7 @@
}());
}(Gun));
var _soul = Gun._.soul, _meta = Gun._.meta, _state = Gun._.state;
var is_val = Gun.is.val, is_rel = Gun.is.rel, is_rel_ify = is_rel.ify, is_node = Gun.is.node, is_node_soul = is_node.soul, is_node_soul_ify = is_node_soul.ify, is_node_ify = is_node.ify, is_node_copy = is_node.copy, is_node_state = is_node.state, is_node_state_ify = is_node_state.ify, HAM_node = Gun.HAM.node;
var is_val = Gun.is.val, is_rel = Gun.is.rel, is_rel_ify = is_rel.ify, is_node = Gun.is.node, is_node_soul = is_node.soul, is_node_soul_ify = is_node_soul.ify, is_node_ify = is_node.ify, is_node_copy = is_node.copy, is_node_state = is_node.state, is_node_state_ify = is_node_state.ify, HAM_node = Gun.HAM.node, is_graph = Gun.is.graph;
Gun.chain = Gun.prototype;
@ -794,7 +782,6 @@
if(!at){
at = gun.__ = gun._;
at.graph = {};
at.by = {};
}
at.opt.uuid = opt.uuid || Gun.text.random;
at.opt.state = opt.state || Gun.time.is;
@ -822,13 +809,57 @@
var at = this, node = cat.node, lex = cat.lex, field = lex.field, rel;
if(obj_has(node, field)){
if(rel = Gun.is.rel(node[field])){
return Gun.get(Gun.at.copy(at, {lex: {soul: rel}}));
return Gun.get(Gun.obj.to(at, {lex: {soul: rel}}));
}
}
at.link(cat, ev);
if(at.link){
at.link(cat, ev);
}
}
;(function(){
Gun.chain.put = function(data, cb, opt){
var back = this, gun, at, put, opts = back.__.opt;
opt = opt || {};
if(back.back){
gun = back;
} else {
// TODO: API CHANGE!!! NO implicit set here!
gun = back.get(is_node_soul(data) || (opt.uuid || opts.uuid)());
}
at = Gun.obj.to(gun._, {put: put = {opt: opt}});
put.any = cb;
put.data = data;
put.state = (opt.state || opts.state)();
at.on('chain', link, at);
return gun;
};
function link(cat, ev){ ev.off(); // TODO: BUG!
var at = this, put = at.put, data, cb;
if(cat.err){ return }
if(!cat.node && (put.opt.init || cat.gun.__.opt.init)){ return }
if(!(data = wrap(cat, put.data))){ // TODO: PERF! Wrap could create a graph version, rather than a document verison that THEN has to get flattened.
if((cb = put.any) && cb instanceof Function){
cb.call(at.gun, {err: Gun.log("No node exists to put " + (typeof at.put.data) + ' "' + at.put.data + '" in!')});
}
return;
}
/*if(ev){
console.log("!!!!!!!!!!!", ev);
put.resume = ev.stun(put.resume);
}*/
Gun.ify(data, end, {
node: function(env, cb){ var eat = env.at;
if(1 === eat.path.length && at.node){
eat.soul = is_rel(at.node[eat.path[0]]);
}
cb(env, eat);
}, value: function(env){ var eat = env.at;
if(!eat.field){ return }
is_node_state_ify(eat.node, {field: eat.field, state: put.state});
}, uuid: at.gun.__.opt.uuid, state: put.state
}, at);
}
function wrap(cat, data){
if(!cat){ return data }
if(cat.lex.field){
@ -842,28 +873,6 @@
}
return data;
}
function link(cat, ev){
// TODO: BUG! Pause execution chain, `var go = this.stop(go)`;
var at = this, put = at.put, data = wrap(cat, put.data), cb; // TODO: PERF! Wrap could create a graph version, rather than a document verison that THEN has to get flattened.
if(!data){
if((cb = put.any) && cb instanceof Function){
cb.call(at.gun, {err: Gun.log("No node exists to put " + (typeof at.put.data) + ' "' + at.put.data + '" in!')});
}
return;
}
var state = at.put.state;
Gun.ify(data, end, {
node: function(env, cb){ var eat = env.at;
if(1 === eat.path.length && at.node){
eat.soul = Gun.is.rel(at.node[eat.path[0]]);
}
cb(env, eat);
}, value: function(env){ var eat = env.at;
if(!eat.field){ return }
Gun.is.node.state.ify(eat.node, {field: eat.field, state: state});
}, uuid: at.gun.__.opt.uuid, state: state
}, at);
}
function end(err, env, at){ var cb;
if(err){
if((cb = at.put.any) && cb instanceof Function){
@ -871,130 +880,104 @@
}
return; // TODO: BUG! Chain emit??
}
key.call(at, err, env); // TODO: Turn into an event emitter!
//console.log("??????????????????", at.lex);
at.lex.soul = at.lex.soul || is_node_soul(env.root);
at.cache = env.root;
Gun.put(Gun.at.copy(at, {graph: env.graph, cb: ack}));
// TODO: RESUME EXECUTION CHAIN.
Gun.on('normalize', Gun.obj.to(at, {err: err, env: env, graph: env.graph}), wire);
}
function key(err, env){ // TODO: Belongs somewhere else!
var at = this;
if(at.put.opt.key){ return }
Gun.is.graph(env.graph, function(node, soul){
var key = {node: at.gun.__.graph[soul]}, tmp;
if(!Gun.is.node.soul(key.node, 'key')){ return }
//if(!gun.__.by(soul).end){ gun.__.by(soul).end = 1 }
Gun.is.node(key.node, function each(rel, s){
var n = at.gun.__.graph[s];
if(n && is_node_soul(n, 'key')){
is_node(n, each);
return;
}
rel = env.graph[s] = env.graph[s] || Gun.is.node.soul.ify({}, s);
Gun.is.node(node, function(v,f){
is_node_state_ify(rel, {field: f, value: v, state: is_node_state(node, f) });
//Gun.is.node.state.ify([rel, node], f, v)
});
Gun.obj.del(env.graph, soul);
});
});
function wire(at){
//at.cache = env.root;
Gun.put(Gun.obj.to(at, {cb: ack}));
}
function ack(err, ok){ var cb;
var at = this;
function ack(err, ok){ var at = this, cb;
if((cb = at.put.any) && cb instanceof Function){
cb.call(at.gun, err, ok);
}
at.on('chain', at);
if(at.put.resume){ at.put.resume() }
if(at.gun.back.back){ return }
//at.on('chain', at);
}
Gun.chain.put = function(data, cb, opt){
var gun = this.back? this : this.chain(), at = Gun.at.copy(gun._, {put: {}}), put = at.put;
//var back = this, gun = back.chain(), at = gun._, put = at.put || (at.put = {});
put.any = cb;
put.data = data;
put.state = Gun.time.is(); // TODO: BUG! Should use NTS capable stuff.
//put.state = opt.state();
put.opt = opt || {};
/*
// START CACHE SHORTCUT
var cache, rel, from = back._, soul;
if(cache = from.cache){
if(soul = is_node_soul(cache)){
link(Gun.at.copy(from, {node: is_node_copy(gun, cache), lex: {soul: soul, field: from.lex.field }}), at);
return gun;
}
}
// END CACHE SHORTCUT
*/
if(!gun.back.back){
link.call(at, at);
} else {
at.on('chain', link, at);
}
return gun;
};
}());
;(function(){
function link(cat, ev){
var at = this;
at.on('any', [cat.err, cat.node]);
if(cat.err){ at.on('err', cat.err) }
if(cat.node){ at.on('ok', cat.node) }
at.on('chain', cat);
}
function got(err, node){
Gun.on('chain', this, link, this);
}
function cache(by, soul, back){
var gun = by[soul] = back.chain(), at = gun._;
at.lex.soul = soul;
at.get = got;
return gun;
}
Gun.chain.get = function(lex, cb, opt){
var gun, back = this, by = back.__.by, tmp;
if(!opt || !opt.path){ var back = this.__.gun; } // TODO: CHANGING API! Remove this line!
var gun, back = back || this;
var get = back._.get || (back._.get = {}), tmp;
if(typeof lex === 'string'){
if(!(gun = by[lex])){
gun = cache(by, lex, back);
if(!(gun = get[lex])){
gun = cache(get, lex, back);
if((tmp = gun._.lex).field){
if(!back._.ons.chain.s.length){ // TODO: CLEAN UP!
back._.on('chain', link, gun._);
}
back._.on('field:' + tmp.field, field, gun._);
}
}
} else
if(!lex && 0 != lex){ // TODO: BUG!?
(gun = back.chain())._.err = {err: Gun.log('Invalid get request!', lex)};
if(cb){ cb.call(gun, gun._.err) }
return gun;
} else
if(num_is(lex)){
return back.get(''+lex, cb, opt);
} else
if(tmp = lex[_soul]){
if(!(gun = by[tmp])){
gun = cache(by, tmp, back);
if(!(gun = get[tmp])){
gun = cache(get, tmp, back);
}
} else
if(tmp = lex.soul){
if(!(gun = by[tmp])){
gun = cache(by, tmp, back);
if(!(gun = get[tmp])){
gun = cache(get, tmp, back);
if(tmp = lex.field){
//cache(gun._.get, tmp, gun);
}
}
}
if(cb && cb instanceof Function){
gun._.on('any', cb, gun);
gun._.on('any', cb, gun); // TODO: Perf! Batch!
}
return gun;
}
function cache(get, key, back){
var gun = get[key] = back.chain(), at = gun._;
at.stream = stream;
if(!back.back){
at.lex.soul = key;
} else {
var lex = at.lex, flex = back._.lex;
lex.field = key;
if(!flex.field && flex.soul){
lex.soul = flex.soul;
}
}
return gun;
}
function stream(err, node){
Gun.on('chain', this, link, this);
}
function link(cat, ev){ var at = this;
at.gun._.val = cat.node; // TODO: CLEANER!
var err = cat.err, node = cat.node, cex = cat.lex, lex = at.lex, rel, val;
if(lex.field && cex.field){
if(obj_has(node, cex.field) && (rel = is_rel(val = node[cex.field]))){
return Gun.get(Gun.obj.to(at, {lex: {soul: rel, field: lex.field}}));
}
}
var field = lex.field;
console.log("length?", at.ons);
at.on('any', [err, (field && node)? node[field] : node, field]); // TODO: Revisit!
if(err){ at.on('err', err) }
if(node){ at.on('ok', (field && node)? node[field] : node, field) } // TODO: Revisit!
is_node(node, map, {cat: cat, at: at});
at.on('chain', cat);
}
function map(val, field){
this.cat.on('field:' + field, this.cat);
}
function field(cat, ev){ var at = this;
at.on('chain', Gun.obj.to(at, {err: cat.err, node: cat.node}));
}
}());
;(function(){
Gun.on('chain', function(cat, e){ // TODO: Belongs someplace else!
if(!is_node_soul(cat.node, 'key')){ return }
var resume = e.stun(1), node = cat.node, pseudo = cat.pseudo = cat.pseudo || is_node_ify({}, is_node_soul(node));
is_node(node, function(n, f){
cat.gun.get(f, function(err, node){
if(!node){ return }
HAM_node(pseudo, node);
cat.node = pseudo;
resume();
});
});
});
function index(cat, ev){
var at = this, cex = cat.lex, lex = at.lex;
//if(cex.soul === lex.soul){ return }
if(cex.soul === lex.key){ return }
at.obj = (1 === is_node_soul(cat.node, 'key'))? obj_copy(cat.node) : obj_put({}, lex.soul, is_rel_ify(lex.soul));
obj_as((at.put = is_node_ify(at.obj, at.key, true))._, 'key', 1);
at.gun.__.gun.put(at.put, function(err, ok){ at.any.call(this, err, ok)}, {/*chain: opt.chain,*/ key: true, init: true});
}
Gun.chain.key = function(key, cb, opt){
if(!key){
if(cb){
@ -1002,119 +985,83 @@
}
return this;
}
var gun = this, at = Gun.at.copy(gun._, {key: key, any: cb || function(){}, opt: opt });
var gun = this, at = Gun.obj.to(gun._, {key: key, any: cb || function(){}, opt: opt });
gun.on('chain', index, at);
return gun;
}
function index(cat, ev){
var at = this, cex = cat.lex, lex = at.lex;
//if(cex.soul === lex.soul){ return }
if(cex.soul === at.key){ return }
at.obj = (1 === is_node_soul(cat.node, 'key'))? obj_copy(cat.node) : obj_put({}, lex.soul, is_rel_ify(lex.soul));
obj_as((at.put = is_node_ify(at.obj, at.key, true))._, 'key', 1);
at.gun.__.gun.put(at.put, at.any, {key: true, init: false});
}
}());
;(function(){ var u;
function got(){ fields.call(this, this) }
function link(cat, ev){ var at = this;
if(!cat.node){ // TODO: I think this is fine, belonging here, but it might need to be pushed further down.
at.back = cat; // TODO: BUG! concerned about race conditions.
at.on('chain', at);
return;
}
if(at.lex === cat.lex || at.gun === cat.gun){
//at.val = at.lex.field? cat.node[at.lex.field] : cat.node;
//at.on('any', cat.node);
at.on('chain', cat);
return;
}
var opt = at.opt, cb, lex = at.lex, field = lex.field, node = cat.node, soul = is_node_soul(node), val, rel, clex = cat.lex, cfield = clex.field;
if(obj_has(clex, 'field')){
if(obj_has(node, cfield)){
if(rel = Gun.is.rel(val = node[cfield])){
return Gun.get(Gun.at.copy(at, {lex: {soul: rel, field: field}}));
Gun.on('chain', function(cat, e){
if(!is_node_soul(cat.node, 'key')){ return }
var resume = e.stun(1), node = cat.node, pseudo = cat.gun._.pseudo || (cat.gun._.pseudo = cat.gun._.node = is_node_ify({}, is_node_soul(node)));
pseudo._.key = 'pseudo';
cat.seen = cat.seen || {}; // TODO: There is a better way.
is_node(node, function(n, f){ // TODO: PERF! BAD! Filter out items we've already seen.
if(cat.seen[f]){ return } cat.seen[f] = true; // TODO: There is a better way.
cat.gun.get(Gun.obj.to(cat.lex, {soul: f}), on);
function on(err, node){
if(!node){ return }
HAM_node(pseudo, node);
cat.node = pseudo;
resume();
}
});
});
Gun.on('normalize', function(cat){
var at = cat, env = at.env;
if(at.put.opt.key){ return }
is_graph(env.graph, function(node, soul){
var key = {node: at.gun.__.graph[soul]}, tmp;
if(!is_node_soul(key.node, 'key')){ return }
//if(!gun.__.by(soul).end){ gun.__.by(soul).end = 1 }
is_node(key.node, function each(rel, s){
var n = at.gun.__.graph[s]; // TODO: BUG! Should we actually load the item or only use what is in memory?
if(n && is_node_soul(n, 'key')){
is_node(n, each);
return;
}
}
}
at.on('chain', cat);
}
function map(val, field){
this.at.on('path:' + field, this.cat);
}
function fields(cat, ev){ var at = this, node;
if(!(node = cat.node)){ return } // TODO: BUG! Still need to emit for fail cases.
var clex = cat.lex, cfield = clex.field, lex = at.lex, rel, val;
if(cfield && !lex.soul){
if(obj_has(node, cfield)){
if(rel = Gun.is.rel(val = node[cfield])){
return Gun.get(Gun.at.copy(at, {lex: {soul: rel, field: at.lex.field}}));
}
}
return;
}
is_node(node, map, {cat: cat, at: at});
}
Gun.chain.path = function(field, cb, opt){
var gun, back = this, from = back._, flex = from.lex, pathed = from.path, path = pathed || (from.path = {}), vert;
if(!field){
if(0 != field){
return back.chain();
}
}
field = ''+field;
if(!(gun = path[field])){
gun = path[field] = back.chain();
var at = gun._, lex = at.lex, via = Gun.at.copy(from);
at.get = got;
lex.field = field;
if(!flex.field && flex.soul){
lex.soul = flex.soul;
via.lex = lex;
via.on('path:' + field, link, at);
} else {
from.on('chain', fields, at);
at.on('path:' + field, link, at);
pathed = 1;
//return gun;
}
}
if(!pathed){
from.on('chain', fields, from);
}
if(cb && cb instanceof Function){
gun._.on('any', cb);
}
return gun;
}
rel = env.graph[s] = env.graph[s] || is_node_soul_ify({}, s);
is_node(node, function(v,f){
is_node_state_ify(rel, {field: f, value: v, state: is_node_state(node, f) });
});
Gun.obj.del(env.graph, soul);
});
});
});
}());
Gun.chain.path = function(field, cb, opt){
return this.get(field, cb, opt || {path: true});
}
;(function(){
function link(cat, ev){
var at = this, opt = at.opt, node = cat.node, lex = at.lex, field = lex.field, cb;
if(!(cb = opt.ok) || cat.err || !node || (field && !Gun.obj.has(node, field))){ return }
cb.call(cat.gun, at.gun._.cache = field? node[field] : node, field || at.gun._.lex.field); // TODO: Wrong gun?
}
Gun.chain.on = function(cb, opt, t){
var gun = this, at = gun._;
// START CACHE SHORTCUT
if(cache = at.cache){
if(cb && cb instanceof Function){
cb.call(gun, is_node_copy(gun, is_node_soul(cache)), at.lex.field); // TODO: BUG! What if the cached item is not a node?
}
return gun;
}
// END CACHE SHORTCUT
if(typeof cb === 'string'){ return at.on(cb, opt, t) }
//opt = Gun.fns.is(opt)? {any: opt, to: Gun.text.is(cb)? cb : u} : Gun.fns.is(cb)? {ok: cb, opt: opt} : {opt: opt};
if(cb && cb instanceof Function){
var cat = at;
(at = Gun.at.copy(at, {opt: opt || {}})).opt.ok = cb;
at.link = link;
at.on('chain', pop, at);
if(!cat.ran){
Gun.get(cat);
}
at.on('ok', cb, gun);
//var at = Gun.obj.to(at, {ok: cb, link: link});
//at.on('chain', pop, at);
}
return gun;
}
}());
;(function(){
function link(cat, ev){
var at = this, node = cat.node, lex = at.lex, field = lex.field, cb;
if(!(cb = at.ok) || cat.err || !node || (field && !Gun.obj.has(node, field))){ return }
cb.call(cat.gun, at.gun._.cache = field? node[field] : node, field || at.gun._.lex.field); // TODO: Wrong gun?
}
/*
function got(err, node){
this.gun._.val = node;
this.ok.call(this.gun, node, this.lex.field);
}
*/
}());
;(function(){
Gun.chain.val = function(cb, opt, t){
var gun = this, at = gun._;
if(at.val){ // TODO: Not null!
@ -1125,11 +1072,15 @@
return gun;
}
if(cb){
var at = Gun.at.copy(at, {get: got, ok: cb});
var at = Gun.obj.to(at, {get: got, ok: cb});
at.on('chain', pop, at);
}
return gun;
}
function got(err, node){
this.gun._.val = node;
this.ok.call(this.gun, node, this.lex.field);
}
}());
}(Gun.chain));
var root = this || {}; // safe for window, global, root, and 'use strict'.
@ -1349,7 +1300,6 @@
delete r.jsonp.poll.s[opt.base];
while(reply.body && reply.body.length && reply.body.shift){ // we're assuming an array rather than chunk encoding. :(
var res = reply.body.shift();
//Gun.log("-- go go go", res);
if(res && res.body){ r.createServer.ing(res, function(){ r(opt.base, null, null, res) }) } // emit extra events.
}
});

View File

@ -1417,17 +1417,16 @@ describe('Gun', function(){
}).key('hello/key', function(err, ok){
expect(err).to.not.be.ok();
done.key = true;
if(done.yes){ done(); }
if(!done.c && done.yes){ done();done.c=1; }
}).key('yes/hello', function(err, ok){
expect(err).to.not.be.ok();
done.yes = true;
if(done.key){ done(); }
if(!done.c && done.key){ done();done.c=1; }
});
});
it('get key null', function(done){
gun.get('yes/key').key('', function(err, ok){
console.log("WAT?", err, ok);
expect(err).to.be.ok();
done();
});
@ -1441,32 +1440,41 @@ describe('Gun', function(){
gun.put({north: 'america'}).key('hello/galaxy');
gun.put({south: 'pole'}).key('hello/galaxy');
gun.get('hello/earth').key('hello/galaxy', function(err, ok){
console.log("111111111", err, ok);
expect(err).to.not.be.ok();
});
var node = (gun.__.by['hello/earth']||{}).node || {};
var node = (gun.__.get['hello/earth']||{}).node || {};
expect(node['hello/galaxy']).to.not.be.ok();
gun.get('hello/earth', function(err, pseudo){
console.log("222222222222", err, pseudo);
expect(pseudo.hello).to.be('world');
expect(pseudo.continent).to.be('africa');
expect(pseudo.place).to.be('asia');
expect(pseudo.north).to.not.be.ok();
});
var galaxy = (gun.__.by['hello/galaxy']||{}).node || {};
var galaxy = (gun.__.get['hello/galaxy']||{}).node || {};
expect(galaxy['hello/earth']).to.not.be.ok();
gun.get('hello/galaxy', function(err, pseudo){
//if(done.c){ return }
console.log("33333333333", err, pseudo);
if(done.c || !pseudo.hello || !pseudo.south || !pseudo.place || !pseudo.continent || !pseudo.north){ return }
expect(pseudo.hello).to.be('world');
expect(pseudo.south).to.be('pole');
expect(pseudo.place).to.be('asia');
expect(pseudo.continent).to.be('africa');
expect(pseudo.north).to.be('america');
//done(); done.c = 1;
done(); done.c = 1;
});
});
return;
function soulnode(gun, kn, r){
r = r || [];
Gun.is.node(kn, function(node, s){
var n = gun.__.graph[s];
if(Gun.is.node.soul(n, 'key')){
soulnode(gun, n, r);
return;
}
r.push(s);
});
return r;
}
it('get node put node merge', function(done){
gun.get('hello/key', function(err, node){
@ -1477,12 +1485,9 @@ return;
}).put({hi: 'you'}, function(err, ok){
expect(err).to.not.be.ok();
var keynode = gun.__.graph[done.soul], soul;
var c = 0;
expect(keynode.hi).to.not.be.ok();
Gun.is.node(keynode, function(node, s){
soul = s;
expect(c++).to.not.be.ok();
});
var c = soulnode(gun, keynode), soul = c[0];
expect(c.length).to.be(1);
var node = gun.__.graph[soul];
expect(node.hello).to.be('key');
expect(node.hi).to.be('you');
@ -1538,11 +1543,8 @@ return;
if(done.c){ return }
expect(err).to.not.be.ok();
var keynode = gun.__.graph[done.soul], soul;
var c = 0;
Gun.is.node(keynode, function(node, s){
soul = s;
expect(c++).to.not.be.ok();
});
var c = soulnode(gun, keynode), soul = c[0];
expect(c.length).to.be(1);
var node = gun.__.graph[soul];
expect(node.hello).to.be('key');
expect(node.hi).to.be('overwritten');
@ -1557,7 +1559,7 @@ return;
});
it('get key path put', function(done){
var gun = Gun().put({foo:'lol'}).key('key/path/put');
var gun = Gun().put({foo:'lol', extra: 'yes'}).key('key/path/put');
var data = gun.get('key/path/put');
data.path('foo').put('epic');
data.val(function(val, field){
@ -1590,12 +1592,13 @@ return;
it('put node path rel', function(done){
gun.put({foo: {bar: 'lol'}}).path('foo', function(err, val, field){
if(done.end){ return } // it is okay for path's callback to be called multiple times.
console.log("oye", err, val, field);
expect(err).to.not.be.ok();
expect(field).to.be('foo');
expect(val.bar).to.be('lol');
done(); done.end = true;
});
});
});return;
it('get node path', function(done){
gun.get('hello/key').path('hi', function(err, val, field){
@ -1665,7 +1668,7 @@ return;
expect(root.yay).to.not.be.ok();
expect(Gun.is.rel(root.hi)).to.be.ok();
expect(Gun.is.rel(root.hi)).to.not.be(soul);
var node = gun.__.by(Gun.is.rel(root.hi)).node;
var node = gun.__.get(Gun.is.rel(root.hi)).node;
expect(node.yay).to.be('value');
if(done.sub){ expect(done.sub).to.be(Gun.is.rel(root.hi)) }
else { done.sub = Gun.is.rel(root.hi) }

View File

@ -1978,6 +1978,7 @@
window.geti = window.geti || 0;
localStorage.clear();
gun.get('users').put({1: {where: {lat: Math.random(), lng: Math.random(), i: 1}}});
//var ok = function(a,b){ console.log('wat', a,b) }
var val = gun.get('users').path(1).path('where').val(ok);
});
//localStorage.clear();
@ -1990,7 +1991,7 @@
val.val(ok);
});
stool.add('on', function(){
gun.get('users').path(1).path('where').val(ok);
gun.get('users').path(1)/*.path('where')*/.val(ok);
});
return;
stool.add('put', function(){