@plotdb/datahub v0.5.9
@plotdb/datahub
Access scoped data via piped operational transformation.
Installation
npm install @plotdb/datahubUsage
after including datahub.bundle.min.js:
# this is our data source.
src = new datahub.src do
ops-out: (ops) -> # update data src by incoming ops
get: -> # return complete data. raw data is returned, users should make their own copy if to use.
# this is our view controller
des = new datahub.des do
ops-in (ops): -> # update ui / widget
# data through pipe, scoped under "my-view"
view-hub = new datahub {scope: ["my-view"]}
# ... from srchub / through view-hub / to deshub
src.pipe view-hub .pipe des
# notify all users (deshub) about data changed
src.ops-in [... /* ops */ ...]
# update data source (srchub)
des.ops-out [... /* ops */ ...]Memhub, Userhub
Datahub also provides auxiliary hubs for quick testing and evaluation.
memhub- data source hub. store data in memory.usrhub- simple destination hub. constructor options:- render(ops): called when there are updates from data source.
A sample usage of memhub and usrhub as follows:
mhub = new datahub.mem!
uhub = new datahub.usr {render: -> console.log('ok'); }
mhub.pipe uhub
document.querySelector('textarea').addEventListener \input, ->
uhub.ops-out [
{ p: ['str',0], si: @value[@value.length - 1] }
]Wrap constructor
Instead of userhub, you can use datahub.as to wrap your constructor to support hub mechanism directly with your own class:
someClass = datahub.as (opt = {}) -> @
someClass.prototype <<< { ... }You can pipe source hub to the constructed hub object:
hub = new myHub();
src.pipe(hub);Wrapped hub only provides following methods:
state()on(name, cb)fire(name, ...args)ops-out(ops)get()
And following member variables to use:
hub: the actual hub object used to accept source data.data: data object from source.
As a wrapped hub user, you should do the following:
- implement
ops-infunction to render / update your application. note:- ops has been applied to
datamember before yourops-inis called. - however any data kept locally should still be updated based on ops.
- ops has been applied to
- watch
open/closeevent or usestatemethod to track data stream status.
Following is a sample wrapped hub:
form = datahub.as (o = {}) ->
# udate based on a input element change
o.node.addEventListener \input, (evt = {}) ~> @update evt.target.value
# keep a local _data to diff original data for ops
@on \open, ~> @_data = JSON.parse(JSON.stringify(@data)); @render!
@ <<< o{name}
form.prototype <<<
# re-render on every ops-in
ops-in: (ops) ->
json0.type.apply @_data, ops
@render!
render: -> console.log @_data
update: (v) ->
if @state! == \closed => return
@_data[@name] = v
@ops-out json0.diff(@data, @_data)For a live, working example, please check web/src/pug/as.pug.
Sharehub
Sharehub provides a simple interface and implementation reference for adopting ShareDB with data hub to keep edited data in database:
uhub = new datahub.usr!
shub = new sharehub({
id: 'my-sharedb-doc-id'
create: -> {} # init obj if doc not found.
})
shub.init!
.then -> shub.pipe uhubSharehub is in a standalone JS file. include sharehub.js / sharehub.min.js / sharehub.bundle.min.js if you want to use it.
Constructor options:
id: id of the sharedb doc to connect. optionalcollection: collection of the sharedb collection to connect. optional, defaultdocif omitted.initConnect: default true. if true, auto connect to sharedb ifidis given.create(): empty object creator function. should return an object for initial value.- when omitted, a creator function returing an empty object is used.
watch(ops, src): watcher function. optionalews:@plotdb/ewsinstance to use. required.
APIs:
connect(opt): connect to sharedb. return Promise, resolved when connected.optis either:- omitted (undefined):
connect()will use storedidandcollectionto (re)connect. - a string for id of the sharedb doc to connect. In this case,
collectionwill be set todoc. - an object with fields:
id: sharedb id. use storedidif omitted. this id will be stored for future use. (e.g., auto-reconnect)collection:docif omitted.force: default true. when true, force to reconnect even ifid/collectionis the same.- when
optis a string or omitted,forcewill also be true.
- when
- omitted (undefined):
- if
id/collectionare provided inopt, they will be stored internal for future use.
disconnect(): disconnect current doc from sharedb. return Promise, resolved when disconnected.- this will be automatically called when internal
sdb-clientis closed.
- this will be automatically called when internal
config(opt): update configuration. opt has following fields:id: sharedb id.collection:docif omitted.
Additionally, sharehub fire following events
open: fired when a connect is successfully done.close: fired whendisconnectis called.error: fired when internal sdb-client object fires error events.
Scoping
Passing scope option ( an array of strings / numbers ) into datahub constructor to filter incoming op and data based on the specified scope. For example, assume our data source keeps data in datasrc variable, then following hub:
new hub({scope: ["users", "deleted"]})will only pass ops that affect object in datasrc.users.deleted. Furthermore, data get from this hub will only be the subtree in datasrc.users.deleted.
You can pipe data source to a hub that is scoped, and pipe this scoped hub to the destination hubs that use the same subtree.
Object API
ops-in(ops): send ops from this hub to subscribers. ( inward / down to client )ops-out(ops): send ops from this hub to src. ( outward / up to server )as-src(o): set this hub as a source hub (provide data and handle outward request).- fields of
o:get(): a function returning a full snapshot of data.ops-out(ops): a function to handle outward ops.
- a source hub is responsible to call
ops-in(ops)when there are data changes from source (inward ops)
- fields of
as-des(o): set this hub as destination hub ( handle inward events by such as rendering )- fields of
o:ops-in(ops): a function to handle inward ops.
- a destination hub is responsible to call
ops-out(ops)when there are data changes to source (outward ops)
- fields of
get(): return a snapshot of source datapipe(hub): pipe down events tohub.addon(ops): prependopsto create node for ops accessing non-existed pathcut(hub): removehubfrom current object's subscriber list.state(s): change state. s can be eitheropenedorclosed.- state propagates automatically. Should only be used by source hub.
- des hub should always call
getto retrieve a new object and reinitialize if needed after eachopenevent.
Class API
as(constructor): wrapconstructoras a hub that can be piped.- constructor options depends on how
constructoris implemented, with following additional fields:scope: thescopeused by hub, as defined above.
- constructor options depends on how
License
MIT
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago