Skip to content

Commit

Permalink
Merge pull request #31 from galenwarren/remove-firebase
Browse files Browse the repository at this point in the history
refactor: refactor to simplify
  • Loading branch information
galenwarren authored Sep 10, 2018
2 parents b9c3a2f + e218b74 commit 92778e9
Show file tree
Hide file tree
Showing 12 changed files with 549 additions and 449 deletions.
657 changes: 377 additions & 280 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"@commitlint/config-conventional": "^7.0.1",
"babel-cli": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babel-preset-vue-app": "^2.0.0",
"commitizen": "^2.10.1",
"coveralls": "^3.0.2",
"cz-conventional-changelog": "^2.1.0",
Expand All @@ -77,8 +78,7 @@
},
"dependencies": {
"memoizee": "^0.4.12",
"object-path": "^0.11.4",
"picolog": "^1.0.4"
"object-path": "^0.11.4"
},
"peerDependencies": {
"rxjs": "^6.0.0",
Expand Down
23 changes: 10 additions & 13 deletions src/__tests__/store.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,32 @@
import Vue from 'vue';

import {
SET_MUTATION,
DELETE_MUTATION,
crackStorePath,
rxSyncMutations,
} from '../store';
import { SET_MUTATION, DELETE_MUTATION, vuexRxSyncMutations } from '../store';

import { crackPath } from '../util';

describe('vuex', () => {
describe('crackStorePath', () => {
describe('crackPath', () => {
it('works with a path of length 2', () => {
expect(crackStorePath(['a', 'b'])).toEqual({
expect(crackPath(['a', 'b'])).toEqual({
trunkPath: ['a'],
leafKey: 'b',
});
});

it('works with a path of length 1', () => {
expect(crackStorePath(['a'])).toEqual({ trunkPath: [], leafKey: 'a' });
expect(crackPath(['a'])).toEqual({ trunkPath: [], leafKey: 'a' });
});

it('fails with a path of length 0', () => {
expect(() => crackStorePath([])).toThrow('Invalid path');
expect(() => crackPath([])).toThrow('Invalid path');
});
});

describe('rxSyncMutations', () => {
describe('vuexRxSyncMutations', () => {
describe(SET_MUTATION, () => {
const vueSet = jest.spyOn(Vue, 'set');

const setMutation = rxSyncMutations[SET_MUTATION];
const setMutation = vuexRxSyncMutations[SET_MUTATION];

it('sets a shallow value', () => {
const state = {};
Expand Down Expand Up @@ -75,7 +72,7 @@ describe('vuex', () => {
describe(DELETE_MUTATION, () => {
const vueDelete = jest.spyOn(Vue, 'delete');

const deleteMutation = rxSyncMutations[DELETE_MUTATION];
const deleteMutation = vuexRxSyncMutations[DELETE_MUTATION];

it('deletes a shallow value', () => {
const state = { key1: 1 };
Expand Down
12 changes: 0 additions & 12 deletions src/__tests__/sync.js

This file was deleted.

56 changes: 56 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Observable } from 'rxjs';
import objectPath from 'object-path';
import { SET_MUTATION, DELETE_MUTATION } from './store';
import { DEFAULT_DISPOSE_DELAY } from './constants';

export class VuexRxSyncConfig {
constructor(store, options = {}) {
this.store = store;
Object.assign(this, options);
}

get disposeDelay() {
return DEFAULT_DISPOSE_DELAY;
}

getStoreValue(path) {
return objectPath.get(this.store.state, path);
}

setStoreValue(path, value) {
this.store.commit(SET_MUTATION, { path, value });
}

deleteStoreValue(path) {
this.store.commit(DELETE_MUTATION, { path });
}

createStoreObservable(path) {
// ensure reactive
this.setStoreValue(path, this.getStoreValue(path));

// the observable for the value in the store we have just ensured exists
return Observable.create(subscriber => {
return this.store.watch(
() => this.getStoreValue(path),
value => subscriber.next(value)
);
});
}

shouldDeleteStoreValue(path, value) {
return value === undefined;
}

updateStore(path, value) {
if (this.shouldDeleteStoreValue(path, value)) {
this.deleteStoreValue(path);
} else {
this.setStoreValue(path, value);
}
}

resetStore(path) {
this.deleteStoreValue(path);
}
}
1 change: 1 addition & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const DEFAULT_DISPOSE_DELAY = 3000;
7 changes: 4 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { VueRxSync } from './plugin';
export { rxSyncMutations } from './store';
export { addAttribute } from './operators';
export { VuexRxSync } from './plugin';
export { VuexRxSyncConfig } from './config';
export { vuexRxSyncMutations } from './store';
export { addAttribute, resolve } from './operators';
23 changes: 21 additions & 2 deletions src/operators.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Observable, of, combineLatest } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';

export function afterUnsubscribe(action, delay) {
return source =>
Expand Down Expand Up @@ -29,3 +29,22 @@ export function addAttribute(key, attributeValue) {
.subscribe(subscriber);
});
}

export function resolve(getKeys, getObservable) {
return source => {
return Observable.create(subscriber => {
return source
.pipe(
switchMap(value => {
const keys = getKeys(value);
if (keys && keys.length) {
return combineLatest(keys.map(getObservable));
} else {
return of([]);
}
})
)
.subscribe(subscriber);
});
};
}
87 changes: 27 additions & 60 deletions src/plugin.js
Original file line number Diff line number Diff line change
@@ -1,78 +1,45 @@
import { combineLatest, of } from 'rxjs';
import { pluck, switchMap } from 'rxjs/operators';
import { pluck } from 'rxjs/operators';
import { syncObservableRefCounted } from './sync';
import { findObservable } from './util';
import { resolve, addAttribute } from './operators';

/**
* Watches a value through the provided vm, returning the current value
* and just returning the new values
*/
export const watchFactory = vm => target => {
return vm
.$watchAsObservable(target, { immediate: true })
.pipe(pluck('newValue'));
};

export const resolve = (value$, getKeys, getObservable) => {
return value$.pipe(
switchMap(value => {
const keys = getKeys(value);
if (keys && keys.length) {
return combineLatest(keys.map(getObservable));
} else {
return of([]);
}
})
);
};
export function watchFactory(vm) {
return target =>
vm.$watchAsObservable(target, { immediate: true }).pipe(pluck('newValue'));
}

export const rxSync = options => {
const sync = syncObservableRefCounted(options);
return function() {
return { sync, resolve, watch: watchFactory(this) };
};
};

// kgw consider contributing this to vue-rx?
export const getObservable = function(name) {
if (this.$observables) {
const observable = this.$observables[name];
if (observable) {
return observable;
}
}
if (this.$parent) {
return this.$parent.$getObservable(name);
}
return null;
};

export const VueRxSync = {
export const VuexRxSync = {
install(Vue, options) {
// kgw remove if contribute to vue-rx
Vue.prototype.$getObservable = getObservable;

// create the sync function to expose here
const sync = syncObservableRefCounted(options);

Vue.prototype.$rxSync = function() {
return {
sync,
resolve,
watch: watchFactory(this),
};
};
// the base context information, everything but 'watch'
const context = { sync, resolve, addAttribute };

// assign the $findObservable helper
Vue.prototype.$findObservable = findObservable;

// assign the $rxSync property
Object.defineProperty(Vue.prototype, '$rxSync', {
get: function() {
return Object.assign({}, context, {
watch: watchFactory(this),
});
},
});

// the vm we use for off-component watching
let vmWatch = null;

Vue.$rxSync = {
sync,
resolve,
// assing a global $rxSync with a watch that uses the
// Vue instance above
Vue.$rxSync = Object.assign({}, context, {
get watch() {
if (!vmWatch) {
vmWatch = new Vue();
}
return watchFactory(vmWatch);
},
};
});
},
};
28 changes: 4 additions & 24 deletions src/store.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,13 @@
import Vue from 'vue';
import objectPath from 'object-path';
import log from 'picolog';
import { crackPath } from './util';

export const SET_MUTATION = 'vue-rx-sync/SET';
export const DELETE_MUTATION = 'vue-rx-sync/DELETE';

export const storeSet = store => (path, value) => {
log.trace('storeSet', path, value);
store.commit(SET_MUTATION, { path, value });
};

export const storeDelete = store => path => {
log.trace('storeDelete', path);
store.commit(DELETE_MUTATION, { path });
};

export function crackStorePath(path) {
if (path.length < 1) {
throw new Error(`Invalid path ${path}, length must be >= 1`);
}

const trunkPath = path.slice();
const leafKey = trunkPath.pop();
return { trunkPath, leafKey };
}

export const rxSyncMutations = {
export const vuexRxSyncMutations = {
[SET_MUTATION](state, { path, value }) {
const { trunkPath, leafKey } = crackStorePath(path);
const { trunkPath, leafKey } = crackPath(path);

const trunk = trunkPath.reduce((obj, propertyName) => {
if (obj.hasOwnProperty(propertyName)) {
Expand All @@ -43,7 +23,7 @@ export const rxSyncMutations = {
},

[DELETE_MUTATION](state, { path }) {
const { trunkPath, leafKey } = crackStorePath(path);
const { trunkPath, leafKey } = crackPath(path);
const trunk = objectPath.get(state, trunkPath);
if (!trunk) {
throw new Error(
Expand Down
Loading

0 comments on commit 92778e9

Please sign in to comment.