Extra DSL extensions for Gun.js
Many of the snippets were extracted from Gun Snippets 0.3.x and upgraded to work with Gun +0.6
Some extra chain methods have been added, such as mapReduce
and iterator
.
Most async methods now come with a ES6 Promises or async/await (ES7) variant.
The Promise methods are prefixed with $
.
As of version 0.8.x, not all of the chain methods have been fully tested yet. Please help test them out and/or add more tests. Thanks.
npm i -S gun-edge
Assuming Babel or similar transpiler setup (2017)
To add all chain methods:
import Gun from 'gun/gun'
import chain from 'gun-edge'
chain(Gun)
To control which chain methods to add:
import {
add
} from 'gun-edge'
add(Gun, 'date', 'fields')
Import individual chain modules
import {
inspect,
addInspect
} from 'gun-edge/edge/inspect'
addInspect(Gun.chain)
Using require
const Gun = require('gun/gun')
require('gun-edge')(Gun)
Chain methods available:
Iteration
.each()
- see each.timed(opts)
- interval based recursive iteration on node (seetimed-iterator.test.js
).mapReduce(options, cb, putCb, opt)
- mapReduce on a bucket (see below).recurse(cb, filter)
- recursively navigate bucket graph/tree structure
Operations
.count(numFun)
- create a CRDT counter, see counter.copy(val)
- make a copy/clone of a value.date(dateValue)
- date field, see date.local(data, cb, opt)
- store locally only, no peer sync.no(cb)
- see no.value(cb, opt)
- get the node value (no meta).valueAt(path, cb, opt)
: get value at thepath
(no meta).valAt(path, cb, opt)
: get value at thepath
.setAt(path, cb, opt)
: set value at thepath
.putAt(path, cb, opt)
: put value at thepath
.localFields()
- get list of local field names (keys) in the bucket.fields(cb)
- return fields to cb.soul()
- return the soul (id) of the node.print(label)
- print value to console (no meta). Note: You can setGun.log
, by default:console.log
Promise enabled methods
ES6 Promise
or ES7 async/await
), always prefixed with $
.$fields(opt)
- get fields (ie. property names).$iterate(opts)
- iterate.$mapReduce(options, putCb, opt)
- map/reduce.$no(opt)
- blocks if no data, see no.$val(opt)
- full value (with meta).$value(opt)
- get value (no meta).$valueAt(path, opt)
- get value at thepath
(no meta).$recurse(filter)
- recursive filter.$timed(opts)
- timed recursion
Observable streams for superior Async flow control
Observable methods are also (currently) prefixed with $
Observable stream support is included for:
Example: Rx.js
// optional
let options = {
log: true,
op: 'live'
}
// or simply $rx(node) or even node.$rx()
let obs = $rx(node, options)
let subscription = obs
.subscribe(x => {
console.log({received: x})
})
Gun.obj.copy(val)
- copy a value
Gun.obj.map(data, function(val, field){ ... }
- map over a node
Gun.fn.is
- check if something is a function
Gun.text.random()
- generate random text
Gun.is.node.soul(data)
- test if data has a soul (ie. is a Gun node)
Gun.node.soul(data)
- return id of Gun node
Please add more internal Gun functions to this list for reference ;)
node.back()
- go one level back/up in the graph
WIP
.out(navOpts, cb)
- traverse edge (WIP).edge(navOpts/data)
orlink
- for linking nodes and traversing links/edges.filter(filterFun, cb)
- filter fields
CSP channel also included :)
The main idea is outlined here
CSP learning resources:
To start a process just pass a generator as a parameter to the go
function.
By using the yield
keyword, you can pause a process, freeing the main thread
Channels are queues. Whenever a process calls take
on a channel, it pauses until a value is put
into that channel.
Processes that put a value on a channel also pause until some other process uses take. Because channels are queues, when a process takes from a channel, the value will not be available for other processes to take. One process puts, one process takes. A channel can be buffered, which means that, for a given number of puts, a put will not make the process pause.
If the channel has a buffer of size 2, the third put will block the process, until someone takes from it.
See the test/channel/
folder for some test examples:
let size = 2
let buffer = csp.buffers.fixed(size)
// let buffer = csp.buffers.sliding(size)
// let buffer = csp.buffers.dropping(size)
// const promiseCh = csp.promiseChan();
// NOTE: optionally customize channel and buffer used
// let promiseCh = csp.chan(buffer)
promiseCh = $csp(node, {
// channel: promiseCh, // will use fixed(2) buffer by default
// log: true,
op: 'live',
// only put on channel when node value has a num field
condition: (val) => val.num
})
node.timed({
maxNum,
logging: true,
cb: resolve
})
let num = 0
let condition = () => num < 5
// Please help improved this!!!
csp.go(function* () {
while (condition()) {
const value = yield csp.take(promiseCh)
console.log('value', value)
}
})
See full mapReduce guide
The project includes a gulpfile
configured to use Babel 6.
All /src
files are compiled to /dist
including source maps.
Scripts:
- start:
npm start
- build:
npm run build
(ie. compile) - watch and start:
npm run watch
- watch and build:
npm run watch:b
npm test
or simply ava test
The /examples
folder will at some point include some example projects, including a web page (with live reload)
For playing around...
Various ideas sketched out in /docs
MIT Kristian Mandrup