UNPKG

@state-sync/redux-path-reducer

Version:
275 lines (274 loc) 10.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); //import { Promise } from 'es6-promise'; var jiff = require("jiff"); var Events_1 = require("./Events"); var InvocationMap_1 = require("./InvocationMap"); var Patch_1 = require("./Patch"); var SyncAreaConfig_1 = require("./SyncAreaConfig"); var find_1 = require("./utils/find"); var SyncArea = /** @class */ (function () { function SyncArea(name, initialState, helper) { this.subscribed = false; this.patchQueue = []; this.initialState = initialState; this.helper = helper; this.name = name; this.subscriptionsCount = 0; this.invocations = new InvocationMap_1.InvocationMap(); this.ready = false; this.modelVersion = 0; } SyncArea.prototype.isReady = function () { return this.ready; }; SyncArea.prototype.init = function () { this.helper.dispatch({ type: '@STATE_SYNC/SYNC_AREA_STATUS', area: this.name, status: 'disconnected', ready: false }); }; SyncArea.prototype.wrap = function (reducer) { var _this = this; return function (state, action, ext) { return _this.reduce(state, action, ext, reducer); }; }; SyncArea.prototype.model = function () { return this.local; }; SyncArea.prototype.select = function (path) { return new Patch_1.OpSelect({ op: 'select', path: path }).apply(this.local); }; /** * Invoke when connection is ready */ SyncArea.prototype.onReady = function () { this.doSubscription(); }; SyncArea.prototype.subscribe = function () { this.subscriptionsCount++; return this.doSubscription(); }; SyncArea.prototype.doSubscription = function () { var _this = this; if (!this.subscribed && this.helper.isFullyConnected()) { this.subscribed = true; return this.invocations.request(function (id) { _this.helper.send(new Events_1.SubscribeAreaRequest(id, _this.name)); }); } else { return new Promise(function (resolve, error) { return resolve(0); }); } }; SyncArea.prototype.unsubscribe = function () { var _this = this; this.subscriptionsCount--; if (this.subscriptionsCount == 0) { this.subscribed = false; this.invocations.request(function (id) { _this.helper.send(new Events_1.UnsubscribeAreaRequest(id, _this.name)); }); } }; SyncArea.prototype.signal = function (command, parameters) { var _this = this; return this.invocations.request(function (id) { _this.helper.send(new Events_1.SignalRequest(id, _this.name, command, parameters)); }); }; SyncArea.prototype.onSignalResponse = function (event) { if (this.invocations.response(event.forId)) { this.pushPatches(); } }; SyncArea.prototype.onSignalError = function (event) { if (this.invocations.error(event.forId, event.error)) { this.pushPatches(); } }; SyncArea.prototype.onSubscribe = function (event) { this.ready = true; this.invocations.response(event.forId); this.config = event.config; this.invocations.timeout = event.config.timeout; this.helper.dispatch({ type: '@STATE_SYNC/SYNC_AREA_INIT', area: event.area, payload: event.model }); this.helper.dispatch({ type: '@STATE_SYNC/SYNC_AREA_STATUS', area: event.area, status: 'ready', ready: true }); }; // tslint:disable SyncArea.prototype.onUnsubscribe = function (event) { this.ready = false; this.invocations.response(event.forId); this.config = new SyncAreaConfig_1.default(); this.helper.dispatch({ type: '@STATE_SYNC/SYNC_AREA_STATUS', area: event.area, status: 'disconnected', ready: false }); this.helper.dispatch({ type: '@STATE_SYNC/SYNC_AREA_INIT', payload: this.initialState }); }; SyncArea.prototype.dispatchSyncPatch = function (event) { this.helper.dispatch({ type: '@STATE_SYNC/SYNC_AREA_SERVER_PATCH', area: event.area, payload: event.patch }); }; SyncArea.prototype.onPatchResponse = function (event) { if (this.invocations.response(event.forId)) { this.pushPatches(); } }; SyncArea.prototype.pushPatches = function () { var _this = this; this.patchQueue.forEach(function (cmd) { _this.dispatchSyncPatch(cmd); }); this.patchQueue = []; }; SyncArea.prototype.onServerPatch = function (event) { if (this.invocations.isEmpty()) { this.dispatchSyncPatch(event); } else { this.patchQueue.push(event); } }; SyncArea.prototype.onPatchAreaError = function (event) { console.error(event); }; SyncArea.prototype.onSubscribeError = function (event) { console.error(event); }; SyncArea.prototype.actionArrayInsertByKey = function (path, item, keyField) { this.actionReduce(path, function (array) { if (array) { var tmp = array.concat([item]); tmp.sort(function (a, b) { var ak = a[keyField]; var bk = b[keyField]; if (ak < bk) { return -1; } if (ak > bk) { return 1; } return 0; }); return tmp; } else { return [item]; } }); }; SyncArea.prototype.actionArrayReplaceByKey = function (path, data, keyField) { this.actionReduce(path, function (array) { var copy = array.slice(); for (var i = 0; i < copy.length; i++) { var item = copy[i]; if (item[keyField] === data[keyField]) { copy[i] = item; } } return copy; }); }; SyncArea.prototype.actionArrayRemoveByKey = function (path, keyField, value) { this.actionReduce(path, function (array) { var tmp = array.slice(); tmp.filter(function (item) { return item[keyField] == value; }); return tmp; }); }; SyncArea.prototype.actionArrayRemoveByIndex = function (path, index) { this.actionReduce(path, function (array) { return array.splice(index, 1); }); }; SyncArea.prototype.actionReplace = function (path, value) { this.helper.dispatch({ type: '@STATE_SYNC/SYNC_AREA_LOCAL_PATCH', area: this.name, payload: [{ op: 'replace', path: path, value: value }] }); }; SyncArea.prototype.actionRemove = function (path, condition) { try { var value = find_1.default(this.local, path); if (!condition || condition(value)) { this.helper.dispatch({ type: '@STATE_SYNC/SYNC_AREA_LOCAL_PATCH', area: this.name, payload: [{ op: 'remove', path: path }] }); } } catch (e) { console.error(e); } }; SyncArea.prototype.actionReduce = function (path, reducer) { try { var value = find_1.default(this.local, path); this.actionReplace(path, reducer(value)); } catch (e) { console.error(e); } }; SyncArea.prototype.actionToggle = function (path) { try { var value = find_1.default(this.local, path); this.actionReplace(path, !value); } catch (e) { console.error(e); } }; SyncArea.prototype.reduce = function (state, action, ext, reducer) { // initialization if (state === undefined) return this.initialState; // sync try { var fit = (this.name === action.area) && action.type.indexOf('@STATE_SYNC/') === 0; if (fit) { switch (action.type) { case '@STATE_SYNC/SYNC_AREA_INIT': this.local = action.payload; this.local.syncStateLastUpdateVersion = this.modelVersion++; return this.local; case '@STATE_SYNC/SYNC_AREA_SERVER_PATCH': this.local = new Patch_1.Patch(action.payload).apply(state); this.local.syncStateLastUpdateVersion = this.modelVersion++; return this.local; case '@STATE_SYNC/SYNC_AREA_LOCAL_PATCH': try { return this.detectChanges(state, this.local = new Patch_1.Patch(action.payload).apply(state)); } catch (e) { console.error('Local patch failed', state, action.payload); } } } } catch (e) { console.error('action failed:', action, e); } // pass action to normal reducers return this.detectChanges(state, this.local = reducer ? reducer(state, action, ext) : state); }; SyncArea.prototype.detectChanges = function (from, to) { var _this = this; if (this.config) { // if state is the same - skip detection. if (to === from) { return to; } var patch_1 = jiff.diff(from, to); var roots_1 = this.config.clientPush; var prefix_1 = '/' + this.config.clientLocalPrefix; patch_1 = patch_1 .filter(function (op) { return op.path.indexOf(prefix_1) < 0; }) .filter(function (op) { return op.op !== 'test'; }) .filter(function (op) { return roots_1.filter(function (root) { return op.path.indexOf(root) === 0; }).length > 0; }); if (patch_1.length > 0) { this.invocations.request(function (id) { _this.helper.send(new Events_1.PatchAreaRequest(id, _this.name, patch_1)); }); } } return to; }; return SyncArea; }()); exports.SyncArea = SyncArea;