修改了缓存行为,当发现指定id的行缺失时也会触发被动获取
This commit is contained in:
parent
a3c0385b73
commit
88bbe7baa3
|
|
@ -77,6 +77,19 @@ export declare class Cache<ED extends EntityDict & BaseEntityDict, Cxt extends A
|
|||
entity: keyof ED;
|
||||
operation: ED[keyof ED]['Operation'];
|
||||
}>): void;
|
||||
fetchRows(missedRows: Array<{
|
||||
entity: keyof ED;
|
||||
selection: ED[keyof ED]['Selection'];
|
||||
}>): void;
|
||||
/**
|
||||
* getById可以处理当本行不在缓存中的自动取
|
||||
* @attention 这里如果访问了一个id不存在的行(被删除?),可能会陷入无限循环。如果遇到了再处理
|
||||
* @param entity
|
||||
* @param data
|
||||
* @param id
|
||||
* @param allowMiss
|
||||
*/
|
||||
getById<T extends keyof ED>(entity: T, data: ED[T]['Selection']['data'], id: string, allowMiss?: boolean): Partial<ED[T]['Schema']> | undefined;
|
||||
private getInner;
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ var Cache = /** @class */ (function (_super) {
|
|||
tslib_1.__extends(Cache, _super);
|
||||
function Cache(storageSchema, aspectWrapper, frontendContextBuilder, checkers, getFullData, localStorage, savedEntities, keepFreshPeriod) {
|
||||
var _this = _super.call(this) || this;
|
||||
_this.refreshing = false;
|
||||
_this.refreshing = 0;
|
||||
_this.refreshRecords = {};
|
||||
_this.aspectWrapper = aspectWrapper;
|
||||
_this.syncEventsCallbacks = [];
|
||||
|
|
@ -69,15 +69,16 @@ var Cache = /** @class */ (function (_super) {
|
|||
switch (_b.label) {
|
||||
case 0:
|
||||
_b.trys.push([0, 2, , 3]);
|
||||
this.refreshing++;
|
||||
return [4 /*yield*/, this.aspectWrapper.exec(name, params)];
|
||||
case 1:
|
||||
_a = _b.sent(), result = _a.result, opRecords = _a.opRecords, message = _a.message;
|
||||
this.refreshing = false;
|
||||
if (opRecords) {
|
||||
this.sync(opRecords);
|
||||
}
|
||||
this.refreshing--;
|
||||
callback && callback(result, opRecords);
|
||||
if (opRecords && !dontPublish) {
|
||||
if (opRecords && opRecords.length > 0 && !dontPublish) {
|
||||
this.publish();
|
||||
}
|
||||
return [2 /*return*/, {
|
||||
|
|
@ -87,6 +88,7 @@ var Cache = /** @class */ (function (_super) {
|
|||
case 2:
|
||||
e_1 = _b.sent();
|
||||
// 如果是数据不一致错误,这里可以让用户知道
|
||||
this.refreshing--;
|
||||
if (e_1 instanceof Exception_1.OakException) {
|
||||
opRecord = e_1.opRecord;
|
||||
if (opRecord) {
|
||||
|
|
@ -317,7 +319,6 @@ var Cache = /** @class */ (function (_super) {
|
|||
}
|
||||
undoSetRefreshRecord = this.addRefreshRecord(entity, key, now);
|
||||
}
|
||||
this.refreshing = true;
|
||||
_b.label = 1;
|
||||
case 1:
|
||||
_b.trys.push([1, 3, , 4]);
|
||||
|
|
@ -350,7 +351,6 @@ var Cache = /** @class */ (function (_super) {
|
|||
}];
|
||||
case 3:
|
||||
err_1 = _b.sent();
|
||||
this.refreshing = false;
|
||||
undoSetRefreshRecord && undoSetRefreshRecord();
|
||||
throw err_1;
|
||||
case 4: return [2 /*return*/];
|
||||
|
|
@ -380,13 +380,11 @@ var Cache = /** @class */ (function (_super) {
|
|||
var result;
|
||||
return tslib_1.__generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
this.refreshing = true;
|
||||
return [4 /*yield*/, this.exec('operate', {
|
||||
entity: entity,
|
||||
operation: operation,
|
||||
option: option,
|
||||
}, callback)];
|
||||
case 0: return [4 /*yield*/, this.exec('operate', {
|
||||
entity: entity,
|
||||
operation: operation,
|
||||
option: option,
|
||||
}, callback)];
|
||||
case 1:
|
||||
result = _a.sent();
|
||||
return [2 /*return*/, result];
|
||||
|
|
@ -499,8 +497,78 @@ var Cache = /** @class */ (function (_super) {
|
|||
});
|
||||
return;
|
||||
};
|
||||
Cache.prototype.getInner = function (entity, selection, allowMiss) {
|
||||
Cache.prototype.fetchRows = function (missedRows) {
|
||||
var _this = this;
|
||||
if (!this.refreshing) {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.warn('缓存被动去获取数据,请查看页面行为并加以优化', missedRows);
|
||||
}
|
||||
this.exec('fetchRows', missedRows, function (result, opRecords) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
||||
var _a, _b, record, d, missedRows_1, missedRows_1_1, mr;
|
||||
var e_5, _c, e_6, _d;
|
||||
return tslib_1.__generator(this, function (_e) {
|
||||
try {
|
||||
// missedRows理论上一定要取到,不能为空集。否则就是程序员有遗漏
|
||||
for (_a = tslib_1.__values(opRecords), _b = _a.next(); !_b.done; _b = _a.next()) {
|
||||
record = _b.value;
|
||||
d = record.d;
|
||||
(0, assert_1.default)(Object.keys(d).length > 0, '在通过fetchRow取不一致数据时返回了空数据,请拿该程序员祭天。');
|
||||
try {
|
||||
for (missedRows_1 = (e_6 = void 0, tslib_1.__values(missedRows)), missedRows_1_1 = missedRows_1.next(); !missedRows_1_1.done; missedRows_1_1 = missedRows_1.next()) {
|
||||
mr = missedRows_1_1.value;
|
||||
(0, assert_1.default)(Object.keys(d[mr.entity]).length > 0, "\u5728\u901A\u8FC7fetchRow\u53D6\u4E0D\u4E00\u81F4\u6570\u636E\u65F6\u8FD4\u56DE\u4E86\u7A7A\u6570\u636E\uFF0C\u8BF7\u62FF\u8BE5\u7A0B\u5E8F\u5458\u796D\u5929\u3002entity\u662F".concat(mr.entity));
|
||||
}
|
||||
}
|
||||
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
||||
finally {
|
||||
try {
|
||||
if (missedRows_1_1 && !missedRows_1_1.done && (_d = missedRows_1.return)) _d.call(missedRows_1);
|
||||
}
|
||||
finally { if (e_6) throw e_6.error; }
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
||||
finally {
|
||||
try {
|
||||
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
|
||||
}
|
||||
finally { if (e_5) throw e_5.error; }
|
||||
}
|
||||
return [2 /*return*/];
|
||||
});
|
||||
}); });
|
||||
}
|
||||
};
|
||||
/**
|
||||
* getById可以处理当本行不在缓存中的自动取
|
||||
* @attention 这里如果访问了一个id不存在的行(被删除?),可能会陷入无限循环。如果遇到了再处理
|
||||
* @param entity
|
||||
* @param data
|
||||
* @param id
|
||||
* @param allowMiss
|
||||
*/
|
||||
Cache.prototype.getById = function (entity, data, id, allowMiss) {
|
||||
var result = this.getInner(entity, {
|
||||
data: data,
|
||||
filter: {
|
||||
id: id,
|
||||
},
|
||||
}, allowMiss);
|
||||
if (result.length === 0 && !allowMiss) {
|
||||
this.fetchRows([{
|
||||
entity: entity,
|
||||
selection: {
|
||||
data: data,
|
||||
filter: {
|
||||
id: id,
|
||||
},
|
||||
}
|
||||
}]);
|
||||
}
|
||||
return result[0];
|
||||
};
|
||||
Cache.prototype.getInner = function (entity, selection, allowMiss) {
|
||||
var autoCommit = false;
|
||||
if (!this.context) {
|
||||
this.begin();
|
||||
|
|
@ -521,44 +589,8 @@ var Cache = /** @class */ (function (_super) {
|
|||
this.rollback();
|
||||
}
|
||||
if (err instanceof Exception_1.OakRowUnexistedException) {
|
||||
if (!this.refreshing && !allowMiss) {
|
||||
var missedRows_1 = err.getRows();
|
||||
this.refreshing = true;
|
||||
this.exec('fetchRows', missedRows_1, function (result, opRecords) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
||||
var _a, _b, record, d, missedRows_2, missedRows_2_1, mr;
|
||||
var e_5, _c, e_6, _d;
|
||||
return tslib_1.__generator(this, function (_e) {
|
||||
try {
|
||||
// missedRows理论上一定要取到,不能为空集。否则就是程序员有遗漏
|
||||
for (_a = tslib_1.__values(opRecords), _b = _a.next(); !_b.done; _b = _a.next()) {
|
||||
record = _b.value;
|
||||
d = record.d;
|
||||
(0, assert_1.default)(Object.keys(d).length > 0, '在通过fetchRow取不一致数据时返回了空数据,请拿该程序员祭天。');
|
||||
try {
|
||||
for (missedRows_2 = (e_6 = void 0, tslib_1.__values(missedRows_1)), missedRows_2_1 = missedRows_2.next(); !missedRows_2_1.done; missedRows_2_1 = missedRows_2.next()) {
|
||||
mr = missedRows_2_1.value;
|
||||
(0, assert_1.default)(Object.keys(d[mr.entity]).length > 0, "\u5728\u901A\u8FC7fetchRow\u53D6\u4E0D\u4E00\u81F4\u6570\u636E\u65F6\u8FD4\u56DE\u4E86\u7A7A\u6570\u636E\uFF0C\u8BF7\u62FF\u8BE5\u7A0B\u5E8F\u5458\u796D\u5929\u3002entity\u662F".concat(mr.entity));
|
||||
}
|
||||
}
|
||||
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
||||
finally {
|
||||
try {
|
||||
if (missedRows_2_1 && !missedRows_2_1.done && (_d = missedRows_2.return)) _d.call(missedRows_2);
|
||||
}
|
||||
finally { if (e_6) throw e_6.error; }
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
||||
finally {
|
||||
try {
|
||||
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
|
||||
}
|
||||
finally { if (e_5) throw e_5.error; }
|
||||
}
|
||||
return [2 /*return*/];
|
||||
});
|
||||
}); });
|
||||
if (!allowMiss) {
|
||||
this.fetchRows(err.getRows());
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,6 +180,12 @@ var RelationAuth = /** @class */ (function (_super) {
|
|||
}
|
||||
catch (err) {
|
||||
this.cache.rollback();
|
||||
if (err instanceof types_1.OakRowUnexistedException) {
|
||||
// 发现缓存中缺失项的话要协助获取
|
||||
var missedRows = err.getRows();
|
||||
this.cache.fetchRows(missedRows);
|
||||
return false;
|
||||
}
|
||||
if (!(err instanceof types_1.OakUserException)) {
|
||||
throw err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ var ListNode = /** @class */ (function (_super) {
|
|||
},
|
||||
filter: filter,
|
||||
sorter: sorter,
|
||||
});
|
||||
}, true);
|
||||
this.ids = result.map(function (ele) { return ele.id; });
|
||||
}
|
||||
}
|
||||
|
|
@ -430,7 +430,7 @@ var ListNode = /** @class */ (function (_super) {
|
|||
var result = this.cache.get(this.entity, {
|
||||
data: data,
|
||||
filter: filter2,
|
||||
}, this.isLoading());
|
||||
}, true);
|
||||
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;
|
||||
|
|
@ -1001,7 +1001,7 @@ var SingleNode = /** @class */ (function (_super) {
|
|||
filter: {
|
||||
id: id,
|
||||
},
|
||||
}, this.isLoading());
|
||||
}, true);
|
||||
if (this.aggr) {
|
||||
(0, lodash_1.merge)(result[0], this.aggr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export class Cache<
|
|||
(opRecords: OpRecord<ED>[]) => void
|
||||
>;
|
||||
private contextBuilder?: () => FrontCxt;
|
||||
private refreshing = false;
|
||||
private refreshing = 0;
|
||||
private savedEntities: (keyof ED)[];
|
||||
private keepFreshPeriod: number;
|
||||
private localStorage: LocalStorage;
|
||||
|
|
@ -119,13 +119,14 @@ export class Cache<
|
|||
dontPublish?: true,
|
||||
) {
|
||||
try {
|
||||
this.refreshing ++;
|
||||
const { result, opRecords, message } = await this.aspectWrapper.exec(name, params);
|
||||
this.refreshing = false;
|
||||
if (opRecords) {
|
||||
this.sync(opRecords);
|
||||
}
|
||||
this.refreshing --;
|
||||
callback && callback(result, opRecords);
|
||||
if (opRecords && !dontPublish) {
|
||||
if (opRecords && opRecords.length > 0 && !dontPublish) {
|
||||
this.publish();
|
||||
}
|
||||
return {
|
||||
|
|
@ -135,6 +136,7 @@ export class Cache<
|
|||
}
|
||||
catch (e) {
|
||||
// 如果是数据不一致错误,这里可以让用户知道
|
||||
this.refreshing --;
|
||||
if (e instanceof OakException) {
|
||||
const { opRecord } = e;
|
||||
if (opRecord) {
|
||||
|
|
@ -375,7 +377,6 @@ export class Cache<
|
|||
undoSetRefreshRecord = this.addRefreshRecord(entity, key, now);
|
||||
}
|
||||
|
||||
this.refreshing = true;
|
||||
try {
|
||||
const { result: { ids, count, aggr } } = await this.exec('select', {
|
||||
entity,
|
||||
|
|
@ -407,7 +408,6 @@ export class Cache<
|
|||
};
|
||||
}
|
||||
catch(err) {
|
||||
this.refreshing = false;
|
||||
undoSetRefreshRecord && undoSetRefreshRecord();
|
||||
|
||||
throw err;
|
||||
|
|
@ -434,7 +434,6 @@ export class Cache<
|
|||
option?: OP,
|
||||
callback?: (result: Awaited<ReturnType<AD['operate']>>) => void,
|
||||
) {
|
||||
this.refreshing = true;
|
||||
const result = await this.exec('operate', {
|
||||
entity,
|
||||
operation,
|
||||
|
|
@ -543,6 +542,58 @@ export class Cache<
|
|||
return;
|
||||
}
|
||||
|
||||
fetchRows(missedRows: Array<{ entity: keyof ED, selection: ED[keyof ED]['Selection']}>) {
|
||||
if (!this.refreshing) {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.warn('缓存被动去获取数据,请查看页面行为并加以优化', missedRows);
|
||||
}
|
||||
this.exec('fetchRows', missedRows, async (result, opRecords) => {
|
||||
// missedRows理论上一定要取到,不能为空集。否则就是程序员有遗漏
|
||||
for (const record of opRecords!) {
|
||||
const { d } = record as SelectOpResult<ED>;
|
||||
assert(Object.keys(d).length > 0, '在通过fetchRow取不一致数据时返回了空数据,请拿该程序员祭天。');
|
||||
for (const mr of missedRows) {
|
||||
assert(Object.keys(d![mr.entity]!).length > 0, `在通过fetchRow取不一致数据时返回了空数据,请拿该程序员祭天。entity是${mr.entity as string}`);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* getById可以处理当本行不在缓存中的自动取
|
||||
* @attention 这里如果访问了一个id不存在的行(被删除?),可能会陷入无限循环。如果遇到了再处理
|
||||
* @param entity
|
||||
* @param data
|
||||
* @param id
|
||||
* @param allowMiss
|
||||
*/
|
||||
getById<T extends keyof ED>(
|
||||
entity: T,
|
||||
data: ED[T]['Selection']['data'],
|
||||
id: string,
|
||||
allowMiss?: boolean
|
||||
): Partial<ED[T]['Schema']> | undefined {
|
||||
const result = this.getInner(entity, {
|
||||
data,
|
||||
filter: {
|
||||
id,
|
||||
},
|
||||
}, allowMiss);
|
||||
if (result.length === 0 && !allowMiss) {
|
||||
this.fetchRows([{
|
||||
entity,
|
||||
selection: {
|
||||
data,
|
||||
filter: {
|
||||
id,
|
||||
},
|
||||
}
|
||||
}]);
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
private getInner<T extends keyof ED>(
|
||||
entity: T,
|
||||
selection: ED[T]['Selection'],
|
||||
|
|
@ -571,19 +622,8 @@ export class Cache<
|
|||
this.rollback();
|
||||
}
|
||||
if (err instanceof OakRowUnexistedException) {
|
||||
if (!this.refreshing && !allowMiss) {
|
||||
const missedRows = err.getRows();
|
||||
this.refreshing = true;
|
||||
this.exec('fetchRows', missedRows, async (result, opRecords) => {
|
||||
// missedRows理论上一定要取到,不能为空集。否则就是程序员有遗漏
|
||||
for (const record of opRecords!) {
|
||||
const { d } = record as SelectOpResult<ED>;
|
||||
assert(Object.keys(d).length > 0, '在通过fetchRow取不一致数据时返回了空数据,请拿该程序员祭天。');
|
||||
for (const mr of missedRows) {
|
||||
assert(Object.keys(d![mr.entity]!).length > 0, `在通过fetchRow取不一致数据时返回了空数据,请拿该程序员祭天。entity是${mr.entity}`);
|
||||
}
|
||||
}
|
||||
})
|
||||
if (!allowMiss) {
|
||||
this.fetchRows(err.getRows());
|
||||
}
|
||||
return [];
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { EntityDict, OperateOption, SelectOption, OpRecord, AspectWrapper, CheckerType, Aspect, SelectOpResult, AuthCascadePath, AuthDeduceRelationMap, OakUserException } from 'oak-domain/lib/types';
|
||||
import { EntityDict, OperateOption, SelectOption, OpRecord, AspectWrapper, CheckerType, Aspect, SelectOpResult, AuthCascadePath, AuthDeduceRelationMap, OakUserException, OakRowUnexistedException } from 'oak-domain/lib/types';
|
||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||
import { CommonAspectDict } from 'oak-common-aspect';
|
||||
import { Feature } from '../types/Feature';
|
||||
|
|
@ -241,6 +241,12 @@ export class RelationAuth<
|
|||
}
|
||||
catch (err) {
|
||||
this.cache.rollback();
|
||||
if (err instanceof OakRowUnexistedException) {
|
||||
// 发现缓存中缺失项的话要协助获取
|
||||
const missedRows = err.getRows();
|
||||
this.cache.fetchRows(missedRows);
|
||||
return false;
|
||||
}
|
||||
if (!(err instanceof OakUserException)) {
|
||||
throw err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ class ListNode<
|
|||
},
|
||||
filter,
|
||||
sorter,
|
||||
});
|
||||
}, true);
|
||||
this.ids = result.map((ele) => ele.id) as unknown as string[];
|
||||
}
|
||||
}
|
||||
|
|
@ -562,7 +562,7 @@ class ListNode<
|
|||
const result = this.cache.get(this.entity, {
|
||||
data,
|
||||
filter: filter2,
|
||||
}, this.isLoading());
|
||||
}, true);
|
||||
|
||||
|
||||
const r2 = result.filter(
|
||||
|
|
@ -1131,7 +1131,7 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
|
|||
filter: {
|
||||
id,
|
||||
},
|
||||
}, this.isLoading());
|
||||
}, true);
|
||||
if (this.aggr) {
|
||||
merge(result[0], this.aggr);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue