几个小BUG,以及对现在属性为undefined会报RowUnexsited错误的处理
This commit is contained in:
parent
f412afd2a9
commit
90c7db02b7
|
|
@ -1,14 +1,18 @@
|
||||||
import { EntityDict, OperateOption, OperationResult, OpRecord, SelectOption } from 'oak-domain/lib/types/Entity';
|
import { DeduceCreateSingleOperation, DeduceRemoveOperation, DeduceUpdateOperation, EntityDict, OperationResult, OpRecord, SelectOption } from 'oak-domain/lib/types/Entity';
|
||||||
import { StorageSchema } from "oak-domain/lib/types/Storage";
|
import { StorageSchema } from "oak-domain/lib/types/Storage";
|
||||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||||
import { Checker, CheckerType, Context } from 'oak-domain/lib/types';
|
import { Checker, CheckerType, Context } from 'oak-domain/lib/types';
|
||||||
import { TreeStore } from 'oak-memory-tree-store';
|
import { TreeStore, TreeStoreOperateOption } from 'oak-memory-tree-store';
|
||||||
|
interface CachStoreOperation extends TreeStoreOperateOption {
|
||||||
|
inSync?: boolean;
|
||||||
|
}
|
||||||
export declare class CacheStore<ED extends EntityDict & BaseEntityDict, Cxt extends Context<ED>> extends TreeStore<ED, Cxt> {
|
export declare class CacheStore<ED extends EntityDict & BaseEntityDict, Cxt extends Context<ED>> extends TreeStore<ED, Cxt> {
|
||||||
private executor;
|
private executor;
|
||||||
private getFullDataFn?;
|
private getFullDataFn?;
|
||||||
private resetInitialDataFn?;
|
private resetInitialDataFn?;
|
||||||
constructor(storageSchema: StorageSchema<ED>, contextBuilder: () => (store: CacheStore<ED, Cxt>) => Cxt, getFullDataFn?: () => any, resetInitialDataFn?: () => void);
|
constructor(storageSchema: StorageSchema<ED>, contextBuilder: () => (store: CacheStore<ED, Cxt>) => Cxt, getFullDataFn?: () => any, resetInitialDataFn?: () => void);
|
||||||
operate<T extends keyof ED, OP extends OperateOption>(entity: T, operation: ED[T]['Operation'], context: Cxt, option: OP): Promise<OperationResult<ED>>;
|
protected updateAbjointRow<T extends keyof ED>(entity: T, operation: DeduceCreateSingleOperation<ED[T]['Schema']> | DeduceUpdateOperation<ED[T]['Schema']> | DeduceRemoveOperation<ED[T]['Schema']>, context: Cxt, option?: CachStoreOperation): Promise<number>;
|
||||||
|
operate<T extends keyof ED, OP extends TreeStoreOperateOption>(entity: T, operation: ED[T]['Operation'], context: Cxt, option: OP): Promise<OperationResult<ED>>;
|
||||||
sync(opRecords: Array<OpRecord<ED>>, context: Cxt): Promise<void>;
|
sync(opRecords: Array<OpRecord<ED>>, context: Cxt): Promise<void>;
|
||||||
check<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Cxt, checkerTypes?: CheckerType[]): Promise<void>;
|
check<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Cxt, checkerTypes?: CheckerType[]): Promise<void>;
|
||||||
select<T extends keyof ED, S extends ED[T]['Selection'], OP extends SelectOption>(entity: T, selection: S, context: Cxt, option: OP): Promise<import("oak-domain/lib/types").SelectionResult<ED[T]["Schema"], S["data"]>>;
|
select<T extends keyof ED, S extends ED[T]['Selection'], OP extends SelectOption>(entity: T, selection: S, context: Cxt, option: OP): Promise<import("oak-domain/lib/types").SelectionResult<ED[T]["Schema"], S["data"]>>;
|
||||||
|
|
@ -24,3 +28,4 @@ export declare class CacheStore<ED extends EntityDict & BaseEntityDict, Cxt exte
|
||||||
*/
|
*/
|
||||||
resetInitialData(): void;
|
resetInitialData(): void;
|
||||||
}
|
}
|
||||||
|
export {};
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ var tslib_1 = require("tslib");
|
||||||
var TriggerExecutor_1 = require("oak-domain/lib/store/TriggerExecutor");
|
var TriggerExecutor_1 = require("oak-domain/lib/store/TriggerExecutor");
|
||||||
var oak_memory_tree_store_1 = require("oak-memory-tree-store");
|
var oak_memory_tree_store_1 = require("oak-memory-tree-store");
|
||||||
var assert_1 = tslib_1.__importDefault(require("assert"));
|
var assert_1 = tslib_1.__importDefault(require("assert"));
|
||||||
|
;
|
||||||
var CacheStore = /** @class */ (function (_super) {
|
var CacheStore = /** @class */ (function (_super) {
|
||||||
tslib_1.__extends(CacheStore, _super);
|
tslib_1.__extends(CacheStore, _super);
|
||||||
function CacheStore(storageSchema, contextBuilder, getFullDataFn, resetInitialDataFn) {
|
function CacheStore(storageSchema, contextBuilder, getFullDataFn, resetInitialDataFn) {
|
||||||
|
|
@ -16,6 +17,28 @@ var CacheStore = /** @class */ (function (_super) {
|
||||||
_this.resetInitialDataFn = resetInitialDataFn;
|
_this.resetInitialDataFn = resetInitialDataFn;
|
||||||
return _this;
|
return _this;
|
||||||
}
|
}
|
||||||
|
CacheStore.prototype.updateAbjointRow = function (entity, operation, context, option) {
|
||||||
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||||
|
var action, data, attributes, key;
|
||||||
|
var _a;
|
||||||
|
return tslib_1.__generator(this, function (_b) {
|
||||||
|
if (!(option === null || option === void 0 ? void 0 : option.inSync)) {
|
||||||
|
action = operation.action, data = operation.data;
|
||||||
|
if (action === 'create') {
|
||||||
|
attributes = this.getSchema()[entity].attributes;
|
||||||
|
for (key in attributes) {
|
||||||
|
if (data[key] === undefined) {
|
||||||
|
Object.assign(data, (_a = {},
|
||||||
|
_a[key] = null,
|
||||||
|
_a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [2 /*return*/, _super.prototype.updateAbjointRow.call(this, entity, operation, context, option)];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
CacheStore.prototype.operate = function (entity, operation, context, option) {
|
CacheStore.prototype.operate = function (entity, operation, context, option) {
|
||||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||||
var autoCommit, result, err_1;
|
var autoCommit, result, err_1;
|
||||||
|
|
@ -77,7 +100,9 @@ var CacheStore = /** @class */ (function (_super) {
|
||||||
_a.label = 2;
|
_a.label = 2;
|
||||||
case 2:
|
case 2:
|
||||||
_a.trys.push([2, 4, , 7]);
|
_a.trys.push([2, 4, , 7]);
|
||||||
return [4 /*yield*/, _super.prototype.sync.call(this, opRecords, context)];
|
return [4 /*yield*/, _super.prototype.sync.call(this, opRecords, context, {
|
||||||
|
inSync: true,
|
||||||
|
})];
|
||||||
case 3:
|
case 3:
|
||||||
result = _a.sent();
|
result = _a.sent();
|
||||||
return [3 /*break*/, 7];
|
return [3 /*break*/, 7];
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
import { EntityDict, SelectOption, Context, RowStore, DeduceCreateOperation, DeduceRemoveOperation, DeduceUpdateOperation, OperateOption, SelectionResult, SelectRowShape } from "oak-domain/lib/types";
|
import { EntityDict, Context, RowStore, DeduceCreateOperation, DeduceRemoveOperation, DeduceUpdateOperation, SelectionResult, SelectRowShape } from "oak-domain/lib/types";
|
||||||
import { TreeStore } from 'oak-memory-tree-store';
|
import { TreeStore, TreeStoreOperateOption, TreeStoreSelectOption } from 'oak-memory-tree-store';
|
||||||
import { StorageSchema, Trigger, Checker } from "oak-domain/lib/types";
|
import { StorageSchema, Trigger, Checker } from "oak-domain/lib/types";
|
||||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||||
interface DebugStoreOperateOption extends OperateOption {
|
interface DebugStoreOperateOption extends TreeStoreOperateOption {
|
||||||
noLock?: true;
|
noLock?: true;
|
||||||
}
|
}
|
||||||
interface DebugStoreSelectOption extends SelectOption {
|
interface DebugStoreSelectOption extends TreeStoreSelectOption {
|
||||||
noLock?: true;
|
noLock?: true;
|
||||||
}
|
}
|
||||||
export declare class DebugStore<ED extends EntityDict & BaseEntityDict, Cxt extends Context<ED>> extends TreeStore<ED, Cxt> {
|
export declare class DebugStore<ED extends EntityDict & BaseEntityDict, Cxt extends Context<ED>> extends TreeStore<ED, Cxt> {
|
||||||
private executor;
|
private executor;
|
||||||
private rwLock;
|
private rwLock;
|
||||||
constructor(storageSchema: StorageSchema<ED>, contextBuilder: (cxtString?: string) => (store: RowStore<ED, Cxt>) => Promise<Cxt>);
|
constructor(storageSchema: StorageSchema<ED>, contextBuilder: (cxtString?: string) => (store: RowStore<ED, Cxt>) => Promise<Cxt>);
|
||||||
|
protected updateAbjointRow<T extends keyof ED, OP extends DebugStoreOperateOption>(entity: T, operation: ED[T]['CreateSingle'] | ED[T]['Update'] | ED[T]['Remove'], context: Cxt, option?: OP): Promise<number>;
|
||||||
protected cascadeUpdate<T extends keyof ED, OP extends DebugStoreOperateOption>(entity: T, operation: DeduceCreateOperation<ED[T]["Schema"]> | DeduceUpdateOperation<ED[T]["Schema"]> | DeduceRemoveOperation<ED[T]["Schema"]>, context: Cxt, option: OP): Promise<import("oak-domain/lib/types").OperationResult<ED>>;
|
protected cascadeUpdate<T extends keyof ED, OP extends DebugStoreOperateOption>(entity: T, operation: DeduceCreateOperation<ED[T]["Schema"]> | DeduceUpdateOperation<ED[T]["Schema"]> | DeduceRemoveOperation<ED[T]["Schema"]>, context: Cxt, option: OP): Promise<import("oak-domain/lib/types").OperationResult<ED>>;
|
||||||
protected cascadeSelect<T extends keyof ED, S extends ED[T]["Selection"], OP extends DebugStoreSelectOption>(entity: T, selection: S, context: Cxt, option: OP): Promise<SelectRowShape<ED[T]['Schema'], S['data']>[]>;
|
protected cascadeSelect<T extends keyof ED, S extends ED[T]["Selection"], OP extends DebugStoreSelectOption>(entity: T, selection: S, context: Cxt, option: OP): Promise<SelectRowShape<ED[T]['Schema'], S['data']>[]>;
|
||||||
operate<T extends keyof ED, OP extends DebugStoreOperateOption>(entity: T, operation: ED[T]['Operation'], context: Cxt, option: OP): Promise<import("oak-domain/lib/types").OperationResult<ED>>;
|
operate<T extends keyof ED, OP extends DebugStoreOperateOption>(entity: T, operation: ED[T]['Operation'], context: Cxt, option: OP): Promise<import("oak-domain/lib/types").OperationResult<ED>>;
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,26 @@ var DebugStore = /** @class */ (function (_super) {
|
||||||
_this.rwLock = new concurrent_1.RWLock();
|
_this.rwLock = new concurrent_1.RWLock();
|
||||||
return _this;
|
return _this;
|
||||||
}
|
}
|
||||||
|
DebugStore.prototype.updateAbjointRow = function (entity, operation, context, option) {
|
||||||
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||||
|
var action, data, attributes, key;
|
||||||
|
var _a;
|
||||||
|
return tslib_1.__generator(this, function (_b) {
|
||||||
|
action = operation.action, data = operation.data;
|
||||||
|
if (action === 'create') {
|
||||||
|
attributes = this.getSchema()[entity].attributes;
|
||||||
|
for (key in attributes) {
|
||||||
|
if (data[key] === undefined) {
|
||||||
|
Object.assign(data, (_a = {},
|
||||||
|
_a[key] = null,
|
||||||
|
_a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [2 /*return*/, _super.prototype.updateAbjointRow.call(this, entity, operation, context, option)];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
DebugStore.prototype.cascadeUpdate = function (entity, operation, context, option) {
|
DebugStore.prototype.cascadeUpdate = function (entity, operation, context, option) {
|
||||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||||
var result;
|
var result;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { EntityDict, OperateOption, SelectOption, OpRecord, Context, AspectWrapper, SelectionResult, CheckerType } from 'oak-domain/lib/types';
|
import { EntityDict, OperateOption, SelectOption, OpRecord, Context, AspectWrapper, CheckerType } from 'oak-domain/lib/types';
|
||||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||||
import { CommonAspectDict } from 'oak-common-aspect';
|
import { CommonAspectDict } from 'oak-common-aspect';
|
||||||
import { Feature } from '../types/Feature';
|
import { Feature } from '../types/Feature';
|
||||||
|
|
@ -36,7 +36,8 @@ export declare class Cache<ED extends EntityDict & BaseEntityDict, Cxt extends C
|
||||||
tryRedoOperationsThenSelect<T extends keyof ED, S extends ED[T]['Selection']>(entity: T, selection: S, opers: Array<{
|
tryRedoOperationsThenSelect<T extends keyof ED, S extends ED[T]['Selection']>(entity: T, selection: S, opers: Array<{
|
||||||
entity: keyof ED;
|
entity: keyof ED;
|
||||||
operation: ED[keyof ED]['Operation'];
|
operation: ED[keyof ED]['Operation'];
|
||||||
}>): Promise<SelectionResult<ED[T]["Schema"], S["data"]>>;
|
}>): Promise<import("oak-domain/lib/types").SelectRowShape<ED[T]["Schema"], S["data"]>[]>;
|
||||||
|
private getInner;
|
||||||
get<T extends keyof ED, S extends ED[T]['Selection']>(entity: T, selection: S, params?: SelectOption): Promise<import("oak-domain/lib/types").SelectRowShape<ED[T]["Schema"], S["data"]>[]>;
|
get<T extends keyof ED, S extends ED[T]['Selection']>(entity: T, selection: S, params?: SelectOption): Promise<import("oak-domain/lib/types").SelectRowShape<ED[T]["Schema"], S["data"]>[]>;
|
||||||
judgeRelation(entity: keyof ED, attr: string): string | 0 | 1 | 2 | string[];
|
judgeRelation(entity: keyof ED, attr: string): string | 0 | 1 | 2 | string[];
|
||||||
bindOnSync(callback: (opRecords: OpRecord<ED>[]) => Promise<void>): void;
|
bindOnSync(callback: (opRecords: OpRecord<ED>[]) => Promise<void>): void;
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,7 @@ var Cache = /** @class */ (function (_super) {
|
||||||
*/
|
*/
|
||||||
Cache.prototype.tryRedoOperationsThenSelect = function (entity, selection, opers) {
|
Cache.prototype.tryRedoOperationsThenSelect = function (entity, selection, opers) {
|
||||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||||
var result, context, opers_1, opers_1_1, oper, e_2_1, err_3, missedRows;
|
var context, opers_1, opers_1_1, oper, e_2_1, result, err_3;
|
||||||
var e_2, _a;
|
var e_2, _a;
|
||||||
return tslib_1.__generator(this, function (_b) {
|
return tslib_1.__generator(this, function (_b) {
|
||||||
switch (_b.label) {
|
switch (_b.label) {
|
||||||
|
|
@ -269,50 +269,63 @@ var Cache = /** @class */ (function (_super) {
|
||||||
(0, selection_1.reinforceSelection)(this.cacheStore.getSchema(), entity, selection);
|
(0, selection_1.reinforceSelection)(this.cacheStore.getSchema(), entity, selection);
|
||||||
_b.label = 10;
|
_b.label = 10;
|
||||||
case 10:
|
case 10:
|
||||||
if (!true) return [3 /*break*/, 20];
|
_b.trys.push([10, 13, , 15]);
|
||||||
_b.label = 11;
|
return [4 /*yield*/, this.getInner(entity, selection, context)];
|
||||||
case 11:
|
case 11:
|
||||||
_b.trys.push([11, 14, , 19]);
|
result = _b.sent();
|
||||||
|
return [4 /*yield*/, context.rollback()];
|
||||||
|
case 12:
|
||||||
|
_b.sent();
|
||||||
|
return [2 /*return*/, result];
|
||||||
|
case 13:
|
||||||
|
err_3 = _b.sent();
|
||||||
|
return [4 /*yield*/, context.rollback()];
|
||||||
|
case 14:
|
||||||
|
_b.sent();
|
||||||
|
throw err_3;
|
||||||
|
case 15: return [2 /*return*/];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Cache.prototype.getInner = function (entity, selection, context) {
|
||||||
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||||
|
var result, err_4, missedRows;
|
||||||
|
return tslib_1.__generator(this, function (_a) {
|
||||||
|
switch (_a.label) {
|
||||||
|
case 0:
|
||||||
|
if (!true) return [3 /*break*/, 8];
|
||||||
|
_a.label = 1;
|
||||||
|
case 1:
|
||||||
|
_a.trys.push([1, 3, , 7]);
|
||||||
return [4 /*yield*/, this.cacheStore.select(entity, selection, context, {
|
return [4 /*yield*/, this.cacheStore.select(entity, selection, context, {
|
||||||
dontCollect: true,
|
dontCollect: true,
|
||||||
})];
|
})];
|
||||||
case 12:
|
case 2:
|
||||||
result = _b.sent();
|
result = (_a.sent()).result;
|
||||||
return [4 /*yield*/, context.rollback()];
|
|
||||||
case 13:
|
|
||||||
_b.sent();
|
|
||||||
return [2 /*return*/, result];
|
return [2 /*return*/, result];
|
||||||
case 14:
|
case 3:
|
||||||
err_3 = _b.sent();
|
err_4 = _a.sent();
|
||||||
if (!(err_3 instanceof Exception_1.OakRowUnexistedException)) return [3 /*break*/, 16];
|
if (!(err_4 instanceof Exception_1.OakRowUnexistedException)) return [3 /*break*/, 5];
|
||||||
missedRows = err_3.getRows();
|
missedRows = err_4.getRows();
|
||||||
return [4 /*yield*/, this.aspectWrapper.exec('fetchRows', missedRows)];
|
return [4 /*yield*/, this.aspectWrapper.exec('fetchRows', missedRows)];
|
||||||
case 15:
|
case 4:
|
||||||
_b.sent();
|
_a.sent();
|
||||||
return [3 /*break*/, 18];
|
return [3 /*break*/, 6];
|
||||||
case 16: return [4 /*yield*/, context.rollback()];
|
case 5: throw err_4;
|
||||||
case 17:
|
case 6: return [3 /*break*/, 7];
|
||||||
_b.sent();
|
case 7: return [3 /*break*/, 0];
|
||||||
throw err_3;
|
case 8: return [2 /*return*/];
|
||||||
case 18: return [3 /*break*/, 19];
|
|
||||||
case 19: return [3 /*break*/, 10];
|
|
||||||
case 20: return [2 /*return*/];
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Cache.prototype.get = function (entity, selection, params) {
|
Cache.prototype.get = function (entity, selection, params) {
|
||||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||||
var context, result;
|
var context;
|
||||||
return tslib_1.__generator(this, function (_a) {
|
return tslib_1.__generator(this, function (_a) {
|
||||||
switch (_a.label) {
|
context = this.contextBuilder();
|
||||||
case 0:
|
return [2 /*return*/, this.getInner(entity, selection, context)];
|
||||||
context = this.contextBuilder();
|
|
||||||
return [4 /*yield*/, this.cacheStore.select(entity, selection, context, {})];
|
|
||||||
case 1:
|
|
||||||
result = (_a.sent()).result;
|
|
||||||
return [2 /*return*/, result];
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ declare class ListNode<ED extends EntityDict & BaseEntityDict, T extends keyof E
|
||||||
entity: T;
|
entity: T;
|
||||||
})[] | undefined>;
|
})[] | undefined>;
|
||||||
getProjection(): Promise<ED[T]['Selection']['data']>;
|
getProjection(): Promise<ED[T]['Selection']['data']>;
|
||||||
constructSelection(withParent?: true): Promise<{
|
constructSelection(withParent?: true, disableOperation?: boolean): Promise<{
|
||||||
data: ED[T]["Selection"]["data"];
|
data: ED[T]["Selection"]["data"];
|
||||||
filter: ED[T]["Selection"]["filter"] | undefined;
|
filter: ED[T]["Selection"]["filter"] | undefined;
|
||||||
sorter: DeduceSorterItem<ED[T]["Schema"]>[];
|
sorter: DeduceSorterItem<ED[T]["Schema"]>[];
|
||||||
|
|
@ -114,7 +114,7 @@ declare class SingleNode<ED extends EntityDict & BaseEntityDict, T extends keyof
|
||||||
};
|
};
|
||||||
addChild(path: string, node: SingleNode<ED, keyof ED, Cxt, AD> | ListNode<ED, keyof ED, Cxt, AD>): void;
|
addChild(path: string, node: SingleNode<ED, keyof ED, Cxt, AD> | ListNode<ED, keyof ED, Cxt, AD>): void;
|
||||||
removeChild(path: string): void;
|
removeChild(path: string): void;
|
||||||
getFreshValue(): Promise<SelectRowShape<ED[T]['Schema'], ED[T]['Selection']['data']> | undefined>;
|
getFreshValue(disableOperation?: boolean): Promise<SelectRowShape<ED[T]['Schema'], ED[T]['Selection']['data']> | undefined>;
|
||||||
doBeforeTrigger(): Promise<void>;
|
doBeforeTrigger(): Promise<void>;
|
||||||
doAfterTrigger(): Promise<void>;
|
doAfterTrigger(): Promise<void>;
|
||||||
addOperation(oper: Omit<ED[T]['Operation'], 'id'>, beforeExecute?: Operation<ED, T>['beforeExecute'], afterExecute?: Operation<ED, T>['afterExecute']): Promise<void>;
|
addOperation(oper: Omit<ED[T]['Operation'], 'id'>, beforeExecute?: Operation<ED, T>['beforeExecute'], afterExecute?: Operation<ED, T>['afterExecute']): Promise<void>;
|
||||||
|
|
@ -124,7 +124,7 @@ declare class SingleNode<ED extends EntityDict & BaseEntityDict, T extends keyof
|
||||||
getProjection(withDecendants?: boolean): Promise<ED[keyof ED]["Selection"]["data"]>;
|
getProjection(withDecendants?: boolean): Promise<ED[keyof ED]["Selection"]["data"]>;
|
||||||
refresh(): Promise<void>;
|
refresh(): Promise<void>;
|
||||||
clean(): void;
|
clean(): void;
|
||||||
getParentFilter<T2 extends keyof ED>(childNode: Node<ED, keyof ED, Cxt, AD>): Promise<ED[T2]['Selection']['filter'] | undefined>;
|
getParentFilter<T2 extends keyof ED>(childNode: Node<ED, keyof ED, Cxt, AD>, disableOperation?: boolean): Promise<ED[T2]['Selection']['filter'] | undefined>;
|
||||||
}
|
}
|
||||||
declare class VirtualNode {
|
declare class VirtualNode {
|
||||||
private dirty;
|
private dirty;
|
||||||
|
|
|
||||||
|
|
@ -600,7 +600,7 @@ var ListNode = /** @class */ (function (_super) {
|
||||||
finally { if (e_9) throw e_9.error; }
|
finally { if (e_9) throw e_9.error; }
|
||||||
}
|
}
|
||||||
if (!needRefresh) return [3 /*break*/, 3];
|
if (!needRefresh) return [3 /*break*/, 3];
|
||||||
return [4 /*yield*/, this.constructSelection(true)];
|
return [4 /*yield*/, this.constructSelection(true, true)];
|
||||||
case 1:
|
case 1:
|
||||||
_a = _c.sent(), filter = _a.filter, sorter = _a.sorter;
|
_a = _c.sent(), filter = _a.filter, sorter = _a.sorter;
|
||||||
return [4 /*yield*/, this.cache.get(this.getEntity(), {
|
return [4 /*yield*/, this.cache.get(this.getEntity(), {
|
||||||
|
|
@ -895,7 +895,7 @@ var ListNode = /** @class */ (function (_super) {
|
||||||
}
|
}
|
||||||
return [4 /*yield*/, this.cache.tryRedoOperationsThenSelect(this.entity, selection, operations)];
|
return [4 /*yield*/, this.cache.tryRedoOperationsThenSelect(this.entity, selection, operations)];
|
||||||
case 4:
|
case 4:
|
||||||
result = (_e.sent()).result;
|
result = _e.sent();
|
||||||
return [2 /*return*/, result];
|
return [2 /*return*/, result];
|
||||||
case 5: return [2 /*return*/, []];
|
case 5: return [2 /*return*/, []];
|
||||||
}
|
}
|
||||||
|
|
@ -1155,7 +1155,7 @@ var ListNode = /** @class */ (function (_super) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
ListNode.prototype.constructSelection = function (withParent) {
|
ListNode.prototype.constructSelection = function (withParent, disableOperation) {
|
||||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||||
var _a, filters, sorters, data, validParentFilter, sorterArr, filterArr, filterOfParent, filters2, filter;
|
var _a, filters, sorters, data, validParentFilter, sorterArr, filterArr, filterOfParent, filters2, filter;
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
|
@ -1200,7 +1200,7 @@ var ListNode = /** @class */ (function (_super) {
|
||||||
filterArr = _b.sent();
|
filterArr = _b.sent();
|
||||||
if (!(withParent && this.parent)) return [3 /*break*/, 5];
|
if (!(withParent && this.parent)) return [3 /*break*/, 5];
|
||||||
if (!(this.parent instanceof SingleNode)) return [3 /*break*/, 5];
|
if (!(this.parent instanceof SingleNode)) return [3 /*break*/, 5];
|
||||||
return [4 /*yield*/, this.parent.getParentFilter(this)];
|
return [4 /*yield*/, this.parent.getParentFilter(this, disableOperation)];
|
||||||
case 4:
|
case 4:
|
||||||
filterOfParent = _b.sent();
|
filterOfParent = _b.sent();
|
||||||
if (filterOfParent) {
|
if (filterOfParent) {
|
||||||
|
|
@ -1400,7 +1400,7 @@ var SingleNode = /** @class */ (function (_super) {
|
||||||
SingleNode.prototype.removeChild = function (path) {
|
SingleNode.prototype.removeChild = function (path) {
|
||||||
(0, lodash_1.unset)(this.children, path);
|
(0, lodash_1.unset)(this.children, path);
|
||||||
};
|
};
|
||||||
SingleNode.prototype.getFreshValue = function () {
|
SingleNode.prototype.getFreshValue = function (disableOperation) {
|
||||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||||
var projection, modies, _a, operations, filter, createOper, parent_1, result;
|
var projection, modies, _a, operations, filter, createOper, parent_1, result;
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
|
@ -1419,31 +1419,38 @@ var SingleNode = /** @class */ (function (_super) {
|
||||||
modies = _a;
|
modies = _a;
|
||||||
operations = modies ? (0, modi_1.createOperationsFromModies)(modies) : [];
|
operations = modies ? (0, modi_1.createOperationsFromModies)(modies) : [];
|
||||||
filter = this.id && { id: this.id };
|
filter = this.id && { id: this.id };
|
||||||
if (!filter) {
|
if (!filter && !disableOperation) {
|
||||||
createOper = this.operations.find(function (ele) { return ele.oper.action === 'create'; });
|
createOper = this.operations.find(function (ele) { return ele.oper.action === 'create'; });
|
||||||
if (createOper) {
|
if (createOper) {
|
||||||
|
(0, assert_1.assert)(createOper.oper.data.id);
|
||||||
filter = {
|
filter = {
|
||||||
id: createOper.oper.data.id
|
id: createOper.oper.data.id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
parent_1 = this.parent;
|
|
||||||
if (parent_1 instanceof ListNode || parent_1 instanceof SingleNode) {
|
|
||||||
filter = parent_1.getParentFilter(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!filter) return [3 /*break*/, 5];
|
if (!!filter) return [3 /*break*/, 5];
|
||||||
operations.push.apply(operations, tslib_1.__spreadArray([], tslib_1.__read(this.operations.map(function (ele) { return ({
|
parent_1 = this.parent;
|
||||||
entity: _this.entity,
|
if (!(parent_1 instanceof ListNode || parent_1 instanceof SingleNode)) return [3 /*break*/, 5];
|
||||||
operation: ele.oper,
|
return [4 /*yield*/, parent_1.getParentFilter(this, disableOperation)];
|
||||||
}); })), false));
|
case 4:
|
||||||
|
filter = _b.sent();
|
||||||
|
_b.label = 5;
|
||||||
|
case 5:
|
||||||
|
if (!filter) return [3 /*break*/, 7];
|
||||||
|
if (!disableOperation) {
|
||||||
|
operations.push.apply(operations, tslib_1.__spreadArray([], tslib_1.__read(this.operations.map(function (ele) { return ({
|
||||||
|
entity: _this.entity,
|
||||||
|
operation: ele.oper,
|
||||||
|
}); })), false));
|
||||||
|
}
|
||||||
return [4 /*yield*/, this.cache.tryRedoOperationsThenSelect(this.entity, {
|
return [4 /*yield*/, this.cache.tryRedoOperationsThenSelect(this.entity, {
|
||||||
data: projection,
|
data: projection,
|
||||||
filter: filter,
|
filter: filter,
|
||||||
}, operations)];
|
}, operations)];
|
||||||
case 4:
|
case 6:
|
||||||
result = (_b.sent()).result;
|
result = _b.sent();
|
||||||
return [2 /*return*/, result[0]];
|
return [2 /*return*/, result[0]];
|
||||||
case 5: return [2 /*return*/];
|
case 7: return [2 /*return*/];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -1863,13 +1870,13 @@ var SingleNode = /** @class */ (function (_super) {
|
||||||
this.children[child].clean();
|
this.children[child].clean();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
SingleNode.prototype.getParentFilter = function (childNode) {
|
SingleNode.prototype.getParentFilter = function (childNode, disableOperation) {
|
||||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||||
var value, key, sliceIdx, key2, rel;
|
var value, key, sliceIdx, key2, rel;
|
||||||
var _a;
|
var _a;
|
||||||
return tslib_1.__generator(this, function (_b) {
|
return tslib_1.__generator(this, function (_b) {
|
||||||
switch (_b.label) {
|
switch (_b.label) {
|
||||||
case 0: return [4 /*yield*/, this.getFreshValue()];
|
case 0: return [4 /*yield*/, this.getFreshValue(disableOperation)];
|
||||||
case 1:
|
case 1:
|
||||||
value = (_b.sent());
|
value = (_b.sent());
|
||||||
if (!value) {
|
if (!value) {
|
||||||
|
|
@ -1882,28 +1889,34 @@ var SingleNode = /** @class */ (function (_super) {
|
||||||
rel = this.judgeRelation(key2);
|
rel = this.judgeRelation(key2);
|
||||||
if (rel === 2) {
|
if (rel === 2) {
|
||||||
// 基于entity/entityId的多对一
|
// 基于entity/entityId的多对一
|
||||||
return [2 /*return*/, {
|
if (value.entityId && value.entity === childNode.getEntity()) {
|
||||||
id: value.entityId,
|
return [2 /*return*/, {
|
||||||
}];
|
id: value.entityId,
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
return [2 /*return*/, undefined];
|
||||||
}
|
}
|
||||||
else if (typeof rel === 'string') {
|
else if (typeof rel === 'string') {
|
||||||
return [2 /*return*/, {
|
if (value["".concat(rel, "Id")]) {
|
||||||
id: value["".concat(rel, "Id")],
|
return [2 /*return*/, {
|
||||||
}];
|
id: value["".concat(rel, "Id")],
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
return [2 /*return*/, undefined];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
(0, assert_1.assert)(rel instanceof Array);
|
(0, assert_1.assert)(rel instanceof Array);
|
||||||
if (rel[1]) {
|
if (rel[1]) {
|
||||||
// 基于普通外键的一对多
|
// 基于普通外键的一对多
|
||||||
return [2 /*return*/, (_a = {},
|
return [2 /*return*/, (_a = {},
|
||||||
_a[rel[1]] = this.id,
|
_a[rel[1]] = value.id,
|
||||||
_a)];
|
_a)];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// 基于entity/entityId的一对多
|
// 基于entity/entityId的一对多
|
||||||
return [2 /*return*/, {
|
return [2 /*return*/, {
|
||||||
entity: this.entity,
|
entity: this.entity,
|
||||||
entityId: this.id,
|
entityId: value.id,
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
import { EntityDict, OperateOption, OperationResult, OpRecord, SelectOption } from 'oak-domain/lib/types/Entity';
|
import { DeduceCreateSingleOperation, DeduceRemoveOperation, DeduceUpdateOperation, EntityDict, OperateOption, OperationResult, OpRecord, SelectOption } from 'oak-domain/lib/types/Entity';
|
||||||
import { StorageSchema } from "oak-domain/lib/types/Storage";
|
import { StorageSchema } from "oak-domain/lib/types/Storage";
|
||||||
import { TriggerExecutor } from 'oak-domain/lib/store/TriggerExecutor';
|
import { TriggerExecutor } from 'oak-domain/lib/store/TriggerExecutor';
|
||||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||||
import { Checker, CheckerType, Context, Trigger } from 'oak-domain/lib/types';
|
import { Checker, CheckerType, Context, Trigger } from 'oak-domain/lib/types';
|
||||||
import { TreeStore } from 'oak-memory-tree-store';
|
import { TreeStore, TreeStoreOperateOption } from 'oak-memory-tree-store';
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
|
||||||
|
interface CachStoreOperation extends TreeStoreOperateOption {
|
||||||
|
inSync?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export class CacheStore<
|
export class CacheStore<
|
||||||
ED extends EntityDict & BaseEntityDict,
|
ED extends EntityDict & BaseEntityDict,
|
||||||
Cxt extends Context<ED>
|
Cxt extends Context<ED>
|
||||||
|
|
@ -28,7 +32,25 @@ export class CacheStore<
|
||||||
this.resetInitialDataFn = resetInitialDataFn;
|
this.resetInitialDataFn = resetInitialDataFn;
|
||||||
}
|
}
|
||||||
|
|
||||||
async operate<T extends keyof ED, OP extends OperateOption>(
|
protected async updateAbjointRow<T extends keyof ED>(entity: T, operation: DeduceCreateSingleOperation<ED[T]['Schema']> | DeduceUpdateOperation<ED[T]['Schema']> | DeduceRemoveOperation<ED[T]['Schema']>, context: Cxt, option?: CachStoreOperation): Promise<number> {
|
||||||
|
if (!option?.inSync) {
|
||||||
|
// 如果不是同步,需要补齐所有的null属性
|
||||||
|
const { action, data } = operation;
|
||||||
|
if (action === 'create') {
|
||||||
|
const { attributes } = this.getSchema()[entity];
|
||||||
|
for (const key in attributes) {
|
||||||
|
if (data[key] === undefined) {
|
||||||
|
Object.assign(data, {
|
||||||
|
[key]: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.updateAbjointRow(entity, operation, context, option);
|
||||||
|
}
|
||||||
|
|
||||||
|
async operate<T extends keyof ED, OP extends TreeStoreOperateOption>(
|
||||||
entity: T,
|
entity: T,
|
||||||
operation: ED[T]['Operation'],
|
operation: ED[T]['Operation'],
|
||||||
context: Cxt,
|
context: Cxt,
|
||||||
|
|
@ -67,7 +89,9 @@ export class CacheStore<
|
||||||
let result;
|
let result;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result = await super.sync(opRecords, context);
|
result = await super.sync<CachStoreOperation>(opRecords, context, {
|
||||||
|
inSync: true,
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (autoCommit) {
|
if (autoCommit) {
|
||||||
await context.rollback();
|
await context.rollback();
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
import { EntityDict, SelectOption, Context, RowStore, DeduceCreateOperation, DeduceRemoveOperation, DeduceUpdateOperation, OperateOption, SelectionResult, SelectRowShape } from "oak-domain/lib/types";
|
import { EntityDict, SelectOption, Context, RowStore, DeduceCreateOperation, DeduceRemoveOperation, DeduceUpdateOperation, OperateOption, SelectionResult, SelectRowShape } from "oak-domain/lib/types";
|
||||||
import { TreeStore } from 'oak-memory-tree-store';
|
import { TreeStore, TreeStoreOperateOption, TreeStoreSelectOption } from 'oak-memory-tree-store';
|
||||||
import { StorageSchema, Trigger, Checker } from "oak-domain/lib/types";
|
import { StorageSchema, Trigger, Checker } from "oak-domain/lib/types";
|
||||||
import { TriggerExecutor } from 'oak-domain/lib/store/TriggerExecutor';
|
import { TriggerExecutor } from 'oak-domain/lib/store/TriggerExecutor';
|
||||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||||
import { RWLock } from 'oak-domain/lib/utils/concurrent';
|
import { RWLock } from 'oak-domain/lib/utils/concurrent';
|
||||||
|
|
||||||
interface DebugStoreOperateOption extends OperateOption {
|
interface DebugStoreOperateOption extends TreeStoreOperateOption {
|
||||||
noLock?: true;
|
noLock?: true;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface DebugStoreSelectOption extends SelectOption {
|
interface DebugStoreSelectOption extends TreeStoreSelectOption {
|
||||||
noLock?: true;
|
noLock?: true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -22,6 +22,26 @@ export class DebugStore<ED extends EntityDict & BaseEntityDict, Cxt extends Cont
|
||||||
this.rwLock = new RWLock();
|
this.rwLock = new RWLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async updateAbjointRow<T extends keyof ED, OP extends DebugStoreOperateOption>(
|
||||||
|
entity: T,
|
||||||
|
operation: ED[T]['CreateSingle'] | ED[T]['Update'] | ED[T]['Remove'],
|
||||||
|
context: Cxt,
|
||||||
|
option?: OP) {
|
||||||
|
// 对于create动作,没有值的属性要置NULL
|
||||||
|
const { action, data } = operation;
|
||||||
|
if (action === 'create') {
|
||||||
|
const { attributes } = this.getSchema()[entity];
|
||||||
|
for (const key in attributes) {
|
||||||
|
if (data[key] === undefined) {
|
||||||
|
Object.assign(data, {
|
||||||
|
[key]: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.updateAbjointRow(entity, operation, context, option);
|
||||||
|
}
|
||||||
|
|
||||||
protected async cascadeUpdate<T extends keyof ED, OP extends DebugStoreOperateOption>(entity: T, operation: DeduceCreateOperation<ED[T]["Schema"]> | DeduceUpdateOperation<ED[T]["Schema"]> | DeduceRemoveOperation<ED[T]["Schema"]>, context: Cxt, option: OP) {
|
protected async cascadeUpdate<T extends keyof ED, OP extends DebugStoreOperateOption>(entity: T, operation: DeduceCreateOperation<ED[T]["Schema"]> | DeduceUpdateOperation<ED[T]["Schema"]> | DeduceRemoveOperation<ED[T]["Schema"]>, context: Cxt, option: OP) {
|
||||||
if (!option.blockTrigger) {
|
if (!option.blockTrigger) {
|
||||||
await this.executor.preOperation(entity, operation, context, option);
|
await this.executor.preOperation(entity, operation, context, option);
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,6 @@ export class Cache<
|
||||||
operation: ED[keyof ED]['Operation'];
|
operation: ED[keyof ED]['Operation'];
|
||||||
}>
|
}>
|
||||||
) {
|
) {
|
||||||
let result: SelectionResult<ED[T]['Schema'], S['data']>;
|
|
||||||
const context = this.contextBuilder!();
|
const context = this.contextBuilder!();
|
||||||
await context.begin();
|
await context.begin();
|
||||||
for (const oper of opers) {
|
for (const oper of opers) {
|
||||||
|
|
@ -188,9 +187,21 @@ export class Cache<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
reinforceSelection(this.cacheStore!.getSchema(), entity, selection);
|
reinforceSelection(this.cacheStore!.getSchema(), entity, selection);
|
||||||
|
try {
|
||||||
|
const result = await this.getInner(entity, selection, context);
|
||||||
|
await context.rollback();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
await context.rollback();
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getInner<T extends keyof ED, S extends ED[T]['Selection']>(entity: T, selection: S, context: Cxt) {
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
result = await this.cacheStore!.select(
|
const { result } = await this.cacheStore!.select(
|
||||||
entity,
|
entity,
|
||||||
selection,
|
selection,
|
||||||
context,
|
context,
|
||||||
|
|
@ -198,15 +209,12 @@ export class Cache<
|
||||||
dontCollect: true,
|
dontCollect: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
await context.rollback();
|
|
||||||
return result;
|
return result;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof OakRowUnexistedException) {
|
if (err instanceof OakRowUnexistedException) {
|
||||||
const missedRows = err.getRows();
|
const missedRows = err.getRows();
|
||||||
await this.aspectWrapper.exec('fetchRows', missedRows);
|
await this.aspectWrapper.exec('fetchRows', missedRows);
|
||||||
} else {
|
} else {
|
||||||
await context.rollback();
|
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -219,13 +227,8 @@ export class Cache<
|
||||||
params?: SelectOption
|
params?: SelectOption
|
||||||
) {
|
) {
|
||||||
const context = this.contextBuilder!();
|
const context = this.contextBuilder!();
|
||||||
const { result } = await this.cacheStore!.select(
|
|
||||||
entity,
|
return this.getInner(entity, selection, context);
|
||||||
selection,
|
|
||||||
context,
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
judgeRelation(entity: keyof ED, attr: string) {
|
judgeRelation(entity: keyof ED, attr: string) {
|
||||||
|
|
|
||||||
|
|
@ -583,7 +583,8 @@ class ListNode<
|
||||||
此时对userRelation的删除动作就会导致user不会被移出list
|
此时对userRelation的删除动作就会导致user不会被移出list
|
||||||
*/
|
*/
|
||||||
if (needRefresh) {
|
if (needRefresh) {
|
||||||
const { filter, sorter } = await this.constructSelection(true);
|
// 这里因为operation还没被移除掉(execute还没有结束),所以同步的时候不能计算动态的operation产生的id
|
||||||
|
const { filter, sorter } = await this.constructSelection(true, true);
|
||||||
const result = await this.cache.get(this.getEntity(), {
|
const result = await this.cache.get(this.getEntity(), {
|
||||||
data: {
|
data: {
|
||||||
id: 1,
|
id: 1,
|
||||||
|
|
@ -815,7 +816,7 @@ class ListNode<
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { result } = await this.cache.tryRedoOperationsThenSelect(this.entity, selection, operations);
|
const result = await this.cache.tryRedoOperationsThenSelect(this.entity, selection, operations);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
|
|
@ -936,7 +937,7 @@ class ListNode<
|
||||||
return projection;
|
return projection;
|
||||||
}
|
}
|
||||||
|
|
||||||
async constructSelection(withParent?: true) {
|
async constructSelection(withParent?: true, disableOperation?: boolean) {
|
||||||
const { filters, sorters } = this;
|
const { filters, sorters } = this;
|
||||||
const data = await this.getProjection();
|
const data = await this.getProjection();
|
||||||
let validParentFilter = true;
|
let validParentFilter = true;
|
||||||
|
|
@ -964,7 +965,7 @@ class ListNode<
|
||||||
|
|
||||||
if (withParent && this.parent) {
|
if (withParent && this.parent) {
|
||||||
if (this.parent instanceof SingleNode) {
|
if (this.parent instanceof SingleNode) {
|
||||||
const filterOfParent = await this.parent.getParentFilter<T>(this);
|
const filterOfParent = await this.parent.getParentFilter<T>(this, disableOperation);
|
||||||
if (filterOfParent) {
|
if (filterOfParent) {
|
||||||
filterArr.push(filterOfParent as any);
|
filterArr.push(filterOfParent as any);
|
||||||
}
|
}
|
||||||
|
|
@ -1149,7 +1150,7 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
|
||||||
unset(this.children, path);
|
unset(this.children, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFreshValue(): Promise<SelectRowShape<ED[T]['Schema'], ED[T]['Selection']['data']> | undefined> {
|
async getFreshValue(disableOperation?: boolean): Promise<SelectRowShape<ED[T]['Schema'], ED[T]['Selection']['data']> | undefined> {
|
||||||
const projection = await this.getProjection(false);
|
const projection = await this.getProjection(false);
|
||||||
|
|
||||||
// 如果本结点是在modi路径上,需要将modi更新之后再得到后项
|
// 如果本结点是在modi路径上,需要将modi更新之后再得到后项
|
||||||
|
|
@ -1159,31 +1160,35 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
|
||||||
operation: ED[keyof ED]['Operation'];
|
operation: ED[keyof ED]['Operation'];
|
||||||
}> : [];
|
}> : [];
|
||||||
let filter = this.id && { id: this.id } as ED[T]['Selection']['filter'];
|
let filter = this.id && { id: this.id } as ED[T]['Selection']['filter'];
|
||||||
if (!filter) {
|
if (!filter && !disableOperation) {
|
||||||
// 可能是create
|
// 可能是create
|
||||||
const createOper = this.operations.find(
|
const createOper = this.operations.find(
|
||||||
(ele) => ele.oper.action === 'create'
|
(ele) => ele.oper.action === 'create'
|
||||||
) as { oper: ED[T]['CreateSingle'] };
|
) as { oper: ED[T]['CreateSingle'] };
|
||||||
if (createOper) {
|
if (createOper) {
|
||||||
|
assert(createOper.oper.data.id);
|
||||||
filter = {
|
filter = {
|
||||||
id: createOper.oper.data.id
|
id: createOper.oper.data.id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!filter) {
|
||||||
// 还可能是来自父级的外键
|
// 还可能是来自父级的外键
|
||||||
const { parent } = this;
|
const { parent } = this;
|
||||||
if (parent instanceof ListNode || parent instanceof SingleNode) {
|
if (parent instanceof ListNode || parent instanceof SingleNode) {
|
||||||
filter = parent.getParentFilter(this);
|
filter = await parent.getParentFilter(this, disableOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (filter) {
|
if (filter) {
|
||||||
operations.push(...this.operations.map(
|
if (!disableOperation) {
|
||||||
ele => ({
|
operations.push(...this.operations.map(
|
||||||
entity: this.entity,
|
ele => ({
|
||||||
operation: ele.oper,
|
entity: this.entity,
|
||||||
})
|
operation: ele.oper,
|
||||||
));
|
})
|
||||||
const { result } = await this.cache.tryRedoOperationsThenSelect(this.entity, {
|
));
|
||||||
|
}
|
||||||
|
const result = await this.cache.tryRedoOperationsThenSelect(this.entity, {
|
||||||
data: projection,
|
data: projection,
|
||||||
filter,
|
filter,
|
||||||
}, operations);
|
}, operations);
|
||||||
|
|
@ -1439,8 +1444,8 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getParentFilter<T2 extends keyof ED>(childNode: Node<ED, keyof ED, Cxt, AD>): Promise<ED[T2]['Selection']['filter'] | undefined> {
|
async getParentFilter<T2 extends keyof ED>(childNode: Node<ED, keyof ED, Cxt, AD>, disableOperation?: boolean): Promise<ED[T2]['Selection']['filter'] | undefined> {
|
||||||
const value = (await this.getFreshValue())!;
|
const value = (await this.getFreshValue(disableOperation))!;
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1452,28 +1457,34 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
|
||||||
const rel = this.judgeRelation(key2);
|
const rel = this.judgeRelation(key2);
|
||||||
if (rel === 2) {
|
if (rel === 2) {
|
||||||
// 基于entity/entityId的多对一
|
// 基于entity/entityId的多对一
|
||||||
return {
|
if (value.entityId && value.entity === childNode.getEntity()) {
|
||||||
id: value.entityId,
|
return {
|
||||||
};
|
id: value.entityId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
else if (typeof rel === 'string') {
|
else if (typeof rel === 'string') {
|
||||||
return {
|
if (value[`${rel}Id`]) {
|
||||||
id: value[`${rel}Id`],
|
return {
|
||||||
};
|
id: value[`${rel}Id`],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert(rel instanceof Array);
|
assert(rel instanceof Array);
|
||||||
if (rel[1]) {
|
if (rel[1]) {
|
||||||
// 基于普通外键的一对多
|
// 基于普通外键的一对多
|
||||||
return {
|
return {
|
||||||
[rel[1]]: this.id,
|
[rel[1]]: value.id,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// 基于entity/entityId的一对多
|
// 基于entity/entityId的一对多
|
||||||
return {
|
return {
|
||||||
entity: this.entity,
|
entity: this.entity,
|
||||||
entityId: this.id,
|
entityId: value.id,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue