we won't have to rollback!

This commit is contained in:
Mark Nadal 2015-07-01 17:11:06 -07:00
parent 6a34359f02
commit 2c96ffcdfa
2 changed files with 192 additions and 97 deletions

116
gun.js
View File

@ -120,6 +120,19 @@
if(!ctx.count){ ctx.cb() } if(!ctx.count){ ctx.cb() }
return ctx; return ctx;
} }
Gun.union.pseudo = function(soul, graph, vertex){
var c = 0, s;
((vertex = vertex || {})._ = {})[Gun._.soul] = soul;
Gun.is.graph(graph, function(node, ss){
c += 1; s = ss;
Gun.HAM(vertex, node, function(){}, function(vertex, field, value){
(vertex._[Gun._.HAM] = vertex._[Gun._.HAM] || {})[field] = node._[Gun._.HAM][field];
vertex[field] = value;
}, function(){});
});
if(1 == c){ return }
return vertex;
}
Gun.HAM = function(vertex, delta, lower, now, upper){ Gun.HAM = function(vertex, delta, lower, now, upper){
upper.max = -Infinity; upper.max = -Infinity;
now.end = true; now.end = true;
@ -151,7 +164,7 @@
upper.call(state, vertex, field, incoming); // signals that there are still future modifications. upper.call(state, vertex, field, incoming); // signals that there are still future modifications.
Gun.schedule(ctx.incoming.state, function(){ Gun.schedule(ctx.incoming.state, function(){
update(incoming, field); update(incoming, field);
if(ctx.incoming.state === upper.max){ upper.last() } if(ctx.incoming.state === upper.max){ (upper.last || function(){})() }
}); });
} }
}); });
@ -249,10 +262,11 @@
} }
proxy.event = function(cb, i){ return proxy(cb, i, 'event') }; proxy.event = function(cb, i){ return proxy(cb, i, 'event') };
proxy.once = function(cb, i){ return proxy(cb, i, 'once') }; proxy.once = function(cb, i){ return proxy(cb, i, 'once') };
proxy.emit = function(at, on){setTimeout(function(){ proxy.emit = function(at, on){//setTimeout(function(){
((on = gun._.on(e)).e = on.e || {})[e] = at; ((on = gun._.on(e)).e = on.e || {})[e] = at;
gun._.on(e).emit(at); gun._.on(e).emit(at);
},0)}; //},0)
};
return proxy; return proxy;
} }
return gun; return gun;
@ -266,37 +280,19 @@
opt = opt || {}; opt = opt || {};
if(opt.force){ load(key) } else if(opt.force){ load(key) } else
if(ctx.soul){ if(ctx.soul){
gun._.at('soul').emit({soul: ctx.soul, GET: 'SOUL'});
if(ctx.node = gun.__.graph[ctx.soul]){ // in memory if(ctx.node = gun.__.graph[ctx.soul]){ // in memory
cb.call(gun, null, Gun.obj.copy(ctx.node)); cb.call(gun, null, Gun.obj.copy(ctx.node))
gun._.at('node').emit({soul: ctx.soul, GET: 'NODE'});
} else { load(key) } // not in memory } else { load(key) } // not in memory
((ctx.node = gun.__.graph[ctx.soul] = gun.__.graph[ctx.soul] || {})._ = {})[Gun._.soul] = ctx.soul;
gun._.at('soul').emit({soul: ctx.soul, GET: 'SOUL'});
} else } else
if(ctx.key){ if(ctx.key){
function get(soul){ function get(soul){
if(ctx.flag){ console.log('???????????') } var graph = gun.__.key.s[ctx.key];
var graph = gun.__.key.s[ctx.key], pseudo; Gun.is.graph(graph, function(node){ ctx.node = node });
Gun.is.graph(graph, function(node){ // TODO: REFACTOR!!!!
if(pseudo){
var hack;
if(soul != ctx.key){
soul = ctx.key;
((pseudo = gun.__.graph[soul] = {})._ = {})[Gun._.soul] = soul;
(hack = Gun.obj.copy(ctx.node))._[Gun._.soul] = soul;
Gun.union(gun, hack);
}
(hack = Gun.obj.copy(node))._[Gun._.soul] = soul;
Gun.union(gun, hack);
}
pseudo = ctx.node = pseudo || node;
});
if(!(soul = Gun.is.soul.on(ctx.node))){ return } if(!(soul = Gun.is.soul.on(ctx.node))){ return }
cb.call(gun, null, Gun.obj.copy(ctx.node)); cb.call(gun, null, Gun.obj.copy(graph));
gun._.at('soul').emit({soul: soul, GET: 'SOUL'}); gun._.at('soul').emit({soul: soul, key: ctx.key, GET: 'SOUL'});
gun._.at('node').emit({soul: soul, GET: 'NODE'});
/*if(!ctx.flag){
Gun.union(gun, {_: {'#': soul}});
}*/
} }
if(gun.__.key.s[ctx.key]){ get() } // in memory if(gun.__.key.s[ctx.key]){ get() } // in memory
else if(ctx.flag = gun.__.flag.start[ctx.key]){ // will be in memory else if(ctx.flag = gun.__.flag.start[ctx.key]){ // will be in memory
@ -308,25 +304,25 @@
function load(key){ function load(key){
if(Gun.fns.is(ctx.hook = gun.__.opt.hooks.get)){ if(Gun.fns.is(ctx.hook = gun.__.opt.hooks.get)){
ctx.hook(key, function(err, data){ // multiple times potentially ctx.hook(key, function(err, data){ // multiple times potentially
console.log("chain.get from load", err, data); console.log("chain.get ", key, "from hook", err, data);
if(err){ return cb.call(gun, err, data) } if(err){ return cb.call(gun, err, data) }
if(!data){ if(!data){
if(ctx.data || ctx.soul){ return } if(ctx.data || ctx.soul){ return }
cb.call(gun, null, null); cb.call(gun, null, null);
if(!ctx.key){ return } // TODO: Maybe want to do a .not on a soul directly?
gun.__.flag.end[ctx.key] = gun.__.flag.end[ctx.key] || function($){ gun.__.flag.end[ctx.key] = gun.__.flag.end[ctx.key] || function($){
// TODO: cover all edge cases, uniqueness? // TODO: cover all edge cases, uniqueness?
delete gun.__.flag.end[ctx.key]; delete gun.__.flag.end[ctx.key];
gun._.at('soul').emit($); gun._.at('soul').emit($);
gun._.at('node').emit($);
}; };
console.log('chain.get null'); console.log('chain.get null');
return gun._.at('null').emit({key: ctx.key, GET: 'NULL'}); return gun._.at('null').emit({key: ctx.key, GET: 'NULL'});
} }
ctx.data = ctx.data || true; ctx.data = ctx.data || true;
if(!Gun.is.graph(data, function(node, soul){ if(!Gun.is.graph(data, function(node, soul){
if(true || ctx.soul === soul){ gun._.at('soul').emit({soul: soul, GET: 'SOUL'}) }
if(err = Gun.union(gun, node).err){ return cb.call(gun, err, node) } if(err = Gun.union(gun, node).err){ return cb.call(gun, err, node) }
if(true || ctx.soul){ gun._.at('node').emit({soul: soul, GET: 'NODE'}) } if(ctx.key){ (gun.__.key.s[ctx.key] = gun.__.key.s[ctx.key] || {})[soul] = gun.__.graph[soul] }
if(true || ctx.soul === soul){ gun._.at('soul').emit({soul: soul, key: ctx.key, GET: 'SOUL'}) }
})){ return cb.call(gun, {err: Gun.log('Not a valid graph!') }, data) } })){ return cb.call(gun, {err: Gun.log('Not a valid graph!') }, data) }
cb.call(gun, null, data); cb.call(gun, null, data);
}, opt); }, opt);
@ -356,7 +352,7 @@
} }
index({soul: opt.soul}); index({soul: opt.soul});
} else { // will be injected via a put } else { // will be injected via a put
(gun.__.flag.start[key] = gun._.at('node')).once(function($){ (gun.__.flag.start[key] = gun._.at('soul')).once(function($){
console.log("chain.key"); console.log("chain.key");
(gun.__.key.s[key] = gun.__.key.s[key] || {})[$.soul] = gun.__.graph[$.soul]; (gun.__.key.s[key] = gun.__.key.s[key] || {})[$.soul] = gun.__.graph[$.soul];
delete gun.__.flag.start[key]; delete gun.__.flag.start[key];
@ -421,7 +417,7 @@
cb = cb || function(){}; cb = cb || function(){};
if(!gun.back._.at){ return cb.call(gun, {err: Gun.log("No context!")}), gun } if(!gun.back._.at){ return cb.call(gun, {err: Gun.log("No context!")}), gun }
// TODO: Hmmm once also? figure it out later. // TODO: Hmmm once also? figure it out later.
gun.back._.at('node').event(function($){ gun.back._.at('soul').event(function($){
var ctx = {path: (Gun.text.ify(path) || '').split('.')}; var ctx = {path: (Gun.text.ify(path) || '').split('.')};
(function trace($){ // TODO: Check for field as well and merge? (function trace($){ // TODO: Check for field as well and merge?
var node = gun.__.graph[$.soul], field = Gun.text.ify(ctx.path.shift()), val; var node = gun.__.graph[$.soul], field = Gun.text.ify(ctx.path.shift()), val;
@ -438,22 +434,20 @@
} else } else
if(!Gun.obj.has(node, field)){ // TODO: THIS MAY NOT BE CORRECT BEHAVIOR!!!! if(!Gun.obj.has(node, field)){ // TODO: THIS MAY NOT BE CORRECT BEHAVIOR!!!!
cb.call(gun, null, null, field); cb.call(gun, null, null, field);
gun._.at('soul').emit({soul: $.soul, field: field, PATH: 'SOUL', WAS: 'ON'}); // WAS ON // if .put is after, makes sense. If anything else, makes sense to wait. gun._.at('soul').emit({soul: $.soul, field: field, PATH: 'SOUL', WAS: 'ON'}); // if .put is after, makes sense. If anything else, makes sense to wait.
gun._.at('node').emit({soul: $.soul, field: field, PATH: 'NODE', WAS: 'ON'}); // WAS ON
} else } else
if(Gun.is.soul(val = node[field])){ if(Gun.is.soul(val = node[field])){
gun.get(val, function(err, data){ gun.get(val, function(err, data){
cb.call(gun, err, data, field); // TODO: Should we attach field here, does map? cb.call(gun, err, data, field); // TODO: Should we attach field here, does map?
if(err || !data){ return } if(err || !data){ return }
gun._.at('node').emit({soul: Gun.is.soul(val), field: null, from: $.soul, at: field, PATH: 'NODE', WAS: 'ON'}); // WAS ON
console.log("PATH -> rel/val"); console.log("PATH -> rel/val");
}); });
((ctx.node = gun.__.graph[ctx.soul] = gun.__.graph[ctx.soul] || {})._ = {})[Gun._.soul] = ctx.soul;
gun._.at('soul').emit({soul: Gun.is.soul(val), field: null, from: $.soul, at: field, PATH: 'SOUL', WAS: 'ON'}); // WAS ON gun._.at('soul').emit({soul: Gun.is.soul(val), field: null, from: $.soul, at: field, PATH: 'SOUL', WAS: 'ON'}); // WAS ON
} else { } else {
console.log("PATH -> field/val", field, val); console.log("PATH -> field/val", field, val);
cb.call(gun, null, val, field); cb.call(gun, null, val, field);
gun._.at('soul').emit({soul: $.soul, field: field, PATH: 'SOUL', WAS: 'ON'}); // WAS ON gun._.at('soul').emit({soul: $.soul, field: field, PATH: 'SOUL', WAS: 'ON'});
gun._.at('node').emit({soul: $.soul, field: field, PATH: 'NODE', WAS: 'ON'}); // WAS ON
} }
}($)); }($));
}); });
@ -465,10 +459,11 @@
cb = cb || root.console.log.bind(root.console); cb = cb || root.console.log.bind(root.console);
opt = opt || {}; opt = opt || {};
console.log("REGISTER VAL", ctx.id = Gun.text.random(4));
gun.on(function($, delta, on){ gun.on(function($, delta, on){
console.log("valvalvalvalval", ctx.id, $);
var node = gun.__.graph[$.soul]; var node = gun.__.graph[$.soul];
if($.key){
node = Gun.union.pseudo($.key, gun.__.key.s[$.key]) || node;
}
if($.field){ if($.field){
if(ctx[$.soul + $.field]){ return } if(ctx[$.soul + $.field]){ return }
ctx[$.soul + $.field] = true; // TODO: unregister instead? ctx[$.soul + $.field] = true; // TODO: unregister instead?
@ -489,16 +484,22 @@
cb = cb || function(){}; cb = cb || function(){};
gun._.at('soul').event(function($){ // TODO: once per soul on graph. (?) gun._.at('soul').event(function($){ // TODO: once per soul on graph. (?)
if(ctx[$.soul]){ return } if(ctx[$.soul]){
ctx[$.soul] = gun.__.on($.soul).event(on() || on); ctx[$.soul](null, $);
function on(delta){ } else {
(ctx[$.soul] = function(delta, $$){
if(opt.raw){ return cb.call(gun, $, delta, this) } var $$ = $$ || $, node = gun.__.graph[$$.soul];
var node = gun.__.graph[$.soul]; if(opt.raw){ return cb.call(gun, $$, delta, this) }
if(!opt.end && delta && Gun.obj.empty(delta, Gun._.meta)){ return } if($$.key){
cb.call(gun, Gun.obj.copy(opt.change? delta || node : node), $.field || $.at); node = Gun.union.pseudo($.key, gun.__.key.s[$.key]) || node;
}
if(!opt.end && delta && Gun.obj.empty(delta, Gun._.meta)){ return }
cb.call(gun, Gun.obj.copy(opt.change? delta || node : node), $$.field || $$.at);
})();
gun.__.on($.soul).event(ctx[$.soul]);
} }
}); });
return gun; return gun;
} }
/* /*
@ -524,10 +525,9 @@
} }
if(gun.back.not){ gun.back.not(call) } if(gun.back.not){ gun.back.not(call) }
//console.log("REGISTER PUT", val, call.id = Gun.text.random(4));
gun.back._.at('soul').event(function($){ // TODO: maybe once per soul? gun.back._.at('soul').event(function($){ // TODO: maybe once per soul?
var ctx = {}, obj = val, $ = Gun.obj.copy($); var ctx = {}, obj = val, $ = Gun.obj.copy($);
console.log("chain.put", call.id, val); console.log("chain.put", val);
if(Gun.is.value(obj)){ if(Gun.is.value(obj)){
if($.from && $.at){ if($.from && $.at){
$.soul = $.from; $.soul = $.from;
@ -584,8 +584,7 @@
Gun.union(gun, node); Gun.union(gun, node);
}); });
if($.from = Gun.is.soul(ify.root[$.field])){ $.soul = $.from; $.field = null } if($.from = Gun.is.soul(ify.root[$.field])){ $.soul = $.from; $.field = null }
gun._.at('soul').emit({soul: $.soul, field: $.field, PUT: 'SOUL', WAS: 'ON'}); // WAS ON gun._.at('soul').emit({soul: $.soul, field: $.field, key: $.key, PUT: 'SOUL', WAS: 'ON'}); // WAS ON
gun._.at('node').emit({soul: $.soul, field: $.field, PUT: 'NODE', WAS: 'ON'}); // WAS ON
if(Gun.fns.is(ctx.hook = gun.__.opt.hooks.put)){ if(Gun.fns.is(ctx.hook = gun.__.opt.hooks.put)){
ctx.hook(ify.graph, function(err, data){ // now iterate through those nodes to a persistence layer and get a callback once all are saved ctx.hook(ify.graph, function(err, data){ // now iterate through those nodes to a persistence layer and get a callback once all are saved
if(err){ return cb.call(gun, err) } if(err){ return cb.call(gun, err) }
@ -613,16 +612,13 @@
gun.get(val, function(err, data){ // TODO: should map have support for `.not`? error? gun.get(val, function(err, data){ // TODO: should map have support for `.not`? error?
if(err || !data){ return } // TODO: Handle this! if(err || !data){ return } // TODO: Handle this!
cb.call(this, data, field); cb.call(this, data, field);
gun._.at('node').emit({soul: Gun.is.soul(val), field: null, from: soul, at: field, MAP: 'NODE'});
// TODO: BUG is this correct? PROBABLY NOT FOO!!!
}); });
((ctx.node = gun.__.graph[ctx.soul] = gun.__.graph[ctx.soul] || {})._ = {})[Gun._.soul] = ctx.soul;
gun._.at('soul').emit({soul: Gun.is.soul(val), field: null, from: soul, at: field, MAP: 'SOUL'}); gun._.at('soul').emit({soul: Gun.is.soul(val), field: null, from: soul, at: field, MAP: 'SOUL'});
} else { } else {
if(opt.node){ return } // {node: true} maps over only sub nodes. if(opt.node){ return } // {node: true} maps over only sub nodes.
cb.call(gun, val, field); cb.call(gun, val, field);
gun._.at('soul').emit({soul: soul, field: field, MAP: 'SOUL'}); gun._.at('soul').emit({soul: soul, field: field, MAP: 'SOUL'});
console.log('chain.map on', field, val);
gun._.at('node').emit({soul: soul, field: field, MAP: 'NODE'});
} }
}); });
}, true); }, true);
@ -633,10 +629,9 @@
var gun = this, ctx = {}, drift = Gun.time.now(); var gun = this, ctx = {}, drift = Gun.time.now();
cb = cb || function(){}; cb = cb || function(){};
opt = opt || {}; opt = opt || {};
console.log("REGISTER SET", ctx.id = Gun.text.random(4));
if(!gun.back){ gun = gun.put({}) } if(!gun.back){ gun = gun.put({}) }
gun = gun.not(function(next, key){ console.log('NOT TIMES?'); return key? this.put({}).key(key) : this.put({}) }); gun = gun.not(function(next, key){ return key? this.put({}).key(key) : this.put({}) });
if(!val && !Gun.is.value(val)){ return gun } if(!val && !Gun.is.value(val)){ return gun }
var obj = {}; var obj = {};
obj['I' + drift + 'R' + Gun.text.random(5)] = val; obj['I' + drift + 'R' + Gun.text.random(5)] = val;
@ -647,12 +642,11 @@
cb = cb || function(){}; cb = cb || function(){};
gun._.at('null').once(function(key){ gun._.at('null').once(function(key){
if(key.soul || gun.__.key.s[key = (key || {}).key] || gun.__.flag.start[key]){ return } if(key.soul || gun.__.key.s[key = (key || {}).key]){ return }
// TODO! BUG? Removed a start flag check and tests passed, but is that an edge case? // TODO! BUG? Removed a start flag check and tests passed, but is that an edge case?
var kick = function(next){ var kick = function(next){
if(++c){ return Gun.log("Warning! Multiple `not` resumes!"); } if(++c){ return Gun.log("Warning! Multiple `not` resumes!"); }
next._.at('soul').once(function($){ $.N0T = 'KICK SOUL'; gun._.at('soul').emit($) }); next._.at('soul').once(function($){ $.N0T = 'KICK SOUL'; gun._.at('soul').emit($) });
next._.at('node').once(function($){ $.N0T = 'KICK NODE'; gun._.at('node').emit($) });
}, chain = gun.chain(), next = cb.call(chain, kick, key), c = -1; }, chain = gun.chain(), next = cb.call(chain, kick, key), c = -1;
if(Gun.is(next)){ kick(next) } if(Gun.is(next)){ kick(next) }
chain._.at('soul').emit({soul: Gun.roulette.call(chain), empty: true, key: key, N0T: 'SOUL', WAS: 'ON'}); // WAS ON chain._.at('soul').emit({soul: Gun.roulette.call(chain), empty: true, key: key, N0T: 'SOUL', WAS: 'ON'}); // WAS ON

View File

@ -767,11 +767,67 @@ describe('Gun', function(){
}); });
}); });
it('pseudo null', function(){
var node = Gun.union.pseudo('pseudo');
expect(Gun.is.soul.on(node)).to.be('pseudo');
});
it('pseudo node', function(){
var graph = {
'asdf': {
_: {'#': 'asdf', '>': {
x: Gun.time.is(),
y: Gun.time.is()
}},
x: 1,
y: 2
}
}
var node = Gun.union.pseudo('soul', graph);
expect(node).to.not.be.ok();
});
it('pseudo graph', function(){
var graph = {
'asdf': {
_: {'#': 'asdf', '>': {
a: Gun.time.is() - 2,
z: Gun.time.is() - 2
}},
a: 1,
z: 1
},
'fdsa': {
_: {'#': 'fdsa', '>': {
b: Gun.time.is() - 1,
z: Gun.time.is() - 1
}},
b: 2,
z: 2
},
'sadf': {
_: {'#': 'sadf', '>': {
c: Gun.time.is(),
z: Gun.time.is() - 100
}},
c: 3,
z: 3
}
}
var node = Gun.union.pseudo('soul', graph);
expect(Gun.is.soul.on(node)).to.be('soul');
expect(node.a).to.be(1);
expect(node.b).to.be(2);
expect(node.c).to.be(3);
expect(node.z).to.be(2);
});
}); });
describe('API', function(){ describe('API', function(){
var gun = Gun(); var gun = Gun();
(function(){
it('put', function(done){ it('put', function(done){
gun.put("hello", function(err){ gun.put("hello", function(err){
expect(err).to.be.ok(); expect(err).to.be.ok();
@ -807,7 +863,11 @@ describe('Gun', function(){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
}).get('yes/key', function(err, data){ }).get('yes/key', function(err, data){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
expect(data.hello).to.be('key'); var c = 0;
Gun.is.graph(data, function(node){
expect(c++).to.be(0);
expect(node.hello).to.be('key');
});
done(); done();
}); });
}); });
@ -819,7 +879,11 @@ describe('Gun', function(){
gun.get('yes/a/key', function(err, data){ gun.get('yes/a/key', function(err, data){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
expect(data.hello).to.be('a key'); var c = 0;
Gun.is.graph(data, function(node){
expect(c++).to.be(0);
expect(node.hello).to.be('a key');
});
done(); done();
}); });
}); });
@ -834,7 +898,11 @@ describe('Gun', function(){
it('get key', function(done){ it('get key', function(done){
gun.get('yes/key', function(err, data){ gun.get('yes/key', function(err, data){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
expect(data.hello).to.be('key'); var c = 0;
Gun.is.graph(data, function(node){
expect(c++).to.be(0);
expect(node.hello).to.be('key');
});
}).key('hello/key', function(err, ok){ }).key('hello/key', function(err, ok){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
done.key = true; done.key = true;
@ -856,7 +924,11 @@ describe('Gun', function(){
it('get node put node merge', function(done){ it('get node put node merge', function(done){
gun.get('hello/key', function(err, data){ gun.get('hello/key', function(err, data){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
done.soul = Gun.is.soul.on(data); var c = 0;
Gun.is.graph(data, function(node){
expect(c++).to.be(0);
done.soul = Gun.is.soul.on(node);
});
}).put({hi: 'you'}, function(err, ok){ }).put({hi: 'you'}, function(err, ok){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
var node = gun.__.graph[done.soul]; var node = gun.__.graph[done.soul];
@ -898,8 +970,12 @@ describe('Gun', function(){
it('get node put node merge conflict', function(done){ it('get node put node merge conflict', function(done){
gun.get('hello/key', function(err, data){ gun.get('hello/key', function(err, data){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
expect(data.hi).to.be('you'); var c = 0;
done.soul = Gun.is.soul.on(data); Gun.is.graph(data, function(node){
expect(c++).to.be(0);
expect(node.hi).to.be('you');
done.soul = Gun.is.soul.on(node);
});
}).put({hi: 'overwritten'}, function(err, ok){ }).put({hi: 'overwritten'}, function(err, ok){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
var node = gun.__.graph[done.soul]; var node = gun.__.graph[done.soul];
@ -920,8 +996,12 @@ describe('Gun', function(){
it('get node path put value', function(done){ it('get node path put value', function(done){
gun.get('hello/key', function(err, data){ gun.get('hello/key', function(err, data){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
expect(data.hi).to.be('overwritten'); var c = 0;
done.soul = Gun.is.soul.on(data); Gun.is.graph(data, function(node){
expect(c++).to.be(0);
expect(node.hi).to.be('overwritten');
done.soul = Gun.is.soul.on(node);
});
}).path('hi').put('again', function(err, ok){ }).path('hi').put('again', function(err, ok){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
var node = gun.__.graph[done.soul]; var node = gun.__.graph[done.soul];
@ -934,8 +1014,12 @@ describe('Gun', function(){
it('get node path put object', function(done){ it('get node path put object', function(done){
gun.get('hello/key', function(err, data){ gun.get('hello/key', function(err, data){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
expect(data.hi).to.be('again'); var c = 0;
done.soul = Gun.is.soul.on(data); Gun.is.graph(data, function(node){
expect(c++).to.be(0);
expect(node.hi).to.be('again');
done.soul = Gun.is.soul.on(node);
});
}).path('hi').put({yay: "value"}, function(err, ok){ }).path('hi').put({yay: "value"}, function(err, ok){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
var root = gun.__.graph[done.soul]; var root = gun.__.graph[done.soul];
@ -950,8 +1034,12 @@ describe('Gun', function(){
it('get node path put object merge', function(done){ it('get node path put object merge', function(done){
gun.get('hello/key', function(err, data){ gun.get('hello/key', function(err, data){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
expect(done.ref = Gun.is.soul(data.hi)).to.be.ok(); var c = 0;
done.soul = Gun.is.soul.on(data); Gun.is.graph(data, function(node){
expect(c++).to.be(0);
expect(done.ref = Gun.is.soul(node.hi)).to.be.ok();
done.soul = Gun.is.soul.on(node);
});
}).path('hi').put({happy: "faces"}, function(err, ok){ }).path('hi').put({happy: "faces"}, function(err, ok){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
var root = gun.__.graph[done.soul]; var root = gun.__.graph[done.soul];
@ -968,8 +1056,12 @@ describe('Gun', function(){
it('get node path put value conflict relation', function(done){ it('get node path put value conflict relation', function(done){
gun.get('hello/key', function(err, data){ gun.get('hello/key', function(err, data){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
expect(done.ref = Gun.is.soul(data.hi)).to.be.ok(); var c = 0;
done.soul = Gun.is.soul.on(data); Gun.is.graph(data, function(node){
expect(c++).to.be(0);
expect(done.ref = Gun.is.soul(node.hi)).to.be.ok();
done.soul = Gun.is.soul.on(node);
});
}).path('hi').put('crushed', function(err, ok){ }).path('hi').put('crushed', function(err, ok){
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
var root = gun.__.graph[done.soul]; var root = gun.__.graph[done.soul];
@ -1317,10 +1409,10 @@ describe('Gun', function(){
gun.put({gender:'f', age:22, name:'beth' }).key('user/beth'); gun.put({gender:'f', age:22, name:'beth' }).key('user/beth');
gun.get('user/alfred').val(function(a){ gun.get('user/alfred').val(function(a){
gun.get('user/beth').path('friend').put(a); // b - friend_of -> a gun.get('user/beth').path('friend').put(a); // b - friend_of -> a
gun.get('user/beth').val(function(b){ // TODO: We should have b.friend by now!
gun.get('user/beth').val(function(b){
gun.get('user/alfred').path('friend').put(b, function(){ // a - friend_of -> b gun.get('user/alfred').path('friend').put(b, function(){ // a - friend_of -> b
gun.get('user/beth').path('cat').put({name: "fluffy", age: 3, coat: "tabby"}, function(err, ok){ gun.get('user/beth').path('cat').put({name: "fluffy", age: 3, coat: "tabby"}, function(err, ok){
gun.get('user/alfred').path('friend.cat').key('the/cat'); gun.get('user/alfred').path('friend.cat').key('the/cat');
gun.get('the/cat').val(function(c){ gun.get('the/cat').val(function(c){
@ -1480,24 +1572,23 @@ describe('Gun', function(){
}); });
it('set multiple', function(done){ it('set multiple', function(done){
Gun.log.verbose = true;
var gun = Gun().get('sets').set(), i = 0; var gun = Gun().get('sets').set(), i = 0;
gun.val(function(val){ gun.val(function(val){
console.log("@@@@@@@@@ BEFORE", val);
expect(done.soul = Gun.is.soul.on(val)).to.be.ok(); expect(done.soul = Gun.is.soul.on(val)).to.be.ok();
expect(Gun.obj.empty(val, '_')).to.be.ok(); expect(Gun.obj.empty(val, '_')).to.be.ok();
}); });
gun.set(1).set(2).set(3).set(4) // if you set an object you'd have to do a `.back` gun.set(1).set(2).set(3).set(4); // if you set an object you'd have to do a `.back`
.map().val(function(val){ // TODO! BUG! If we instead do gun.map().val() we will get stale data, fix this. gun.map().val(function(val){
i += 1; i += 1;
console.log('@@@@@@@@@', i, val);
expect(val).to.be(i); expect(val).to.be(i);
if(i % 4 === 0){ if(i % 4 === 0){
done.i = 0; setTimeout(function(){
Gun.obj.map(gun.__.graph, function(){ done.i++ }); done.i = 0;
expect(done.i).to.be(1); // make sure there isn't double. Gun.obj.map(gun.__.graph, function(){ done.i++ });
done() expect(done.i).to.be(1); // make sure there isn't double.
done()
},10);
} }
}); });
}); });
@ -1506,11 +1597,11 @@ describe('Gun', function(){
var hooks = {get: function(key, cb, opt){ var hooks = {get: function(key, cb, opt){
cb(); cb();
}, put: function(nodes, cb, opt){ }, put: function(nodes, cb, opt){
//root.console.log("put hook", nodes); //console.log("put hook", nodes);
Gun.union(gun1, nodes); Gun.union(gun1, nodes);
cb(); cb();
}, key: function(key, soul, cb, opt){ }, key: function(key, soul, cb, opt){
//root.console.log("key hook", key, soul); //console.log("key hook", key, soul);
gun1.key(key, null, soul); gun1.key(key, null, soul);
cb(); cb();
}}, }},
@ -1527,7 +1618,7 @@ describe('Gun', function(){
},10); },10);
},10); },10);
}); });
}()); return;
it('get pseudo merge', function(done){ it('get pseudo merge', function(done){
var gun = Gun(); var gun = Gun();
@ -1535,20 +1626,33 @@ describe('Gun', function(){
gun.put({b: 2, z: 0}).key('pseudo'); gun.put({b: 2, z: 0}).key('pseudo');
gun.get('pseudo').val(function(val){ gun.get('pseudo').val(function(val){
console.log('pseudo?!!!!!', val);
expect(val.a).to.be(1); expect(val.a).to.be(1);
expect(val.b).to.be(2); expect(val.b).to.be(2);
expect(val.z).to.be(0); expect(val.z).to.be(0);
done(); done();
}); });
}); });
return;
it('get pseudo merge on', function(done){
var gun = Gun();
gun.put({a: 1, z: -1}).key('pseudon');
gun.put({b: 2, z: 0}).key('pseudon');
gun.get('pseudon').on(function(val){
expect(val.a).to.be(1);
expect(val.b).to.be(2);
expect(val.z).to.be(0);
done();
});
});
it('get pseudo merge across peers', function(done){ it('get pseudo merge across peers', function(done){
Gun.on('opt').event(function(gun, o){ Gun.on('opt').event(function(gun, o){
gun.__.opt.hooks = {get: function(key, cb, opt){ gun.__.opt.hooks = {get: function(key, cb, opt){
var other = (o.alice? gun2 : gun1); var other = (o.alice? gun2 : gun1);
if(connect){ if(connect){
console.log('connect to peer and get', key); //console.log('connect to peer and get', key);
other.get(key, cb); other.get(key, cb);
} else { } else {
cb(); cb();
@ -1584,18 +1688,15 @@ describe('Gun', function(){
setTimeout(function(){ setTimeout(function(){
// CONNECT THE TWO PEERS // CONNECT THE TWO PEERS
connect = true; connect = true;
Gun.log.verbose = true;
gun1.get('pseudo/merge', null, {force: true}); // fake a browser refersh, in real world we should auto-reconnect gun1.get('pseudo/merge', null, {force: true}); // fake a browser refersh, in real world we should auto-reconnect
gun2.get('pseudo/merge', null, {force: true}); // fake a browser refersh, in real world we should auto-reconnect gun2.get('pseudo/merge', null, {force: true}); // fake a browser refersh, in real world we should auto-reconnect
setTimeout(function(){ setTimeout(function(){
gun1.val(function(val){ gun1.val(function(val){
console.log('@@@@@@@@@@@@1', val);
expect(val.hello).to.be('world!'); expect(val.hello).to.be('world!');
expect(val.hi).to.be('mars!'); expect(val.hi).to.be('mars!');
done.gun1 = true; done.gun1 = true;
}); });
gun2.val(function(val){ gun2.val(function(val){
console.log('@@@@@@@@@@@@2', val);
expect(val.hello).to.be('world!'); expect(val.hello).to.be('world!');
expect(val.hi).to.be('mars!'); expect(val.hi).to.be('mars!');
expect(done.gun1).to.be.ok(); expect(done.gun1).to.be.ok();