对cache中的context进行了单例化,一个cache在一次begin/end之间使用唯一的context

This commit is contained in:
Xu Chang 2023-08-28 21:21:17 +08:00
parent 1ce9e13101
commit f00f50b45a
13 changed files with 176 additions and 134 deletions

View File

@ -5,7 +5,6 @@
.title {
padding-block: 20px 10px;
padding-inline: 10px;
color: #888;
font-size: 14px;
font-weight: 500;
text-align: left;
@ -24,6 +23,7 @@
.renderLabel {
min-width: 140px;
margin-right: 16px;
color: rgba(0, 0, 0, 0.45);
}
.renderValue {
display: -webkit-box;

View File

@ -20,13 +20,13 @@ export declare class Cache<ED extends EntityDict & BaseEntityDict, Cxt extends A
private localStorage;
private getFullDataFn;
private refreshRecords;
private context?;
constructor(storageSchema: StorageSchema<ED>, aspectWrapper: AspectWrapper<ED, Cxt, AD>, frontendContextBuilder: () => (store: CacheStore<ED, FrontCxt>) => FrontCxt, checkers: Array<Checker<ED, keyof ED, FrontCxt | Cxt>>, getFullData: () => any, localStorage: LocalStorage, savedEntities?: (keyof ED)[], keepFreshPeriod?: number);
/**
* cache中需要缓存的数据
*/
private initSavedLogic;
getSchema(): StorageSchema<ED>;
getCurrentUserId(allowUnloggedIn?: boolean): string | undefined;
exec<K extends keyof AD>(name: K, params: Parameters<AD[K]>[0], callback?: (result: Awaited<ReturnType<AD[K]>>, opRecords?: OpRecord<ED>[]) => void, dontPublish?: true): Promise<{
result: Awaited<ReturnType<AD[K]>>;
message: string | null | undefined;
@ -76,16 +76,16 @@ export declare class Cache<ED extends EntityDict & BaseEntityDict, Cxt extends A
redoOperation(opers: Array<{
entity: keyof ED;
operation: ED[keyof ED]['Operation'];
}>, context: FrontCxt): void;
}>): void;
private getInner;
get<T extends keyof ED>(entity: T, selection: ED[T]['Selection'], context?: FrontCxt, allowMiss?: boolean): Partial<ED[T]["Schema"]>[];
get<T extends keyof ED>(entity: T, selection: ED[T]['Selection'], allowMiss?: boolean): Partial<ED[T]["Schema"]>[];
judgeRelation(entity: keyof ED, attr: string): string | 0 | 1 | string[] | 2;
bindOnSync(callback: (opRecords: OpRecord<ED>[]) => void): void;
unbindOnSync(callback: (opRecords: OpRecord<ED>[]) => void): void;
getCachedData(): { [T in keyof ED]?: ED[T]["OpSchema"][] | undefined; };
getFullData(): any;
begin(): FrontCxt;
commit(context: FrontCxt): void;
rollback(context: FrontCxt): void;
commit(): void;
rollback(): void;
}
export {};

View File

