一些定义上的修正

This commit is contained in:
Xu Chang 2022-11-07 22:41:41 +08:00
parent 31c5a334eb
commit b66d409e1f
19 changed files with 1366 additions and 1140 deletions

View File

@ -1,17 +1,13 @@
import { DeduceCreateSingleOperation, DeduceRemoveOperation, DeduceUpdateOperation, EntityDict, OperationResult, OpRecord, SelectOption } from 'oak-domain/lib/types/Entity';
import { EntityDict, OperationResult, OpRecord, SelectOption } from 'oak-domain/lib/types/Entity';
import { StorageSchema } from "oak-domain/lib/types/Storage";
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
import { Checker, CheckerType, Context } from 'oak-domain/lib/types';
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> {
private executor;
private getFullDataFn?;
private resetInitialDataFn?;
constructor(storageSchema: StorageSchema<ED>, contextBuilder: () => (store: CacheStore<ED, Cxt>) => Cxt, getFullDataFn?: () => any, resetInitialDataFn?: () => void);
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>;
check<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Cxt, checkerTypes?: CheckerType[]): Promise<void>;
@ -28,4 +24,3 @@ export declare class CacheStore<ED extends EntityDict & BaseEntityDict, Cxt exte
*/
resetInitialData(): void;
}
export {};

View File

@ -17,28 +17,6 @@ var CacheStore = /** @class */ (function (_super) {
_this.resetInitialDataFn = resetInitialDataFn;
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) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var autoCommit, result, err_1;
@ -100,9 +78,7 @@ var CacheStore = /** @class */ (function (_super) {
_a.label = 2;
case 2:
_a.trys.push([2, 4, , 7]);
return [4 /*yield*/, _super.prototype.sync.call(this, opRecords, context, {
inSync: true,
})];
return [4 /*yield*/, _super.prototype.sync.call(this, opRecords, context, {})];
case 3:
result = _a.sent();
return [3 /*break*/, 7];

View File

@ -12,7 +12,6 @@ export declare class DebugStore<ED extends EntityDict & BaseEntityDict, Cxt exte
private executor;
private rwLock;
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 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>>;

View File

@ -15,26 +15,6 @@ var DebugStore = /** @class */ (function (_super) {
_this.rwLock = new concurrent_1.RWLock();
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) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var result;

View File

@ -5,24 +5,18 @@ import { NamedFilterItem, NamedSorterItem } from "../types/NamedCondition";
import { Cache } from './cache';
import { Pagination } from '../types/Pagination';
import { Feature } from '../types/Feature';
declare type Operation<ED extends EntityDict & BaseEntityDict, T extends keyof ED, OmitId extends boolean = false> = {
oper: OmitId extends true ? Omit<ED[T]['Operation'], 'id'> : ED[T]['Operation'];
beforeExecute?: () => Promise<void>;
afterExecute?: () => Promise<void>;
};
declare abstract class Node<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>, AD extends CommonAspectDict<ED, Cxt>> {
protected entity: T;
protected schema: StorageSchema<ED>;
protected projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>);
protected parent?: Node<ED, keyof ED, Cxt, AD> | VirtualNode;
protected parent?: SingleNode<ED, keyof ED, Cxt, AD> | ListNode<ED, T, Cxt, AD> | VirtualNode;
protected dirty?: boolean;
protected cache: Cache<ED, Cxt, AD>;
protected loading: boolean;
protected loadingMore: boolean;
protected executing: boolean;
protected operations: Operation<ED, T>[];
protected modiIds: string[] | undefined;
constructor(entity: T, schema: StorageSchema<ED>, cache: Cache<ED, Cxt, AD>, projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>), parent?: Node<ED, keyof ED, Cxt, AD> | VirtualNode);
constructor(entity: T, schema: StorageSchema<ED>, cache: Cache<ED, Cxt, AD>, projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>), parent?: SingleNode<ED, keyof ED, Cxt, AD> | ListNode<ED, T, Cxt, AD> | VirtualNode);
getEntity(): T;
getSchema(): StorageSchema<ED>;
protected abstract getChildPath(child: Node<ED, keyof ED, Cxt, AD>): string;
@ -40,7 +34,7 @@ declare abstract class Node<ED extends EntityDict & BaseEntityDict, T extends ke
isLoadingMore(): boolean;
isExecuting(): boolean;
setExecuting(executing: boolean): void;
getParent(): Node<ED, keyof ED, Cxt, AD> | VirtualNode | undefined;
getParent(): SingleNode<ED, keyof ED, Cxt, AD> | ListNode<ED, T, Cxt, AD> | VirtualNode | undefined;
protected getProjection(): Promise<ED[T]["Selection"]["data"]>;
protected judgeRelation(attr: string): string | 0 | 1 | 2 | string[];
protected contains(filter: ED[T]['Selection']['filter'], conditionalFilter: ED[T]['Selection']['filter']): boolean;
@ -48,6 +42,7 @@ declare abstract class Node<ED extends EntityDict & BaseEntityDict, T extends ke
}
declare class ListNode<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>, AD extends CommonAspectDict<ED, Cxt>> extends Node<ED, T, Cxt, AD> {
private children;
private updates;
private filters;
private sorters;
private pagination;
@ -58,7 +53,7 @@ declare class ListNode<ED extends EntityDict & BaseEntityDict, T extends keyof E
checkIfClean(): void;
onCacheSync(records: OpRecord<ED>[]): Promise<void>;
destroy(): void;
constructor(entity: T, schema: StorageSchema<ED>, cache: Cache<ED, Cxt, AD>, projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>), parent?: Node<ED, keyof ED, Cxt, AD> | VirtualNode, filters?: NamedFilterItem<ED, T>[], sorters?: NamedSorterItem<ED, T>[], pagination?: Pagination);
constructor(entity: T, schema: StorageSchema<ED>, cache: Cache<ED, Cxt, AD>, projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>), parent?: SingleNode<ED, keyof ED, Cxt, AD> | VirtualNode, filters?: NamedFilterItem<ED, T>[], sorters?: NamedSorterItem<ED, T>[], pagination?: Pagination);
getPagination(): Pagination;
setPagination(pagination: Pagination): Promise<void>;
getChild(path: string): SingleNode<ED, T, Cxt, AD> | undefined;
@ -78,13 +73,22 @@ declare class ListNode<ED extends EntityDict & BaseEntityDict, T extends keyof E
removeNamedSorter(sorter: NamedSorterItem<ED, T>, refresh?: boolean): Promise<void>;
removeNamedSorterByName(name: string, refresh: boolean): Promise<void>;
getFreshValue(): Promise<Array<SelectRowShape<ED[T]['Schema'], ED[T]['Selection']['data']>>>;
addOperation(oper: Omit<ED[T]['Operation'], 'id'>, beforeExecute?: Operation<ED, T>['beforeExecute'], afterExecute?: Operation<ED, T>['afterExecute']): Promise<void>;
addItem(item: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): Promise<void>;
removeItem(id: string, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): Promise<void>;
recoverItem(id: string): Promise<void>;
/**
* itemId进行更新
* @param data
* @param id
* @param beforeExecute
* @param afterExecute
*/
updateItem(data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): Promise<void>;
updateItems(data: Record<string, ED[T]['Update']['data']>, action?: ED[T]['Action']): Promise<void>;
doBeforeTrigger(): Promise<void>;
doAfterTrigger(): Promise<void>;
getParentFilter(childNode: SingleNode<ED, T, Cxt, AD>): Promise<ED[T]['Selection']['filter'] | undefined>;
composeOperations(): Promise<(ED[T]["Operation"] & {
entity: T;
})[] | undefined>;
composeOperations(): Promise<any[] | undefined>;
getProjection(): Promise<ED[T]['Selection']['data']>;
constructSelection(withParent?: true, disableOperation?: boolean): Promise<{
data: ED[T]["Selection"]["data"];
@ -100,7 +104,9 @@ declare class ListNode<ED extends EntityDict & BaseEntityDict, T extends keyof E
declare class SingleNode<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>, AD extends CommonAspectDict<ED, Cxt>> extends Node<ED, T, Cxt, AD> {
private id?;
private children;
constructor(entity: T, schema: StorageSchema<ED>, cache: Cache<ED, Cxt, AD>, projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>), parent?: Node<ED, keyof ED, Cxt, AD> | VirtualNode, id?: string);
private operation?;
constructor(entity: T, schema: StorageSchema<ED>, cache: Cache<ED, Cxt, AD>, projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>), parent?: SingleNode<ED, keyof ED, Cxt, AD> | ListNode<ED, T, Cxt, AD> | VirtualNode, id?: string);
private tryGetParentFilter;
protected getChildPath(child: Node<ED, keyof ED, Cxt, AD>): string;
setLoading(loading: boolean): void;
checkIfClean(): void;
@ -117,11 +123,14 @@ declare class SingleNode<ED extends EntityDict & BaseEntityDict, T extends keyof
getFreshValue(disableOperation?: boolean): Promise<SelectRowShape<ED[T]['Schema'], ED[T]['Selection']['data']> | undefined>;
doBeforeTrigger(): Promise<void>;
doAfterTrigger(): Promise<void>;
addOperation(oper: Omit<ED[T]['Operation'], 'id'>, beforeExecute?: Operation<ED, T>['beforeExecute'], afterExecute?: Operation<ED, T>['afterExecute']): Promise<void>;
composeOperations(): Promise<(ED[T]["Operation"] & {
create(data: Partial<Omit<ED[T]['CreateSingle']['data'], 'id'>>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): Promise<void>;
update(data: ED[T]['Update']['data'], action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): Promise<void>;
remove(beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): Promise<void>;
composeOperations(): Promise<Array<{
entity: T;
})[] | undefined>;
getProjection(withDecendants?: boolean): Promise<ED[keyof ED]["Selection"]["data"]>;
operation: ED[T]['Update'];
}> | undefined>;
getProjection(withDecendants?: boolean): Promise<ED[T]["Selection"]["data"]>;
refresh(): Promise<void>;
clean(): void;
getParentFilter<T2 extends keyof ED>(childNode: Node<ED, keyof ED, Cxt, AD>, disableOperation?: boolean): Promise<ED[T2]['Selection']['filter'] | undefined>;
@ -133,7 +142,7 @@ declare class VirtualNode {
getActiveModies(child: any): Promise<undefined>;
setDirty(): void;
addChild(path: string, child: SingleNode<any, any, any, any> | ListNode<any, any, any, any>): void;
getChild(path: string): ListNode<any, any, any, any> | SingleNode<any, any, any, any> | undefined;
getChild(path: string): SingleNode<any, any, any, any> | ListNode<any, any, any, any> | undefined;
getParent(): undefined;
destroy(): void;
getFreshValue(): Promise<undefined>;
@ -170,13 +179,19 @@ export declare class RunningTree<ED extends EntityDict & BaseEntityDict, Cxt ext
destroyNode(path: string): void;
getFreshValue(path: string): Promise<SelectRowShape<ED[keyof ED]["Schema"], ED[keyof ED]["Selection"]["data"]> | undefined> | Promise<SelectRowShape<ED[keyof ED]["Schema"], ED[keyof ED]["Selection"]["data"]>[]> | undefined;
isDirty(path: string): boolean;
addOperation<T extends keyof ED>(path: string, operation: Omit<ED[T]['Operation'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): Promise<void>;
addItem<T extends keyof ED>(path: string, data: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): Promise<void>;
removeItem(path: string, id: string, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): Promise<void>;
updateItem<T extends keyof ED>(path: string, data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): Promise<void>;
recoverItem(path: string, id: string): Promise<void>;
create<T extends keyof ED>(path: string, data: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): Promise<void>;
update<T extends keyof ED>(path: string, data: ED[T]['Update']['data'], action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): Promise<void>;
remove(path: string, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>): Promise<void>;
isLoading(path: string): boolean;
isLoadingMore(path: string): boolean;
isExecuting(path: string): boolean;
refresh(path: string): Promise<void>;
loadMore(path: string): Promise<void>;
getPagination<T extends keyof ED>(path: string): Pagination;
getPagination(path: string): Pagination;
setId(path: string, id: string): Promise<void>;
unsetId(path: string): Promise<void>;
getId(path: string): string | undefined;
@ -193,14 +208,10 @@ export declare class RunningTree<ED extends EntityDict & BaseEntityDict, Cxt ext
setNamedSorters<T extends keyof ED>(path: string, sorters: NamedSorterItem<ED, T>[], refresh?: boolean): Promise<void>;
addNamedSorter<T extends keyof ED>(path: string, sorter: NamedSorterItem<ED, T>, refresh?: boolean): Promise<void>;
removeNamedSorter<T extends keyof ED>(path: string, sorter: NamedSorterItem<ED, T>, refresh?: boolean): Promise<void>;
removeNamedSorterByName<T extends keyof ED>(path: string, name: string, refresh?: boolean): Promise<void>;
removeNamedSorterByName(path: string, name: string, refresh?: boolean): Promise<void>;
tryExecute(path: string): Promise<boolean>;
getOperations(path: string): Promise<any[] | (ED[keyof ED]["Operation"] & {
entity: keyof ED;
})[] | undefined>;
execute<T extends keyof ED>(path: string, operation?: Omit<ED[T]['Operation'], 'id'>): Promise<any[] | (ED[keyof ED]["Operation"] & {
entity: keyof ED;
})[]>;
getOperations(path: string): Promise<any[] | undefined>;
execute<T extends keyof ED>(path: string, data?: ED[T]['Update']['data'] | Record<string, ED[T]['Update']['data']>, action?: ED[T]['Action']): Promise<any[]>;
clean(path: string): Promise<void>;
getRoot(): Record<string, VirtualNode | SingleNode<ED, keyof ED, Cxt, AD> | ListNode<ED, keyof ED, Cxt, AD>>;
}

File diff suppressed because it is too large Load Diff

1
lib/index.d.ts vendored
View File

@ -7,3 +7,4 @@ export * from './utils/upload';
export * from './types/Notification';
export * from './types/Message';
export * from './utils/bluetooth';
export * from './types/Page';

View File

@ -9,3 +9,4 @@ tslib_1.__exportStar(require("./utils/upload"), exports);
tslib_1.__exportStar(require("./types/Notification"), exports);
tslib_1.__exportStar(require("./types/Message"), exports);
tslib_1.__exportStar(require("./utils/bluetooth"), exports);
tslib_1.__exportStar(require("./types/Page"), exports);

22
lib/page.common.d.ts vendored
View File

@ -1,16 +1,12 @@
import { Context, EntityDict } from 'oak-domain/lib/types';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
import { OakComponentOption, ComponentFullThisType } from './types/Page';
export declare function subscribe<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>): void;
export declare function unsubscribe<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>): void;
export declare function onPathSet<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>, option: OakComponentOption<ED, T, Cxt, any, any, any, any, any, {}, {}, {}>): Promise<void>;
export declare function reRender<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>, option: OakComponentOption<ED, T, Cxt, any, any, any, any, any, {}, {}, {}>, extra?: Record<string, any>): Promise<void>;
export declare function refresh<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>): Promise<void>;
export declare function loadMore<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>): Promise<void>;
export declare function execute<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>, operation?: Omit<ED[T]['Operation'], 'id'>, path?: string): Promise<any[] | (ED[keyof ED]["Operation"] & {
entity: keyof ED;
})[]>;
export declare function callPicker<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>, attr: string, params?: Record<string, any>): void;
export declare function setUpdateData<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>, attr: string, data: any): Promise<void>;
export declare function setMultiAttrUpdateData<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>, data: Record<string, any>): Promise<void>;
export declare function destroyNode<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>): void;
export declare function subscribe<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, any, Cxt>): void;
export declare function unsubscribe<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, any, Cxt>): void;
export declare function onPathSet<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, any, Cxt>, option: OakComponentOption<ED, T, Cxt, any, any, any, any, any, {}, {}, {}>): Promise<void>;
export declare function reRender<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, any, Cxt>, option: OakComponentOption<ED, T, Cxt, any, any, any, any, any, {}, {}, {}>, extra?: Record<string, any>): Promise<void>;
export declare function refresh<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, any, Cxt>): Promise<void>;
export declare function loadMore<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, any, Cxt>): Promise<void>;
export declare function execute<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, any, Cxt>, data?: ED[T]['Update']['data'] | Record<string, ED[T]['Update']['data']>, path?: string): Promise<any[]>;
export declare function callPicker<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, any, Cxt>, attr: string, params?: Record<string, any>): void;
export declare function destroyNode<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, any, Cxt>): void;

