all core tests passing.

This commit is contained in:
Mark Nadal 2016-01-23 20:49:05 -08:00
parent 6908df0405
commit 85ee6fd07c
3 changed files with 156 additions and 125 deletions

View File

@ -2,11 +2,11 @@
## 0.3
Migration Guide! Migrate by changing `.attach(` to `.wsp(` on your server if you have one with gun. Change `.set()` (empty call) to `` (aka delete it), and change `.set($DATA)` (where you call set with something) to `.path('I' + Date.now() + 'R' + Gun.text.random(5)).put($DATA)`. If you have NodeJS style callbacks in your `.get` (which documentation previously recommended that you shouldn't) they previous took `err, graph` and now they take `err, node` (which means now using callback style is fine to use). If you are a module developer, use `opt.wire` now instead of `opt.hooks` and message Mark since he needs to talk to you since the wire protocol has changed.
Migration Guide! Migrate by changing `.attach(` to `.wsp(` on your server if you have one with gun. Change `.set()` (empty call) to `` (aka delete it), and change `.set($DATA)` (where you call set with something) to `.path('I' + Date.now() + 'R' + Gun.text.random(5)).put($DATA)`. If you have NodeJS style callbacks in your `.get` (which documentation previously recommended that you shouldn't) they previous took `err, graph` and now they take `err, node` (which means now using callback style is fine to use). Inside of `.not()` no longer use `return` or `this`, instead (probably) use `gun` and no `return`. If you are a module developer, use `opt.wire` now instead of `opt.hooks` and message Mark since he needs to talk to you since the wire protocol has changed.
- Server side default `.wsp()` renamed from `.attach()`.
- `.set()` deprecated because it did a bunch of random inconsistent things. Its useful behavior has now become implicit (see below) or can be done explicitly.
- `.not()` it was previously common to `return` the chain inside of .not, beware that if you have code like `gun.get(key).not(function(){ return this.put({}).key(key) }).val()` it will cause `.val()` to be triggered twice (this is intentional, because it funnels two separate chains together) which previously didn't happen. To fix this, just don't return the chain.
- `.not()` it was previously common to `return` the chain inside of .not, beware that if you have code like `gun.get(key).not(function(){ return this.put({}).key(key) }).val()` cause `.val()` to be triggered twice (this is intentional, because it funnels two separate chains together) which previously didn't happen. To fix this, just don't return the chain.
- `.put()` and `.path()` do implicit `.init()` by default, turn on explicit behavior with `Gun({init: true})`.
- `.get(soul, cb)` cb is called back with `err, node` rather than `err, graph`.
- Options `opt.wire` renamed from `opt.hooks`.

138
gun.js
View File

@ -345,9 +345,7 @@
if(!ctx.graph){ ctx.err = {err: Gun.log("No graph!") } }
if(!prime){ ctx.err = {err: Gun.log("No data to merge!") } }
if(ctx.soul = Gun.is.node.soul(prime)){ prime = Gun.is.graph.ify(prime) }
if(!Gun.is.graph(prime, function(node, soul){
//ctx.graph[soul] = ctx.graph[soul] || Gun.is.node.ify({}, soul); // TODO: BUG! Without this path thinks it has to load it.
}, function(val, field, node){ var meta;
if(!Gun.is.graph(prime, null, function(val, field, node){ var meta;
if(!(meta = (node||{})[Gun._.meta]) || !(meta = meta[Gun._.state]) || !Gun.num.is(meta[field])){
return ctx.err = {err: Gun.log("No state on '" + field + "'!") }
}
@ -356,8 +354,13 @@
Gun.on('operating').emit(gun, at);
}
(function union(graph, prime){
var prime = Gun.obj.map(prime, function(n,s,t){t(n)}).sort(function(A,B){
var s = Gun.is.node.soul(A);
if(graph[s]){ return 1 }
return 0;
});
ctx.count += 1;
ctx.err = Gun.obj.map(prime, function(node, soul){
ctx.err = Gun.list.map(prime, function(node, soul){
soul = Gun.is.node.soul(node);
if(!soul){ return {err: Gun.log("Soul missing or mismatching!")} }
ctx.count += 1;
@ -386,7 +389,6 @@
}
Gun.union.ify = function(gun, prime, cb, opt){
/*
if(gun){ gun = (gun.__ && gun.__.graph)? gun.__.graph : gun }
if(Gun.text.is(prime)){
if(gun && gun[prime]){
@ -396,16 +398,6 @@
}
}
var vertex = Gun.is.node.soul.ify({}, Gun.is.node.soul(prime)), prime = Gun.is.graph.ify(prime) || prime;
*/
if(gun){ gun = (gun.__ && gun.__.graph)? gun.__.graph : gun }
if(Gun.text.is(prime)){
if(gun && gun[prime]){
prime = gun[prime];
} else {
return Gun.is.node.ify({_: Gun.obj.put({}, 'key', 1) }, prime);
}
}
var vertex = Gun.is.node.soul.ify({_: Gun.obj.put({}, 'key', 1)}, Gun.is.node.soul(prime)), prime = Gun.is.graph.ify(prime) || prime;
if(Gun.is.graph(prime, null, function(val, field){ var node;
function merge(a, f, v){ Gun.is.node.state.ify(a, f, v) }
if(Gun.is.rel(val)){ node = gun? gun[field] || prime[field] : prime[field] }
@ -496,7 +488,7 @@
return Gun.obj.map(proxy.mem[proxy.e], function(at){
i.stat = {first: true};
cb.call(i, at);
}), i;
}), i.stat = {}, i;
}
proxy.map = function(cb, i){
return proxy.event(cb, i);
@ -560,10 +552,11 @@
ctx.soul = at.field? at.soul : (at.at && at.at.soul) || at.soul; // figure out where we are
ctx.field = at.field? at.field : (at.at && at.at.field) || at.field; // did we come from some where?
ctx.by = chain.__.by(ctx.soul);
ctx.not = at.not || (at.at && at.at.not);
Gun.obj.del(at, 'not'); Gun.obj.del(at.at || at, 'not'); // the data is no longer not known! // TODO: BUG! It could have been asynchronous by the time we now delete these properties. Don't other parts of the code assume their deletion is synchronous?
if(ctx.field){ Gun.obj.as(ctx.obj = {}, ctx.field, val) } // if there is a field, then data is actually getting put on the parent.
else if(!Gun.obj.is(val)){ return cb.call(chain, ctx.err = {err: Gun.log("No node exists to put " + (typeof val) + ' "' + val + '" in!')}), chain._.at('err').emit(ctx.err) } // if the data is a primitive and there is no context for it yet, then we have an error.
// TODO: BUG? gun.get(key).path(field).put() isn't doing it as pseudo.
console.debug(1, 'chain.put', val, at);
function soul(env, cb, map){ var eat;
if(!env || !(eat = env.at) || !env.at.node){ return }
if(!eat.node._){ eat.node._ = {} }
@ -571,11 +564,9 @@
if(!Gun.is.node.soul(eat.node)){
if(ctx.obj === eat.obj){
Gun.obj.as(env.graph, eat.soul = Gun.obj.as(eat.node._, Gun._.soul, Gun.is.node.soul(eat.obj) || ctx.soul), eat.node);
console.debug(2, 'chain.put soul root', eat.soul);
cb(eat, eat.soul);
} else {
var path = function(err, node){
console.debug(4, 'chain.put soul path RESOLVED', err, node);
if(path.opt && path.opt.on && path.opt.on.off){ path.opt.on.off() }
if(path.opt.done){ return }
path.opt.done = true;
@ -583,9 +574,8 @@
eat.soul = Gun.is.node.soul(node) || Gun.is.node.soul(eat.obj) || Gun.is.node.soul(eat.node) || Gun.text.random();
Gun.obj.as(env.graph, Gun.obj.as(eat.node._, Gun._.soul, eat.soul), eat.node);
cb(eat, eat.soul);
}; path.opt = {once: true, rel: true, stun: true, init: true};
console.debug(3, 'chain.put soul path', eat.path, at);
(at.not)? path() : ((at.field || at.at)? gun.back : gun).path(eat.path || [], path, path.opt);
}; path.opt = {put: true};
(ctx.not)? path() : ((at.field || at.at)? gun.back : gun).path(eat.path || [], path, path.opt);
}
}
if(!eat.field){ return }
@ -609,9 +599,13 @@
if(!Gun.log.count('no-wire-put')){ Gun.log("Warning! You have no persistence layer to save to!") }
cb.call(chain, null); // This is in memory success, hardly "success" at all.
}
Gun.obj.del(at, 'not'); Gun.obj.del(at.at || at, 'not'); // the data is no longer not known!
ctx.field? chain.get(ctx.soul).path(ctx.field, null, {chain: opt.chain || chain, via: 'put end'})
: chain.get(ctx.soul, null, {chain: opt.chain || chain});
if(ctx.field){
return gun.back.path(ctx.field, null, {chain: opt.chain || chain});
}
if(ctx.not){
return gun.__.gun.get(ctx.soul, null, {chain: opt.chain || chain});
}
chain.get(ctx.soul, null, {chain: opt.chain || chain, at: gun._.at })
}
Gun.ify(ctx.obj, soul, {pure: true})(end); // serialize the data!
}
@ -620,34 +614,35 @@
} else { // else if we are on an existing chain then...
gun._.at('soul').map(put); // put data on every soul that flows through this chain.
var back = function(gun){
if(gun.back === gun){ return }
if(gun.back === gun || gun._.not){ return } // TODO: CLEAN UP! Would be ideal to accomplish this in a more ideal way.
gun._.at('null').event(function(at){
if(opt.init || gun.__.opt.init){ return Gun.log("Warning! You have no context to `.put`", val, "!") }
gun.init();
});
}, -999);
return back(gun.back);
};
back(gun)
if(!opt.init && !gun.__.opt.init){ back(gun) }
}
chain.back = gun.back;
return chain;
}
Gun.chain.get = (function(){
Gun.on('operating').event(function(gun, at){
if(gun.__.by && !gun.__.by(at.soul).node){ gun.__.by(at.soul).node = gun.__.graph[at.soul] }
if(!gun.__.by(at.soul).node){ gun.__.by(at.soul).node = gun.__.graph[at.soul] }
if(at.field){ return } // TODO: It would be ideal to reuse HAM's field emit.
console.debug(1, 'HAM emitted to operating state', at);
gun.__.on(at.soul).emit(at);
});
Gun.on('get').event(function(gun, at, ctx, opt, cb){
if(ctx.halt){ ctx.halt = false; return } // TODO: CLEAN UP with event emitter option?
if(ctx.halt){ return } // TODO: CLEAN UP with event emitter option?
at.change = at.change || gun.__.by(at.soul).node;
if(opt.raw){ return cb.call(opt.on, at) }
console.debug(3, 'get on.get', at);
cb.call(ctx.by.chain, null, Gun.obj.copy(at.change));
if(!ctx.cb.no){ cb.call(ctx.by.chain, null, Gun.obj.copy(ctx.node || gun.__.by(at.soul).node)) }
gun._.at('soul').emit(at).chain(opt.chain);
console.debug(4, 'get done on.get', at);
},0);
Gun.on('get').event(function(gun, at, ctx){
if(ctx.halt){ ctx.halt = false; return } // TODO: CLEAN UP with event emitter option?
}, Infinity);
return function(lex, cb, opt){ // get opens up a reference to a node and loads it.
var gun = this, ctx = {
opt: opt || {},
@ -655,11 +650,11 @@
lex: (Gun.text.is(lex) || Gun.num.is(lex))? Gun.is.rel.ify(lex) : lex,
};
ctx.force = ctx.opt.force;
if(cb !== ctx.cb){ ctx.cb.no = true }
if(!Gun.obj.is(ctx.lex)){ return ctx.cb.call(gun = gun.chain(), {err: Gun.log('Invalid get request!', lex)}), gun }
if(!(ctx.soul = ctx.lex[Gun._.soul])){ return ctx.cb.call(gun = this.chain(), {err: Gun.log('No soul to get!')}), gun } // TODO: With `.all` it'll be okay to not have an exact match!
ctx.by = gun.__.by(ctx.soul);
ctx.by.chain = ctx.by.chain || gun.chain();
ctx.by.at = ctx.by.at || gun.__.at(ctx.soul);
function load(lex){
var cached = gun.__.by(lex[Gun._.soul]).node;
if(ctx.force){ ctx.force = false }
@ -691,10 +686,9 @@
function on(at){
if(on.ran = true){ ctx.opt.on = this }
if(load(ctx.lex)){ return }
console.debug(2, 'chain.get', at);
Gun.on('get').emit(ctx.by.chain, at, ctx, ctx.opt, ctx.cb, ctx.lex);
}
ctx.opt.on = ctx.by.at.event(on);
ctx.opt.on = (ctx.opt.at || gun.__.at)(ctx.soul).event(on);
if(!ctx.opt.ran && !on.ran){ on.call(ctx.opt.on, {soul: ctx.soul}) }
return ctx.by.chain;
}
@ -718,14 +712,14 @@
if(ctx.halt){ return } // TODO: CLEAN UP with event emitter option?
if(opt.key && opt.key.soul){
at.soul = opt.key.soul;
var pseudo = gun.__.by(opt.key.soul).node = Gun.union.ify(gun, opt.key.soul); // TODO: Check performance?
(pseudo||{_:{}})._['key'] = 'pseudo';
at.change = pseudo;
gun.__.by(opt.key.soul).node = Gun.union.ify(gun, opt.key.soul); // TODO: Check performance?
gun.__.by(opt.key.soul).node._['key'] = 'pseudo';
at.change = Gun.is.node.soul.ify(at.change || gun.__.by(at.soul).node, at.soul, true);
return;
}
var node = at.change || gun.__.graph[at.soul];
if(!(Gun.is.node.soul(node, 'key') === 1)){ return }
function map(rel, soul){ gun.__.gun.get(rel, cb, {raw: false, key: ctx, chain: opt.chain || gun, force: opt.force}) }
function map(rel, soul){ gun.__.gun.get(rel, cb, {key: ctx, chain: opt.chain || gun, force: opt.force}) }
ctx.halt = true;
Gun.is.node(node, map);
},-999);
@ -738,9 +732,9 @@
var ctx = {node: gun.__.graph[at.soul]};
if(at.soul === key || at.key === key){ return }
if(cb.hash[at.hash = at.hash || Gun.on.at.hash(at)]){ return } cb.hash[at.hash] = true;
ctx.obj = (1 === Gun.is.node.soul(ctx.node, 'key'))? ctx.node : Gun.obj.put({}, at.soul, Gun.is.rel.ify(at.soul));
ctx.obj = (1 === Gun.is.node.soul(ctx.node, 'key'))? Gun.obj.copy(ctx.node) : Gun.obj.put({}, at.soul, Gun.is.rel.ify(at.soul));
Gun.obj.as((ctx.put = Gun.is.node.ify(ctx.obj, key, null, true))._, 'key', 1);
gun.__.gun.put(ctx.put, function(err, ok){cb.call(this, err, ok)}, {chain: opt.chain, key: true});
gun.__.gun.put(ctx.put, function(err, ok){cb.call(this, err, ok)}, {chain: opt.chain, key: true, init: true});
}
if(opt.soul){
index({soul: opt.soul});
@ -761,8 +755,9 @@
cb = cb || function(){};
function map(at){
opt.on = opt.on || this;
if(opt.raw){ return cb.call(opt.on, at) }
var ctx = {by: gun.__.by(at.soul)}, change = ctx.by.node;
if(opt.on.stat && opt.on.stat.first){ (at = Gun.on.at.copy(at)).change = ctx.by.node }
if(opt.raw){ return cb.call(opt.on, at) }
if(opt.once){ this.off() }
if(opt.change){ change = at.change }
if(!opt.empty && Gun.obj.empty(change, Gun._.meta)){ return }
@ -779,54 +774,56 @@
if(opt.path){ at.at = opt.path }
var xtc = {soul: lex[Gun._.soul], field: lex[Gun._.field]};
xtc.change = at.change || gun.__.by(at.soul).node;
/*
if(xtc.field){ // TODO: future feature!
console.log("there is never a lexical field", lex);
if(!Gun.obj.has(xtc.change, xtc.field)){ return }
ctx.node = Gun.is.node.soul.ify({}, at.soul); // TODO: CLEAN UP! ctx.node usage.
Gun.is.node.state.ify([ctx.node, xtc.change], xtc.field, xtc.change[xtc.field]);
at.change = ctx.node; at.field = xtc.field;
}
*/
},-99);
Gun.on('get').event(function(gun, at, ctx, opt, cb, lex){
if(ctx.halt){ return } // TODO: CLEAN UP with event emitter option?
var xtc = {}; xtc.change = at.change || gun.__.by(at.soul).node;
console.debug(5, 'path on.get', at);
Gun.is.node(xtc.change, function(v,f){
var fat = Gun.on.at.copy(at); fat.field = f; fat.value = v;
Gun.obj.del(fat, 'at'); // TODO: CLEAN THIS UP! It would be nice in every other function every where else it didn't matter whether there was a cascading at.at.at.at or not, just and only whether the current context as a field or should rely on a previous field. But maybe that is the gotcha right there?
fat.change = fat.change || xtc.change;
if(v = Gun.is.rel(fat.value)){ fat = {soul: v, at: fat} }
gun._.at('path:' + f).emit(fat).chain(opt.chain);
});
if(!opt.put){ // TODO: CLEAN UP be nice if path didn't have to worry about this.
Gun.is.node(xtc.change, function(v,f){
var fat = Gun.on.at.copy(at); fat.field = f; fat.value = v;
Gun.obj.del(fat, 'at'); // TODO: CLEAN THIS UP! It would be nice in every other function every where else it didn't matter whether there was a cascading at.at.at.at or not, just and only whether the current context as a field or should rely on a previous field. But maybe that is the gotcha right there?
fat.change = fat.change || xtc.change;
if(v = Gun.is.rel(fat.value)){ fat = {soul: v, at: fat} }
gun._.at('path:' + f).emit(fat).chain(opt.chain);
});
}
if(!ctx.end && ctx.by.end){
ctx.end = gun._.at('end').emit(at).chain(opt.chain);
}
},99);
return function(path, cb, opt){
opt = opt || {};
cb = cb || function(){}; cb.hash = {};
cb = cb || (function(){ var cb = function(){}; cb.no = true; return cb }()); cb.hash = {};
var gun = this, chain = gun.chain(), f, c, u;
if(!Gun.list.is(path)){ if(!Gun.text.is(path)){ if(!Gun.num.is(path)){ // if not a list, text, or number
return cb.call(chain, {err: Gun.log("Invalid path '" + path + "'!")}), chain; // then complain
} else { return this.path(path + '', cb, opt) } } else { return this.path(path.split('.'), cb, opt) } } // else coerce upward to a list.
if(gun === gun.back){
cb.call(chain, {err: Gun.log('You have no context to `.path`', path, '!')});
cb.call(chain, opt.put? null : {err: Gun.log('You have no context to `.path`', path, '!')});
return chain;
}
gun._.at('path:' + path[0]).event(function(at){
console.log("path", path, opt.stun);
if(opt.once || opt.stun){ this.off() }
if(opt.done){ this.off(); return } // TODO: BUG - THIS IS A FIX FOR A BUG! TEST #"context no double emit", COMMENT THIS LINE OUT AND SEE IT FAIL!
var ctx = {soul: at.soul, field: at.field, by: gun.__.by(at.soul)}, field = path[0];
var on = Gun.obj.as(cb.hash, at.hash, {off: function(){}});
if(at.soul === on.soul){ return }
else { on.off() }
if(ctx.rel = (Gun.is.rel(at.value) || Gun.is.rel(at.at && at.at.value))){
var get = function(err, node){ if(err || 1 === path.length){ cb.call(this, err, node? node : u, field) } };
ctx.opt = {opt: opt, chain: opt.chain || chain, path: {soul: (at.at && at.at.soul) || at.soul, stun: opt.stun, field: field}};
gun.__.gun.get(ctx.rel || at.soul, get, ctx.opt);
if(opt.put && 1 === path.length){
return cb.call(ctx.by.chain || chain, null, Gun.is.node.soul.ify({}, ctx.rel));
}
var get = function(err, node){
if(!err && 1 !== path.length){ return }
cb.call(this, err, node, field);
};
ctx.opt = {chain: opt.chain || chain, put: opt.put, path: {soul: (at.at && at.at.soul) || at.soul, field: field }};
gun.__.gun.get(ctx.rel || at.soul, cb.no? null : get, ctx.opt);
(opt.on = cb.hash[at.hash] = on = ctx.opt.on).soul = at.soul; // TODO: BUG! CB getting reused as the hash point for multiple paths potentially! Could cause problems!
return;
}
@ -835,6 +832,10 @@
});
gun._.at('null').only(function(at){
if(!at.field){ return }
if(at.not){
gun.put({}, null, {init: true});
if(opt.init || gun.__.opt.init){ return }
}
(at = Gun.on.at.copy(at)).field = path[0];
at.not = true;
chain._.at('null').emit(at).chain(opt.chain);
@ -887,7 +888,7 @@
Gun.on('operating').event(function(gun, at, end){
if(!Gun.obj.empty(at.change, Gun._.meta)){ return }
(end = gun.__.by(at.soul)).end = (end.end || 0) + 1;
});
},-999);
return function(cb, opt){
var gun = this, args = Gun.list.slit.call(arguments);
cb = Gun.fns.is(cb)? cb : function(val, field){ root.console.log.apply(root.console, args.concat([field && (field += ':'), val])) }; cb.hash = {};
@ -898,7 +899,7 @@
if(at.field && Gun.obj.has(node, at.field)){
return cb.hash[hash] = true, cb.call(ctx.by.chain || gun, Gun.obj.copy(node[at.field]), at.field);
}
if(!opt.empty && Gun.obj.empty(node, Gun._.meta)){ return } // TODO: CLEAN THIS UP? .on already does this without the .raw!
if(!opt.empty && Gun.obj.empty(node, Gun._.meta)){ return } // TODO: CLEAN UP! .on already does this without the .raw!
if(!ctx.by.end){ return }
return cb.hash[hash] = true, cb.call(ctx.by.chain || gun, Gun.obj.copy(node), field);
}
@ -932,13 +933,14 @@
}
gun._.at.all(not);
if(gun === gun.back){ Gun.log('You have no context to `.not`!') }
chain._.not = true; // TODO: CLEAN UP! Would be ideal if we could accomplish this in a more elegant way.
return chain;
}
Gun.chain.init = function(cb, opt){
var gun = this;
gun._.at('null').event(function(at){
if(!at.not){ return }
if(!at.not){ return } // TODO: BUG! This check is synchronous but it could be asynchronous!
var ctx = {by: gun.__.by(at.soul)};
if(at.field){
if(Gun.obj.has(ctx.by.node, at.field)){ return }
@ -948,10 +950,10 @@
if(at.soul){
if(ctx.by.node){ return }
var soul = Gun.text.random();
gun.__.gun.put(Gun.is.node.soul.ify({}, soul));
gun.__.gun.put(Gun.is.node.soul.ify({}, soul, {init: true}));
gun.__.gun.key(at.soul, null, soul);
}
});
}, {raw: true});
return gun;
}
@ -1162,7 +1164,7 @@
tab.peers = function(cb, o){
if(Gun.text.is(cb)){ return (o = {})[cb] = {}, o }
if(cb && !cb.peers){ setTimeout(function(){
if(!cb.local){ console.log("Warning! You have no peers to connect to!") }
if(!cb.local){ if(!Gun.log.count('no-peers')){ Gun.log("Warning! You have no peers to connect to!") } }
if(!(cb.graph || cb.node)){ cb(null) }
},1)}
}

View File

@ -1054,7 +1054,7 @@ describe('Gun', function(){
done(); done.c = 1;
});
});
describe('timeywimey', function(){ return;
it('kitty', function(done){
@ -1236,6 +1236,16 @@ describe('Gun', function(){
}
});
it('get key no override', function(done){
var gun = Gun();
gun.put({cream: 'pie'}).key('cream/pie').get('cream/pie', function(err, node){
expect(Gun.is.node.soul(node)).to.be('cream/pie');
if(done.c){ done(); } done.c = 1;
});
gun.get('cream/pie').key('pie/cream');
gun.get('pie/cream').put({pie: 'cream'});
});
it('get key', function(done){
gun.get('yes/key', function(err, node){
expect(err).to.not.be.ok();
@ -1427,7 +1437,7 @@ describe('Gun', function(){
});
});
it.skip('put node get field', function(done){ // future feature.
it('put node get field', function(done){ // future feature.
var gun = Gun();
gun.put({_:{'#': 'soul/field'}, hi: 'lol', foo: 'bar'});//.key('key/field');
gun.get({'#': 'soul/field', '.': 'hi'}, function(err, val){
@ -1559,7 +1569,7 @@ describe('Gun', function(){
},50);
},50);
});
it('get path wire shallow swoop', function(done){
var gun = Gun();
var get = gun.get('slightly/shallow/path/swoop');
@ -1597,7 +1607,9 @@ describe('Gun', function(){
var get = gun.get('hello/key/iso');
var puthi = get.put({hi: 'you'});
puthi.on(function(node){
if(done.hi){ return }
expect(node.hi).to.be('you');
done.hi = 1;
});
setTimeout(function(){
var get2 = gun.get('hello/key/iso');
@ -1765,7 +1777,7 @@ describe('Gun', function(){
done();
}, 1);
});
it('get path put', function(done){
gun.get('hello/world').path('hello').put('World').val(function(val){
expect(val).to.be('World');
@ -2198,85 +2210,90 @@ describe('Gun', function(){
});
});
it.only('path should not slowdown', function(done){
it('path should not slowdown', function(done){
this.timeout(5000);
//this.timeout(60000);
Gun.log.debug = 100; console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
//Gun.log.debug = 100; console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
var gun = Gun({init: true}).put({
history: {}
});
console.log("---------- setup data done -----------");
var prev, diff, max = 25, total = 10, largest = -1, gone = {};
//console.log("---------- setup data done -----------");
var prev, diff, max = 25, total = 100, largest = -1, gone = {};
// TODO: It would be nice if we could change these numbers for different platforms/versions of javascript interpreters so we can squeeze as much out of them.
gun.path('history').map(function(time, index){
//if(turns != index){ return }
diff = Gun.time.is() - time;
//expect(gone[index]).to.not.be.ok();
diff = Gun.time.is() - time;
expect(gone[index]).to.not.be.ok();
gone[index] = diff;
largest = (largest < diff)? diff : largest;
console.log(turns, index, largest, diff);
//expect(diff > max).to.not.be.ok();
//console.log(turns, index, 'largest', largest, diff);
expect(diff > max).to.not.be.ok();
});
//var p = gun.path('history');
console.log("-------- map set up -----------");
//console.log("-------- map set up -----------");
var turns = 0;
var many = setInterval(function(){
if(turns > total || (diff || 0) > (max + 5)){
return;
clearTimeout(many);
expect(diff).to.be.ok();
clearTimeout(many);
expect(Gun.num.is(diff)).to.be.ok();
if(done.c){ return } done(); done.c = 1;
//console.log(turns, largest);
return;
}
//if(turns === 233){ Gun.log.debug = 1; console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") }
prev = Gun.time.is();
Gun.log.base = Gun.log.ref = Gun.log.fer = prev;
var put = {}; put[turns += 1] = prev;
//{11: 123456789}
console.log("------------------", turns,"---------------------------")
if(turns === 9){ Gun.log.debug = 1; console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") }
gun.put({history: put});
//p.put(put);
//gun.path('history').put(put);
}, 1);
});
//return;
it('path rel should not slowdown', function(done){
this.timeout(5000);
//this.timeout(60000);
//Gun.log.debug = 1; console.log("~~~~~ START ~~~~~~");
var gun = Gun(gopt).put({
history: {}
});
var prev, diff, max = 100, total = 100;
//console.log("-------- DATA SET UP -----------");
var prev, diff, max = 100, total = 100, largest = -1, gone = {};
gun.path('history').map(function(entry, index){
//if(!entry){ return } // TODO: BUG! KNOWN BUG!!!!!!! FIX!!!!!
//console.log("WAT", index, entry);
//console.log("THE GRAPH\n", gun.__.graph);
//expect(gone[index]).to.not.be.ok();
gone[index] = diff;
diff = Gun.time.is() - (entry.time || prev);
//console.log('turn', turns, 'diff', diff);
largest = (largest < diff)? diff : largest;
//console.log('turn', turns, 'index', index, 'diff', diff, 'largest', largest);
expect(diff > max).to.not.be.ok();
});
var turns = 0;
//console.log("------------ PATH MAP SET UP --------------");
var many = setInterval(function(){
if(turns > total || diff > (max + 5)){
clearTimeout(many);
expect(diff).to.be.ok();
expect(Gun.num.is(diff)).to.be.ok();
if(done.c){ return } done(); done.c = 1;
return;
}
prev = Gun.time.is();
Gun.log.base = Gun.log.ref = Gun.log.fer = prev;
//console.log("-------------- TEST PUT BEGIN", turns + 1, "-----------------");
gun.path(['history', turns += 1]).put({
//if(turns === 0){ Gun.log.debug = 1; console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); }
//console.log("-------------- ", turns + 1, "-----------------");
var val = {
x: 1,
y: 1,
axis: 'y',
direction: 1,
time: prev
});
}, 1);
}
var put = {}; put[turns += 1] = val;
gun.put({history: put});
//gun.path(['history', turns += 1]).put({
},1);
});
it('val path put val', function(done){
@ -2469,7 +2486,7 @@ describe('Gun', function(){
});
it('node path node path node path', function(done){
var gun = Gun();
var gun = Gun(gopt);
var data = gun.get('data');
gun.put({
a: 1,
@ -2578,8 +2595,7 @@ describe('Gun', function(){
it('implicit put on empty get explicit not', function(done){
var gun = Gun().get('init/not').not();
gun.on(function(val){
expect(val.not).to.be(true);
if(done.c){ return } done.c = 1;
done.c = 1;
});
gun.put({not: true});
setTimeout(function(){
@ -2679,7 +2695,6 @@ describe('Gun', function(){
expect(Gun.obj.empty(keynode, Gun._.meta)).to.not.be.ok();
});
gun.set(1); //.set(2).set(3).set(4); // if you set an object you'd have to do a `.back`
Gun.log.debug = 1; console.log("~~~~~~ START ~~~~~~~~");
gun.map(function(val, field){
//gun.map().val(function(val, field){ // TODO: SEAN! DON'T LET ME FORGET!
console.log("\n TEST 2+", field, val);
@ -2704,12 +2719,13 @@ describe('Gun', function(){
var users = Gun().get('example').path('users');
users.path(Gun.text.random()).put('bob');
users.path(Gun.text.random()).put('sam');
users.val(function(v){
expect(Gun.is.rel(v)).to.not.be.ok();
expect(Object.keys(v).length).to.be(3);
done();
});
setTimeout(function(){
users.val(function(v){
expect(Gun.is.rel(v)).to.not.be.ok();
expect(Object.keys(v).length).to.be(3);
done();
});
},100);
});
it('peer 1 get key, peer 2 put key, peer 1 val', function(done){
@ -2847,9 +2863,7 @@ describe('Gun', function(){
}); // this is now a list of passengers that we will map over.
var ctx = {n: 0, d: 0, l: 0};
passengers.map().val(function(passenger, id){
//console.log("~~~~~~~~ START ~~~~~~~~~"); Gun.log.debug = 1;
this.map().val(function(change, field){
//console.log("Passenger", passenger.name, "had", field, "change to:", change, '\n\n');
if('name' == field){ expect(change).to.be(passenger.name); ctx.n++ }
if('direction' == field){ expect(change).to.be(passenger.direction); ctx.d++ }
if('location' == field){
@ -2865,10 +2879,25 @@ describe('Gun', function(){
});
});
it("put map", function(done){
var gun = Gun();
var get = gun.get('map/that');
var put = gun.put({a: 1, b: 2, c: 3}).key('map/that');
get.map(function(v,f){
if(1 === v){ done.a = true }
if(2 === v){ done.b = true }
if(3 === v){ done.c = true }
if(done.a && done.b && done.c){
if(done.done){ return }
done(); done.done = 1;
}
});
});
it("get map map val", function(done){ // Terje's bug
var gun = Gun({init: true}); // we can test GUN locally.
var passengers = gun.get('passengers/map').not(function(key){
this.put({randombob: {
gun.put({randombob: {
name: "Bob",
location: {'lat': '37.6159', 'lng': '-128.5'},
direction: '128.2'
@ -2970,7 +2999,7 @@ describe('Gun', function(){
}, 100);
});
it.skip('gun get put, sub path put, original val', function(done){ // bug from Jesse working on Trace //
it('gun get put, sub path put, original val', function(done){ // bug from Jesse working on Trace //
var gun = Gun(gopt).get('players');
gun.put({
@ -2987,9 +3016,8 @@ describe('Gun', function(){
// TODO: BUG! There is a variation of this, where we just do `.val` rather than `gun.val` and `.val` by itself (chained off of the sub-paths) doesn't even get called. :(
gun.on(function(players){ // this val is subscribed to the original put and therefore does not get any of the sub-path listeners, therefore it gets called EARLY with the original/old data rather than waiting for the sub-path data to "finish" and then get called.
console.log("DEM PLAYERS", players);
expect(players.taken).to.be(false);
expect(players.history).to.be(null);
expect(players.taken).to.be(false);
if(done.c){ return } done(); done.c = 1;
});
});
@ -3285,7 +3313,7 @@ describe('Gun', function(){
},t || 10);
};
put({on: 'bus', not: 'transparent'});
put({on: null, not: 'torrent'}, 200);return;
put({on: null, not: 'torrent'}, 200);
put({on: 'sub', not: 'parent'}, 250, true);
});
@ -3459,8 +3487,8 @@ describe('Gun', function(){
})
});
});
describe('Streams', function(){ return; // TODO: BUG! UNDO THIS!
describe('Streams', function(){
var gun = Gun(), g = function(){
return Gun({wire: {get: ctx.get}});
}, ctx = {gen: 9, extra: 100, network: 2};
@ -3472,13 +3500,13 @@ describe('Gun', function(){
var c = 0;
cb = cb || function(){};
key = key[Gun._.soul];
if('big' !== key){ return cb(null, null) }
if('big' !== key){ return cb(null) }
setTimeout(function badNetwork(){
c += 1;
var soul = Gun.is.node.soul(ref);
var graph = {};
var data = /*graph[soul] = */ {_: {'#': soul, '>': {}}};
if(!ref['f' + c]){
if(!ref['f' + c]){
return cb(null, data), cb(null, {});
}
data._[Gun._.state]['f' + c] = ref._[Gun._.state]['f' + c];
@ -3501,7 +3529,7 @@ describe('Gun', function(){
gun.opt({wire: {get: ctx.get}});
});
});
it('map chain', function(done){
var set = gun.put({a: {here: 'you'}, b: {go: 'dear'}, c: {sir: '!'} });
set.map().val(function(obj, field){
@ -3593,7 +3621,7 @@ describe('Gun', function(){
}
}, true);
});
it('get val', function(done){
this.timeout(ctx.gen * ctx.extra);
g().get('big').val(function(obj){
@ -3603,10 +3631,11 @@ describe('Gun', function(){
var raw = Gun.obj.copy(ctx.get.fake);
delete raw._;
expect(obj).to.be.eql(raw);
Gun.log.debug = 0;
done();
});
});
it('get big map val', function(done){
this.timeout(ctx.gen * ctx.extra);
var test = {c: 0, seen: {}};