mirror of
https://github.com/amark/gun.git
synced 2025-06-07 22:56:42 +00:00
171 lines
5.3 KiB
JavaScript
171 lines
5.3 KiB
JavaScript
|
|
var Gun = require('./root');
|
|
Gun.chain.put = function(data, cb, as){
|
|
// #soul.field=value>state
|
|
// ~who#where.where=what>when@was
|
|
// TODO: BUG! Put probably cannot handle plural chains!
|
|
var gun = this, at = (gun._), root = at.root, tmp;
|
|
as = as || {};
|
|
as.data = data;
|
|
as.gun = as.gun || gun;
|
|
if(typeof cb === 'string'){
|
|
as.soul = cb;
|
|
} else {
|
|
as.ack = cb;
|
|
}
|
|
if(at.soul){
|
|
as.soul = at.soul;
|
|
}
|
|
if(as.soul || root === gun){
|
|
if(!obj_is(as.data)){
|
|
(as.ack||noop).call(as, as.out = {err: Gun.log("Data saved to the root level of the graph must be a node (an object), not a", (typeof as.data), 'of "' + as.data + '"!')});
|
|
if(as.res){ as.res() }
|
|
return gun;
|
|
}
|
|
as.gun = gun = root.get(as.soul = as.soul || (as.not = Gun.node.soul(as.data) || ((root._).opt.uuid || Gun.text.random)()));
|
|
as.ref = as.gun;
|
|
ify(as);
|
|
return gun;
|
|
}
|
|
if(Gun.is(data)){
|
|
data.get(function(at,ev){ev.off();
|
|
var s = Gun.node.soul(at.put);
|
|
if(!s){Gun.log("The reference you are saving is a", typeof at.put, '"'+ as.put +'", not a node (object)!');return}
|
|
gun.put(Gun.val.rel.ify(s), cb, as);
|
|
});
|
|
return gun;
|
|
}
|
|
as.ref = as.ref || (root === (tmp = at.back))? gun : tmp;
|
|
if(as.ref._.soul && Gun.val.is(as.data) && at.get){
|
|
as.data = obj_put({}, at.get, as.data);
|
|
as.ref.put(as.data, as.soul, as);
|
|
return gun;
|
|
}
|
|
as.ref.get('_').get(any, {as: as});
|
|
if(!as.out){
|
|
// TODO: Perf idea! Make a global lock, that blocks everything while it is on, but if it is on the lock it does the expensive lookup to see if it is a dependent write or not and if not then it proceeds full speed. Meh? For write heavy async apps that would be terrible.
|
|
as.res = as.res || stun; // Gun.on.stun(as.ref); // TODO: BUG! Deal with locking?
|
|
as.gun._.stun = as.ref._.stun;
|
|
}
|
|
return gun;
|
|
};
|
|
|
|
function ify(as){
|
|
as.batch = batch;
|
|
var opt = as.opt||{}, env = as.env = Gun.state.map(map, opt.state);
|
|
env.soul = as.soul;
|
|
as.graph = Gun.graph.ify(as.data, env, as);
|
|
if(env.err){
|
|
(as.ack||noop).call(as, as.out = {err: Gun.log(env.err)});
|
|
if(as.res){ as.res() }
|
|
return;
|
|
}
|
|
as.batch();
|
|
}
|
|
|
|
function stun(cb){
|
|
if(cb){ cb() }
|
|
return;
|
|
var as = this;
|
|
if(!as.ref){ return }
|
|
if(cb){
|
|
as.after = as.ref._.tag;
|
|
as.now = as.ref._.tag = {};
|
|
cb();
|
|
return;
|
|
}
|
|
if(as.after){
|
|
as.ref._.tag = as.after;
|
|
}
|
|
}
|
|
|
|
function batch(){ var as = this;
|
|
if(!as.graph || obj_map(as.stun, no)){ return }
|
|
(as.res||iife)(function(){
|
|
var cat = (as.gun.back(-1)._), ask = cat.ask(function(ack){
|
|
this.off(); // One response is good enough for us currently. Later we may want to adjust this.
|
|
if(!as.ack){ return }
|
|
as.ack(ack, this);
|
|
}, as.opt);
|
|
(as.ref._).on('out', {
|
|
gun: as.ref, put: as.out = as.env.graph, opt: as.opt, '#': ask
|
|
});
|
|
}, as);
|
|
if(as.res){ as.res() }
|
|
} function no(v,f){ if(v){ return true } }
|
|
|
|
function map(v,f,n, at){ var as = this;
|
|
if(f || !at.path.length){ return }
|
|
(as.res||iife)(function(){
|
|
var path = at.path, ref = as.ref, opt = as.opt;
|
|
var i = 0, l = path.length;
|
|
for(i; i < l; i++){
|
|
ref = ref.get(path[i]);
|
|
}
|
|
if(as.not || Gun.node.soul(at.obj)){
|
|
var id = Gun.node.soul(at.obj) || ((as.opt||{}).uuid || as.gun.back('opt.uuid') || Gun.text.random)();
|
|
ref.back(-1).get(id);
|
|
at.soul(id);
|
|
return;
|
|
}
|
|
(as.stun = as.stun || {})[path] = true;
|
|
ref.get('_').get(soul, {as: {at: at, as: as}});
|
|
}, {as: as, at: at});
|
|
}
|
|
|
|
function soul(at, ev){ var as = this.as, cat = as.at; as = as.as;
|
|
//ev.stun(); // TODO: BUG!?
|
|
if(!at.gun || !at.gun._.back){ return } // TODO: Handle
|
|
ev.off();
|
|
at = (at.gun._.back._);
|
|
var id = Gun.node.soul(cat.obj) || Gun.node.soul(at.put) || Gun.val.rel.is(at.put) || ((as.opt||{}).uuid || as.gun.back('opt.uuid') || Gun.text.random)(); // TODO: BUG!? Do we really want the soul of the object given to us? Could that be dangerous?
|
|
at.gun.back(-1).get(id);
|
|
cat.soul(id);
|
|
as.stun[cat.path] = false;
|
|
as.batch();
|
|
}
|
|
|
|
function any(at, ev){
|
|
var as = this.as;
|
|
if(!at.gun || !at.gun._){ return } // TODO: Handle
|
|
if(at.err){ // TODO: Handle
|
|
console.log("Please report this as an issue! Put.any.err");
|
|
return;
|
|
}
|
|
var cat = (at.gun._.back._), data = cat.put, opt = as.opt||{}, root, tmp;
|
|
ev.off();
|
|
if(as.ref !== as.gun){
|
|
tmp = (as.gun._).get || cat.get;
|
|
if(!tmp){ // TODO: Handle
|
|
console.log("Please report this as an issue! Put.no.get"); // TODO: BUG!??
|
|
return;
|
|
}
|
|
as.data = obj_put({}, tmp, as.data);
|
|
tmp = null;
|
|
}
|
|
if(u === data){
|
|
if(!cat.get){ return } // TODO: Handle
|
|
if(!cat.soul){
|
|
tmp = cat.gun.back(function(at){
|
|
if(at.soul){ return at.soul }
|
|
as.data = obj_put({}, at.get, as.data);
|
|
});
|
|
}
|
|
tmp = tmp || cat.get;
|
|
cat = (cat.root.get(tmp)._);
|
|
as.not = as.soul = tmp;
|
|
data = as.data;
|
|
}
|
|
if(!as.not && !(as.soul = Gun.node.soul(data))){
|
|
if(as.path && obj_is(as.data)){ // Apparently necessary
|
|
as.soul = (opt.uuid || cat.root._.opt.uuid || Gun.text.random)();
|
|
} else {
|
|
//as.data = obj_put({}, as.gun._.get, as.data);
|
|
as.soul = at.soul || cat.soul || (opt.uuid || cat.root._.opt.uuid || Gun.text.random)();
|
|
}
|
|
}
|
|
as.ref.put(as.data, as.soul, as);
|
|
}
|
|
var obj = Gun.obj, obj_is = obj.is, obj_put = obj.put, obj_map = obj.map;
|
|
var u, empty = {}, noop = function(){}, iife = function(fn,as){fn.call(as||empty)};
|
|
|