uci-utils-datastore-rx/src/datastore.js

93 lines
2.6 KiB
JavaScript

import { Store } from 'data-store'
import { BehaviorSubject, Subject, from } from 'rxjs'
import { distinctUntilChanged, takeUntil } from 'rxjs/operators'
import _get from 'get-value'
import _set from 'set-value'
import _del from 'unset-value'
import equal from 'deep-equal'
// import autobind from 'auto-bind'
// ammend/react datastore class
export default class StoreRx extends Store {
constructor(opts){
// console.log('constructor', opts)
super(opts)
this.name = opts.name
this._observers = {}
this._deleted = {}
this.emitter = opts.emitter
this.event = opts.event || 'datastore'
this.handler=opts.handler
this.get = this.get.bind(this)
this.set = this.set.bind(this)
}
// TODO manage all subscriptions
getObs(path) {
path = this.formatPath(path)
return path ? _get(this._observers,path):this._observers
}
delObs(path) {
// TODO support deleting all observers, would require traversing _observers
path = this.formatPath(path)
_get(this._deleted,path).next('deleted')
_del(this._deleted,path)
_del(this._observers,path)
}
setObs(path) {
path = this.formatPath(path)
const obs = this.getObs(path)
if (obs) return obs
_set(this._deleted,path,from(new Subject()))
_set(this._observers,path,from(new BehaviorSubject(super.get(path))).pipe(
distinctUntilChanged(),
takeUntil(_get(this._deleted,path))
))
return this.getObs(path)
}
get(path,handler){
// console.log('get>>>>',path,handler)
// console.log(this._observers)
path = this.formatPath(path)
if (typeof handler==='function') {
let obs = this.getObs(path)
if (!obs) obs = this.setObs(path)
// console.log(obs)
return obs.subscribe(handler)
}
return super.get(path)
}
// TODO trap delete and delete observer too
set(path,value){
// TODO support path as object to merge per super.set
// TODO if value not set del obs as well
path = this.formatPath(path)
const curValue = this.get(path)
// console.log('set>>>>',path,curValue,value)
if (!equal(curValue,value) || !value) {
let obs = this.getObs(path)
if (obs) obs.next(value)
if (this.emit) this.emit(this.event,{path:path,key:path,value:value})
// console.log('pushing in datastore set',path,value)
if (this.handler) this.handler({path:path,key:path,value:value})
return super.set(path,value)
}
return this
}
formatPath(path) {
if (path==null) return path
if (Array.isArray(path)) {
path = path.filter(Boolean).join('.')
} else path = path.replace(/\/:/g, '.')
return path
}
} // end datastore class