cache开启和关闭事务机制的再整理

This commit is contained in:
Xu Chang 2024-03-28 14:58:04 +08:00
parent e7ba378388
commit 7715cccca6
22 changed files with 426 additions and 320 deletions

View File

@ -119,7 +119,7 @@ export declare class Cache<ED extends EntityDict & BaseEntityDict, Cxt extends A
unbindOnSync(callback: (opRecords: OpRecord<ED>[]) => void): void;
getCachedData(): { [T in keyof ED]?: ED[T]["OpSchema"][] | undefined; };
getFullData(): any;
begin(): FrontCxt;
begin(allowExists?: boolean): FrontCxt | undefined;
commit(): void;
rollback(): void;
getContext(): FrontCxt;

View File

@ -486,8 +486,13 @@ export class Cache extends Feature {
getFullData() {
return this.getFullDataFn();
}
begin() {
assert(!this.context);
begin(allowExists) {
if (this.context) {
if (allowExists) {
return;
}
assert(false);
}
this.context = this.contextBuilder();
this.context.begin();
return this.context;

View File

@ -74,68 +74,74 @@ export class ContextMenuFactory extends Feature {
}
getMenusByContext(entity, entityId) {
assert(this.menus, '应当先调用setMenus才能动态判定菜单');
this.cache.begin();
const menus = this.menus
.filter((menu) => {
const { entity: destEntity, paths, action } = menu;
// 如果没有关联在entity上则默认显示由页面自己处理用户权限
if (!destEntity || !paths) {
return true;
}
assert(action);
const filters = paths && paths.length > 0
? this.makeMenuFilters(destEntity, paths, entity, entityId)
: [{}]; // 如果没有path视为无法推断操作的filter直接返回无任何限制
if (filters.length > 0) {
// 这里应该是or关系paths表达的路径中只要有一条满足就可能满足
const allows = filters.map((filter) => {
if (filter === true) {
return true;
}
// relationAuth和其它的checker现在分开判断
let result = false;
if (action instanceof Array) {
for (let i = 0; i < action.length; i++) {
// action有一个满足就行了
const checkResult = this.relationAuth.checkRelation(destEntity, {
action: action[i],
filter,
}) &&
this.cache.checkOperation(destEntity, {
action: action[i],
filter: filter,
}, [
'logical',
'row',
]);
if (checkResult) {
result = checkResult === true;
break;
}
}
return result;
}
return (this.relationAuth.checkRelation(destEntity, {
action,
filter,
}) &&
this.cache.checkOperation(destEntity, {
action,
filter: filter,
}, [
'logical',
'row',
]));
});
if (allows.indexOf(true) >= 0) {
const needRollback = !!this.cache.begin(true);
try {
const menus = this.menus
.filter((menu) => {
const { entity: destEntity, paths, action } = menu;
// 如果没有关联在entity上则默认显示由页面自己处理用户权限
if (!destEntity || !paths) {
return true;
}
assert(action);
const filters = paths && paths.length > 0
? this.makeMenuFilters(destEntity, paths, entity, entityId)
: [{}]; // 如果没有path视为无法推断操作的filter直接返回无任何限制
if (filters.length > 0) {
// 这里应该是or关系paths表达的路径中只要有一条满足就可能满足
const allows = filters.map((filter) => {
if (filter === true) {
return true;
}
// relationAuth和其它的checker现在分开判断
let result = false;
if (action instanceof Array) {
for (let i = 0; i < action.length; i++) {
// action有一个满足就行了
const checkResult = this.relationAuth.checkRelation(destEntity, {
action: action[i],
filter,
}) &&
this.cache.checkOperation(destEntity, {
action: action[i],
filter: filter,
}, [
'logical',
'row',
]);
if (checkResult) {
result = checkResult === true;
break;
}
}
return result;
}
return (this.relationAuth.checkRelation(destEntity, {
action,
filter,
}) &&
this.cache.checkOperation(destEntity, {
action,
filter: filter,
}, [
'logical',
'row',
]));
});
if (allows.indexOf(true) >= 0) {
return true;
}
return false;
}
return false;
}
return false;
})
.map((wrapper) => omit(wrapper, ['filtersMaker']));
this.cache.rollback();
return menus;
})
.map((wrapper) => omit(wrapper, ['filtersMaker']));
needRollback && this.cache.rollback();
return menus;
}
catch (err) {
needRollback && this.cache.rollback();
throw err;
}
}
}

View File

@ -249,8 +249,7 @@ export declare class RunningTree<ED extends EntityDict & BaseEntityDict, Cxt ext
checkIsModiNode(path: string): boolean;
private findNode;
destroyNode(path: string): void;
redoBranchOperations(path: string): void;
rollbackRedoBranchOperations(): void;
redoBranchOperations(path: string): () => void;
getFreshValue(path: string): Partial<ED[keyof ED]["Schema"]> | Partial<ED[keyof ED]["Schema"]>[] | undefined;
isDirty(path: string): boolean;
addItem<T extends keyof ED>(path: string, data: Omit<ED[T]['CreateSingle']['data'], 'id'> & {

View File

@ -1656,18 +1656,19 @@ export class RunningTree extends Feature {
const paths = path.split('.');
const root = this.root[paths[0]];
const opers = root.composeOperations();
this.cache.begin();
if (opers) {
this.cache.redoOperation(opers);
const cxt = this.cache.begin();
if (cxt) {
if (opers) {
this.cache.redoOperation(opers);
}
const includeModi = path.includes(MODI_NEXT_PATH_SUFFIX);
if (includeModi) {
const modiOperations = (root instanceof SingleNode || root instanceof VirtualNode) && root.getModiOperations();
modiOperations && this.cache.redoOperation(modiOperations);
}
return () => this.cache.rollback();
}
const includeModi = path.includes(MODI_NEXT_PATH_SUFFIX);
if (includeModi) {
const modiOperations = (root instanceof SingleNode || root instanceof VirtualNode) && root.getModiOperations();
modiOperations && this.cache.redoOperation(modiOperations);
}
}
rollbackRedoBranchOperations() {
this.cache.rollback();
return () => undefined;
}
getFreshValue(path) {
const node = this.findNode(path);

View File

@ -405,7 +405,7 @@ export function reRender(option, extra) {
const localeState = features.locales.getState();
if (this.state.oakEntity && this.state.oakFullpath) {
// 现在取数据需要把runningTree上的更新应用了再取判定actions也一样
this.features.runningTree.redoBranchOperations(this.state.oakFullpath);
const cleanFn = this.features.runningTree.redoBranchOperations(this.state.oakFullpath);
try {
const rows = this.features.runningTree.getFreshValue(this.state.oakFullpath);
const oakLegalActions = rows && checkActionsAndCascadeEntities.call(this, rows, option);
@ -459,10 +459,10 @@ export function reRender(option, extra) {
Object.assign(data, extra);
}
this.setState(data);
this.features.runningTree.rollbackRedoBranchOperations();
cleanFn();
}
catch (err) {
this.features.runningTree.rollbackRedoBranchOperations();
cleanFn();
throw err;
}
}

View File

@ -188,10 +188,16 @@ const oakBehavior = Behavior({
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.redoBranchOperations(path2);
const value = this.features.runningTree.getFreshValue(path2);
this.features.runningTree.rollbackRedoBranchOperations();
return value;
const cleanFn = this.features.runningTree.redoBranchOperations(path2);
try {
const value = this.features.runningTree.getFreshValue(path2);
cleanFn();
return value;
}
catch (err) {
cleanFn();
throw err;
}
},
checkOperation(entity, { action, data, filter }, checkerTypes) {
if (checkerTypes?.includes('relation')) {
@ -459,11 +465,17 @@ const oakBehavior = Behavior({
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.redoBranchOperations(path2);
const value = this.features.runningTree.getFreshValue(path2);
this.features.runningTree.rollbackRedoBranchOperations();
assert(!(value instanceof Array));
return value?.$$createAt$$ === 1;
const cleanFn = this.features.runningTree.redoBranchOperations(path2);
try {
const value = this.features.runningTree.getFreshValue(path2);
assert(!(value instanceof Array));
cleanFn();
return value?.$$createAt$$ === 1;
}
catch (err) {
cleanFn();
throw err;
}
},
async aggregate(aggregation) {
return await this.features.cache.aggregate(this.state.oakEntity, aggregation);

View File

@ -151,11 +151,17 @@ class OakComponentBase extends React.PureComponent {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.redoBranchOperations(path2);
const value = this.features.runningTree.getFreshValue(path2);
this.features.runningTree.rollbackRedoBranchOperations();
assert(!(value instanceof Array));
return value?.$$createAt$$ === 1;
const cleanFn = this.features.runningTree.redoBranchOperations(path2);
try {
const value = this.features.runningTree.getFreshValue(path2);
assert(!(value instanceof Array));
cleanFn();
return value?.$$createAt$$ === 1;
}
catch (err) {
cleanFn();
throw err;
}
}
clean(path) {
const path2 = path
@ -176,10 +182,16 @@ class OakComponentBase extends React.PureComponent {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.redoBranchOperations(path2);
const value = this.features.runningTree.getFreshValue(path2);
this.features.runningTree.rollbackRedoBranchOperations();
return value;
const cleanFn = this.features.runningTree.redoBranchOperations(path2);
try {
const value = this.features.runningTree.getFreshValue(path2);
cleanFn();
return value;
}
catch (err) {
cleanFn();
throw err;
}
}
checkOperation(entity, operation, checkerTypes) {
if (checkerTypes?.includes('relation')) {

View File

@ -119,7 +119,7 @@ export declare class Cache<ED extends EntityDict & BaseEntityDict, Cxt extends A
unbindOnSync(callback: (opRecords: OpRecord<ED>[]) => void): void;
getCachedData(): { [T in keyof ED]?: ED[T]["OpSchema"][] | undefined; };
getFullData(): any;
begin(): FrontCxt;
begin(allowExists?: boolean): FrontCxt | undefined;
commit(): void;
rollback(): void;
getContext(): FrontCxt;

View File

@ -489,8 +489,13 @@ class Cache extends Feature_1.Feature {
getFullData() {
return this.getFullDataFn();
}
begin() {
(0, assert_1.assert)(!this.context);
begin(allowExists) {
if (this.context) {
if (allowExists) {
return;
}
(0, assert_1.assert)(false);
}
this.context = this.contextBuilder();
this.context.begin();
return this.context;

View File

@ -77,69 +77,75 @@ class ContextMenuFactory extends Feature_1.Feature {
}
getMenusByContext(entity, entityId) {
(0, assert_1.assert)(this.menus, '应当先调用setMenus才能动态判定菜单');
this.cache.begin();
const menus = this.menus
.filter((menu) => {
const { entity: destEntity, paths, action } = menu;
// 如果没有关联在entity上则默认显示由页面自己处理用户权限
if (!destEntity || !paths) {
return true;
}
(0, assert_1.assert)(action);
const filters = paths && paths.length > 0
? this.makeMenuFilters(destEntity, paths, entity, entityId)
: [{}]; // 如果没有path视为无法推断操作的filter直接返回无任何限制
if (filters.length > 0) {
// 这里应该是or关系paths表达的路径中只要有一条满足就可能满足
const allows = filters.map((filter) => {
if (filter === true) {
return true;
}
// relationAuth和其它的checker现在分开判断
let result = false;
if (action instanceof Array) {
for (let i = 0; i < action.length; i++) {
// action有一个满足就行了
const checkResult = this.relationAuth.checkRelation(destEntity, {
action: action[i],
filter,
}) &&
this.cache.checkOperation(destEntity, {
action: action[i],
filter: filter,
}, [
'logical',
'row',
]);
if (checkResult) {
result = checkResult === true;
break;
}
}
return result;
}
return (this.relationAuth.checkRelation(destEntity, {
action,
filter,
}) &&
this.cache.checkOperation(destEntity, {
action,
filter: filter,
}, [
'logical',
'row',
]));
});
if (allows.indexOf(true) >= 0) {
const needRollback = !!this.cache.begin(true);
try {
const menus = this.menus
.filter((menu) => {
const { entity: destEntity, paths, action } = menu;
// 如果没有关联在entity上则默认显示由页面自己处理用户权限
if (!destEntity || !paths) {
return true;
}
(0, assert_1.assert)(action);
const filters = paths && paths.length > 0
? this.makeMenuFilters(destEntity, paths, entity, entityId)
: [{}]; // 如果没有path视为无法推断操作的filter直接返回无任何限制
if (filters.length > 0) {
// 这里应该是or关系paths表达的路径中只要有一条满足就可能满足
const allows = filters.map((filter) => {
if (filter === true) {
return true;
}
// relationAuth和其它的checker现在分开判断
let result = false;
if (action instanceof Array) {
for (let i = 0; i < action.length; i++) {
// action有一个满足就行了
const checkResult = this.relationAuth.checkRelation(destEntity, {
action: action[i],
filter,
}) &&
this.cache.checkOperation(destEntity, {
action: action[i],
filter: filter,
}, [
'logical',
'row',
]);
if (checkResult) {
result = checkResult === true;
break;
}
}
return result;
}
return (this.relationAuth.checkRelation(destEntity, {
action,
filter,
}) &&
this.cache.checkOperation(destEntity, {
action,
filter: filter,
}, [
'logical',
'row',
]));
});
if (allows.indexOf(true) >= 0) {
return true;
}
return false;
}
return false;
}
return false;
})
.map((wrapper) => (0, lodash_1.omit)(wrapper, ['filtersMaker']));
this.cache.rollback();
return menus;
})
.map((wrapper) => (0, lodash_1.omit)(wrapper, ['filtersMaker']));
needRollback && this.cache.rollback();
return menus;
}
catch (err) {
needRollback && this.cache.rollback();
throw err;
}
}
}
exports.ContextMenuFactory = ContextMenuFactory;

View File

@ -249,8 +249,7 @@ export declare class RunningTree<ED extends EntityDict & BaseEntityDict, Cxt ext
checkIsModiNode(path: string): boolean;
private findNode;
destroyNode(path: string): void;
redoBranchOperations(path: string): void;
rollbackRedoBranchOperations(): void;
redoBranchOperations(path: string): () => void;
getFreshValue(path: string): Partial<ED[keyof ED]["Schema"]> | Partial<ED[keyof ED]["Schema"]>[] | undefined;
isDirty(path: string): boolean;
addItem<T extends keyof ED>(path: string, data: Omit<ED[T]['CreateSingle']['data'], 'id'> & {

View File

@ -1659,18 +1659,19 @@ class RunningTree extends Feature_1.Feature {
const paths = path.split('.');
const root = this.root[paths[0]];
const opers = root.composeOperations();
this.cache.begin();
if (opers) {
this.cache.redoOperation(opers);
const cxt = this.cache.begin();
if (cxt) {
if (opers) {
this.cache.redoOperation(opers);
}
const includeModi = path.includes(exports.MODI_NEXT_PATH_SUFFIX);
if (includeModi) {
const modiOperations = (root instanceof SingleNode || root instanceof VirtualNode) && root.getModiOperations();
modiOperations && this.cache.redoOperation(modiOperations);
}
return () => this.cache.rollback();
}
const includeModi = path.includes(exports.MODI_NEXT_PATH_SUFFIX);
if (includeModi) {
const modiOperations = (root instanceof SingleNode || root instanceof VirtualNode) && root.getModiOperations();
modiOperations && this.cache.redoOperation(modiOperations);
}
}
rollbackRedoBranchOperations() {
this.cache.rollback();
return () => undefined;
}
getFreshValue(path) {
const node = this.findNode(path);

View File

@ -409,7 +409,7 @@ function reRender(option, extra) {
const localeState = features.locales.getState();
if (this.state.oakEntity && this.state.oakFullpath) {
// 现在取数据需要把runningTree上的更新应用了再取判定actions也一样
this.features.runningTree.redoBranchOperations(this.state.oakFullpath);
const cleanFn = this.features.runningTree.redoBranchOperations(this.state.oakFullpath);
try {
const rows = this.features.runningTree.getFreshValue(this.state.oakFullpath);
const oakLegalActions = rows && checkActionsAndCascadeEntities.call(this, rows, option);
@ -463,10 +463,10 @@ function reRender(option, extra) {
Object.assign(data, extra);
}
this.setState(data);
this.features.runningTree.rollbackRedoBranchOperations();
cleanFn();
}
catch (err) {
this.features.runningTree.rollbackRedoBranchOperations();
cleanFn();
throw err;
}
}

View File

@ -191,10 +191,16 @@ const oakBehavior = Behavior({
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.redoBranchOperations(path2);
const value = this.features.runningTree.getFreshValue(path2);
this.features.runningTree.rollbackRedoBranchOperations();
return value;
const cleanFn = this.features.runningTree.redoBranchOperations(path2);
try {
const value = this.features.runningTree.getFreshValue(path2);
cleanFn();
return value;
}
catch (err) {
cleanFn();
throw err;
}
},
checkOperation(entity, { action, data, filter }, checkerTypes) {
if (checkerTypes?.includes('relation')) {
@ -462,11 +468,17 @@ const oakBehavior = Behavior({
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.redoBranchOperations(path2);
const value = this.features.runningTree.getFreshValue(path2);
this.features.runningTree.rollbackRedoBranchOperations();
(0, assert_1.assert)(!(value instanceof Array));
return value?.$$createAt$$ === 1;
const cleanFn = this.features.runningTree.redoBranchOperations(path2);
try {
const value = this.features.runningTree.getFreshValue(path2);
(0, assert_1.assert)(!(value instanceof Array));
cleanFn();
return value?.$$createAt$$ === 1;
}
catch (err) {
cleanFn();
throw err;
}
},
async aggregate(aggregation) {
return await this.features.cache.aggregate(this.state.oakEntity, aggregation);

View File

@ -156,11 +156,17 @@ class OakComponentBase extends react_1.default.PureComponent {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.redoBranchOperations(path2);
const value = this.features.runningTree.getFreshValue(path2);
this.features.runningTree.rollbackRedoBranchOperations();
(0, assert_1.assert)(!(value instanceof Array));
return value?.$$createAt$$ === 1;
const cleanFn = this.features.runningTree.redoBranchOperations(path2);
try {
const value = this.features.runningTree.getFreshValue(path2);
(0, assert_1.assert)(!(value instanceof Array));
cleanFn();
return value?.$$createAt$$ === 1;
}
catch (err) {
cleanFn();
throw err;
}
}
clean(path) {
const path2 = path
@ -181,10 +187,16 @@ class OakComponentBase extends react_1.default.PureComponent {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.redoBranchOperations(path2);
const value = this.features.runningTree.getFreshValue(path2);
this.features.runningTree.rollbackRedoBranchOperations();
return value;
const cleanFn = this.features.runningTree.redoBranchOperations(path2);
try {
const value = this.features.runningTree.getFreshValue(path2);
cleanFn();
return value;
}
catch (err) {
cleanFn();
throw err;
}
}
checkOperation(entity, operation, checkerTypes) {
if (checkerTypes?.includes('relation')) {

View File

@ -655,8 +655,13 @@ export class Cache<
return this.getFullDataFn();
}
begin() {
assert(!this.context);
begin(allowExists?: boolean) {
if (this.context) {
if (allowExists) {
return;
}
assert(false);
}
this.context = this.contextBuilder!();
this.context.begin();
return this.context;

View File

@ -23,7 +23,7 @@ export class ContextMenuFactory<
Cxt extends AsyncContext<ED>,
FrontCxt extends SyncContext<ED>,
AD extends CommonAspectDict<ED, Cxt> & Record<string, Aspect<ED, Cxt>>
> extends Feature {
> extends Feature {
cache: Cache<ED, Cxt, FrontCxt, AD>;
menus?: IMenu<ED, keyof ED>[];
relationAuth: RelationAuth<ED, Cxt, FrontCxt, AD>;
@ -122,93 +122,99 @@ export class ContextMenuFactory<
entityId: string
) {
assert(this.menus, '应当先调用setMenus才能动态判定菜单');
this.cache.begin();
const menus = this.menus
.filter((menu) => {
const { entity: destEntity, paths, action } = menu;
// 如果没有关联在entity上则默认显示由页面自己处理用户权限
if (!destEntity || !paths) {
return true;
}
assert(action);
const filters =
paths && paths.length > 0
? this.makeMenuFilters(
destEntity!,
paths!,
entity,
entityId
)
: [{}]; // 如果没有path视为无法推断操作的filter直接返回无任何限制
if (filters.length > 0) {
// 这里应该是or关系paths表达的路径中只要有一条满足就可能满足
const allows = filters.map((filter) => {
if (filter === true) {
return true;
}
// relationAuth和其它的checker现在分开判断
let result = false;
if (action instanceof Array) {
for (let i = 0; i < action.length; i++) {
// action有一个满足就行了
const checkResult =
this.relationAuth.checkRelation(
destEntity,
{
action: action[i],
filter,
} as Omit<
ED[keyof ED]['Operation'],
'id'
>
) &&
this.cache.checkOperation(
destEntity,
{
action: action[i],
filter: filter,
} as Omit<ED[keyof ED]['Operation'], 'id'>,
[
'logical',
'row',
]
);
if (checkResult) {
result = checkResult === true;
break;
}
}
return result;
}
return (
this.relationAuth.checkRelation(destEntity, {
action,
filter,
} as Omit<ED[keyof ED]['Operation'], 'id'>) &&
this.cache.checkOperation(
destEntity,
{
action,
filter: filter,
} as Omit<ED[keyof ED]['Operation'], 'id'>,
[
'logical',
'row',
]
)
);
});
if (allows.indexOf(true) >= 0) {
const needRollback = !!this.cache.begin(true);
try {
const menus = this.menus
.filter((menu) => {
const { entity: destEntity, paths, action } = menu;
// 如果没有关联在entity上则默认显示由页面自己处理用户权限
if (!destEntity || !paths) {
return true;
}
return false;
}
return false;
})
.map((wrapper) => omit(wrapper, ['filtersMaker'])) as OMenu[];
this.cache.rollback();
assert(action);
const filters =
paths && paths.length > 0
? this.makeMenuFilters(
destEntity!,
paths!,
entity,
entityId
)
: [{}]; // 如果没有path视为无法推断操作的filter直接返回无任何限制
if (filters.length > 0) {
// 这里应该是or关系paths表达的路径中只要有一条满足就可能满足
const allows = filters.map((filter) => {
if (filter === true) {
return true;
}
// relationAuth和其它的checker现在分开判断
let result = false;
if (action instanceof Array) {
for (let i = 0; i < action.length; i++) {
// action有一个满足就行了
const checkResult =
this.relationAuth.checkRelation(
destEntity,
{
action: action[i],
filter,
} as Omit<
ED[keyof ED]['Operation'],
'id'
>
) &&
this.cache.checkOperation(
destEntity,
{
action: action[i],
filter: filter,
} as Omit<ED[keyof ED]['Operation'], 'id'>,
[
'logical',
'row',
]
);
return menus;
if (checkResult) {
result = checkResult === true;
break;
}
}
return result;
}
return (
this.relationAuth.checkRelation(destEntity, {
action,
filter,
} as Omit<ED[keyof ED]['Operation'], 'id'>) &&
this.cache.checkOperation(
destEntity,
{
action,
filter: filter,
} as Omit<ED[keyof ED]['Operation'], 'id'>,
[
'logical',
'row',
]
)
);
});
if (allows.indexOf(true) >= 0) {
return true;
}
return false;
}
return false;
})
.map((wrapper) => omit(wrapper, ['filtersMaker'])) as OMenu[];
needRollback && this.cache.rollback();
return menus;
}
catch (err) {
needRollback && this.cache.rollback();
throw err;
}
}
}

View File

@ -229,7 +229,7 @@ class ListNode<
case 'c': {
const { e, d } = record as CreateOpResult<ED, T>;
if (e === this.entity) {
const context = this.cache.begin();
const context = this.cache.begin()!;
const { filter } = this.constructSelection();
if (d instanceof Array) {
d.forEach(
@ -276,7 +276,7 @@ class ListNode<
}
}
else {
const context = this.cache.begin();
const context = this.cache.begin()!;
for (const id in this.sr) {
if (!f || checkFilterContains<ED, T, FrontCxt>(e, context, f, { id }, true)) {
unset(this.sr, id);
@ -625,7 +625,7 @@ class ListNode<
private removeItemInner(id: string) {
if (this.updates[id] && this.updates[id].action === 'create') {
// 如果是新增项,在这里抵消
unset(this.updates, id);
unset(this.updates, id);
} else {
this.updates[id] = {
id: generateNewId(),
@ -1012,7 +1012,7 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
}
}
}
getModiOperations(): Array<{
entity: keyof ED;
operation: ED[keyof ED]['Operation'];
@ -2023,20 +2023,21 @@ export class RunningTree<
const root = this.root[paths[0]];
const opers = root.composeOperations();
this.cache.begin();
if (opers) {
this.cache.redoOperation(opers);
}
const includeModi = path.includes(MODI_NEXT_PATH_SUFFIX);
if (includeModi) {
const modiOperations = (root instanceof SingleNode || root instanceof VirtualNode) && root.getModiOperations();
modiOperations && this.cache.redoOperation(modiOperations);
}
}
const cxt = this.cache.begin();
if (cxt) {
if (opers) {
this.cache.redoOperation(opers);
}
rollbackRedoBranchOperations() {
this.cache.rollback();
const includeModi = path.includes(MODI_NEXT_PATH_SUFFIX);
if (includeModi) {
const modiOperations = (root instanceof SingleNode || root instanceof VirtualNode) && root.getModiOperations();
modiOperations && this.cache.redoOperation(modiOperations);
}
return () => this.cache.rollback();
}
return () => undefined;
}
getFreshValue(path: string) {

View File

@ -505,7 +505,7 @@ export function reRender<
const localeState = features.locales.getState();
if (this.state.oakEntity && this.state.oakFullpath) {
// 现在取数据需要把runningTree上的更新应用了再取判定actions也一样
this.features.runningTree.redoBranchOperations(this.state.oakFullpath);
const cleanFn = this.features.runningTree.redoBranchOperations(this.state.oakFullpath);
try {
const rows = this.features.runningTree.getFreshValue(this.state.oakFullpath);
const oakLegalActions = rows && checkActionsAndCascadeEntities.call(
@ -570,10 +570,10 @@ export function reRender<
}
this.setState(data);
this.features.runningTree.rollbackRedoBranchOperations();
cleanFn();
}
catch (err) {
this.features.runningTree.rollbackRedoBranchOperations();
cleanFn();
throw err;
}
} else {

View File

@ -322,10 +322,16 @@ const oakBehavior = Behavior<
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.redoBranchOperations(path2);
const value = this.features.runningTree.getFreshValue(path2);
this.features.runningTree.rollbackRedoBranchOperations();
return value;
const cleanFn = this.features.runningTree.redoBranchOperations(path2);
try {
const value = this.features.runningTree.getFreshValue(path2);
cleanFn();
return value;
}
catch (err) {
cleanFn();
throw err;
}
},
checkOperation(entity, { action, data, filter }, checkerTypes) {
@ -675,11 +681,17 @@ const oakBehavior = Behavior<
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.redoBranchOperations(path2);
const value = this.features.runningTree.getFreshValue(path2);
this.features.runningTree.rollbackRedoBranchOperations();
assert(!(value instanceof Array));
return value?.$$createAt$$ === 1;
const cleanFn = this.features.runningTree.redoBranchOperations(path2);
try {
const value = this.features.runningTree.getFreshValue(path2);
assert(!(value instanceof Array));
cleanFn();
return value?.$$createAt$$ === 1;
}
catch (err) {
cleanFn();
throw err;
}
},
async aggregate(aggregation) {

View File

@ -304,11 +304,17 @@ abstract class OakComponentBase<
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.redoBranchOperations(path2);
const value = this.features.runningTree.getFreshValue(path2);
this.features.runningTree.rollbackRedoBranchOperations();
assert(!(value instanceof Array));
return value?.$$createAt$$ === 1;
const cleanFn = this.features.runningTree.redoBranchOperations(path2);
try {
const value = this.features.runningTree.getFreshValue(path2);
assert(!(value instanceof Array));
cleanFn();
return value?.$$createAt$$ === 1;
}
catch (err) {
cleanFn();
throw err;
}
}
clean(path?: string) {
@ -338,10 +344,16 @@ abstract class OakComponentBase<
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.redoBranchOperations(path2);
const value = this.features.runningTree.getFreshValue(path2);
this.features.runningTree.rollbackRedoBranchOperations();
return value;
const cleanFn = this.features.runningTree.redoBranchOperations(path2);
try {
const value = this.features.runningTree.getFreshValue(path2);
cleanFn();
return value;
}
catch (err) {
cleanFn();
throw err;
}
}
checkOperation<T2 extends keyof ED>(