UNPKG

orbit-state-tree

Version:
1,211 lines (1,052 loc) 33.7 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var invariant = _interopDefault(require('invariant')); var normalize = _interopDefault(require('json-api-normalizer')); var Jsona = _interopDefault(require('jsona')); var core = require('@orbit/core'); var build = _interopDefault(require('redux-object')); 'use strict'; var domain; // This constructor is used to store event handlers. Instantiating this is // faster than explicitly calling `Object.create(null)` to get a "clean" empty // object (tested with v8 v4.9). function EventHandlers() {} EventHandlers.prototype = Object.create(null); function EventEmitter() { EventEmitter.init.call(this); } // nodejs oddity // require('events') === require('events').EventEmitter EventEmitter.EventEmitter = EventEmitter; EventEmitter.usingDomains = false; EventEmitter.prototype.domain = undefined; EventEmitter.prototype._events = undefined; EventEmitter.prototype._maxListeners = undefined; // By default EventEmitters will print a warning if more than 10 listeners are // added to it. This is a useful default which helps finding memory leaks. EventEmitter.defaultMaxListeners = 10; EventEmitter.init = function() { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. if (domain.active && !(this instanceof domain.Domain)) { this.domain = domain.active; } } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { this._events = new EventHandlers(); this._eventsCount = 0; } this._maxListeners = this._maxListeners || undefined; }; // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { if (typeof n !== 'number' || n < 0 || isNaN(n)) throw new TypeError('"n" argument must be a positive number'); this._maxListeners = n; return this; }; function $getMaxListeners(that) { if (that._maxListeners === undefined) return EventEmitter.defaultMaxListeners; return that._maxListeners; } EventEmitter.prototype.getMaxListeners = function getMaxListeners() { return $getMaxListeners(this); }; // These standalone emit* functions are used to optimize calling of event // handlers for fast cases because emit() itself often has a variable number of // arguments and can be deoptimized because of that. These functions always have // the same number of arguments and thus do not get deoptimized, so the code // inside them can execute faster. function emitNone(handler, isFn, self) { if (isFn) handler.call(self); else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) listeners[i].call(self); } } function emitOne(handler, isFn, self, arg1) { if (isFn) handler.call(self, arg1); else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) listeners[i].call(self, arg1); } } function emitTwo(handler, isFn, self, arg1, arg2) { if (isFn) handler.call(self, arg1, arg2); else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) listeners[i].call(self, arg1, arg2); } } function emitThree(handler, isFn, self, arg1, arg2, arg3) { if (isFn) handler.call(self, arg1, arg2, arg3); else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) listeners[i].call(self, arg1, arg2, arg3); } } function emitMany(handler, isFn, self, args) { if (isFn) handler.apply(self, args); else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) listeners[i].apply(self, args); } } EventEmitter.prototype.emit = function emit(type) { var er, handler, len, args, i, events, domain; var needDomainExit = false; var doError = (type === 'error'); events = this._events; if (events) doError = (doError && events.error == null); else if (!doError) return false; domain = this.domain; // If there is no 'error' event listener then throw. if (doError) { er = arguments[1]; if (domain) { if (!er) er = new Error('Uncaught, unspecified "error" event'); er.domainEmitter = this; er.domain = domain; er.domainThrown = false; domain.emit('error', er); } else if (er instanceof Error) { throw er; // Unhandled 'error' event } else { // At least give some kind of context to the user var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); err.context = er; throw err; } return false; } handler = events[type]; if (!handler) return false; var isFn = typeof handler === 'function'; len = arguments.length; switch (len) { // fast cases case 1: emitNone(handler, isFn, this); break; case 2: emitOne(handler, isFn, this, arguments[1]); break; case 3: emitTwo(handler, isFn, this, arguments[1], arguments[2]); break; case 4: emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]); break; // slower default: args = new Array(len - 1); for (i = 1; i < len; i++) args[i - 1] = arguments[i]; emitMany(handler, isFn, this, args); } if (needDomainExit) domain.exit(); return true; }; function _addListener(target, type, listener, prepend) { var m; var events; var existing; if (typeof listener !== 'function') throw new TypeError('"listener" argument must be a function'); events = target._events; if (!events) { events = target._events = new EventHandlers(); target._eventsCount = 0; } else { // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (events.newListener) { target.emit('newListener', type, listener.listener ? listener.listener : listener); // Re-assign `events` because a newListener handler could have caused the // this._events to be assigned to a new object events = target._events; } existing = events[type]; } if (!existing) { // Optimize the case of one listener. Don't need the extra array object. existing = events[type] = listener; ++target._eventsCount; } else { if (typeof existing === 'function') { // Adding the second element, need to change to array. existing = events[type] = prepend ? [listener, existing] : [existing, listener]; } else { // If we've already got an array, just append. if (prepend) { existing.unshift(listener); } else { existing.push(listener); } } // Check for listener leak if (!existing.warned) { m = $getMaxListeners(target); if (m && m > 0 && existing.length > m) { existing.warned = true; var w = new Error('Possible EventEmitter memory leak detected. ' + existing.length + ' ' + type + ' listeners added. ' + 'Use emitter.setMaxListeners() to increase limit'); w.name = 'MaxListenersExceededWarning'; w.emitter = target; w.type = type; w.count = existing.length; emitWarning(w); } } } return target; } function emitWarning(e) { typeof console.warn === 'function' ? console.warn(e) : console.log(e); } EventEmitter.prototype.addListener = function addListener(type, listener) { return _addListener(this, type, listener, false); }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.prependListener = function prependListener(type, listener) { return _addListener(this, type, listener, true); }; function _onceWrap(target, type, listener) { var fired = false; function g() { target.removeListener(type, g); if (!fired) { fired = true; listener.apply(target, arguments); } } g.listener = listener; return g; } EventEmitter.prototype.once = function once(type, listener) { if (typeof listener !== 'function') throw new TypeError('"listener" argument must be a function'); this.on(type, _onceWrap(this, type, listener)); return this; }; EventEmitter.prototype.prependOnceListener = function prependOnceListener(type, listener) { if (typeof listener !== 'function') throw new TypeError('"listener" argument must be a function'); this.prependListener(type, _onceWrap(this, type, listener)); return this; }; // emits a 'removeListener' event iff the listener was removed EventEmitter.prototype.removeListener = function removeListener(type, listener) { var list, events, position, i, originalListener; if (typeof listener !== 'function') throw new TypeError('"listener" argument must be a function'); events = this._events; if (!events) return this; list = events[type]; if (!list) return this; if (list === listener || (list.listener && list.listener === listener)) { if (--this._eventsCount === 0) this._events = new EventHandlers(); else { delete events[type]; if (events.removeListener) this.emit('removeListener', type, list.listener || listener); } } else if (typeof list !== 'function') { position = -1; for (i = list.length; i-- > 0;) { if (list[i] === listener || (list[i].listener && list[i].listener === listener)) { originalListener = list[i].listener; position = i; break; } } if (position < 0) return this; if (list.length === 1) { list[0] = undefined; if (--this._eventsCount === 0) { this._events = new EventHandlers(); return this; } else { delete events[type]; } } else { spliceOne(list, position); } if (events.removeListener) this.emit('removeListener', type, originalListener || listener); } return this; }; EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) { var listeners, events; events = this._events; if (!events) return this; // not listening for removeListener, no need to emit if (!events.removeListener) { if (arguments.length === 0) { this._events = new EventHandlers(); this._eventsCount = 0; } else if (events[type]) { if (--this._eventsCount === 0) this._events = new EventHandlers(); else delete events[type]; } return this; } // emit removeListener for all listeners on all events if (arguments.length === 0) { var keys = Object.keys(events); for (var i = 0, key; i < keys.length; ++i) { key = keys[i]; if (key === 'removeListener') continue; this.removeAllListeners(key); } this.removeAllListeners('removeListener'); this._events = new EventHandlers(); this._eventsCount = 0; return this; } listeners = events[type]; if (typeof listeners === 'function') { this.removeListener(type, listeners); } else if (listeners) { // LIFO order do { this.removeListener(type, listeners[listeners.length - 1]); } while (listeners[0]); } return this; }; EventEmitter.prototype.listeners = function listeners(type) { var evlistener; var ret; var events = this._events; if (!events) ret = []; else { evlistener = events[type]; if (!evlistener) ret = []; else if (typeof evlistener === 'function') ret = [evlistener.listener || evlistener]; else ret = unwrapListeners(evlistener); } return ret; }; EventEmitter.listenerCount = function(emitter, type) { if (typeof emitter.listenerCount === 'function') { return emitter.listenerCount(type); } else { return listenerCount.call(emitter, type); } }; EventEmitter.prototype.listenerCount = listenerCount; function listenerCount(type) { var events = this._events; if (events) { var evlistener = events[type]; if (typeof evlistener === 'function') { return 1; } else if (evlistener) { return evlistener.length; } } return 0; } EventEmitter.prototype.eventNames = function eventNames() { return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : []; }; // About 1.5x faster than the two-arg version of Array#splice(). function spliceOne(list, index) { for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) list[i] = list[k]; list.pop(); } function arrayClone(arr, i) { var copy = new Array(i); while (i--) copy[i] = arr[i]; return copy; } function unwrapListeners(arr) { var ret = new Array(arr.length); for (var i = 0; i < ret.length; ++i) { ret[i] = arr[i].listener || arr[i]; } return ret; } var asyncGenerator = function () { function AwaitValue(value) { this.value = value; } function AsyncGenerator(gen) { var front, back; function send(key, arg) { return new Promise(function (resolve, reject) { var request = { key: key, arg: arg, resolve: resolve, reject: reject, next: null }; if (back) { back = back.next = request; } else { front = back = request; resume(key, arg); } }); } function resume(key, arg) { try { var result = gen[key](arg); var value = result.value; if (value instanceof AwaitValue) { Promise.resolve(value.value).then(function (arg) { resume("next", arg); }, function (arg) { resume("throw", arg); }); } else { settle(result.done ? "return" : "normal", result.value); } } catch (err) { settle("throw", err); } } function settle(type, value) { switch (type) { case "return": front.resolve({ value: value, done: true }); break; case "throw": front.reject(value); break; default: front.resolve({ value: value, done: false }); break; } front = front.next; if (front) { resume(front.key, front.arg); } else { back = null; } } this._invoke = send; if (typeof gen.return !== "function") { this.return = undefined; } } if (typeof Symbol === "function" && Symbol.asyncIterator) { AsyncGenerator.prototype[Symbol.asyncIterator] = function () { return this; }; } AsyncGenerator.prototype.next = function (arg) { return this._invoke("next", arg); }; AsyncGenerator.prototype.throw = function (arg) { return this._invoke("throw", arg); }; AsyncGenerator.prototype.return = function (arg) { return this._invoke("return", arg); }; return { wrap: function (fn) { return function () { return new AsyncGenerator(fn.apply(this, arguments)); }; }, await: function (value) { return new AwaitValue(value); } }; }(); var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var defineProperty = function (obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }; /** * Serialize plain objects into json api format */ var Serializer = function () { function Serializer(schema) { classCallCheck(this, Serializer); this._formatter = new Jsona(); this._schema = schema; } /** * Augment object with attributes needed by formatter * * @param {String} type Object type * @param {Object} object */ createClass(Serializer, [{ key: '_augmentObject', value: function _augmentObject(type, object) { var _this = this; var relationships = this._schema.models[type].relationships; var relationshipNames = relationships ? Object.keys(relationships) : []; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { var _loop = function _loop() { var relationshipName = _step.value; if (!object[relationshipName]) { return 'continue'; } if (Array.isArray(object[relationshipName])) { object[relationshipName] = object[relationshipName].map(function (relationshipObject) { return _this._augmentObject(relationships[relationshipName].model, relationshipObject); }); return 'continue'; } object[relationshipName] = _this._augmentObject(relationships[relationshipName].model, object[relationshipName]); }; for (var _iterator = relationshipNames[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var _ret = _loop(); if (_ret === 'continue') continue; } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return Object.assign({ type: type, relationshipNames: relationshipNames }, object); } /** * Serialize an object into json api format * * @param {String} type Object type * @param {Object} object Object * @returns {Object} */ }, { key: 'serialize', value: function serialize(type, object) { invariant(type in this._schema.models, 'serialized type must exist in schema'); return this._formatter.serialize({ stuff: this._augmentObject(type, object) }); } }]); return Serializer; }(); var StateTree = function () { /** * Initialize the state tree with your store and schema instances * * @param {Object} {store, schema} * @memberof StateTree */ function StateTree(_ref) { var store = _ref.store, schema = _ref.schema; classCallCheck(this, StateTree); invariant(store, 'Store instance required'); invariant(schema, 'Schema instance required'); this._store = store; this._schema = schema; this._serializer = new Serializer(this._schema); this._events = new EventEmitter(); this._lastRequestId = 0; this._state = { entities: {}, requests: {} }; } /** * Listen for tree changes, receving a new tree every time a change is comitted * * @param {Function} callback */ createClass(StateTree, [{ key: 'onChange', value: function onChange(callback) { return this._events.addListener('change', callback); } /** * Listen for unhandled errors, errors coming from orbitjs are described on request object * * @param {Function} callback */ }, { key: 'onUnhandledError', value: function onUnhandledError(callback) { return this._events.addListener('unhandledError', callback); } /** * Adds an record * * @param {String} type * @param {Object} object */ }, { key: 'addRecord', value: function addRecord(type, object) { return this._storeUpdate('addRecord', [this._serialize(type, object)]); } /** * Replaces an entire record * * @param {String} type * @param {Object} object */ }, { key: 'replaceRecord', value: function replaceRecord(type, object) { return this._storeUpdate('replaceRecord', [this._serialize(type, object)]); } /** * Removes an record * * @param {String} type * @param {String} id */ }, { key: 'removeRecord', value: function removeRecord(type, id) { return this._storeUpdate('removeRecord', [{ type: type, id: id }]); } /** * Replaces a key * * @param {String} type * @param {String} id * @param {String} keyName * @param {String} keyValue */ }, { key: 'replaceKey', value: function replaceKey(type, id, keyName, keyValue) { return this._storeUpdate('replaceKey', [{ type: type, id: id }, keyName, keyValue]); } /** * Replaces an attribute * * @param {String} type * @param {String} id * @param {String} attributeName * @param {String} attributeValue */ }, { key: 'replaceAttribute', value: function replaceAttribute(type, id, attributeName, attributeValue) { return this._storeUpdate('replaceAttribute', [{ type: type, id: id }, attributeName, attributeValue]); } /** * Adds a member to a to-many relationship * * @param {String} type * @param {String} id * @param {String} relationshipName * @param {String} relationshipId */ }, { key: 'addToRelatedRecords', value: function addToRelatedRecords(type, id, relationshipName, relationshipId) { this._validateRelationship(type, relationshipName, 'hasMany'); var relationshipType = this._schema.models[type].relationships[relationshipName].model; return this._storeUpdate('addToRelatedRecords', [{ type: type, id: id }, relationshipName, { type: relationshipType, id: relationshipId }]); } /** * Removes a member from a to-many relationship * * @param {String} type * @param {String} id * @param {String} relationshipName * @param {String} relationshipId */ }, { key: 'removeFromRelatedRecords', value: function removeFromRelatedRecords(type, id, relationshipName, relationshipId) { this._validateRelationship(type, relationshipName, 'hasMany'); var relationshipType = this._schema.models[type].relationships[relationshipName].model; return this._storeUpdate('removeFromRelatedRecords', [{ type: type, id: id }, relationshipName, { type: relationshipType, id: relationshipId }]); } /** * Replaces every member of a to-many relationship * * @param {String} type * @param {String} id * @param {String} relationshipName * @param {String[]} relationshipIds */ }, { key: 'replaceRelatedRecords', value: function replaceRelatedRecords(type, id, relationshipName, relationshipIds) { this._validateRelationship(type, relationshipName, 'hasMany'); var relationshipType = this._schema.models[type].relationships[relationshipName].model; var data = relationshipIds.map(function (id) { return { type: relationshipType, id: id }; }); return this._storeUpdate('replaceRelatedRecords', [{ type: type, id: id }, relationshipName, data]); } /** * Replaces a to-one relationship * * @param {String} type * @param {String} id * @param {String} relationshipName * @param {String} relationshipId */ }, { key: 'replaceRelatedRecord', value: function replaceRelatedRecord(type, id, relationshipName, relationshipId) { this._validateRelationship(type, relationshipName, 'hasOne'); var relationshipType = this._schema.models[type].relationships[relationshipName].model; return this._storeUpdate('replaceRelatedRecord', [{ type: type, id: id }, relationshipName, { type: relationshipType, id: relationshipId }]); } /** * Find a record by its identity. * * @param {String} type * @param {String} id */ }, { key: 'findRecord', value: function findRecord(type, id) { return this._storeQuery('findRecord', [{ type: type, id: id }]); } /** * Find all records of a specific type. * * @param {String} type * @param {Object} query */ }, { key: 'findRecords', value: function findRecords(type, query) { var hook = function hook(builder) { if (query.filter) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = query.filter[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var filter = _step.value; builder.filter(filter); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } if (query.sort) { var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = query.sort[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var sort = _step2.value; builder.sort(sort); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } } if (query.page) { builder.page(query.page); } return builder; }; return this._storeQuery('findRecords', [type], hook); } /** * Find a related record in a to-one relationship * * @param {String} type * @param {String} id * @param {String} relationship */ }, { key: 'findRelatedRecord', value: function findRelatedRecord(type, id, relationship) { this._validateRelationship(type, relationship, 'hasOne'); return this._storeQuery('findRelatedRecord', [{ type: type, id: id }, relationship]); } /** * Find a related record in a to-one relationship * * @param {String} type * @param {String} id * @param {String} relationship */ }, { key: 'findRelatedRecords', value: function findRelatedRecords(type, id, relationship) { this._validateRelationship(type, relationship, 'hasMany'); return this._storeQuery('findRelatedRecords', [{ type: type, id: id }, relationship]); } }, { key: '_validateRelationship', value: function _validateRelationship(type, name, relationshipType) { var isValid = this._schema.models[type] && this._schema.models[type].relationships[name] && (!relationshipType || this._schema.models[type].relationships[name].type === relationshipType); if (!isValid) { throw new Error('Invalid relationship ' + name + ' on model ' + type + ' with type ' + relationshipType); } } }, { key: '_serialize', value: function _serialize(type, object) { return this._serializer.serialize(type, object).data; } }, { key: '_storeUpdate', value: function _storeUpdate(method, args) { var _this = this; var requestId = this._createRequest(); var promise = this._store.update(function (t) { return t[method].apply(t, args); }).then(function (jsonApiObject) { return _this._handeRequestSuccess(requestId, jsonApiObject); }).catch(function (error) { return _this._handleRequestError(requestId, error); }); return { requestId: requestId, promise: promise }; } }, { key: '_storeQuery', value: function _storeQuery(method, args, hook) { var _this2 = this; var requestId = this._createRequest(); var promise = this._store.query(function (queryBuilder) { var query = queryBuilder[method].apply(queryBuilder, args); if (hook) { query = hook(query); } return query; }).then(function (jsonApiObject) { return _this2._handeRequestSuccess(requestId, jsonApiObject); }).catch(function (error) { return _this2._handleRequestError(requestId, error); }); return { requestId: requestId, promise: promise }; } }, { key: '_createRequest', value: function _createRequest() { var requestId = ++this._lastRequestId; this._mergeState({ requests: defineProperty({}, requestId, { id: requestId, completed: false, timestamp: new Date().getTime() }) }); return requestId; } }, { key: '_handeRequestSuccess', value: function _handeRequestSuccess(requestId, response) { var idsByType = {}; if (Array.isArray(response)) { var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = response[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var item = _step3.value; if (!idsByType[item.type]) { idsByType[item.type] = []; } idsByType[item.type].push(item.id); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } } else if (response && response.type) { idsByType[response.type] = [response.id]; } this._insertEntities(requestId, normalize({ data: response }), idsByType); } }, { key: '_handleRequestError', value: function _handleRequestError(requestId, error) { if (!(error instanceof core.Exception)) { this._events.emit('unhandledError', error, requestId); return error; } var request = { id: requestId, completed: true, result: {}, error: { message: error.message, description: error.description, type: error.type, id: error.id, relationship: error.relationship } }; this._mergeState({ entities: {}, requests: defineProperty({}, requestId, request) }); } }, { key: '_insertEntities', value: function _insertEntities(requestId, entities, idsByType) { var request = { id: requestId, completed: true, result: idsByType, error: null }; this._mergeState({ entities: entities, requests: defineProperty({}, requestId, request) }); } }, { key: '_mergeState', value: function _mergeState(mergedState) { var newState = Object.assign({}, this._state); for (var key in mergedState.entities) { newState.entities[key] = Object.assign({}, this._state.entities[key], mergedState.entities[key]); } for (var _key in mergedState.requests) { newState.requests[_key] = Object.assign({}, this._state.requests[_key], mergedState.requests[_key]); } this._state = newState; this._events.emit('change', this._state); } }]); return StateTree; }(); /** * Returns an request object from current state tree */ function requestSelector(state, requestId) { return state.requests[requestId]; } /** * Return a record from current state tree */ function recordSelector(state, type, id) { return build(state.entities, type, id); } exports.StateTree = StateTree; exports.requestSelector = requestSelector; exports.recordSelector = recordSelector; //# sourceMappingURL=orbit-state-tree.js.map