@aitianyu.cn/tianyu-store
Version:
tianyu storage for nodejs.
210 lines • 10 kB
JavaScript
"use strict";
/** @format */
Object.defineProperty(exports, "__esModule", { value: true });
exports.StoreInstanceImpl = void 0;
const types_1 = require("@aitianyu.cn/types");
const DiffHelper_1 = require("../../common/DiffHelper");
const Message_1 = require("../../infra/Message");
const Action_1 = require("../../types/Action");
const ExternalRegister_1 = require("../modules/ExternalRegister");
const RedoUndoStackImpl_1 = require("../storage/RedoUndoStackImpl");
const RedoUndoStack_1 = require("../storage/interface/RedoUndoStack");
const StoreState_1 = require("../storage/interface/StoreState");
const InstanceIdImpl_1 = require("./InstanceIdImpl");
const InstanceParentHolder_1 = require("../modules/InstanceParentHolder");
const RedoUndoStack_2 = require("../../types/RedoUndoStack");
const ObjectUtils_1 = require("../../utils/ObjectUtils");
class StoreInstanceImpl {
// external object will not be redo/undo
// even it is created, only when the whole store instance is destroied or delete it manually,
// the external objects are always kept
externalObjectMap;
parentChildHolder;
storeState;
instanceId;
changeCache;
diffCache;
constructor(state, instanceId) {
this.storeState = state;
this.changeCache = {};
this.diffCache = {};
this.instanceId = instanceId;
this.externalObjectMap = new Map();
this.parentChildHolder = new InstanceParentHolder_1.InstanceParentHolder();
// to init the root external register
const externalRegister = new ExternalRegister_1.ExternalRegister();
if (this.storeState[StoreState_1.STORE_STATE_SYSTEM].config.redoUndo) {
externalRegister.add(RedoUndoStack_1.STORE_STATE_EXTERNAL_REDOUNDO_STACK, new RedoUndoStackImpl_1.RedoUndoStackImpl());
}
this.externalObjectMap.set(instanceId.toString(), externalRegister);
}
getRecentChanges() {
const redoUndoStack = this.externalObjectMap
.get(this.instanceId.toString())
?.get(RedoUndoStack_1.STORE_STATE_EXTERNAL_REDOUNDO_STACK);
return redoUndoStack?.getCurrent() || {};
}
getHistories() {
const redoUndoStack = this.externalObjectMap
.get(this.instanceId.toString())
?.get(RedoUndoStack_1.STORE_STATE_EXTERNAL_REDOUNDO_STACK);
return redoUndoStack?.getHistroies() || /* istanbul ignore next */ { histroy: [], index: -1 };
}
addStoreType(storeType) {
if (!this.storeState[StoreState_1.STORE_STATE_INSTANCE][storeType]) {
this.storeState[StoreState_1.STORE_STATE_INSTANCE][storeType] = {};
}
}
getRawState() {
return types_1.ObjectHelper.clone(this.storeState);
}
getExternalRegister(instanceId, creating) {
const externalObject = this.externalObjectMap.get(instanceId.toString());
if (!externalObject) {
throw new Error(Message_1.MessageBundle.getText("STORE_INSTANCE_EXTRERNAL_MANAGER_NOT_FOUND", instanceId.toString()));
}
return externalObject;
}
getState(instanceId, creating) {
if (InstanceIdImpl_1.InstanceIdImpl.isAncestor(instanceId)) {
// if the instance id indicates an entity it self
// return whole store state
return this.storeState;
}
const instanceId2String = instanceId.toString();
const storeType = instanceId.storeType;
if (!storeType) {
throw new Error(Message_1.MessageBundle.getText("INSTANCE_ID_NOT_VALID", instanceId2String));
}
const cachedState = this.changeCache[storeType]?.[instanceId2String];
if (cachedState?.type === RedoUndoStack_2.DifferenceChangeType.Delete) {
// instance is deleted and it does not be able to be used
throw new Error(Message_1.MessageBundle.getText("STORE_INSTANCE_USE_DELETED", storeType, instanceId2String));
}
const instances = this.storeState[StoreState_1.STORE_STATE_INSTANCE][storeType];
const ins = cachedState?.state || instances[instanceId2String];
if (!ins && !creating) {
throw new Error(Message_1.MessageBundle.getText("STORE_INSTANCE_NOT_EXIST", instanceId2String));
}
return ins;
}
getOriginState(instanceId) {
if (InstanceIdImpl_1.InstanceIdImpl.isAncestor(instanceId)) {
// if the instance id indicates an entity it self
// return whole store state
return this.storeState;
}
const instanceId2String = instanceId.toString();
const storeType = instanceId.storeType;
if (!storeType) {
throw new Error(Message_1.MessageBundle.getText("INSTANCE_ID_NOT_VALID", instanceId2String));
}
const instances = this.storeState[StoreState_1.STORE_STATE_INSTANCE][storeType];
const ins = instances[instanceId2String];
if (!ins) {
throw new Error(Message_1.MessageBundle.getText("STORE_INSTANCE_NOT_EXIST", instanceId2String));
}
return ins;
}
applyChanges() {
let redoUndoSupport = true;
let recordRedoUndo = true;
const diff = this.diffCache;
this.diffCache = {};
if ((0, ObjectUtils_1.isChangesEmpty)(diff)) {
const changes = this.changeCache;
this.changeCache = {};
for (const storyType of Object.keys(changes)) {
const instances = changes[storyType];
for (const insId of Object.keys(instances)) {
const changeItem = instances[insId];
const oldState = this.storeState[StoreState_1.STORE_STATE_INSTANCE][storyType]?.[insId];
if (types_1.ObjectHelper.compareObjects(oldState, changeItem.state) === "different") {
// ensure the state is changed
if (!diff[storyType]) {
diff[storyType] = {};
}
diff[storyType][insId] = {
new: changeItem.state,
old: oldState,
type: changeItem.type,
};
}
if (changeItem.type === RedoUndoStack_2.DifferenceChangeType.Create) {
this.parentChildHolder.createInstance(new InstanceIdImpl_1.InstanceIdImpl(insId), this.storeState[StoreState_1.STORE_STATE_SYSTEM].instanceMap);
}
// this is for state redo/undo checking
// when there is a view action
// should clean all redo/undo stack due to the state is could not be navigated
redoUndoSupport = redoUndoSupport && changeItem.redoUndo;
// this is for state redo/undo recording checking
// when there is a redo/undo action
// should not to record the state change again
recordRedoUndo = recordRedoUndo && changeItem.record;
}
}
}
else {
recordRedoUndo = false;
}
this.storeState = (0, DiffHelper_1.mergeDiff)(this.storeState, diff);
this.parentChildHolder.applyChanges(this.storeState[StoreState_1.STORE_STATE_SYSTEM].instanceMap);
const redoUndoStack = this.externalObjectMap
.get(this.instanceId.toString())
?.get(RedoUndoStack_1.STORE_STATE_EXTERNAL_REDOUNDO_STACK);
if (redoUndoSupport) {
recordRedoUndo && redoUndoStack?.record(diff);
}
else {
redoUndoStack?.resetRedoUndo();
}
return diff;
}
discardChanges() {
this.changeCache = {};
this.parentChildHolder.discardChanges();
}
pushStateChange(storeType, instanceId, actionType, newState, notRedoUndo) {
if (!this.changeCache[storeType]) {
this.changeCache[storeType] = {};
}
const redoUndo = !notRedoUndo && actionType !== Action_1.ActionType.VIEW_ACTION;
const record = actionType !== Action_1.ActionType.REDO && actionType !== Action_1.ActionType.UNDO;
this.changeCache[storeType][instanceId] = {
state: newState,
type: actionType === Action_1.ActionType.CREATE
? RedoUndoStack_2.DifferenceChangeType.Create
: actionType === Action_1.ActionType.DESTROY
? RedoUndoStack_2.DifferenceChangeType.Delete
: RedoUndoStack_2.DifferenceChangeType.Change,
redoUndo,
record,
};
if (actionType === Action_1.ActionType.CREATE) {
// for create new instance, to create a new external object manager
this.externalObjectMap.set(instanceId, new ExternalRegister_1.ExternalRegister());
}
if (actionType === Action_1.ActionType.DESTROY) {
// for destroy instance, to destroy its children
const instances = this.parentChildHolder.removeInstance(instanceId, this.storeState[StoreState_1.STORE_STATE_SYSTEM].instanceMap);
for (const insId of instances) {
const ins = new InstanceIdImpl_1.InstanceIdImpl(insId);
const storeType = ins.storeType;
this.changeCache[storeType][insId] = {
state: undefined,
type: RedoUndoStack_2.DifferenceChangeType.Delete,
redoUndo,
record,
};
}
}
}
pushDiffChange(diff) {
this.diffCache = diff;
}
validateActionInstance(action) {
//
}
}
exports.StoreInstanceImpl = StoreInstanceImpl;
//# sourceMappingURL=StoreInstanceImpl.js.map