Skip to content

Commit

Permalink
disallow multiple stores of the same type
Browse files Browse the repository at this point in the history
- also slight refactor to (kinda) hide "private" methods.
  • Loading branch information
Jeff Gran committed Mar 24, 2016
1 parent 78d2745 commit 5abffe9
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### Unreleased

- disallow multiple stores of the same `type`. MobStore only knows how to work with one of each anyway. This is a good thing. You can use "sidecar" stores to have multiple sub-stores. Examples/docs to come.

### 0.4.3

- stop using babel's dynamic object key
Expand Down
28 changes: 17 additions & 11 deletions src/MobStore.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {observable, extendObservable, isObservable, transaction} from 'mobx';
import Type from './Type';

let stores = [];
let $stores = {};
let $inject = Symbol('inject');
let $pushOrMerge = Symbol('pushOrMerge');

/**
* Base class for making observable datastores.
Expand All @@ -28,6 +30,8 @@ export default class MobStore {
* @param {Object[]} options.associations - Array of associations to connect this type to another store.
*/
constructor({collectionName, type, associations, instanceMethods, afterInject, afterAdd, afterUpdate}) {
if (undefined !== $stores[type]) { throw new Error('It is not allowed to create duplicate MobStore instances. Only create one per `type`'); }

this.collectionName = collectionName;

/// TODO reject/throw if type by this name already exists.
Expand All @@ -48,7 +52,7 @@ export default class MobStore {

this.injectCallbackCache = [];

stores.push(this);
$stores[type] = this;
}

get collection() {
Expand All @@ -58,15 +62,17 @@ export default class MobStore {
/**
* Inject JSON data into this store.
* @param {Object|Object[]} jsondata - A single instance or an array of instances to inject into this store.
* @param {number} level - internal use only
* @param {function[]} callbackFns - internal use only
*/
inject(jsondata, level = 0, callbackFns = []) {
inject(jsondata) {
return this[$inject](jsondata);
}

[$inject](jsondata, level = 0, callbackFns = []) {
const objs = MobStore.wrap(jsondata);

return transaction(() => {
const instances = objs.map((obj) => {
const {instance, callbacks} = this.pushOrMerge(obj);
const {instance, callbacks} = this[$pushOrMerge](obj);
MobStore.merge(callbackFns,callbacks);
const associatedObjects = this.type.associatedObjectsFor(obj);

Expand All @@ -75,7 +81,7 @@ export default class MobStore {
if (assocStore) {
let aInstances;
if (value) {
let result = assocStore.inject(value, level + 1, callbackFns);
let result = assocStore[$inject](value, level + 1, callbackFns);
aInstances = result.instances;
callbackFns = result.callbackFns;
}
Expand All @@ -101,10 +107,10 @@ export default class MobStore {
};
}
});

}

pushOrMerge(object) {

[$pushOrMerge](object) {
let callbacks = [];
let instance = this.find(object.id);
if (instance && Object.keys(instance).length > 0) {
Expand Down Expand Up @@ -183,11 +189,11 @@ export default class MobStore {
}

static storeForType(typeName) {
return stores.find(s => s.type.name == typeName);
return $stores[typeName];
}

static clearStores() {
stores = [];
$stores = {};
}

// fast way to merge two arrays, per https://jsperf.com/array-prototype-push-apply-vs-concat/5
Expand Down
69 changes: 69 additions & 0 deletions tests/ErrorTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import {MobStore} from '../src/index.js';
import test from 'tape';

test.skip("Injecting an inconsistent circular reference throws an error", t => {

const postStore = new MobStore({
collectionName: "posts",
type: "post",
associations: [
{
key: "comments",
type: "comment",
plural: true
}
]
});

const commentStore = new MobStore({
collectionName: "comments",
type: "comment",
associations: [
{
key: "post",
type: 'post'
}
]
});


// TODO - this is kinda hard but would be VERY nice if the library catches this kind of mistake for you.
t.throws(() => {
postStore.inject({
id: 1,
title: "Post 1 title",
comments: [
{
id: 7,
text: "Comment 7 text",
post: {
id: 2 // this is "wrong" -- it came from post 1, but the inverse is setting it to post 2. only one can be right.
}
}
]
});


}, /inconsistent/,
"should error if the data is inconsistent");

t.end();
});



test("don't allow multiple stores of the same type", t => {
const one = new MobStore({
collectionName: 'foos',
type: 'foo'
});

t.throws(() => {
const two = new MobStore({
collectionName: 'otherFoos',
type: 'foo'
});
}, /duplicate/,
"should error if there is a duplicate store detected");
t.end();
});

0 comments on commit 5abffe9

Please sign in to comment.