tsbase
Version:
Base class libraries for TypeScript
175 lines • 7.63 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.EventStore = exports.NoTransactionToRedo = exports.NoTransactionToUndo = exports.StateChangeUnnecessary = void 0;
var tslib_1 = require("tslib");
var dlv_1 = tslib_1.__importDefault(require("dlv"));
var dset_1 = require("dset");
var Queryable_1 = require("../../Collections/Queryable/Queryable");
var Strings_1 = require("../../System/Strings");
var Query_1 = require("../CommandQuery/Query");
var Observable_1 = require("../Observable/Observable");
exports.StateChangeUnnecessary = 'State change unnecessary - nothing changed';
exports.NoTransactionToUndo = 'No transaction to undo';
exports.NoTransactionToRedo = 'No transaction to redo';
var EventStore = /** @class */ (function () {
function EventStore(state) {
this.state = state;
this.stateObservers = new Map();
this.ledger = new Array();
}
EventStore.prototype.GetState = function (member) {
if (typeof member === 'string') {
return this.getStateAtPath(member);
}
var clone = this.cloneOf(this.state);
return member ? member(clone) : clone;
};
EventStore.prototype.SetState = function (memberOrState, state) {
var _this = this;
return new Query_1.Query(function () {
var isGranularUpdate = ['function', 'string'].includes(typeof memberOrState) && state !== undefined;
var getCurrentState = function () {
if (isGranularUpdate && typeof memberOrState === 'function') {
return memberOrState(_this.cloneOf(_this.state));
}
else if (isGranularUpdate && typeof memberOrState === 'string') {
return _this.getStateAtPath(memberOrState);
}
else {
return _this.cloneOf(_this.state);
}
};
var newState = isGranularUpdate ? state : memberOrState;
if (JSON.stringify(getCurrentState()) !== JSON.stringify(newState)) {
_this.updateState(isGranularUpdate ? memberOrState : Strings_1.Strings.Empty, getCurrentState(), newState);
}
else {
throw new Error(exports.StateChangeUnnecessary);
}
return getCurrentState();
}).Execute();
};
EventStore.prototype.ObservableAt = function (member) {
var path = typeof member === 'string' ? member : this.getPathFromMemberFunction(member);
if (!this.stateObservers.has(path)) {
this.stateObservers.set(path, new Observable_1.Observable());
}
;
return this.stateObservers.get(path);
};
EventStore.prototype.GetLedger = function () {
return this.ledger.slice();
};
EventStore.prototype.Undo = function () {
var _this = this;
return new Query_1.Query(function () {
var queryableLedger = Queryable_1.Queryable.From(_this.ledger);
var lastVoidableTransaction = queryableLedger.Last(function (t) { return !t.voided; });
if (lastVoidableTransaction) {
lastVoidableTransaction.voided = true;
_this.updateState(lastVoidableTransaction.path, lastVoidableTransaction.toState, lastVoidableTransaction.fromState, false);
}
else {
throw new Error(exports.NoTransactionToUndo);
}
return _this.getStateAtPath(lastVoidableTransaction.path);
}).Execute();
};
EventStore.prototype.Redo = function () {
var _this = this;
return new Query_1.Query(function () {
var lastRedoableTransaction = null;
for (var index = _this.ledger.length - 1; index >= 0; index--) {
var element = _this.ledger[index];
if (!element.voided) {
break;
}
else {
lastRedoableTransaction = element;
}
}
if (lastRedoableTransaction) {
lastRedoableTransaction.voided = false;
_this.updateState(lastRedoableTransaction.path, lastRedoableTransaction.fromState, lastRedoableTransaction.toState, false);
}
else {
throw new Error(exports.NoTransactionToRedo);
}
return _this.getStateAtPath(lastRedoableTransaction.path);
}).Execute();
};
EventStore.prototype.cloneOf = function (value) {
return value ? JSON.parse(JSON.stringify(value)) : value;
};
EventStore.prototype.getPathFromMemberFunction = function (member) {
var regex = /[.][a-zA-Z0-9]*/g;
var path = Strings_1.Strings.Empty;
if (member) {
var match = void 0;
while ((match = regex.exec(member.toString())) !== null) {
var matchValue = path.length ? match[0] : match[0].replace('.', Strings_1.Strings.Empty);
path += matchValue;
}
}
return path;
};
EventStore.prototype.getStateAtPath = function (path) {
return this.cloneOf((0, dlv_1.default)(this.state, path));
};
EventStore.prototype.updateState = function (member, previousState, value, updateLedger) {
if (updateLedger === void 0) { updateLedger = true; }
if (typeof member !== 'string') {
member = this.getPathFromMemberFunction(member);
}
if (updateLedger) {
this.ledger.push({
path: member,
timestamp: Date.now(),
toState: this.cloneOf(value),
fromState: previousState,
voided: false
});
}
var rootUpdate = Strings_1.Strings.IsEmptyOrWhiteSpace(member.toString());
if (rootUpdate) {
this.state = value;
}
else {
(0, dset_1.dset)(this.state, member.toString(), value);
}
this.publishToDependentObservers(member);
};
EventStore.prototype.publishToDependentObservers = function (path) {
var _this = this;
var targetObserverKeys = this.getTargetObservers(path);
targetObserverKeys.forEach(function (key) {
_this.stateObservers.get(key).Publish(Strings_1.Strings.IsEmptyOrWhiteSpace(key) ?
_this.GetState() :
_this.cloneOf((0, dlv_1.default)(_this.state, key)));
});
};
EventStore.prototype.getTargetObservers = function (path) {
var _this = this;
var observerKeys = Array.from(this.stateObservers.keys());
return Strings_1.Strings.IsEmptyOrWhiteSpace(path) ? observerKeys :
observerKeys.filter(function (k) {
return k === Strings_1.Strings.Empty ||
k === path ||
_this.childOf(k, path) ||
_this.parentOf(k, path);
});
};
EventStore.prototype.childOf = function (parentPath, childPath) {
return parentPath.startsWith("".concat(childPath, ".")) ||
parentPath.startsWith(".".concat(childPath)) ||
parentPath.indexOf(".".concat(childPath, ".")) >= 0;
};
EventStore.prototype.parentOf = function (parentPath, childPath) {
return childPath.startsWith("".concat(parentPath, ".")) ||
childPath.startsWith(".".concat(parentPath)) ||
childPath.indexOf(".".concat(parentPath, ".")) >= 0;
};
return EventStore;
}());
exports.EventStore = EventStore;
//# sourceMappingURL=EventStore.js.map