View File

@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.destroyNode = exports.setMultiAttrUpdateData = exports.setUpdateData = exports.callPicker = exports.execute = exports.loadMore = exports.refresh = exports.reRender = exports.onPathSet = exports.unsubscribe = exports.subscribe = void 0;
exports.destroyNode = exports.callPicker = exports.execute = exports.loadMore = exports.refresh = exports.reRender = exports.onPathSet = exports.unsubscribe = exports.subscribe = void 0;
var tslib_1 = require("tslib");
var assert_1 = require("oak-domain/lib/utils/assert");
var types_1 = require("oak-domain/lib/types");
@ -138,13 +138,11 @@ function onPathSet(option) {
Object.assign(this.state, {
oakEntity: entity2,
oakFullpath: oakPath2,
oakIsReady: true,
});
return [3 /*break*/, 4];
case 2:
Object.assign(this.state, {
oakFullpath: oakPath2,
oakIsReady: true,
});
// 创建virtualNode
return [4 /*yield*/, features.runningTree.createNode({
@ -265,7 +263,6 @@ function reRender(option, extra) {
this.setState(data);
return [3 /*break*/, 15];
case 11:
if (!this.state.oakFullpath) return [3 /*break*/, 15];
if (!formData) return [3 /*break*/, 13];
return [4 /*yield*/, formData.call(this, {
features: features,
@ -346,53 +343,26 @@ function loadMore() {
});
}
exports.loadMore = loadMore;
function execute(operation, path) {
function execute(data, path) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var fullpath, result, err_4, attrs, entity_1, message, attrNames;
var _this = this;
var fullpath, result;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
if (this.state.oakExecuting) {
throw new Error('请仔细设计按钮状态,不要允许重复点击!');
}
_a.label = 1;
fullpath = path ? "".concat(this.state.oakFullpath, ".").concat(path) : this.state.oakFullpath;
return [4 /*yield*/, this.features.runningTree.execute(fullpath, data)];
case 1:
_a.trys.push([1, 4, , 5]);
fullpath = path
? "".concat(this.state.oakFullpath, ".").concat(path)
: this.state.oakFullpath;
return [4 /*yield*/, this.features.runningTree.execute(fullpath, operation)];
case 2:
result = _a.sent();
return [4 /*yield*/, this.setMessage({
type: 'success',
content: '操作成功',
})];
case 3:
case 2:
_a.sent();
return [2 /*return*/, result];
case 4:
err_4 = _a.sent();
if (err_4 instanceof types_1.OakUserException) {
if (err_4 instanceof types_1.OakInputIllegalException) {
attrs = err_4.getAttributes();
entity_1 = err_4.getEntity();
message = err_4.message;
attrNames = attrs.map(function (attr) { return _this.t("".concat(entity_1, ":attr.").concat(attr)); }).filter(function (ele) { return !!ele; });
this.setMessage({
type: 'error',
content: attrNames.length > 0 ? "\u300C".concat(attrNames.join(','), "\u300D").concat(message) : message,
});
throw err_4;
}
}
this.setMessage({
type: 'error',
content: err_4.message,
});
throw err_4;
case 5: return [2 /*return*/];
}
});
});
@ -421,62 +391,6 @@ function callPicker(attr, params) {
});
}
exports.callPicker = callPicker;
function setUpdateData(attr, data) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a, _b;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
(0, assert_1.assert)(attr.indexOf('.') === -1, 'setUpdateData只能设置当前对象属性子层对象请写完整的addOperation');
if (!this.props.oakId) return [3 /*break*/, 1];
return [2 /*return*/, this.addOperation({
action: 'update',
data: (_a = {},
_a[attr] = data,
_a)
})];
case 1: return [4 /*yield*/, this.addOperation({
action: 'create',
data: (_b = {},
_b[attr] = data,
_b)
})];
case 2:
_c.sent();
_c.label = 3;
case 3: return [2 /*return*/];
}
});
});
}
exports.setUpdateData = setUpdateData;
function setMultiAttrUpdateData(data) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var key;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
for (key in data) {
(0, assert_1.assert)(key.indexOf('.') === -1, 'setMultiAttrUpdateData只能设置当前对象属性子层对象请写完整的addOperation');
}
if (!this.props.oakId) return [3 /*break*/, 1];
return [2 /*return*/, this.addOperation({
action: 'update',
data: data,
})];
case 1: return [4 /*yield*/, this.addOperation({
action: 'create',
data: data,
})];
case 2:
_a.sent();
_a.label = 3;
case 3: return [2 /*return*/];
}
});
});
}
exports.setMultiAttrUpdateData = setMultiAttrUpdateData;
function destroyNode() {
(0, assert_1.assert)(this.state.oakFullpath);
this.features.runningTree.destroyNode(this.state.oakFullpath);

View File

@ -21,7 +21,7 @@ var OakComponentBase = /** @class */ (function (_super) {
page_common_1.unsubscribe.call(this);
};
OakComponentBase.prototype.onPathSet = function () {
return page_common_1.onPathSet.call(this, this.option);
return page_common_1.onPathSet.call(this, this.oakOption);
};
OakComponentBase.prototype.triggerEvent = function (name, detail, options) {
};
@ -77,7 +77,7 @@ var OakComponentBase = /** @class */ (function (_super) {
return this.features.message.consumeMessage();
};
OakComponentBase.prototype.reRender = function (extra) {
return page_common_1.reRender.call(this, this.option, extra);
return page_common_1.reRender.call(this, this.oakOption, extra);
};
OakComponentBase.prototype.navigateTo = function (options, state, disableNamespace) {
var url = options.url, rest = tslib_1.__rest(options, ["url"]);
@ -184,11 +184,28 @@ var OakComponentBase = /** @class */ (function (_super) {
return this.props.navigate(url2, { replace: true });
}
} */
OakComponentBase.prototype.addOperation = function (operation, beforeExecute, afterExecute, path) {
var path2 = path ? "".concat(this.state.oakFullpath, ".").concat(path) : this.state.oakFullpath;
return this.features.runningTree.addOperation(path2, operation, beforeExecute, afterExecute);
OakComponentBase.prototype.addItem = function (data, beforeExecute, afterExecute) {
return this.features.runningTree.addItem(this.state.oakFullpath, data, beforeExecute, afterExecute);
};
OakComponentBase.prototype.cleanOperation = function (path) {
OakComponentBase.prototype.removeItem = function (id, beforeExecute, afterExecute) {
return this.features.runningTree.removeItem(this.state.oakFullpath, id, beforeExecute, afterExecute);
};
OakComponentBase.prototype.updateItem = function (data, id, action, beforeExecute, afterExecute) {
return this.features.runningTree.updateItem(this.state.oakFullpath, data, id, action, beforeExecute, afterExecute);
};
OakComponentBase.prototype.recoverItem = function (id) {
return this.features.runningTree.recoverItem(this.state.oakFullpath, id);
};
OakComponentBase.prototype.create = function (data, beforeExecute, afterExecute) {
return this.features.runningTree.create(this.state.oakFullpath, data, beforeExecute, afterExecute);
};
OakComponentBase.prototype.update = function (data, action, beforeExecute, afterExecute) {
return this.features.runningTree.update(this.state.oakFullpath, data, action, beforeExecute, afterExecute);
};
OakComponentBase.prototype.remove = function (beforeExecute, afterExecute) {
return this.features.runningTree.remove(this.state.oakFullpath, beforeExecute, afterExecute);
};
OakComponentBase.prototype.clean = function (path) {
var path2 = path ? "".concat(this.state.oakFullpath, ".").concat(path) : this.state.oakFullpath;
return this.features.runningTree.clean(path2);
};
@ -199,8 +216,8 @@ var OakComponentBase = /** @class */ (function (_super) {
if (params === void 0) { params = {}; }
return page_common_1.callPicker.call(this, attr, params);
};
OakComponentBase.prototype.execute = function (operation) {
return page_common_1.execute.call(this, operation);
OakComponentBase.prototype.execute = function (data) {
return page_common_1.execute.call(this, data);
};
OakComponentBase.prototype.getFreshValue = function (path) {
var path2 = path ? "".concat(this.state.oakFullpath, ".").concat(path) : this.state.oakFullpath;
@ -220,12 +237,6 @@ var OakComponentBase = /** @class */ (function (_super) {
OakComponentBase.prototype.refresh = function () {
return page_common_1.refresh.call(this);
};
OakComponentBase.prototype.setUpdateData = function (attr, data) {
return page_common_1.setUpdateData.call(this, attr, data);
};
OakComponentBase.prototype.setMultiAttrUpdateData = function (data) {
return page_common_1.setMultiAttrUpdateData.call(this, data);
};
OakComponentBase.prototype.loadMore = function () {
return page_common_1.loadMore.call(this);
};
@ -477,34 +488,141 @@ function translateObservers(observers) {
}
var DEFAULT_REACH_BOTTOM_DISTANCE = 50;
function createComponent(option, features) {
var _a = option, data = _a.data, projection = _a.projection, properties = _a.properties, entity = _a.entity, methods = _a.methods, lifetimes = _a.lifetimes, observers = _a.observers, render = _a.render, path = _a.path;
var _a = option, data = _a.data, methods = _a.methods, lifetimes = _a.lifetimes, observers = _a.observers, getRender = _a.getRender, path = _a.path;
var fn = translateObservers(observers).fn;
var OakComponentWrapper = /** @class */ (function (_super) {
tslib_1.__extends(OakComponentWrapper, _super);
function OakComponentWrapper(props) {
var _a;
var _this = _super.call(this, props) || this;
_this.features = features;
_this.option = option;
_this.oakOption = option;
_this.isReachBottom = false;
_this.scrollEvent = function () {
_this.checkReachBottom();
};
var methodProps = {
t: function (key, params) { return _this.t(key, params); },
execute: function (data) {
return _this.execute(data);
},
refresh: function () {
return _this.refresh();
},
setNotification: function (data) {
return _this.setNotification(data);
},
setMessage: function (data) {
return _this.setMessage(data);
},
navigateTo: function (options, state, disableNamespace) {
return _this.navigateTo(options, state, disableNamespace);
},
navigateBack: function (options) {
return _this.navigateBack(options);
},
redirectTo: function (options, state, disableNamespace) {
return _this.redirectTo(options, state, disableNamespace);
},
clean: function (path) {
return _this.clean(path);
}
};
if (option.isList) {
Object.assign(methodProps, {
addItem: function (data, beforeExecute, afterExecute) {
return _this.addItem(data, beforeExecute, afterExecute);
},
removeItem: function (id, beforeExecute, afterExecute) {
return _this.removeItem(id, beforeExecute, afterExecute);
},
updateItem: function (data, id, action, beforeExecute, afterExecute) {
return _this.updateItem(data, id, action, beforeExecute, afterExecute);
},
setFilters: function (filters) {
return _this.setFilters(filters);
},
addNamedFilter: function (filter, refresh) {
return _this.addNamedFilter(filter, refresh);
},
removeNamedFilter: function (filter, refresh) {
return _this.removeNamedFilter(filter, refresh);
},
removeNamedFilterByName: function (name, refresh) {
return _this.removeNamedFilterByName(name, refresh);
},
setNamedSorters: function (sorters) {
return _this.setNamedSorters(sorters);
},
addNamedSorter: function (sorter, refresh) {
return _this.addNamedSorter(sorter, refresh);
},
removeNamedSorter: function (sorter, refresh) {
return _this.removeNamedSorter(sorter, refresh);
},
removeNamedSorterByName: function (name, refresh) {
return _this.removeNamedSorterByName(name, refresh);
},
setPageSize: function (pageSize) {
return _this.setPageSize(pageSize);
},
setCurrentPage: function (current) {
return _this.setCurrentPage(current);
},
loadMore: function () {
return _this.loadMore();
}
});
}
else {
Object.assign(methodProps, {
create: function (data, beforeExecute, afterExecute) {
return _this.create(data, beforeExecute, afterExecute);
},
update: function (data, action, beforeExecute, afterExecute) {
return _this.update(data, action, beforeExecute, afterExecute);
},
remove: function (beforeExecute, afterExecute) {
return _this.remove(beforeExecute, afterExecute);
},
});
}
if (methods) {
for (var m in methods) {
Object.assign(_this, (_a = {},
_a[m] = methods[m].bind(_this),
var _loop_1 = function (m) {
var _a, _b;
Object.assign(this_1, (_a = {},
_a[m] = function () {
var _a;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return (_a = methods[m]).call.apply(_a, tslib_1.__spreadArray([_this], tslib_1.__read(args), false));
},
_a));
Object.assign(methodProps, (_b = {},
_b[m] = function () {
var _a;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return (_a = methods[m]).call.apply(_a, tslib_1.__spreadArray([_this], tslib_1.__read(args), false));
},
_b));
};
var this_1 = this;
for (var m in methods) {
_loop_1(m);
}
}
_this.state = Object.assign({}, data, {
oakLoading: false,
oakLoadingMore: false,
oakPullDownRefreshLoading: false,
oakIsReady: false,
oakExecuting: false,
oakDirty: false,
});
_this.methodProps = methodProps;
(lifetimes === null || lifetimes === void 0 ? void 0 : lifetimes.created) && lifetimes.created.call(_this);
return _this;
}
@ -596,9 +714,9 @@ function createComponent(option, features) {
};
OakComponentWrapper.prototype.render = function () {
var _this = this;
var Render = render.call(this);
var oakPullDownRefreshLoading = this.state.oakPullDownRefreshLoading;
var _a = this.props.oakDisablePulldownRefresh, oakDisablePulldownRefresh = _a === void 0 ? false : _a;
var Render = getRender.call(this);
if (this.supportPullDownRefresh() && !oakDisablePulldownRefresh) {
var Child = react_1.default.cloneElement((0, jsx_runtime_1.jsx)(web_1.PullToRefresh, { onRefresh: function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
@ -619,10 +737,10 @@ function createComponent(option, features) {
finish: this.t('common:ptrFinish'),
} }), {
getScrollContainer: function () { return document.body; },
}, Render);
}, (0, jsx_runtime_1.jsx)(Render, { methods: this.methodProps, data: tslib_1.__assign(tslib_1.__assign({}, this.state), this.props) }));
return Child;
}
return Render;
return (0, jsx_runtime_1.jsx)(Render, { methods: this.methodProps, data: tslib_1.__assign(tslib_1.__assign({}, this.state), this.props) });
};
return OakComponentWrapper;
}(OakComponentBase));

32
lib/types/Page.d.ts vendored
View File

@ -58,14 +58,15 @@ export declare type ComponentPublicThisType<ED extends EntityDict & BaseEntityDi
props: ComponentProps<IsList, TProperty>;
setState: (data: Partial<ComponentData<ED, T, FormedData, TData>>, callback?: () => void) => void;
triggerEvent: <DetailType = any>(name: string, detail?: DetailType, options?: WechatMiniprogram.Component.TriggerEventOption) => void;
} & TMethod & OakCommonComponentMethods<ED, T> & (IsList extends true ? OakListComponentMethods<ED, T> : {});
export declare type ComponentFullThisType<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>> = {
} & TMethod & OakCommonComponentMethods<ED, T> & (IsList extends true ? OakListComponentMethods<ED, T> : OakSingleComponentMethods<ED, T>);
export declare type ComponentFullThisType<ED extends EntityDict & BaseEntityDict, T extends keyof ED, IsList extends boolean, Cxt extends Context<ED>> = {
subscribed?: () => void;
features: BasicFeatures<ED, Cxt, CommonAspectDict<ED, Cxt>>;
state: OakComponentData<ED, T>;
props: ComponentProps<true, {}>;
setState: (data: Partial<OakComponentData<ED, T>>, callback?: () => void) => void;
triggerEvent: <DetailType = any>(name: string, detail?: DetailType, options?: WechatMiniprogram.Component.TriggerEventOption) => void;
} & OakCommonComponentMethods<ED, T> & OakListComponentMethods<ED, T> & OakHiddenComponentMethods;
} & OakCommonComponentMethods<ED, T> & (IsList extends true ? OakListComponentMethods<ED, T> : OakSingleComponentMethods<ED, T>);
export declare type OakComponentOption<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends Context<ED>, AD extends Record<string, Aspect<ED, Cxt>>, FD extends Record<string, Feature>, Proj extends ED[T]['Selection']['data'], FormedData extends Record<string, any>, IsList extends boolean, TData extends Record<string, any>, TProperty extends WechatMiniprogram.Component.PropertyOption, TMethod extends Record<string, Function>> = ComponentOption<ED, T, Cxt, AD, FD, Proj, FormedData, IsList, TProperty> & Partial<{
data?: TData;
properties: TProperty;
@ -146,20 +147,22 @@ export declare type OakCommonComponentMethods<ED extends EntityDict & BaseEntity
delta: number;
}) => Promise<void>;
redirectTo: <T2 extends keyof ED>(options: Parameters<typeof wx.redirectTo>[0] & OakNavigateToParameters<ED, T2>, state?: Record<string, any>, disableNamespace?: boolean) => Promise<void>;
addOperation: (operation: Omit<ED[T]['Operation'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>, path?: string) => Promise<void>;
cleanOperation: (path?: string) => void;
clean: (path?: string) => void;
t(key: string, params?: object): string;
callPicker: (attr: string, params: Record<string, any>) => void;
execute: (operation?: Omit<ED[T]['Operation'], 'id'>, path?: string) => Promise<ED[T]['Operation'][]>;
execute: (data?: ED[T]['Update']['data'] | Record<string, ED[T]['Update']['data']>, path?: string) => Promise<ED[T]['Operation'][]>;
checkOperation: (ntity: T, action: ED[T]['Action'], filter?: ED[T]['Update']['filter'], checkerTypes?: CheckerType[]) => Promise<boolean>;
tryExecute: (path?: string) => Promise<boolean>;
getOperations: (path?: string) => Promise<ED[T]['Operation'][] | undefined>;
refresh: (extra?: any) => Promise<void>;
setUpdateData: (data: string, attr: any) => Promise<void>;
setMultiAttrUpdateData: (data: Record<string, any>) => Promise<void>;
refresh: () => Promise<void>;
};
export declare type OakSingleComponentMethods<ED extends EntityDict & BaseEntityDict, T extends keyof ED> = {
setId: (id: string) => Promise<void>;
unsetId: () => void;
getId: () => string | undefined;
create: (data: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => Promise<void>;
update: (data: ED[T]['Update']['data'], action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => Promise<void>;
remove: (beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => Promise<void>;
};
export declare type OakListComponentMethods<ED extends EntityDict & BaseEntityDict, T extends keyof ED> = {
loadMore: () => Promise<void>;
@ -178,6 +181,9 @@ export declare type OakListComponentMethods<ED extends EntityDict & BaseEntityDi
getPagination: () => Pagination | undefined;
setPageSize: (pageSize: number) => void;
setCurrentPage: (current: number) => void;
addItem: (data: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => Promise<void>;
removeItem: (id: string, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => Promise<void>;
updateItem: (data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => Promise<void>;
};
declare type ComponentOnPropsChangeOption = {
path?: string;
@ -200,9 +206,15 @@ export declare type OakComponentData<ED extends EntityDict & BaseEntityDict, T e
oakLoadingMore: boolean;
oakPullDownRefreshLoading: boolean;
oakEntity: T;
oakIsReady: boolean;
oakFullpath: string;
oakLegalActions?: ED[T]['Action'][];
};
export declare type MakeOakComponent<ED extends EntityDict & BaseEntityDict, Cxt extends Context<ED>, AD extends Record<string, Aspect<ED, Cxt>>, FD extends Record<string, Feature>> = <T extends keyof ED, Proj extends ED[T]['Selection']['data'], FormedData extends WechatMiniprogram.Component.DataOption, IsList extends boolean, TData extends WechatMiniprogram.Component.DataOption, TProperty extends WechatMiniprogram.Component.PropertyOption, TMethod extends WechatMiniprogram.Component.MethodOption>(options: OakComponentOption<ED, T, Cxt, AD, FD, Proj, FormedData, IsList, TData, TProperty, TMethod>) => React.ComponentType<any>;
export declare type WebComponentCommonMethodNames = 'setNotification' | 'setMessage' | 'navigateTo' | 'navigateBack' | 'redirectTo' | 'clean' | 't' | 'execute' | 'refresh';
export declare type WebComponentListMethodNames = 'loadMore' | 'setFilters' | 'addNamedFilter' | 'removeNamedFilter' | 'removeNamedFilterByName' | 'setNamedSorters' | 'addNamedSorter' | 'removeNamedSorter' | 'removeNamedSorterByName' | 'setPageSize' | 'setCurrentPage' | 'addItem' | 'removeItem' | 'updateItem';
export declare type WebComponentSingleMethodNames = 'create' | 'update' | 'remove';
export declare type WebComponentProps<ED extends EntityDict & BaseEntityDict, T extends keyof ED, IsList extends boolean, TData extends WechatMiniprogram.Component.DataOption = {}, TMethod extends WechatMiniprogram.Component.MethodOption = {}> = {
methods: TMethod & Pick<OakCommonComponentMethods<ED, T>, WebComponentCommonMethodNames> & (IsList extends true ? Pick<OakListComponentMethods<ED, T>, WebComponentListMethodNames> : Pick<OakSingleComponentMethods<ED, T>, WebComponentSingleMethodNames>);
data: TData & OakComponentData<ED, T> & (IsList extends true ? OakListComponentProperties : {});
};
export {};

View File

@ -6,9 +6,7 @@ import { Checker, CheckerType, Context, Trigger } from 'oak-domain/lib/types';
import { TreeStore, TreeStoreOperateOption } from 'oak-memory-tree-store';
import assert from 'assert';
interface CachStoreOperation extends TreeStoreOperateOption {
inSync?: boolean;
};
interface CachStoreOperation extends TreeStoreOperateOption {};
export class CacheStore<
ED extends EntityDict & BaseEntityDict,
@ -32,24 +30,6 @@ export class CacheStore<
this.resetInitialDataFn = resetInitialDataFn;
}
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,
operation: ED[T]['Operation'],
@ -89,9 +69,7 @@ export class CacheStore<
let result;
try {
result = await super.sync<CachStoreOperation>(opRecords, context, {
inSync: true,
});
result = await super.sync<CachStoreOperation>(opRecords, context, {});
} catch (err) {
if (autoCommit) {
await context.rollback();

View File

@ -22,26 +22,6 @@ export class DebugStore<ED extends EntityDict & BaseEntityDict, Cxt extends Cont
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) {
if (!option.blockTrigger) {
await this.executor.preOperation(entity, operation, context, option);

View File

@ -23,7 +23,7 @@ abstract class Node<ED extends EntityDict & BaseEntityDict, T extends keyof ED,
// protected fullPath: string;
protected schema: StorageSchema<ED>;
protected projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>); // 只在Page层有
protected parent?: Node<ED, keyof ED, Cxt, AD> | VirtualNode;
protected parent?: SingleNode<ED, keyof ED, Cxt, AD> | ListNode<ED, T, Cxt, AD> | VirtualNode;
protected dirty?: boolean;
protected cache: Cache<ED, Cxt, AD>;
protected loading: boolean;
@ -34,7 +34,7 @@ abstract class Node<ED extends EntityDict & BaseEntityDict, T extends keyof ED,
constructor(entity: T, schema: StorageSchema<ED>, cache: Cache<ED, Cxt, AD>,
projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>),
parent?: Node<ED, keyof ED, Cxt, AD> | VirtualNode) {
parent?: SingleNode<ED, keyof ED, Cxt, AD> | ListNode<ED, T, Cxt, AD> | VirtualNode) {
this.entity = entity;
this.schema = schema;
this.cache = cache;
@ -44,7 +44,7 @@ abstract class Node<ED extends EntityDict & BaseEntityDict, T extends keyof ED,
this.loading = false;
this.loadingMore = false;
this.executing = false;
this.modiIds = undefined;
this.modiIds = undefined;
}
getEntity() {
@ -617,7 +617,7 @@ class ListNode<
projection:
| ED[T]['Selection']['data']
| (() => Promise<ED[T]['Selection']['data']>),
parent?: Node<ED, keyof ED, Cxt, AD> | VirtualNode,
parent?: SingleNode<ED, keyof ED, Cxt, AD> | VirtualNode,
filters?: NamedFilterItem<ED, T>[],
sorters?: NamedSorterItem<ED, T>[],
pagination?: Pagination
@ -783,7 +783,7 @@ class ListNode<
if (operation.action === 'create') {
const { data } = operation;
assert(!(data instanceof Array));
createdIds.push(data.id);
createdIds.push(data.id);
}
}
@ -818,15 +818,14 @@ class ListNode<
filter: combineFilters([filter, { id: { $in: createdIds } }].filter(ele => !!ele), true),
});
}
const result = await this.cache.tryRedoOperationsThenSelect(this.entity, selection, operations);
return result;
}
return [];
}
async addItem(item: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute: () => Promise<void>, afterExecute: () => Promise<void>) {
assert(Object.keys(this.children).length === 0, ``);
async addItem(item: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
const id = await generateNewId();
assert(!this.updates[id]);
this.updates[id] = {
@ -841,19 +840,25 @@ class ListNode<
this.setDirty();
}
async removeItem(id: string, beforeExecute: () => Promise<void>, afterExecute: () => Promise<void>) {
this.updates[id] = {
beforeExecute,
afterExecute,
operation: {
id: await generateNewId(),
action: 'remove',
data: {},
filter: {
id,
},
} as ED[T]['Remove'],
};
async removeItem(id: string, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
if (this.updates[id] && this.updates[id].operation.action === 'create') {
// 如果是新增项,在这里抵消
unset(this.updates, id);
}
else {
this.updates[id] = {
beforeExecute,
afterExecute,
operation: {
id: await generateNewId(),
action: 'remove',
data: {},
filter: {
id,
},
} as ED[T]['Remove'],
};
}
this.setDirty();
}
@ -863,11 +868,23 @@ class ListNode<
unset(this.updates, id);
}
async updateItem(data: ED[T]['Update']['data'], id: string, beforeExecute: () => Promise<void>, afterExecute: () => Promise<void>) {
/**
* itemId进行更新
* @param data
* @param id
* @param beforeExecute
* @param afterExecute
*/
async updateItem(data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
assert(Object.keys(this.children).length === 0, `更新子结点应该落在相应的component上`);
if (this.updates[id]) {
const { operation } = this.updates[id];
const { data: dataOrigin } = operation;
merge(dataOrigin, data);
if (action && operation.action !== action) {
assert(operation.action === 'update');
operation.action = action;
}
}
else {
this.updates[id] = {
@ -875,7 +892,7 @@ class ListNode<
afterExecute,
operation: {
id: await generateNewId(),
action: 'update',
action: action || 'update',
data,
filter: {
id,
@ -886,6 +903,12 @@ class ListNode<
this.setDirty();
}
async updateItems(data: Record<string, ED[T]['Update']['data']>, action?: ED[T]['Action']) {
for (const id in data) {
await this.updateItem(data[id], id, action);
}
}
async doBeforeTrigger(): Promise<void> {
for (const k in this.updates) {
const update = this.updates[k];
@ -913,16 +936,7 @@ class ListNode<
}
async getParentFilter(childNode: SingleNode<ED, T, Cxt, AD>): Promise<ED[T]['Selection']['filter'] | undefined> {
/* let idx = 0;
while (idx < this.ids!.length) {
if (this.children[idx] === childNode) {
return {
id: this.ids![idx],
}
}
idx++;
} */
for(const id in this.children) {
for (const id in this.children) {
if (this.children[id] === childNode) {
return {
id,
@ -935,52 +949,32 @@ class ListNode<
if (!this.dirty) {
return;
}
const childOperations = await Promise.all(
Object.keys(this.children).map(
async ele => {
const child = this.children[ele];
const childOperations = await child.composeOperations();
if (childOperations) {
assert(childOperations.length === 1);
return childOperations[0];
}
}
)
);
const operations: ED[T]['Operation'][] = cloneDeep(this.operations.map(ele => ele.oper));
for (const oper of childOperations) {
if (oper) {
const {
index,
eliminated,
} = findOperationToMerge(this.entity, this.schema, oper, operations);
if (index) {
// 可以合并
const result = mergeOperationOper(this.entity, this.schema, oper, index);
if (result) {
// 说明相互抵消了
pull(operations, index);
}
else {
}
}
else {
operations.push(oper);
}
for (const eli of eliminated) {
if (eli) {
pull(operations, eli);
}
}
const childOperations: Record<string, ED[T]['Update']> = {};
for (const id in this.children) {
const childOperation = await this.children[id].composeOperations();
if (childOperation) {
assert(childOperation.length === 1);
childOperations[id] = childOperation[0].operation;
}
}
const operations: ED[T]['Operation'][] = [];
for (const id in this.updates) {
const operation = cloneDeep(this.updates[id].operation);
if (childOperations[id]) {
const childOperation = childOperations[id];
// 在list有operation在singleNode上也有目前只允许一种情况即list上create在single上update
assert(operation.action === 'create' && childOperation.action === 'update');
Object.assign(operation.data, childOperation.data);
unset(childOperations, id);
}
operations.push(operation);
}
operations.push(...Object.values(childOperations));
await repairOperations(this.entity, this.schema, operations);
return operations.map(
ele => Object.assign(ele, {
ele => Object.assign({
operation: ele,
entity: this.entity,
})
);
@ -1078,7 +1072,7 @@ class ListNode<
if (getCount) {
this.pagination.total = count;
}
const ids = data.map(
ele => ele.id!
) as string[];
@ -1115,7 +1109,7 @@ class ListNode<
clean() {
this.dirty = undefined;
this.operations = [];
this.updates = {};
for (const k in this.children) {
this.children[k].clean();
@ -1131,15 +1125,38 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
private children: {
[K: string]: SingleNode<ED, keyof ED, Cxt, AD> | ListNode<ED, keyof ED, Cxt, AD>;
};
private operation?: {
beforeExecute?: () => Promise<void>;
afterExecute?: () => Promise<void>;
operation: ED[T]['CreateSingle'] | ED[T]['Update'] | ED[T]['Remove'];
};
constructor(entity: T, schema: StorageSchema<ED>, cache: Cache<ED, Cxt, AD>,
projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>),
parent?: Node<ED, keyof ED, Cxt, AD> | VirtualNode, id?: string) {
parent?: SingleNode<ED, keyof ED, Cxt, AD> | ListNode<ED, T, Cxt, AD> | VirtualNode, id?: string) {
super(entity, schema, cache, projection, parent);
this.children = {};
if (id) {
this.id = id;
}
else {
// 若没有父结点上的filter则一定是create动作
this.tryGetParentFilter()
.then(
() => this.create({})
);
}
}
private async tryGetParentFilter(disableOperation?: boolean) {
const parent = this.getParent();
if (parent instanceof SingleNode) {
const filter = await parent.getParentFilter<T>(this, disableOperation);
return filter;
}
else if (parent instanceof ListNode) {
return await parent.getParentFilter(this);
}
}
protected getChildPath(child: Node<ED, keyof ED, Cxt, AD>): string {
@ -1159,7 +1176,7 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
}
checkIfClean(): void {
if (this.operations.length > 0) {
if (this.operation) {
return;
}
for (const k in this.children) {
@ -1219,33 +1236,17 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
operation: ED[keyof ED]['Operation'];
}> : [];
let filter = this.id && { id: this.id } as ED[T]['Selection']['filter'];
if (!filter && !disableOperation) {
// 可能是create
const createOper = this.operations.find(
(ele) => ele.oper.action === 'create'
) as { oper: ED[T]['CreateSingle'] };
if (createOper) {
assert(createOper.oper.data.id);
filter = {
id: createOper.oper.data.id
};
}
}
if (!filter) {
// 还可能是来自父级的外键
const parent = this.getParent();
if (parent instanceof ListNode || parent instanceof SingleNode) {
filter = await parent.getParentFilter(this, disableOperation);
}
filter = await this.tryGetParentFilter(disableOperation);
}
if (filter) {
if (!disableOperation) {
operations.push(...this.operations.map(
ele => ({
entity: this.entity,
operation: ele.oper,
})
));
if (!disableOperation && this.operation) {
operations.push({
entity: this.entity,
operation: this.operation.operation,
});
}
const result = await this.cache.tryRedoOperationsThenSelect(this.entity, {
data: projection,
@ -1257,10 +1258,8 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
async doBeforeTrigger(): Promise<void> {
for (const operation of this.operations) {
if (operation.beforeExecute) {
await operation.beforeExecute();
}
if (this.operation?.beforeExecute) {
await this.operation.beforeExecute();
}
for (const k in this.children) {
@ -1269,12 +1268,9 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
}
}
async doAfterTrigger(): Promise<void> {
for (const operation of this.operations) {
if (operation.afterExecute) {
await operation.afterExecute();
}
if (this.operation?.afterExecute) {
await this.operation.afterExecute();
}
for (const k in this.children) {
@ -1283,133 +1279,125 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
}
}
async addOperation(oper: Omit<ED[T]['Operation'], 'id'>, beforeExecute?: Operation<ED, T>['beforeExecute'], afterExecute?: Operation<ED, T>['afterExecute']) {
if (this.id) {
if (oper.action === 'create') {
oper.action = 'update';
}
if (!oper.filter) {
Object.assign(oper, {
async create(data: Partial<Omit<ED[T]['CreateSingle']['data'], 'id'>>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
const id = await generateNewId();
this.id = id;
this.operation = {
operation: {
id: await generateNewId(),
action: 'create',
data: Object.assign({}, data, { id }),
},
beforeExecute,
afterExecute,
};
this.setDirty();
}
async update(data: ED[T]['Update']['data'], action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
if (!this.operation) {
const operation: ED[T]['Update'] = {
id: await generateNewId(),
action: action || 'update',
data,
};
if (this.id) {
Object.assign(operation, {
filter: {
id: this.id,
},
});
}
else {
assert(oper.filter.id === this.id);
}
}
const operation = {
oper,
beforeExecute,
afterExecute,
};
if (this.operations.length === 0) {
// 处理一下create
if (oper.action === 'create') {
const id = await generateNewId();
Object.assign(oper.data, {
id,
});
}
Object.assign(oper, { id: await generateNewId() });
this.operations.push(operation as Operation<ED, T>);
this.operation = {
operation,
beforeExecute,
afterExecute,
};
}
else {
// singleNode上应当有且只有一个operation无论什么情况
const result = mergeOperationOper(this.entity, this.schema, oper, this.operations[0].oper);
assert(!result);
const { operation } = this.operation;
assert(['create', 'update', action].includes(operation.action));
Object.assign(operation.data, data);
if (action && operation.action !== action) {
operation.action = action;
}
}
this.setDirty();
}
async composeOperations() {
async remove(beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
const operation: ED[T]['Remove'] = {
id: await generateNewId(),
action: 'remove',
data: {},
};
if (this.id) {
Object.assign(operation, {
filter: {
id: this.id,
},
});
}
this.operation = {
operation,
beforeExecute,
afterExecute,
};
this.setDirty();
}
async composeOperations(): Promise<Array<{
entity: T;
operation: ED[T]['Update'];
}> | undefined> {
if (!this.dirty) {
return;
}
const childOperations = await Promise.all(
Object.keys(this.children).map(
async (ele) => {
const child = this.children[ele];
const childOperations = await child!.composeOperations();
let subOper;
if (childOperations) {
if (child instanceof SingleNode) {
subOper = childOperations[0];
}
else {
assert(child instanceof ListNode);
subOper = childOperations;
}
}
let operation: ED[T]['Update'] = this.operation ? cloneDeep(this.operation.operation) : {
id: await generateNewId(),
action: 'update',
data: {},
}; // 如果本结点是create在初始化时就应该置上operation
if (this.id && !operation.filter) {
Object.assign(operation, {
filter: {
id: this.id,
}
});
}
if (subOper) {
const sliceIdx = ele.indexOf(':');
const ele2 = sliceIdx > 0 ? ele.slice(0, sliceIdx) : ele;
if (this.id) {
return {
id: 'dummy', // 因为肯定会被merge掉所以无所谓了
action: 'update',
data: {
[ele2]: subOper,
},
filter: {
id: this.id,
}
} as ED[T]['Operation'];
}
else {
return {
id: 'dummy', // 因为肯定会被merge掉所以无所谓了
action: 'create',
data: {
[ele2]: subOper,
},
} as ED[T]['Operation'];
}
for (const ele in this.children) {
const child = this.children[ele];
const childOperations = await child!.composeOperations();
const sliceIdx = ele.indexOf(':');
const ele2 = sliceIdx > 0 ? ele.slice(0, sliceIdx) : ele;
if (childOperations) {
if (child instanceof SingleNode) {
assert(childOperations.length === 1);
assert(!operation.data[ele2]); // 多对一的子结点不应该有多项
Object.assign(operation.data, {
[ele2]: childOperations[0].operation,
});
}
else {
assert(child instanceof ListNode);
const childOpers = childOperations.map(
ele => ele.operation
);
if (operation.data[ele2]) {
operation.data[ele2].push(...childOpers);
}
else {
operation.data[ele2] = childOpers;
}
}
)
);
}
}
const operations: ED[T]['Operation'][] = [];
if (this.operations.length > 0) {
assert(this.operations.length === 1);
// 这里不能直接改this.operations只能克隆一个新的
operations.push(cloneDeep(this.operations[0].oper));
}
else {
if (this.id) {
operations.push({
id: await generateNewId(),
action: 'update',
data: {},
filter: {
id: this.id,
} as any,
});
}
else {
operations.push({
id: await generateNewId(),
action: 'create',
data: {
id: await generateNewId(),
},
});
}
}
for (const oper of childOperations) {
if (oper) {
mergeOperationOper(this.entity, this.schema, oper, operations[0]); // SingleNode貌似不可能不merge成功
}
}
await repairOperations(this.entity, this.schema, operations);
return operations.map(
ele => Object.assign(ele, {
entity: this.entity,
})
);
return [{
entity: this.entity,
operation,
}];
}
async getProjection(withDecendants?: boolean) {
@ -1455,8 +1443,10 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
async refresh() {
// SingleNode如果是非根结点其id应该在第一次refresh的时候来确定
if (!this.id) {
let id = this.id;
if (!id) {
if (this.parent instanceof ListNode) {
// list的子项不需要refresh由list负责刷新数据
assert(this.parent.getEntity() === this.entity);
// id = this.parent.getChildPath(this);
// this.id = id;
@ -1465,16 +1455,16 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
else if (this.parent instanceof SingleNode) {
const parentFilter = await this.parent.getParentFilter(this);
if (parentFilter) {
const { id } = parentFilter;
this.id = id;
const { id: id2 } = parentFilter!;
id = id2;
}
}
}
if (!this.id) {
if (!id) {
return;
}
const projection = await this.getProjection();
const filter = { id: this.id };
const filter = { id };
this.setLoading(true);
try {
const { data: [value] } = await this.cache.refresh(this.entity, {
@ -1496,14 +1486,14 @@ class SingleNode<ED extends EntityDict & BaseEntityDict,
clean() {
this.dirty = undefined;
this.operations = [];
this.operation = undefined;
for (const child in this.children) {
this.children[child]!.clean();
}
}
async getParentFilter<T2 extends keyof ED>(childNode: Node<ED, keyof ED, Cxt, AD>, disableOperation?: boolean): 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(disableOperation))!;
if (!value) {
return;
@ -1729,7 +1719,7 @@ export class RunningTree<
ED extends EntityDict & BaseEntityDict,
Cxt extends Context<ED>,
AD extends CommonAspectDict<ED, Cxt>
> extends Feature {
> extends Feature {
private cache: Cache<ED, Cxt, AD>;
private schema: StorageSchema<ED>;
private root: Record<
@ -1769,7 +1759,7 @@ export class RunningTree<
// 目前只有一种情况合法即parentNode是list列表中的位置移动引起的重用
if (parentNode instanceof ListNode) {
}
else if (process.env.NODE_ENV === 'development') {
else if (process.env.NODE_ENV === 'development') {
console.error(`创建node时发现已有结点不能重用。「${fullPath}`);
}
return;
@ -1777,6 +1767,7 @@ export class RunningTree<
if (entity) {
if (isList) {
assert(!(parentNode instanceof ListNode));
node = new ListNode<ED, T, Cxt, AD>(
entity,
this.schema!,
@ -1793,7 +1784,7 @@ export class RunningTree<
this.schema!,
this.cache,
projection!,
parentNode,
parentNode as VirtualNode, // 过编译
id
);
}
@ -1860,11 +1851,52 @@ export class RunningTree<
return node ? node.isDirty() : false;
}
@Action
async addOperation<T extends keyof ED>(path: string, operation: Omit<ED[T]['Operation'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
async addItem<T extends keyof ED>(path: string, data: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
const node = this.findNode(path);
assert(node && (node instanceof SingleNode || node instanceof ListNode));
await node.addOperation(operation, beforeExecute, afterExecute);
assert(node instanceof ListNode);
await node.addItem(data, beforeExecute, afterExecute);
}
@Action
async removeItem(path: string, id: string, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
const node = this.findNode(path);
assert(node instanceof ListNode);
await node.removeItem(id, beforeExecute, afterExecute);
}
@Action
async updateItem<T extends keyof ED>(path: string, data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
const node = this.findNode(path);
assert(node instanceof ListNode);
await node.updateItem(data, id, action, beforeExecute, afterExecute);
}
@Action
async recoverItem(path: string, id: string) {
const node = this.findNode(path);
assert(node instanceof ListNode);
await node.recoverItem(id);
}
@Action
async create<T extends keyof ED>(path: string, data: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
const node = this.findNode(path);
assert(node instanceof SingleNode);
await node.create(data, beforeExecute, afterExecute);
}
@Action
async update<T extends keyof ED>(path: string, data: ED[T]['Update']['data'], action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
const node = this.findNode(path);
assert (node instanceof SingleNode);
await node.update(data, action, beforeExecute, afterExecute);
}
@Action
async remove(path: string, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
const node = this.findNode(path);
assert(node instanceof SingleNode);
await node.remove(beforeExecute, afterExecute);
}
isLoading(path: string) {
@ -1904,7 +1936,7 @@ export class RunningTree<
await node.loadMore();
}
getPagination<T extends keyof ED>(path: string) {
getPagination(path: string) {
const node = this.findNode(path);
assert(node instanceof ListNode);
return node.getPagination();
@ -2054,7 +2086,7 @@ export class RunningTree<
}
@Action
async removeNamedSorterByName<T extends keyof ED>(
async removeNamedSorterByName(
path: string,
name: string,
refresh: boolean = false
@ -2080,11 +2112,16 @@ export class RunningTree<
}
@Action
async execute<T extends keyof ED>(path: string, operation?: Omit<ED[T]['Operation'], 'id'>) {
async execute<T extends keyof ED>(path: string, data?: ED[T]['Update']['data'] | Record<string, ED[T]['Update']['data']>, action?: ED[T]['Action']) {
const node = this.findNode(path)!;
if (operation) {
assert(node instanceof ListNode || node instanceof SingleNode);
await node.addOperation(operation);
if (data) {
if(node instanceof SingleNode) {
await node.update(data, action);
}
else {
assert(node instanceof ListNode);
node.updateItems(data);
}
}
assert(node.isDirty());
@ -2093,7 +2130,7 @@ export class RunningTree<
await node.doBeforeTrigger();
const operations = (await node.composeOperations())!;
// 这里理论上virtualNode下面可以有多个不同的entity的组件但实际中不应当出现这样的设计
// 这里理论上virtualNode下面可以有多个不同的entity的组件但实际中不应当出现这样的设计
const entities = uniq(
operations.filter(ele => !!ele).map(
ele => ele.entity
@ -2102,7 +2139,7 @@ export class RunningTree<
await this.aspectWrapper.exec('operate', {
entity: entities[0],
operation: operations.filter(ele => !!ele),
operation: operations.filter(ele => !!ele).map(ele => ele.operation),
});
await node.doAfterTrigger();

View File

@ -7,4 +7,5 @@ export * from './features/localStorage';
export * from './utils/upload';
export * from './types/Notification';
export * from './types/Message';
export * from './utils/bluetooth';
export * from './utils/bluetooth';
export * from './types/Page';

View File

@ -18,7 +18,7 @@ import { unset } from 'oak-domain/lib/utils/lodash';
export function subscribe<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>): void {
Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, any, Cxt>): void {
if (!this.subscribed) {
this.subscribed = FeactureSubscribe(() => this.reRender());
}
@ -27,7 +27,7 @@ export function subscribe<
export function unsubscribe<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>): void {
Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, any, Cxt>): void {
if (this.subscribed) {
this.subscribed();
this.subscribed = undefined;
@ -38,7 +38,7 @@ export async function onPathSet<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends Context<ED>>(
this: ComponentFullThisType<ED, T, Cxt>,
this: ComponentFullThisType<ED, T, any, Cxt>,
option: OakComponentOption<ED, T, Cxt, any, any, any, any, any, {}, {}, {}>) {
const { props, state } = this;
const { oakPath, oakProjection, oakIsPicker, oakFilters, oakSorters, oakId } = props;
@ -142,7 +142,7 @@ export async function reRender<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends Context<ED>>(
this: ComponentFullThisType<ED, T, Cxt>,
this: ComponentFullThisType<ED, T, any, Cxt>,
option: OakComponentOption<ED, T, Cxt, any, any, any, any, any, {}, {}, {}>,
extra?: Record<string, any>) {
const { features } = this;
@ -224,7 +224,7 @@ export async function reRender<
});
this.setState(data);
} else if (this.state.oakFullpath) {
} else {
const data: Record<string, any> = formData
? await formData.call(this, {
features,
@ -244,7 +244,7 @@ export async function refresh<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends Context<ED>>(
this: ComponentFullThisType<ED, T, Cxt>
this: ComponentFullThisType<ED, T, any, Cxt>
) {
if (this.state.oakFullpath) {
try {
@ -261,7 +261,7 @@ export async function refresh<
export async function loadMore<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>) {
Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, any, Cxt>) {
if (this.state.oakEntity && this.state.oakFullpath) {
try {
await this.features.runningTree.loadMore(this.state.oakFullpath);
@ -278,8 +278,8 @@ export async function execute<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends Context<ED>>(
this: ComponentFullThisType<ED, T, Cxt>,
operation?: Omit<ED[T]['Operation'], 'id'>,
this: ComponentFullThisType<ED, T, any, Cxt>,
data?: ED[T]['Update']['data'] | Record<string, ED[T]['Update']['data']>,
path?: string) {
if (this.state.oakExecuting) {
throw new Error('请仔细设计按钮状态,不要允许重复点击!');
@ -287,49 +287,20 @@ export async function execute<
/* this.setState({
oakFocused: undefined,
}); */
try {
const fullpath = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
const result = await this.features.runningTree.execute(fullpath, operation);
await this.setMessage({
type: 'success',
content: '操作成功',
});
return result;
} catch (err) {
if (err instanceof OakUserException) {
if (err instanceof OakInputIllegalException) {
const attrs = err.getAttributes();
const entity = err.getEntity();
const message = err.message;
/* this.setState({
oakFocused: {
attr: attrs[0],
message,
},
oakExecuting: false,
}); */
const attrNames = attrs.map(attr => this.t(`${entity}:attr.${attr}`)).filter(ele => !!ele);
this.setMessage({
type: 'error',
content: attrNames.length > 0 ? `${attrNames.join(',')}${message}` : message,
});
throw err;
}
}
this.setMessage({
type: 'error',
content: (err as Error).message,
});
throw err;
}
const fullpath = path ? `${this.state.oakFullpath}.${path}` : this.state.oakFullpath;
const result = await this.features.runningTree.execute(fullpath, data);
await this.setMessage({
type: 'success',
content: '操作成功',
});
return result;
}
export function callPicker<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>, attr: string, params: Record<string, any> = {}) {
Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, any, Cxt>, attr: string, params: Record<string, any> = {}) {
if (this.state.oakExecuting) {
return;
}
@ -354,55 +325,12 @@ export function callPicker<
});
}
export async function setUpdateData<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>, attr: string, data: any) {
assert(attr.indexOf('.') === -1, 'setUpdateData只能设置当前对象属性子层对象请写完整的addOperation')
if (this.props.oakId) {
return this.addOperation({
action: 'update',
data: {
[attr]: data,
}
} as ED[T]['Update']);
}
else {
await this.addOperation({
action: 'create',
data: {
[attr]: data,
}
} as ED[T]['CreateSingle']);
}
}
export async function setMultiAttrUpdateData<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends Context<ED>>(this: ComponentFullThisType<ED, T, Cxt>, data: Record<string, any>) {
for (const key in data) {
assert(key.indexOf('.') === -1, 'setMultiAttrUpdateData只能设置当前对象属性子层对象请写完整的addOperation');
}
if (this.props.oakId) {
return this.addOperation({
action: 'update',
data,
} as ED[T]['Update']);
}
else {
await this.addOperation({
action: 'create',
data,
} as ED[T]['CreateSingle']);
}
}
export function destroyNode<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends Context<ED>>(
this: ComponentFullThisType<ED, T, Cxt>) {
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends Context<ED>>(
this: ComponentFullThisType<ED, T, any, Cxt>) {
assert(this.state.oakFullpath);
this.features.runningTree.destroyNode(this.state.oakFullpath);
unset(this.state, ['oakFullpath', 'oakEntity']);

View File

@ -4,7 +4,7 @@ import React from 'react';
import { withRouter, PullToRefresh } from './platforms/web';
import { get } from 'oak-domain/lib/utils/lodash';
import { CommonAspectDict } from 'oak-common-aspect';
import { Aspect, CheckerType, Context, DeduceSorterItem, EntityDict } from 'oak-domain/lib/types';
import { Action, Aspect, CheckerType, Context, DeduceSorterItem, EntityDict } from 'oak-domain/lib/types';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
import { BasicFeatures } from './features';
import { NamedFilterItem, NamedSorterItem } from './types/NamedCondition';
@ -14,11 +14,14 @@ import {
ComponentProps,
OakComponentOption,
OakNavigateToParameters,
WebComponentCommonMethodNames,
WebComponentListMethodNames,
WebComponentSingleMethodNames,
} from './types/Page';
import {
subscribe, unsubscribe, onPathSet, reRender, refresh,
loadMore, execute, callPicker, setUpdateData, setMultiAttrUpdateData,
loadMore, execute, callPicker,
destroyNode,
} from './page.common';
import { MessageProps } from './types/Message';
@ -38,7 +41,7 @@ abstract class OakComponentBase<
TMethod extends WechatMiniprogram.Component.MethodOption
> extends React.PureComponent<ComponentProps<IsList, TProperty>, ComponentData<ED, T, FormedData, TData>> {
abstract features: FD & BasicFeatures<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>;
abstract option: OakComponentOption<ED, T, Cxt, AD, FD, Proj, FormedData, IsList, TData, TProperty, TMethod>;
abstract oakOption: OakComponentOption<ED, T, Cxt, AD, FD, Proj, FormedData, IsList, TData, TProperty, TMethod>;
subscribe() {
subscribe.call(this as any);
@ -49,7 +52,7 @@ abstract class OakComponentBase<
}
onPathSet() {
return onPathSet.call(this as any, this.option as any);
return onPathSet.call(this as any, this.oakOption as any);
}
triggerEvent<DetailType = any>(
@ -123,10 +126,10 @@ abstract class OakComponentBase<
}
reRender(extra?: Record<string, any>) {
return reRender.call(this as any, this.option as any, extra);
return reRender.call(this as any, this.oakOption as any, extra);
}
navigateTo(options: { url: string } & OakNavigateToParameters<ED, T>, state?: Record<string, any>, disableNamespace?: boolean) {
navigateTo<T2 extends keyof ED>(options: { url: string } & OakNavigateToParameters<ED, T2>, state?: Record<string, any>, disableNamespace?: boolean) {
const { url, ...rest } = options;
let url2 = url.includes('?')
? url.concat(
@ -158,7 +161,7 @@ abstract class OakComponentBase<
return this.props.navigate(url2, { replace: false, state });
}
navigateBack(option: { delta?: number }) {
navigateBack(option?: { delta?: number }) {
const { delta } = option || {};
return new Promise((resolve, reject) => {
try {
@ -170,7 +173,7 @@ abstract class OakComponentBase<
});
}
redirectTo(options: { url: string } & OakNavigateToParameters<ED, T>, state?: Record<string, any>, disableNamespace?: boolean) {
redirectTo<T2 extends keyof ED>(options: { url: string } & OakNavigateToParameters<ED, T2>, state?: Record<string, any>, disableNamespace?: boolean) {
const { url, ...rest } = options;
let url2 = url.includes('?')
? url.concat(
@ -245,12 +248,35 @@ abstract class OakComponentBase<
}
} */
addOperation(operation: Omit<ED[T]['Operation'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>, path?: string) {
const path2 = path ? `${this.state.oakFullpath}.${path}` : this.state.oakFullpath;
return this.features.runningTree.addOperation(path2, operation, beforeExecute, afterExecute);
addItem<T extends keyof ED>(data: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
return this.features.runningTree.addItem(this.state.oakFullpath, data, beforeExecute, afterExecute);
}
cleanOperation(path?: string) {
removeItem(id: string, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
return this.features.runningTree.removeItem(this.state.oakFullpath, id, beforeExecute, afterExecute);
}
updateItem<T extends keyof ED>(data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
return this.features.runningTree.updateItem(this.state.oakFullpath, data, id, action, beforeExecute, afterExecute);
}
recoverItem(id: string) {
return this.features.runningTree.recoverItem(this.state.oakFullpath, id);
}
create<T extends keyof ED>(data: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
return this.features.runningTree.create(this.state.oakFullpath, data, beforeExecute, afterExecute);
}
update<T extends keyof ED>(data: ED[T]['Update']['data'], action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
return this.features.runningTree.update(this.state.oakFullpath, data, action, beforeExecute, afterExecute);
}
remove(beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) {
return this.features.runningTree.remove(this.state.oakFullpath, beforeExecute, afterExecute);
}
clean(path?: string) {
const path2 = path ? `${this.state.oakFullpath}.${path}` : this.state.oakFullpath;
return this.features.runningTree.clean(path2);
}
@ -263,12 +289,12 @@ abstract class OakComponentBase<
return callPicker.call(this as any, attr, params);
}
execute(operation?: ED[T]['Operation']) {
return execute.call(this as any, operation);
execute(data?: ED[T]['Update']['data'] | Record<string, ED[T]['Update']['data']>) {
return execute.call(this as any, data);
}
getFreshValue(path?: string) {
const path2 = path? `${this.state.oakFullpath}.${path}` : this.state.oakFullpath;
const path2 = path ? `${this.state.oakFullpath}.${path}` : this.state.oakFullpath;
return this.features.runningTree.getFreshValue(path2) as Promise<ED[keyof ED]['Schema'][] | ED[keyof ED]['Schema'] | undefined>;
}
@ -290,14 +316,6 @@ abstract class OakComponentBase<
return refresh.call(this as any);
}
setUpdateData(attr: string, data: any) {
return setUpdateData.call(this as any, attr, data);
}
setMultiAttrUpdateData(data: Record<string, any>) {
return setMultiAttrUpdateData.call(this as any, data);
}
loadMore() {
return loadMore.call(this as any);
}
@ -534,7 +552,7 @@ export function createComponent<
features: BasicFeatures<ED, Cxt, AD & CommonAspectDict<ED, Cxt>> & FD,
) {
const {
data, projection, properties, entity, methods, lifetimes, observers, Render, path
data, methods, lifetimes, observers, getRender, path
} = option as OakComponentOption<
ED,
T,
@ -548,28 +566,121 @@ export function createComponent<
TProperty,
TMethod
> & {
Render: React.ComponentType<any>;
getRender: () => React.ComponentType<any>;
};
const { fn } = translateObservers(observers);
const props = {} as Record<string, any>;
class OakComponentWrapper extends OakComponentBase<ED, T, Cxt, AD, FD, Proj, FormedData, IsList, TData, TProperty, TMethod> {
features = features;
option = option;
oakOption = option;
isReachBottom = false;
methodProps: Record<string, Function>;
constructor(props: ComponentProps<IsList, TProperty>) {
super(props);
const methodProps: Record<string, Function> = {
const methodProps: Record<WebComponentCommonMethodNames, Function> = {
t: (key: string, params?: object) => this.t(key, params),
execute: async (data: Record<string, any>) => {
await this.setMultiAttrUpdateData(data);
await this.execute();
execute: (data: Record<string, any>) => {
return this.execute(data);
},
tryExecute: async (data: Record<string, any>, path?: string) => this.tryExecute(path),
};
refresh: () => {
return this.refresh();
},
setNotification: (data: NotificationProps) => {
return this.setNotification(data);
},
setMessage: (data: MessageProps) => {
return this.setMessage(data);
},
navigateTo: <T2 extends keyof ED>(
options: { url: string } & OakNavigateToParameters<ED, T2>,
state?: Record<string, any>,
disableNamespace?: boolean
) => {
return this.navigateTo(options, state, disableNamespace);
},
navigateBack: (options?: { delta: number }) => {
return this.navigateBack(options);
},
redirectTo: <T2 extends keyof ED>(
options: Parameters<typeof wx.redirectTo>[0] &
OakNavigateToParameters<ED, T2>,
state?: Record<string, any>,
disableNamespace?: boolean
) => {
return this.redirectTo(options, state, disableNamespace);
},
clean: (path?: string) => {
return this.clean(path);
}
};
if (option.isList) {
Object.assign(methodProps, {
addItem: (data: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => {
return this.addItem(data, beforeExecute, afterExecute);
},
removeItem: (id: string, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => {
return this.removeItem(id, beforeExecute, afterExecute);
},
updateItem: (data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => {
return this.updateItem(data, id, action, beforeExecute, afterExecute);
},
setFilters: (filters: NamedFilterItem<ED, T>[]) => {
return this.setFilters(filters);
},
addNamedFilter: (filter: NamedFilterItem<ED, T>, refresh?: boolean) => {
return this.addNamedFilter(filter, refresh);
},
removeNamedFilter: (
filter: NamedFilterItem<ED, T>,
refresh?: boolean
) => {
return this.removeNamedFilter(filter, refresh);
},
removeNamedFilterByName: (name: string, refresh?: boolean) => {
return this.removeNamedFilterByName(name, refresh);
},
setNamedSorters: (sorters: NamedSorterItem<ED, T>[]) => {
return this.setNamedSorters(sorters);
},
addNamedSorter: (sorter: NamedSorterItem<ED, T>, refresh?: boolean) => {
return this.addNamedSorter(sorter, refresh);
},
removeNamedSorter: (
sorter: NamedSorterItem<ED, T>,
refresh?: boolean
) => {
return this.removeNamedSorter(sorter, refresh);
},
removeNamedSorterByName: (name: string, refresh?: boolean) => {
return this.removeNamedSorterByName(name, refresh);
},
setPageSize: (pageSize: number) => {
return this.setPageSize(pageSize);
},
setCurrentPage: (current: number) => {
return this.setCurrentPage(current);
},
loadMore: () => {
return this.loadMore();
}
} as Record<WebComponentListMethodNames, Function>);
}
else {
Object.assign(methodProps, {
create: (data: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => {
return this.create(data, beforeExecute, afterExecute);
},
update: (data: ED[T]['Update']['data'], action: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => {
return this.update(data, action, beforeExecute, afterExecute);
},
remove: (beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => {
return this.remove(beforeExecute, afterExecute);
},
} as Record<WebComponentSingleMethodNames, Function>);
}
if (methods) {
for (const m in methods) {
Object.assign(this, {
@ -673,6 +784,7 @@ export function createComponent<
render(): React.ReactNode {
const { oakPullDownRefreshLoading } = this.state;
const { oakDisablePulldownRefresh = false } = this.props;
const Render = getRender.call(this);
if (this.supportPullDownRefresh() && !oakDisablePulldownRefresh) {
const Child = React.cloneElement(
@ -694,11 +806,17 @@ export function createComponent<
{
getScrollContainer: () => document.body,
},
<Render method={this.methodProps} data={this.state}/>
<Render methods={this.methodProps} data={{
...this.state,
...this.props,
}} />
);
return Child;
}
return <Render method={this.methodProps} data={this.state}/>;
return <Render methods={this.methodProps} data={{
...this.state,
...this.props,
}}/>;
}
};
return withRouter(OakComponentWrapper, option);

View File

@ -116,13 +116,15 @@ export type ComponentPublicThisType<
detail?: DetailType,
options?: WechatMiniprogram.Component.TriggerEventOption
) => void;
} & TMethod & OakCommonComponentMethods<ED, T> & (IsList extends true ? OakListComponentMethods<ED, T> : {});
} & TMethod & OakCommonComponentMethods<ED, T> & (IsList extends true ? OakListComponentMethods<ED, T> : OakSingleComponentMethods<ED, T>);
export type ComponentFullThisType<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
IsList extends boolean,
Cxt extends Context<ED>
> = {
subscribed?: () => void;
features: BasicFeatures<ED, Cxt, CommonAspectDict<ED, Cxt>>;
state: OakComponentData<ED, T>;
props: ComponentProps<true, {}>;
@ -135,7 +137,7 @@ export type ComponentFullThisType<
detail?: DetailType,
options?: WechatMiniprogram.Component.TriggerEventOption
) => void;
} & OakCommonComponentMethods<ED, T> & OakListComponentMethods<ED, T> & OakHiddenComponentMethods;
} & OakCommonComponentMethods<ED, T> & (IsList extends true ? OakListComponentMethods<ED, T> : OakSingleComponentMethods<ED, T>);
export type OakComponentOption<
ED extends EntityDict & BaseEntityDict,
@ -247,23 +249,26 @@ export type OakCommonComponentMethods<
disableNamespace?: boolean
) => Promise<void>;
// setProps: (props: Record<string, any>, usingState?: true) => void;
addOperation: (operation: Omit<ED[T]['Operation'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>, path?: string) => Promise<void>;
cleanOperation: (path?: string) => void;
clean: (path?: string) => void;
t(key: string, params?: object): string;
callPicker: (attr: string, params: Record<string, any>) => void;
execute: (operation?: Omit<ED[T]['Operation'], 'id'>, path?: string) => Promise<ED[T]['Operation'][]>;
execute: (data?: ED[T]['Update']['data'] | Record<string, ED[T]['Update']['data']>, path?: string) => Promise<ED[T]['Operation'][]>;
checkOperation: (ntity: T, action: ED[T]['Action'], filter?: ED[T]['Update']['filter'], checkerTypes?: CheckerType[]) => Promise<boolean>;
tryExecute: (path?: string) => Promise<boolean>;
getOperations: (path?: string) => Promise<ED[T]['Operation'][] | undefined>;
refresh: (extra?: any) => Promise<void>;
setUpdateData: (data: string, attr: any) => Promise<void>;
setMultiAttrUpdateData: (data: Record<string, any>) => Promise<void>;
setId: (id: string) => Promise<void>;
unsetId: () => void;
getId: () => string | undefined;
refresh: () => Promise<void>;
};
export type OakSingleComponentMethods<ED extends EntityDict & BaseEntityDict, T extends keyof ED> = {
setId: (id: string) => Promise<void>;
unsetId: () => void;
getId: () => string | undefined;
create: (data: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => Promise<void>;
update: (data: ED[T]['Update']['data'], action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => Promise<void>;
remove: (beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => Promise<void>;
}
export type OakListComponentMethods<ED extends EntityDict & BaseEntityDict, T extends keyof ED> = {
loadMore: () => Promise<void>;
setFilters: (filters: NamedFilterItem<ED, T>[]) => Promise<void>;
@ -291,6 +296,10 @@ export type OakListComponentMethods<ED extends EntityDict & BaseEntityDict, T ex
getPagination: () => Pagination | undefined;
setPageSize: (pageSize: number) => void;
setCurrentPage: (current: number) => void;
addItem: (data: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => Promise<void>;
removeItem: (id: string, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => Promise<void>;
updateItem: (data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => Promise<void>;
};
type ComponentOnPropsChangeOption = {
@ -307,21 +316,21 @@ export type OakComponentOnlyMethods = {
export type OakComponentData<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED
> = {
oakExecuting: boolean;
oakAllowExecuting: boolean | OakUserException;
oakFocused: {
attr: string;
message: string;
> = {
oakExecuting: boolean;
oakAllowExecuting: boolean | OakUserException;
oakFocused: {
attr: string;
message: string;
};
oakDirty: boolean;
oakLoading: boolean;
oakLoadingMore: boolean;
oakPullDownRefreshLoading: boolean;
oakEntity: T;
oakFullpath: string;
oakLegalActions?: ED[T]['Action'][];
};
oakDirty: boolean;
oakLoading: boolean;
oakLoadingMore: boolean;
oakPullDownRefreshLoading: boolean;
oakEntity: T;
oakFullpath: string;
oakLegalActions?: ED[T]['Action'][];
};
export type MakeOakComponent<
ED extends EntityDict & BaseEntityDict,
@ -351,3 +360,24 @@ export type MakeOakComponent<
TMethod
>
) => React.ComponentType<any>;
// 暴露给组件的方法
export type WebComponentCommonMethodNames = 'setNotification' | 'setMessage' | 'navigateTo' | 'navigateBack' | 'redirectTo' | 'clean' | 't' | 'execute' | 'refresh';
// 暴露给list组件的方法
export type WebComponentListMethodNames = 'loadMore' | 'setFilters' | 'addNamedFilter' | 'removeNamedFilter' | 'removeNamedFilterByName' | 'setNamedSorters'
| 'addNamedSorter' | 'removeNamedSorter' | 'removeNamedSorterByName' | 'setPageSize' | 'setCurrentPage' | 'addItem' | 'removeItem' | 'updateItem';
// 暴露给single组件的方法
export type WebComponentSingleMethodNames = 'create' | 'update' | 'remove';
export type WebComponentProps<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
IsList extends boolean,
TData extends WechatMiniprogram.Component.DataOption = {},
TMethod extends WechatMiniprogram.Component.MethodOption = {}> = {
methods: TMethod & Pick<OakCommonComponentMethods<ED, T>, WebComponentCommonMethodNames>
& (IsList extends true ? Pick<OakListComponentMethods<ED, T>, WebComponentListMethodNames> : Pick<OakSingleComponentMethods<ED, T>, WebComponentSingleMethodNames>);
data: TData & OakComponentData<ED, T> & (IsList extends true ? OakListComponentProperties : {});
}