@ -58,10 +58,10 @@ var Cache = /** @class */ (function (_super) {
Cache.prototype.getSchema = function () {
return this.cacheStore.getSchema();
};
Cache.prototype.getCurrentUserId = function (allowUnloggedIn) {
var context = this.contextBuilder && this.contextBuilder();
return context === null || context === void 0 ? void 0 : context.getCurrentUserId(allowUnloggedIn);
};
/* getCurrentUserId(allowUnloggedIn?: boolean) {
const context = this.contextBuilder && this.contextBuilder();
return context?.getCurrentUserId(allowUnloggedIn);
} */
Cache.prototype.exec = function (name, params, callback, dontPublish) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a, result, opRecords, message, e_1, opRecord;
@ -426,14 +426,13 @@ var Cache = /** @class */ (function (_super) {
*/
Cache.prototype.tryRedoOperations = function (operations) {
var e_4, _a;
var context = this.contextBuilder();
context.begin();
this.begin();
try {
try {
for (var operations_1 = tslib_1.__values(operations), operations_1_1 = operations_1.next(); !operations_1_1.done; operations_1_1 = operations_1.next()) {
var oper = operations_1_1.value;
var entity = oper.entity, operation = oper.operation;
this.cacheStore.operate(entity, operation, context, {
this.context.operate(entity, operation, {
dontCollect: true,
dontCreateOper: true,
dontCreateModi: true,
@ -447,11 +446,11 @@ var Cache = /** @class */ (function (_super) {
}
finally { if (e_4) throw e_4.error; }
}
context.rollback();
this.rollback();
return true;
}
catch (err) {
context.rollback();
this.rollback();
if (!(err instanceof Exception_1.OakUserException)) {
throw err;
}
@ -459,31 +458,39 @@ var Cache = /** @class */ (function (_super) {
}
};
Cache.prototype.checkOperation = function (entity, action, data, filter, checkerTypes) {
var context = this.contextBuilder();
context.begin();
var autoCommit = false;
if (!this.context) {
this.begin();
autoCommit = true;
}
var operation = {
action: action,
filter: filter,
data: data
};
try {
this.cacheStore.check(entity, operation, context, checkerTypes);
context.rollback();
this.cacheStore.check(entity, operation, this.context, checkerTypes);
if (autoCommit) {
this.rollback();
}
return true;
}
catch (err) {
context.rollback();
if (autoCommit) {
this.rollback();
}
if (!(err instanceof Exception_1.OakUserException)) {
throw err;
}
return false;
}
};
Cache.prototype.redoOperation = function (opers, context) {
Cache.prototype.redoOperation = function (opers) {
var _this = this;
(0, assert_1.default)(this.context);
opers.forEach(function (oper) {
var entity = oper.entity, operation = oper.operation;
_this.cacheStore.operate(entity, operation, context, {
_this.cacheStore.operate(entity, operation, _this.context, {
dontCollect: true,
dontCreateOper: true,
blockTrigger: true,
@ -492,16 +499,27 @@ var Cache = /** @class */ (function (_super) {
});
return;
};
Cache.prototype.getInner = function (entity, selection, context, allowMiss) {
Cache.prototype.getInner = function (entity, selection, allowMiss) {
var _this = this;
var autoCommit = false;
if (!this.context) {
this.begin();
autoCommit = true;
}
try {
var result = this.cacheStore.select(entity, selection, context, {
var result = this.cacheStore.select(entity, selection, this.context, {
dontCollect: true,
includedDeleted: true,
});
if (autoCommit) {
this.commit();
}
return result;
}
catch (err) {
if (autoCommit) {
this.rollback();
}
if (err instanceof Exception_1.OakRowUnexistedException) {
if (!this.refreshing && !allowMiss) {
var missedRows_1 = err.getRows();
@ -549,9 +567,8 @@ var Cache = /** @class */ (function (_super) {
}
}
};
Cache.prototype.get = function (entity, selection, context, allowMiss) {
var context2 = context || this.contextBuilder();
return this.getInner(entity, selection, context2, allowMiss);
Cache.prototype.get = function (entity, selection, allowMiss) {
return this.getInner(entity, selection, allowMiss);
};
Cache.prototype.judgeRelation = function (entity, attr) {
return this.cacheStore.judgeRelation(entity, attr);
@ -569,15 +586,20 @@ var Cache = /** @class */ (function (_super) {
return this.getFullDataFn();
};
Cache.prototype.begin = function () {
var context = this.contextBuilder();
context.begin();
return context;
(0, assert_1.default)(!this.context);
this.context = this.contextBuilder();
this.context.begin();
return this.context;
};
Cache.prototype.commit = function (context) {
context.commit();
Cache.prototype.commit = function () {
(0, assert_1.default)(this.context);
this.context.commit();
this.context = undefined;
};
Cache.prototype.rollback = function (context) {
context.rollback();
Cache.prototype.rollback = function () {
(0, assert_1.default)(this.context);
this.context.rollback();
this.context = undefined;
};
return Cache;
}(Feature_1.Feature));

View File

@ -179,13 +179,13 @@ var RelationAuth = /** @class */ (function (_super) {
this.baseRelationAuth.checkRelationSync(entity, operation, context);
}
catch (err) {
context.rollback();
this.cache.rollback();
if (!(err instanceof types_1.OakUserException)) {
throw err;
}
return false;
}
context.rollback();
this.cache.rollback();
return true;
};
RelationAuth.prototype.getRelationIdByName = function (entity, name, entityId) {

View File

@ -48,7 +48,7 @@ declare abstract class Node<ED extends EntityDict & BaseEntityDict, T extends ke
isExecuting(): boolean;
setExecuting(executing: boolean): void;
getParent(): SingleNode<ED, keyof ED, Cxt, FrontCxt, AD> | ListNode<ED, T, Cxt, FrontCxt, AD> | VirtualNode<ED, Cxt, FrontCxt, AD> | undefined;
protected getProjection(context?: FrontCxt): ED[T]['Selection']['data'] | undefined;
protected getProjection(): ED[T]['Selection']['data'] | undefined;
setProjection(projection: ED[T]['Selection']['data']): void;
protected judgeRelation(attr: string): string | 0 | 1 | string[] | 2;
}
@ -95,7 +95,7 @@ declare class ListNode<ED extends EntityDict & BaseEntityDict, T extends keyof E
addNamedSorter(sorter: NamedSorterItem<ED, T>, refresh?: boolean): void;
removeNamedSorter(sorter: NamedSorterItem<ED, T>, refresh?: boolean): void;
removeNamedSorterByName(name: string, refresh: boolean): void;
getFreshValue(context: FrontCxt): Array<Partial<ED[T]['Schema']>>;
getFreshValue(): Array<Partial<ED[T]['Schema']>>;
addItem(item: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): void;
removeItem(id: string, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): void;
recoverItem(id: string): void;
@ -116,9 +116,9 @@ declare class ListNode<ED extends EntityDict & BaseEntityDict, T extends keyof E
entity: keyof ED;
operation: ED[keyof ED]['Operation'];
}> | undefined;
getProjection(context?: FrontCxt): ED[T]["Selection"]["data"] | undefined;
getProjection(): ED[T]["Selection"]["data"] | undefined;
private constructFilters;
constructSelection(withParent?: true, ignoreNewParent?: boolean, context?: FrontCxt, ignoreUnapplied?: true): {
constructSelection(withParent?: true, ignoreNewParent?: boolean, ignoreUnapplied?: true): {
data: ED[T]["Selection"]["data"];
filter: ED[T]["Selection"]["filter"] | undefined;
sorter: ED[T]["Selection"]["sorter"];
@ -152,7 +152,7 @@ declare class SingleNode<ED extends EntityDict & BaseEntityDict, T extends keyof
};
addChild(path: string, node: SingleNode<ED, keyof ED, Cxt, FrontCxt, AD> | ListNode<ED, keyof ED, Cxt, FrontCxt, AD>): void;
removeChild(path: string): void;
getFreshValue(context?: FrontCxt): Partial<ED[T]['Schema']> | undefined;
getFreshValue(): Partial<ED[T]['Schema']> | undefined;
doBeforeTrigger(): Promise<void>;
doAfterTrigger(): Promise<void>;
create(data: Partial<Omit<ED[T]['CreateSingle']['data'], 'id'>>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): void;
@ -162,7 +162,7 @@ declare class SingleNode<ED extends EntityDict & BaseEntityDict, T extends keyof
entity: keyof ED;
operation: ED[keyof ED]['Operation'];
}> | undefined;
getProjection(context?: FrontCxt, withDecendants?: boolean): ED[T]["Selection"]["data"] | undefined;
getProjection(withDecendants?: boolean): ED[T]["Selection"]["data"] | undefined;
refresh(): Promise<void>;
clean(): void;
private getFilter;
@ -173,7 +173,7 @@ declare class SingleNode<ED extends EntityDict & BaseEntityDict, T extends keyof
* @param disableOperation
* @returns
*/
getParentFilter<T2 extends keyof ED>(childNode: Node<ED, keyof ED, Cxt, FrontCxt, AD>, context?: FrontCxt, ignoreNewParent?: boolean): ED[T2]['Selection']['filter'] | undefined;
getParentFilter<T2 extends keyof ED>(childNode: Node<ED, keyof ED, Cxt, FrontCxt, AD>, ignoreNewParent?: boolean): ED[T2]['Selection']['filter'] | undefined;
}
declare class VirtualNode<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>, AD extends CommonAspectDict<ED, Cxt>> extends Feature {
private dirty;

View File

@ -105,7 +105,7 @@ var Node = /** @class */ (function (_super) {
Node.prototype.getParent = function () {
return this.parent;
};
Node.prototype.getProjection = function (context) {
Node.prototype.getProjection = function () {
var projection = typeof this.projection === 'function' ? this.projection() : (this.projection && (0, lodash_1.cloneDeep)(this.projection));
return projection;
};
@ -241,7 +241,7 @@ var ListNode = /** @class */ (function (_super) {
此时对userRelation的删除动作就会导致user不会被移出list
*/
if (needRefresh) {
var _b = this.constructSelection(true, false, undefined, true), filter = _b.filter, sorter = _b.sorter;
var _b = this.constructSelection(true, false, true), filter = _b.filter, sorter = _b.sorter;
if (filter) {
var result = this.cache.get(this.getEntity(), {
data: {
@ -400,7 +400,7 @@ var ListNode = /** @class */ (function (_super) {
this.publish();
}
};
ListNode.prototype.getFreshValue = function (context) {
ListNode.prototype.getFreshValue = function () {
var _this = this;
/**
* 满足当前结点的数据应当是所有满足当前filter条件且ids在当前ids中的数据
@ -414,7 +414,7 @@ var ListNode = /** @class */ (function (_super) {
*
* 这里不能用sorter排序enum的排序顺序目前前后台尚不一致 by Xc 20230809
*/
var _a = this.constructSelection(true, false, context, true), data = _a.data, filter = _a.filter;
var _a = this.constructSelection(true, false, true), data = _a.data, filter = _a.filter;
if (filter || this.ids) {
var filter2 = filter && this.ids ? {
$or: [filter, {
@ -430,7 +430,7 @@ var ListNode = /** @class */ (function (_super) {
var result = this.cache.get(this.entity, {
data: data,
filter: filter2,
}, context, this.isLoading());
}, this.isLoading());
var r2_1 = result.filter(function (ele) { var _a; return ele.$$createAt$$ === 1 || ((_a = _this.ids) === null || _a === void 0 ? void 0 : _a.includes(ele.id)); }).sort(function (ele1, ele2) {
if (ele1.$$createAt$$ === 1) {
return -1;
@ -464,7 +464,7 @@ var ListNode = /** @class */ (function (_super) {
id: { $in: finalIds },
},
sorter,
}, context, this.isLoading()); */
}, this.isLoading()); */
};
ListNode.prototype.addItem = function (item, beforeExecute, afterExecute) {
var id = (0, uuid_1.generateNewId)();
@ -713,8 +713,8 @@ var ListNode = /** @class */ (function (_super) {
}
return operations;
};
ListNode.prototype.getProjection = function (context) {
var projection = _super.prototype.getProjection.call(this, context);
ListNode.prototype.getProjection = function () {
var projection = _super.prototype.getProjection.call(this);
// List必须自主决定Projection
/* if (this.children.length > 0) {
const subProjection = await this.children[0].getProjection();
@ -722,7 +722,7 @@ var ListNode = /** @class */ (function (_super) {
} */
return projection;
};
ListNode.prototype.constructFilters = function (context, withParent, ignoreNewParent, ignoreUnapplied) {
ListNode.prototype.constructFilters = function (withParent, ignoreNewParent, ignoreUnapplied) {
var ownFilters = this.filters;
var filters = ownFilters.filter(function (ele) { return !ignoreUnapplied || ele.applied === true || ele.applied === undefined; } // 如果是undefined说明不可以移除构造时就存在也得返回
).map(function (ele) {
@ -734,7 +734,7 @@ var ListNode = /** @class */ (function (_super) {
});
if (withParent && this.parent) {
if (this.parent instanceof SingleNode) {
var filterOfParent = this.parent.getParentFilter(this, context, ignoreNewParent);
var filterOfParent = this.parent.getParentFilter(this, ignoreNewParent);
if (filterOfParent) {
filters.push(filterOfParent);
}
@ -747,9 +747,9 @@ var ListNode = /** @class */ (function (_super) {
// 返回的filter在上层做check的时候可能被改造掉
return (0, lodash_1.cloneDeep)(filters);
};
ListNode.prototype.constructSelection = function (withParent, ignoreNewParent, context, ignoreUnapplied) {
ListNode.prototype.constructSelection = function (withParent, ignoreNewParent, ignoreUnapplied) {
var sorters = this.sorters;
var data = this.getProjection(context);
var data = this.getProjection();
(0, assert_1.assert)(data, '取数据时找不到projection信息');
var sorterArr = sorters.filter(function (ele) { return !ignoreUnapplied || ele.applied; }).map(function (ele) {
var sorter = ele.sorter;
@ -759,7 +759,7 @@ var ListNode = /** @class */ (function (_super) {
return sorter;
})
.filter(function (ele) { return !!ele; });
var filters = this.constructFilters(context, withParent, ignoreNewParent, ignoreUnapplied);
var filters = this.constructFilters(withParent, ignoreNewParent, ignoreUnapplied);
var filters2 = filters === null || filters === void 0 ? void 0 : filters.filter(function (ele) { return !!ele; });
var filter = filters2 ? (0, filter_1.combineFilters)(this.entity, this.schema, filters2) : undefined;
return {
@ -992,8 +992,8 @@ var SingleNode = /** @class */ (function (_super) {
SingleNode.prototype.removeChild = function (path) {
(0, lodash_1.unset)(this.children, path);
};
SingleNode.prototype.getFreshValue = function (context) {
var projection = this.getProjection(context, false);
SingleNode.prototype.getFreshValue = function () {
var projection = this.getProjection(false);
var id = this.getId();
if (projection) {
var result = this.cache.get(this.entity, {
@ -1001,7 +1001,7 @@ var SingleNode = /** @class */ (function (_super) {
filter: {
id: id,
},
}, context, this.isLoading());
}, this.isLoading());
if (this.aggr) {
(0, lodash_1.merge)(result[0], this.aggr);
}
@ -1216,18 +1216,18 @@ var SingleNode = /** @class */ (function (_super) {
}];
}
};
SingleNode.prototype.getProjection = function (context, withDecendants) {
SingleNode.prototype.getProjection = function (withDecendants) {
var _a, _b, _c;
if (this.parent && this.parent instanceof ListNode) {
return this.parent.getProjection(context);
return this.parent.getProjection();
}
var projection = _super.prototype.getProjection.call(this, context);
var projection = _super.prototype.getProjection.call(this);
if (projection && withDecendants) {
for (var k in this.children) {
if (k.indexOf(':') === -1) {
var rel = this.judgeRelation(k);
if (rel === 2) {
var subProjection = this.children[k].getProjection(context, true);
var subProjection = this.children[k].getProjection(true);
Object.assign(projection, (_a = {
entity: 1,
entityId: 1
@ -1236,7 +1236,7 @@ var SingleNode = /** @class */ (function (_super) {
_a));
}
else if (typeof rel === 'string') {
var subProjection = this.children[k].getProjection(context, true);
var subProjection = this.children[k].getProjection(true);
Object.assign(projection, (_b = {},
_b["".concat(k, "Id")] = 1,
_b[k] = subProjection,
@ -1270,7 +1270,7 @@ var SingleNode = /** @class */ (function (_super) {
this.publish();
return [2 /*return*/];
}
projection = this.getProjection(undefined, true);
projection = this.getProjection(true);
filter = this.getFilter();
if (!(projection && filter)) return [3 /*break*/, 5];
this.setLoading(true);
@ -1358,9 +1358,9 @@ var SingleNode = /** @class */ (function (_super) {
* @param disableOperation
* @returns
*/
SingleNode.prototype.getParentFilter = function (childNode, context, ignoreNewParent) {
SingleNode.prototype.getParentFilter = function (childNode, ignoreNewParent) {
var _a, _b, _c, _d;
var value = this.getFreshValue(context);
var value = this.getFreshValue();
if (value && value.$$createAt$$ === 1 && ignoreNewParent) {
return;
}
@ -1830,20 +1830,20 @@ var RunningTree = /** @class */ (function (_super) {
var root = this.root[paths[0]];
var includeModi = path.includes(exports.MODI_NEXT_PATH_SUFFIX);
if (node) {
var context_1 = this.cache.begin();
this.cache.begin();
(0, assert_1.assert)(node instanceof ListNode || node instanceof SingleNode);
if (includeModi) {
var opers2 = node.getActiveModiOperations();
if (opers2) {
this.cache.redoOperation(opers2, context_1);
this.cache.redoOperation(opers2);
}
}
var opers = root === null || root === void 0 ? void 0 : root.composeOperations();
if (opers) {
this.cache.redoOperation(opers, context_1);
this.cache.redoOperation(opers);
}
var value = node.getFreshValue(context_1);
context_1.rollback();
var value = node.getFreshValue();
this.cache.rollback();
return value;
}
};

View File

@ -43,7 +43,7 @@ function initialize(storageSchema, frontendContextBuilder, backendContextBuilder
case 0:
context = features2.cache.begin();
str = context.toString();
context.commit();
features2.cache.commit();
return [4 /*yield*/, backendContextBuilder(str)(debugStore)];
case 1:
contextBackend = _a.sent();

View File

@ -30,7 +30,7 @@ function initialize(storageSchema, frontendContextBuilder, connector, checkers,
switch (_b.label) {
case 0:
context = features2.cache.begin();
context.commit();
features.cache.commit();
return [4 /*yield*/, connector.callAspect(name, params, context)];
case 1:
_a = _b.sent(), result = _a.result, opRecords = _a.opRecords, message = _a.message;

View File

@ -39,6 +39,7 @@ export class Cache<
private refreshRecords: {
[T in keyof ED]?: Record<string, number>;
} = {};
private context?: FrontCxt;
constructor(
storageSchema: StorageSchema<ED>,
@ -105,10 +106,10 @@ export class Cache<
return this.cacheStore.getSchema();
}
getCurrentUserId(allowUnloggedIn?: boolean) {
/* getCurrentUserId(allowUnloggedIn?: boolean) {
const context = this.contextBuilder && this.contextBuilder();
return context?.getCurrentUserId(allowUnloggedIn);
}
} */
async exec<K extends keyof AD>(
name: K,
@ -472,21 +473,20 @@ export class Cache<
* @returns
*/
tryRedoOperations<T extends keyof ED>(operations: ({ operation: ED[T]['Operation']; entity: T })[]) {
const context = this.contextBuilder!();
context.begin();
this.begin();
try {
for (const oper of operations) {
const { entity, operation } = oper;
this.cacheStore!.operate(entity, operation, context, {
this.context!.operate(entity, operation, {
dontCollect: true,
dontCreateOper: true,
dontCreateModi: true,
});
}
context.rollback();
this.rollback();
return true;
} catch (err) {
context.rollback();
this.rollback();
if (!(err instanceof OakUserException)) {
throw err;
}
@ -495,20 +495,27 @@ export class Cache<
}
checkOperation<T extends keyof ED>(entity: T, action: ED[T]['Action'], data?: ED[T]['Update']['data'], filter?: ED[T]['Update']['filter'], checkerTypes?: CheckerType[]) {
const context = this.contextBuilder!();
context.begin();
let autoCommit = false;
if (!this.context) {
this.begin();
autoCommit = true;
}
const operation = {
action,
filter,
data
} as ED[T]['Update'];
try {
this.cacheStore!.check(entity, operation, context, checkerTypes);
context.rollback();
this.cacheStore!.check(entity, operation, this.context!, checkerTypes);
if (autoCommit) {
this.rollback();
}
return true;
}
catch (err) {
context.rollback();
if (autoCommit) {
this.rollback();
}
if (!(err instanceof OakUserException)) {
throw err;
}
@ -519,11 +526,12 @@ export class Cache<
redoOperation(opers: Array<{
entity: keyof ED;
operation: ED[keyof ED]['Operation'];
}>, context: FrontCxt) {
}>) {
assert(this.context);
opers.forEach(
(oper) => {
const { entity, operation } = oper;
this.cacheStore!.operate(entity, operation, context, {
this.cacheStore!.operate(entity, operation, this.context!, {
dontCollect: true,
dontCreateOper: true,
blockTrigger: true,
@ -537,20 +545,30 @@ export class Cache<
private getInner<T extends keyof ED>(
entity: T,
selection: ED[T]['Selection'],
context: SyncContext<ED>,
allowMiss?: boolean): Partial<ED[T]['Schema']>[] {
let autoCommit = false;
if (!this.context) {
this.begin();
autoCommit = true;
}
try {
const result = this.cacheStore!.select(
entity,
selection,
context,
this.context!,
{
dontCollect: true,
includedDeleted: true,
}
);
if (autoCommit) {
this.commit();
}
return result;
} catch (err) {
if (autoCommit) {
this.rollback();
}
if (err instanceof OakRowUnexistedException) {
if (!this.refreshing && !allowMiss) {
const missedRows = err.getRows();
@ -576,12 +594,9 @@ export class Cache<
get<T extends keyof ED>(
entity: T,
selection: ED[T]['Selection'],
context?: FrontCxt,
allowMiss?: boolean
) {
const context2 = context || this.contextBuilder!();
return this.getInner(entity, selection, context2, allowMiss);
return this.getInner(entity, selection, allowMiss);
}
judgeRelation(entity: keyof ED, attr: string) {
@ -605,16 +620,21 @@ export class Cache<
}
begin() {
const context = this.contextBuilder!();
context.begin();
return context;
assert(!this.context);
this.context = this.contextBuilder!();
this.context.begin();
return this.context;
}
commit(context: FrontCxt) {
context.commit();
commit() {
assert(this.context);
this.context.commit();
this.context = undefined;
}
rollback(context: FrontCxt) {
context.rollback();
rollback() {
assert(this.context);
this.context.rollback();
this.context = undefined;
}
}

View File

@ -240,13 +240,13 @@ export class RelationAuth<
this.baseRelationAuth.checkRelationSync(entity, operation, context);
}
catch (err) {
context.rollback();
this.cache.rollback();
if (!(err instanceof OakUserException)) {
throw err;
}
return false;
}
context.rollback();
this.cache.rollback();
return true;
}

View File

@ -160,7 +160,7 @@ abstract class Node<
return this.parent;
}
protected getProjection(context?: FrontCxt): ED[T]['Selection']['data'] | undefined {
protected getProjection(): ED[T]['Selection']['data'] | undefined {
const projection = typeof this.projection === 'function' ? (this.projection as Function)() : (this.projection && cloneDeep(this.projection));
return projection;
@ -320,7 +320,7 @@ class ListNode<
userRelation的删除动作就会导致user不会被移出list
*/
if (needRefresh) {
const { filter, sorter } = this.constructSelection(true, false, undefined, true);
const { filter, sorter } = this.constructSelection(true, false, true);
if (filter) {
const result = this.cache.get(this.getEntity(), {
data: {
@ -532,7 +532,7 @@ class ListNode<
}
}
getFreshValue(context: FrontCxt): Array<Partial<ED[T]['Schema']>> {
getFreshValue(): Array<Partial<ED[T]['Schema']>> {
/**
* filter条件且ids在当前ids中的数据
* create的行则例外create的数据
@ -545,7 +545,7 @@ class ListNode<
*
* sorter排序enum的排序顺序目前前后台尚不一致 by Xc 20230809
*/
const { data, filter } = this.constructSelection(true, false, context, true);
const { data, filter } = this.constructSelection(true, false, true);
if (filter || this.ids) {
const filter2 = filter && this.ids ? {
@ -562,7 +562,7 @@ class ListNode<
const result = this.cache.get(this.entity, {
data,
filter: filter2,
}, context, this.isLoading());
}, this.isLoading());
const r2 = result.filter(
@ -607,7 +607,7 @@ class ListNode<
id: { $in: finalIds },
},
sorter,
}, context, this.isLoading()); */
}, this.isLoading()); */
}
addItem(
@ -810,8 +810,8 @@ class ListNode<
return operations;
}
getProjection(context?: FrontCxt) {
const projection = super.getProjection(context);
getProjection() {
const projection = super.getProjection();
// List必须自主决定Projection
/* if (this.children.length > 0) {
const subProjection = await this.children[0].getProjection();
@ -820,7 +820,7 @@ class ListNode<
return projection;
}
private constructFilters(context?: FrontCxt, withParent?: boolean, ignoreNewParent?: boolean, ignoreUnapplied?: true) {
private constructFilters(withParent?: boolean, ignoreNewParent?: boolean, ignoreUnapplied?: true) {
const { filters: ownFilters } = this;
const filters = ownFilters.filter(
ele => !ignoreUnapplied || ele.applied === true || ele.applied === undefined // 如果是undefined说明不可以移除构造时就存在也得返回
@ -834,7 +834,7 @@ class ListNode<
if (withParent && this.parent) {
if (this.parent instanceof SingleNode) {
const filterOfParent = this.parent.getParentFilter<T>(this, context, ignoreNewParent);
const filterOfParent = this.parent.getParentFilter<T>(this, ignoreNewParent);
if (filterOfParent) {
filters.push(filterOfParent as any);
} else {
@ -848,9 +848,9 @@ class ListNode<
return cloneDeep(filters);
}
constructSelection(withParent?: true, ignoreNewParent?: boolean, context?: FrontCxt, ignoreUnapplied?: true) {
constructSelection(withParent?: true, ignoreNewParent?: boolean, ignoreUnapplied?: true) {
const { sorters } = this;
const data = this.getProjection(context);
const data = this.getProjection();
assert(data, '取数据时找不到projection信息');
const sorterArr = sorters.filter(
ele => !ignoreUnapplied || ele.applied
@ -863,7 +863,7 @@ class ListNode<
})
.filter((ele) => !!ele) as ED[T]['Selection']['sorter'];
const filters = this.constructFilters(context, withParent, ignoreNewParent, ignoreUnapplied);
const filters = this.constructFilters(withParent, ignoreNewParent, ignoreUnapplied);
const filters2 = filters?.filter((ele) => !!ele);
const filter = filters2 ? combineFilters<ED, T>(this.entity, this.schema, filters2) : undefined;
@ -1122,8 +1122,8 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
unset(this.children, path);
}
getFreshValue(context?: FrontCxt): Partial<ED[T]['Schema']> | undefined {
const projection = this.getProjection(context, false);
getFreshValue(): Partial<ED[T]['Schema']> | undefined {
const projection = this.getProjection(false);
const id = this.getId();
if (projection) {
const result = this.cache.get(this.entity, {
@ -1131,7 +1131,7 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
filter: {
id,
},
}, context, this.isLoading());
}, this.isLoading());
if (this.aggr) {
merge(result[0], this.aggr);
}
@ -1311,17 +1311,17 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
}
}
getProjection(context?: FrontCxt, withDecendants?: boolean) {
getProjection(withDecendants?: boolean) {
if (this.parent && this.parent instanceof ListNode) {
return this.parent.getProjection(context);
return this.parent.getProjection();
}
const projection = super.getProjection(context);
const projection = super.getProjection();
if (projection && withDecendants) {
for (const k in this.children) {
if (k.indexOf(':') === -1) {
const rel = this.judgeRelation(k);
if (rel === 2) {
const subProjection = this.children[k].getProjection(context, true);
const subProjection = this.children[k].getProjection(true);
Object.assign(projection, {
entity: 1,
entityId: 1,
@ -1329,7 +1329,7 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
});
}
else if (typeof rel === 'string') {
const subProjection = this.children[k].getProjection(context, true);
const subProjection = this.children[k].getProjection(true);
Object.assign(projection, {
[`${k}Id`]: 1,
[k]: subProjection,
@ -1359,7 +1359,7 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
return;
}
// SingleNode如果是非根结点其id应该在第一次refresh的时候来确定
const projection = this.getProjection(undefined, true);
const projection = this.getProjection(true);
const filter = this.getFilter();
if (projection && filter) {
this.setLoading(true);
@ -1445,8 +1445,8 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
* @param disableOperation
* @returns
*/
getParentFilter<T2 extends keyof ED>(childNode: Node<ED, keyof ED, Cxt, FrontCxt, AD>, context?: FrontCxt, ignoreNewParent?: boolean): ED[T2]['Selection']['filter'] | undefined {
const value = this.getFreshValue(context);
getParentFilter<T2 extends keyof ED>(childNode: Node<ED, keyof ED, Cxt, FrontCxt, AD>, ignoreNewParent?: boolean): ED[T2]['Selection']['filter'] | undefined {
const value = this.getFreshValue();
if (value && value.$$createAt$$ === 1 && ignoreNewParent) {
return;
@ -1958,20 +1958,20 @@ export class RunningTree<
const root = this.root[paths[0]];
const includeModi = path.includes(MODI_NEXT_PATH_SUFFIX);
if (node) {
const context = this.cache.begin();
this.cache.begin();
assert(node instanceof ListNode || node instanceof SingleNode);
if (includeModi) {
const opers2 = node.getActiveModiOperations();
if (opers2) {
this.cache.redoOperation(opers2, context);
this.cache.redoOperation(opers2);
}
}
const opers = root?.composeOperations();
if (opers) {
this.cache.redoOperation(opers, context);
this.cache.redoOperation(opers);
}
const value = node.getFreshValue(context);
context.rollback();
const value = node.getFreshValue();
this.cache.rollback();
return value;
}
}

View File

@ -98,7 +98,7 @@ export function initialize<
exec: async (name, params) => {
const context = features2.cache.begin();
const str = context.toString();
context.commit();
features2.cache.commit();
const contextBackend = await backendContextBuilder(str)(debugStore);
await contextBackend.begin();
let result;

View File

@ -53,7 +53,7 @@ export function initialize<
const wrapper: AspectWrapper<ED, Cxt, AD & CommonAspectDict<ED, Cxt>> = {
exec: async (name, params) => {
const context = features2.cache.begin();
context.commit();
features.cache.commit();
const { result, opRecords, message } = await connector.callAspect(name as string, params, context);
return {
result,