From a67eff8eead959d3edfcfbda3fac91ede9d0e1bf Mon Sep 17 00:00:00 2001 From: David Kebler Date: Mon, 10 Feb 2020 21:51:49 -0800 Subject: [PATCH] 0.1.3 enhanced datastore by adding rxjs reactiving to set properties --- .eslintrc.js | 37 ++++++++++++++++++ .gitignore | 2 + .npmignore | 5 +++ examples/example.js | 14 +++++++ package.json | 39 +++++++++++++++++++ readme.md | 3 ++ src/datastore.js | 92 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 192 insertions(+) create mode 100644 .eslintrc.js create mode 100644 .gitignore create mode 100644 .npmignore create mode 100644 examples/example.js create mode 100644 package.json create mode 100644 readme.md create mode 100644 src/datastore.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..49bac18 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,37 @@ +module.exports = { + "ecmaFeatures": { + "modules": true, + "spread" : true, + "restParams" : true + }, + // "plugins": [ + // "unicorn" + // ], + "env": { + "es6": true, + "node": true, + "mocha": true + }, + "parserOptions": { + "ecmaVersion": 2017, + "sourceType": "module" + }, + "extends": "eslint:recommended", + "rules": { + "indent": [ + "error", + 2 + ], + // "unicorn/no-array-instanceof": "error", + "no-console": 0, + "semi": ["error", "never"], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "single" + ] + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e61051f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/node_modules/ +/coverage/ diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..2f680a8 --- /dev/null +++ b/.npmignore @@ -0,0 +1,5 @@ +tests/ +test/ +*.test.js +testing/ +examples/ diff --git a/examples/example.js b/examples/example.js new file mode 100644 index 0000000..d827741 --- /dev/null +++ b/examples/example.js @@ -0,0 +1,14 @@ +import DataStore from '../src/datastore' + + +// let circuits = await this.db.getAll('circuits') +// console.log(circuits) +// // let obs = this.db.getStore('circuits').addObserver(undefined,'bogus') +// let obs = this.db.getStore('circuits').addObserver('uy0cADaONfPv38th.prop1',{prop1:'test'}) +// console.log(this.db.getStore('circuits')._observers) +// obs.subscribe(console.log) +// obs.next({prop1:'test'}) +// obs.next({prop1:'test'}) +// obs.next({prop1:'test'}) +// obs.next({prop1:'test'}) +// obs.next({prop1:'test2'}) diff --git a/package.json b/package.json new file mode 100644 index 0000000..3523963 --- /dev/null +++ b/package.json @@ -0,0 +1,39 @@ +{ + "name": "@uci-utils/data-store-rx", + "version": "0.1.3", + "description": "A Extended Class Data Store Module ", + "main": "src/datastore.js", + "scripts": { + "example": "node -r esm examples/example", + "example:dev": "./node_modules/.bin/nodemon -r esm examples/example", + "test": "./node_modules/.bin/mocha -r esm --timeout 30000" + }, + "author": "David Kebler", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/uCOMmandIt/.git" + }, + "keywords": [ + "node.js" + ], + "bugs": { + "url": "https://github.com/uCOMmandIt/uci-utils/issues" + }, + "homepage": "https://github.com/uCOMmandIt/uci-utils#readme", + "dependencies": { + "data-store": "^4.0.3", + "deep-equal": "^2.0.1", + "get-value": "^3.0.1", + "is-plain-object": "^3.0.0", + "rxjs": "^6.5.4", + "set-value": "^3.0.1", + "unset-value": "^1.0.0" + }, + "devDependencies": { + "chai": "^4.2.0", + "esm": "^3.2.25", + "mocha": "^6.2.2", + "nodemon": "^1.19.4" + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..5f38a03 --- /dev/null +++ b/readme.md @@ -0,0 +1,3 @@ +### uCOMmandIt Ready Class + +Watches a list of events and/or promises that resolve to a boolean. When all a met it emits true otherwise at each event it emits false diff --git a/src/datastore.js b/src/datastore.js new file mode 100644 index 0000000..f004131 --- /dev/null +++ b/src/datastore.js @@ -0,0 +1,92 @@ +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