This commit is contained in:
Xu Chang 2022-05-27 09:42:00 +08:00
commit 8e85bcbe65
18 changed files with 1406 additions and 236 deletions

View File

@ -6,7 +6,11 @@ export declare class Cache<ED extends EntityDict, Cxt extends Context<ED>, AD ex
createContext: (store: RowStore<ED, Cxt>, scene: string) => Cxt;
private syncEventsCallbacks;
constructor(storageSchema: StorageSchema<ED>, createContext: (store: RowStore<ED, Cxt>, scene: string) => Cxt, checkers?: Array<Checker<ED, keyof ED, Cxt>>);
refresh<T extends keyof ED>(entity: T, selection: ED[T]['Selection'], scene: string, params?: object): Promise<OperationResult>;
refresh<T extends keyof ED>(entity: T, selection: ED[T]['Selection'], scene: string, params?: object): ReturnType<(AD & {
operate: typeof import("../aspects/crud").operate;
select: typeof import("../aspects/crud").select;
amap: typeof import("../aspects/amap").amap;
})["select"]>;
sync(records: OpRecord<ED>[]): Promise<void>;
/**
* operation只可能是测试权限

View File

@ -25,9 +25,9 @@ class Cache extends Feature_1.Feature {
this.syncEventsCallbacks = [];
}
refresh(entity, selection, scene, params) {
return this.getAspectProxy().operate({
return this.getAspectProxy().select({
entity: entity,
operation: (0, lodash_1.assign)({}, selection, { action: 'select' }),
selection,
params,
}, scene);
}

View File

@ -2,12 +2,14 @@ import { Aspect, Checker, Context, EntityDict, RowStore } from 'oak-domain/lib/t
import { Cache } from './cache';
import { Location } from './location';
import { RunningNode } from './node';
import { Upload } from './uplpad';
import { Upload } from './upload';
import { StorageSchema } from 'oak-domain/lib/types/Storage';
import { RunningTree } from './runningTree';
export declare function initialize<ED extends EntityDict, Cxt extends Context<ED>, AD extends Record<string, Aspect<ED, Cxt>>>(storageSchema: StorageSchema<ED>, createContext: (store: RowStore<ED, Cxt>, scene: string) => Cxt, checkers?: Array<Checker<ED, keyof ED, Cxt>>): BasicFeatures<ED, Cxt, AD>;
export declare type BasicFeatures<ED extends EntityDict, Cxt extends Context<ED>, AD extends Record<string, Aspect<ED, Cxt>>> = {
cache: Cache<ED, Cxt, AD>;
location: Location;
runningNode: RunningNode<ED, Cxt, AD>;
runningTree: RunningTree<ED, Cxt, AD>;
upload: Upload;
};

View File

@ -4,16 +4,19 @@ exports.initialize = void 0;
const cache_1 = require("./cache");
const location_1 = require("./location");
const node_1 = require("./node");
const uplpad_1 = require("./uplpad");
const upload_1 = require("./upload");
const runningTree_1 = require("./runningTree");
function initialize(storageSchema, createContext, checkers) {
const cache = new cache_1.Cache(storageSchema, createContext, checkers);
const location = new location_1.Location();
const runningNode = new node_1.RunningNode(cache);
const upload = new uplpad_1.Upload();
const runningTree = new runningTree_1.RunningTree(cache);
const upload = new upload_1.Upload();
return {
cache,
location,
runningNode,
runningTree,
upload,
};
}

View File

@ -354,13 +354,14 @@ class ListNode extends Node {
return filter;
}));
this.refreshing = true;
const { ids } = await this.cache.refresh(entity, {
const { result } = await this.cache.refresh(entity, {
data: proj,
filter: filterss.length > 0 ? (0, filter_1.combineFilters)(filterss) : undefined,
sorter: sorterss,
indexFrom: 0,
count: step,
}, scene);
const ids = result.map(ele => ele.id);
(0, assert_1.default)(ids);
this.ids = ids;
this.pagination.indexFrom = 0;

146
lib/features/runningTree.d.ts vendored Normal file
View File

@ -0,0 +1,146 @@
import { EntityDict, Aspect, Context, DeduceUpdateOperation, StorageSchema, OpRecord, SelectRowShape, DeduceOperation } from "oak-domain/lib/types";
import { NamedFilterItem, NamedSorterItem } from "../types/NamedCondition";
import { Cache } from './cache';
import { Pagination } from '../types/Pagination';
import { Feature } from '../types/Feature';
declare abstract class Node<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>, AD extends Record<string, Aspect<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>;
protected action?: ED[T]['Action'];
protected dirty: boolean;
protected updateData: DeduceUpdateOperation<ED[T]['OpSchema']>['data'];
protected cache: Cache<ED, Cxt, AD>;
protected refreshing: boolean;
private beforeExecute?;
private afterExecute?;
abstract onCachSync(opRecords: OpRecord<ED>[]): Promise<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>, action?: ED[T]['Action'], updateData?: DeduceUpdateOperation<ED[T]['OpSchema']>['data']);
getEntity(): T;
setUpdateData(attr: string, value: any): void;
getUpdateData(): import("oak-domain/lib/types").DeduceUpdateOperationData<ED[T]["OpSchema"]>;
setMultiUpdateData(updateData: DeduceUpdateOperation<ED[T]['OpSchema']>['data']): void;
setDirty(): void;
setAction(action: ED[T]['Action']): void;
isDirty(): boolean;
getParent(): Node<ED, keyof ED, Cxt, AD> | undefined;
getProjection(): Promise<ED[T]["Selection"]["data"]>;
setBeforeExecute(_beforeExecute?: (updateData: DeduceUpdateOperation<ED[T]['OpSchema']>['data'], action: ED[T]['Action']) => Promise<void>): void;
setAfterExecute(_afterExecute?: (updateData: DeduceUpdateOperation<ED[T]['OpSchema']>['data'], action: ED[T]['Action']) => Promise<void>): void;
getBeforeExecute(): ((updateData: import("oak-domain/lib/types").DeduceUpdateOperationData<ED[T]["OpSchema"]>, action: ED[T]["Action"]) => Promise<void>) | undefined;
getAfterExecute(): ((updateData: import("oak-domain/lib/types").DeduceUpdateOperationData<ED[T]["OpSchema"]>, action: ED[T]["Action"]) => Promise<void>) | undefined;
destroy(): void;
protected judgeRelation(attr: string): string | 0 | 2 | 1 | string[];
protected contains(filter: ED[T]['Selection']['filter'], conditionalFilter: ED[T]['Selection']['filter']): boolean;
protected repel(filter1: ED[T]['Selection']['filter'], filter2: ED[T]['Selection']['filter']): boolean;
}
declare class ListNode<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>, AD extends Record<string, Aspect<ED, Cxt>>> extends Node<ED, T, Cxt, AD> {
private children;
private newBorn;
private filters;
private sorters;
private pagination;
private projectionShape;
onCachSync(records: OpRecord<ED>[]): Promise<void>;
constructor(entity: T, schema: StorageSchema<ED>, cache: Cache<ED, Cxt, AD>, projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>), projectionShape: ED[T]['Selection']['data'], parent?: Node<ED, keyof ED, Cxt, AD>, action?: ED[T]['Action'], updateData?: DeduceUpdateOperation<ED[T]['OpSchema']>['data'], filters?: NamedFilterItem<ED, T>[], sorters?: NamedSorterItem<ED, T>[], pagination?: Pagination);
getChild(path: string): SingleNode<ED, T, Cxt, AD>;
getChildren(): SingleNode<ED, T, Cxt, AD>[];
getNewBorn(): SingleNode<ED, T, Cxt, AD>[];
removeChild(path: string): void;
setValue(value: SelectRowShape<ED[T]['OpSchema'], ED[T]['Selection']['data']>[]): void;
getNamedFilters(): NamedFilterItem<ED, T>[];
getNamedFilterByName(name: string): NamedFilterItem<ED, T> | undefined;
setNamedFilters(filters: NamedFilterItem<ED, T>[]): void;
addNamedFilter(filter: NamedFilterItem<ED, T>): void;
removeNamedFilter(filter: NamedFilterItem<ED, T>): void;
removeNamedFilterByName(name: string): void;
getNamedSorters(): NamedSorterItem<ED, T>[];
getNamedSorterByName(name: string): NamedSorterItem<ED, T> | undefined;
setNamedSorters(sorters: NamedSorterItem<ED, T>[]): void;
addNamedSorter(sorter: NamedSorterItem<ED, T>): void;
removeNamedSorter(sorter: NamedSorterItem<ED, T>): void;
removeNamedSorterByName(name: string): void;
getValue(): SelectRowShape<ED[T]['Schema'], ED[T]['Selection']['data']>[];
getAction(): "update" | ED[T]["Action"];
composeOperation(action?: string, realId?: boolean): Promise<DeduceOperation<ED[T]['Schema']> | DeduceOperation<ED[T]['Schema']>[] | undefined>;
refresh(scene: string): Promise<void>;
resetUpdateData(): void;
pushNode(options: Pick<CreateNodeOptions<ED, T>, 'updateData' | 'beforeExecute' | 'afterExecute'>): void;
popNode(path: string): void;
}
declare class SingleNode<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>, AD extends Record<string, Aspect<ED, Cxt>>> extends Node<ED, T, Cxt, AD> {
private id?;
private value?;
private children;
onCachSync(records: OpRecord<ED>[]): Promise<void>;
constructor(entity: T, schema: StorageSchema<ED>, cache: Cache<ED, Cxt, AD>, projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>), projectionShape: ED[T]['Selection']['data'], parent?: Node<ED, keyof ED, Cxt, AD>, action?: ED[T]['Action'], updateData?: DeduceUpdateOperation<ED[T]['OpSchema']>['data']);
getChild(path: string): SingleNode<ED, keyof ED, Cxt, AD> | ListNode<ED, keyof ED, Cxt, AD>;
getChildren(): {
[K: string]: SingleNode<ED, keyof ED, Cxt, AD> | ListNode<ED, keyof ED, Cxt, AD>;
};
removeChild(path: string): void;
setValue(value: SelectRowShape<ED[T]['OpSchema'], ED[T]['Selection']['data']>): void;
updateValue(value: SelectRowShape<ED[T]['Schema'], ED[T]['Selection']['data']>): void;
getValue(): SelectRowShape<ED[T]['Schema'], ED[T]['Selection']['data']>;
getAction(): "create" | "update" | ED[T]["Action"];
composeOperation(action2?: string, realId?: boolean): Promise<import("oak-domain/lib/types").DeduceCreateMultipleOperation<ED[T]["Schema"]> | DeduceUpdateOperation<ED[T]["Schema"]> | undefined>;
refresh(scene: string): Promise<void>;
resetUpdateData(): void;
}
export declare type CreateNodeOptions<ED extends EntityDict, T extends keyof ED> = {
path: string;
parent?: string;
entity: T;
isList?: boolean;
isPicker?: boolean;
projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>);
pagination?: Pagination;
filters?: NamedFilterItem<ED, T>[];
sorters?: NamedSorterItem<ED, T>[];
action?: ED[T]['Action'];
id?: string;
ids?: string[];
updateData?: DeduceUpdateOperation<ED[T]['OpSchema']>['data'];
beforeExecute?: (updateData: DeduceUpdateOperation<ED[T]['OpSchema']>['data'], action: ED[T]['Action']) => Promise<void>;
afterExecute?: (updateData: DeduceUpdateOperation<ED[T]['OpSchema']>['data'], action: ED[T]['Action']) => Promise<void>;
};
export declare class RunningTree<ED extends EntityDict, Cxt extends Context<ED>, AD extends Record<string, Aspect<ED, Cxt>>> extends Feature<ED, Cxt, AD> {
private cache;
private schema?;
private root;
constructor(cache: Cache<ED, Cxt, AD>);
createNode<T extends keyof ED>(options: CreateNodeOptions<ED, T>): Promise<ListNode<ED, T, Cxt, AD> | SingleNode<ED, T, Cxt, AD>>;
private findNode;
destroyNode(path: string): void;
setStorageSchema(schema: StorageSchema<ED>): void;
private applyOperation;
getValue(path: string): Promise<(SelectRowShape<ED[keyof ED]["Schema"], ED[keyof ED]["Selection"]["data"]> | undefined)[]>;
isDirty(path: string): boolean;
private setUpdateDataInner;
setUpdateData(path: string, attr: string, value: any): Promise<void>;
setAction<T extends keyof ED>(path: string, action: ED[T]['Action']): Promise<void>;
setForeignKey(path: string, id: string): Promise<void>;
refresh(path: string): Promise<void>;
getNamedFilters<T extends keyof ED>(path: string): NamedFilterItem<ED, keyof ED>[];
getNamedFilterByName<T extends keyof ED>(path: string, name: string): NamedFilterItem<ED, keyof ED> | undefined;
setNamedFilters<T extends keyof ED>(path: string, filters: NamedFilterItem<ED, T>[], refresh?: boolean): Promise<void>;
addNamedFilter<T extends keyof ED>(path: string, filter: NamedFilterItem<ED, T>, refresh?: boolean): Promise<void>;
removeNamedFilter<T extends keyof ED>(path: string, filter: NamedFilterItem<ED, T>, refresh?: boolean): Promise<void>;
removeNamedFilterByName<T extends keyof ED>(path: string, name: string, refresh?: boolean): Promise<void>;
getNamedSorters<T extends keyof ED>(path: string): NamedSorterItem<ED, keyof ED>[];
getNamedSorterByName<T extends keyof ED>(path: string, name: string): NamedSorterItem<ED, keyof ED> | undefined;
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>;
testAction(path: string, action: string, realId?: boolean): Promise<{
node: SingleNode<ED, keyof ED, Cxt, AD> | ListNode<ED, keyof ED, Cxt, AD>;
operation: DeduceOperation<ED[keyof ED]["Schema"]> | DeduceOperation<ED[keyof ED]["Schema"]>[];
}>;
private beforeExecute;
execute(path: string, action: string): Promise<void>;
pushNode<T extends keyof ED>(path: string, options: Pick<CreateNodeOptions<ED, T>, 'updateData' | 'beforeExecute' | 'afterExecute'>): void;
removeNode(parent: string, path: string): Promise<void>;
}
export {};

1081
lib/features/runningTree.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,7 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];

View File

@ -1,11 +1,7 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
@ -63,6 +59,7 @@ function initialize(storageSchema, createFeatures, createContext, triggers, chec
basicFeatures.cache.registerCheckers(adCheckers);
}
basicFeatures.runningNode.setStorageSchema(storageSchema);
basicFeatures.runningTree.setStorageSchema(storageSchema);
const userDefinedfeatures = createFeatures(basicFeatures);
const intersect = (0, lodash_1.intersection)((0, lodash_1.keys)(basicFeatures), (0, lodash_1.keys)(userDefinedfeatures));
if (intersect.length > 0) {

View File

@ -33,7 +33,6 @@ interface OakPageOption<ED extends EntityDict, T extends keyof ED, Cxt extends C
declare type OakComponentProperties = {
oakEntity: StringConstructor;
oakPath: StringConstructor;
oakValue: ObjectConstructor;
oakParent: StringConstructor;
};
declare type OakPageProperties = {
@ -62,7 +61,12 @@ declare type OakNavigateToParameters<ED extends EntityDict, T extends keyof ED>
oakActions?: Array<ED[T]['Action']>;
};
declare type OakComponentMethods<ED extends EntityDict, T extends keyof ED> = {
addNode: (path?: string, options?: Pick<CreateNodeOptions<ED, keyof ED>, 'updateData' | 'beforeExecute' | 'afterExecute'>) => Promise<void>;
subscribed?: () => void;
subscribe: () => void;
unsubscribe: () => void;
reRender: (extra?: any) => Promise<void>;
pushNode: (path?: string, options?: Pick<CreateNodeOptions<ED, keyof ED>, 'updateData' | 'beforeExecute' | 'afterExecute'>) => void;
removeNode: (parent: string, path: string) => void;
setUpdateData: (attr: string, input: any) => void;
callPicker: (attr: string, params: Record<string, any>) => void;
setFilters: (filters: NamedFilterItem<ED, T>[]) => void;
@ -80,13 +84,9 @@ declare type OakComponentMethods<ED extends EntityDict, T extends keyof ED> = {
navigateTo: <T2 extends keyof ED>(options: Parameters<typeof wx.navigateTo>[0] & OakNavigateToParameters<ED, T2>) => ReturnType<typeof wx.navigateTo>;
};
declare type OakPageMethods<ED extends EntityDict, T extends keyof ED> = OakComponentMethods<ED, T> & {
reRender: (extra?: any) => Promise<void>;
refresh: (extra?: any) => Promise<void>;
onPullDownRefresh: () => Promise<void>;
onLoad: () => Promise<void>;
subscribed?: () => void;
subscribe: () => void;
unsubscribe: () => void;
setForeignKey: (id: string, goBackDelta?: number) => Promise<void>;
onForeignKeyPicked: (touch: WechatMiniprogram.Touch) => void;
execute: (action: ED[T]['Action'], afterExecuted?: () => any) => Promise<void>;

View File

@ -11,7 +11,7 @@ const assert_1 = __importDefault(require("assert"));
const lodash_1 = require("lodash");
;
async function execute(features, fullpath, action) {
await features.runningNode.execute(fullpath, action);
await features.runningTree.execute(fullpath, action);
}
function callPicker(features, attr, params, entity, parent) {
const relation = features.cache.judgeRelation(entity, attr);
@ -51,7 +51,7 @@ function createPageOptions(options, doSubscribe, features, exceptionRouterDict)
methods: {
async reRender() {
if (this.data.oakFullpath) {
const $rows = await features.runningNode.get(this.data.oakFullpath);
const $rows = await features.runningTree.getValue(this.data.oakFullpath);
const data = await formData.call(this, $rows, features);
for (const k in data) {
if (data[k] === undefined) {
@ -60,13 +60,13 @@ function createPageOptions(options, doSubscribe, features, exceptionRouterDict)
});
}
}
const dirty = await features.runningNode.isDirty(this.data.oakFullpath);
const dirty = features.runningTree.isDirty(this.data.oakFullpath);
(0, lodash_1.assign)(data, { oakDirty: dirty });
if (this.data.newOakActions) {
const oakLegalActions = [];
for (const action of this.data.newOakActions) {
try {
await features.runningNode.testAction(this.data.oakFullpath, action);
await features.runningTree.testAction(this.data.oakFullpath, action);
oakLegalActions.push(action);
}
catch (e) {
@ -82,14 +82,16 @@ function createPageOptions(options, doSubscribe, features, exceptionRouterDict)
this.setData(data);
}
},
async addNode(path, options) {
await features.runningNode.addNode((0, lodash_1.assign)({
parent: path ? `${this.data.oakFullpath}.${path}` : this.data.oakFullpath
}, options));
pushNode(path, options) {
const path2 = path ? `${this.data.oakFullpath}.${path}` : this.data.oakFullpath;
features.runningTree.pushNode(path2, options || {});
},
removeNode(parent, path) {
features.runningTree.removeNode(parent, path);
},
async refresh() {
if (options.projection) {
await features.runningNode.refresh(this.data.oakFullpath);
await features.runningTree.refresh(this.data.oakFullpath);
}
},
async onPullDownRefresh() {
@ -113,7 +115,7 @@ function createPageOptions(options, doSubscribe, features, exceptionRouterDict)
if (this.data.oakExecuting) {
return;
}
return features.runningNode.setUpdateData(this.data.oakFullpath, attr, value);
return features.runningTree.setUpdateData(this.data.oakFullpath, attr, value);
},
callPicker(attr, params) {
if (this.data.oakExecuting) {
@ -127,7 +129,7 @@ function createPageOptions(options, doSubscribe, features, exceptionRouterDict)
}
const { oakIsPicker } = this.data;
(0, assert_1.default)(oakIsPicker);
await features.runningNode.setForeignKey(this.data.oakFullpath, id);
await features.runningTree.setForeignKey(this.data.oakFullpath, id);
if (goBackDelta !== 0) {
wx.navigateBack({
delta: goBackDelta,
@ -139,10 +141,10 @@ function createPageOptions(options, doSubscribe, features, exceptionRouterDict)
this.setForeignKey(id);
},
setFilters(filters) {
return features.runningNode.setNamedFilters(this.data.oakFullpath, filters);
return features.runningTree.setNamedFilters(this.data.oakFullpath, filters);
},
async getFilters() {
const namedFilters = await features.runningNode.getNamedFilters(this.data.oakFullpath);
const namedFilters = features.runningTree.getNamedFilters(this.data.oakFullpath);
const filters = await Promise.all(namedFilters.map(({ filter }) => {
if (typeof filter === 'function') {
return filter();
@ -152,7 +154,7 @@ function createPageOptions(options, doSubscribe, features, exceptionRouterDict)
return filters;
},
async getFilterByName(name) {
const filter = await features.runningNode.getNamedFilterByName(this.data.oakFullpath, name);
const filter = features.runningTree.getNamedFilterByName(this.data.oakFullpath, name);
if (filter?.filter) {
if (typeof filter.filter === 'function') {
return filter.filter();
@ -162,19 +164,19 @@ function createPageOptions(options, doSubscribe, features, exceptionRouterDict)
return;
},
addNamedFilter(filter, refresh = false) {
return features.runningNode.addNamedFilter(this.data.oakFullpath, filter, refresh);
return features.runningTree.addNamedFilter(this.data.oakFullpath, filter, refresh);
},
removeNamedFilter(filter, refresh = false) {
return features.runningNode.removeNamedFilter(this.data.oakFullpath, filter, refresh);
return features.runningTree.removeNamedFilter(this.data.oakFullpath, filter, refresh);
},
removeNamedFilterByName(name, refresh = false) {
return features.runningNode.removeNamedFilterByName(this.data.oakFullpath, name, refresh);
return features.runningTree.removeNamedFilterByName(this.data.oakFullpath, name, refresh);
},
setNamedSorters(sorters) {
return features.runningNode.setNamedSorters(this.data.oakFullpath, sorters);
return features.runningTree.setNamedSorters(this.data.oakFullpath, sorters);
},
async getSorters() {
const namedSorters = await features.runningNode.getNamedSorters(this.data.oakFullpath);
const namedSorters = features.runningTree.getNamedSorters(this.data.oakFullpath);
const sorters = await Promise.all(namedSorters.map(({ sorter }) => {
if (typeof sorter === 'function') {
return sorter();
@ -184,7 +186,7 @@ function createPageOptions(options, doSubscribe, features, exceptionRouterDict)
return sorters;
},
async getSorterByName(name) {
const sorter = await features.runningNode.getNamedSorterByName(this.data.oakFullpath, name);
const sorter = await features.runningTree.getNamedSorterByName(this.data.oakFullpath, name);
if (sorter?.sorter) {
if (typeof sorter.sorter === 'function') {
return sorter.sorter();
@ -194,13 +196,13 @@ function createPageOptions(options, doSubscribe, features, exceptionRouterDict)
return;
},
addNamedSorter(sorter, refresh = false) {
return features.runningNode.addNamedSorter(this.data.oakFullpath, sorter, refresh);
return features.runningTree.addNamedSorter(this.data.oakFullpath, sorter, refresh);
},
removeNamedSorter(sorter, refresh = false) {
return features.runningNode.removeNamedSorter(this.data.oakFullpath, sorter, refresh);
return features.runningTree.removeNamedSorter(this.data.oakFullpath, sorter, refresh);
},
removeNamedSorterByName(name, refresh = false) {
return features.runningNode.removeNamedSorterByName(this.data.oakFullpath, name, refresh);
return features.runningTree.removeNamedSorterByName(this.data.oakFullpath, name, refresh);
},
async execute(action, afterExecuted) {
if (this.data.oakExecuting) {
@ -350,7 +352,7 @@ function createPageOptions(options, doSubscribe, features, exceptionRouterDict)
};
}));
}
const node = features.runningNode.createNode({
const node = await features.runningTree.createNode({
path: oakPath || options.path,
parent: oakParent,
entity: (oakEntity || options.entity),
@ -372,18 +374,17 @@ function createPageOptions(options, doSubscribe, features, exceptionRouterDict)
}
},
lifetimes: {
async created() {
created() {
this.features = features;
},
async attached() {
attached() {
this.subscribe();
},
async ready() {
await this.refresh();
ready() {
this.refresh();
},
async detached() {
console.log('page detached');
await features.runningNode.destroyNode(this.data.oakFullpath);
detached() {
features.runningTree.destroyNode(this.data.oakFullpath);
this.unsubscribe();
// await context.rollback();
},
@ -400,34 +401,18 @@ function createPageOptions(options, doSubscribe, features, exceptionRouterDict)
};
return componentOptions;
}
function createComponentOptions(options, features, exceptionRouterDict) {
function createComponentOptions(options, features, doSubscribe, exceptionRouterDict) {
const { formData } = options;
const componentOptions = {
properties: {
oakValue: Object,
oakEntity: String,
oakPath: String,
oakParent: String,
},
observers: {
"oakValue": function (value) {
/* const $rows = value instanceof Array ? value : [value];
const fileCarrier = this.data.oakFullpath && await features.runningNode.getFileCarrier(this.data.oakFullpath);
const data = await formData.call(this, $rows, features, fileCarrier as any);
for (const k in data) {
if (data[k] === undefined) {
assign(data, {
[k]: null,
});
}
}
const dirty = await features.runningNode.isDirty(this.data.oakFullpath);
this.setData(assign({}, data, {
oakDirty: dirty,
oakValue: $rows,
})); */
"oakPath": function (path) {
return this.onPropsChanged({
value,
path,
});
},
"oakParent": function (parent) {
@ -437,22 +422,20 @@ function createComponentOptions(options, features, exceptionRouterDict) {
}
},
methods: {
async onPropsChanged(options) {
const value2 = options.hasOwnProperty('value') ? options.value : this.data.oakValue;
const parent2 = options.hasOwnProperty('parent') && options.parent;
const $rows = value2 instanceof Array ? value2 : [value2];
const data2 = {};
if (parent2) {
const node = features.runningNode.createNode({
path: this.data.oakPath,
parent: parent2,
});
(0, lodash_1.assign)(data2, {
oakFullpath: `${parent2}.${this.data.oakPath}`,
oakEntity: node.getEntity(),
});
subscribe() {
if (!this.subscribed) {
this.subscribed = doSubscribe(() => this.reRender());
}
const fullpath = data2.oakFullpath || this.data.oakFullpath;
},
unsubscribe() {
if (this.subscribed) {
this.subscribed();
this.subscribed = undefined;
}
},
async reRender() {
if (this.data.oakFullpath) {
const $rows = await features.runningTree.getValue(this.data.oakFullpath);
const data = await formData.call(this, $rows, features);
for (const k in data) {
if (data[k] === undefined) {
@ -461,19 +444,48 @@ function createComponentOptions(options, features, exceptionRouterDict) {
});
}
}
const dirty = fullpath && await features.runningNode.isDirty(fullpath);
this.setData((0, lodash_1.assign)(data2, data, {
oakDirty: !!dirty,
// oakValue: value2,
}));
const dirty = features.runningTree.isDirty(this.data.oakFullpath);
(0, lodash_1.assign)(data, { oakDirty: dirty });
/* if (this.data.newOakActions) {
const oakLegalActions = [];
for (const action of this.data.newOakActions) {
try {
await features.runningTree.testAction(this.data.oakFullpath, action);
oakLegalActions.push(action);
}
catch (e) {
if (e instanceof OakInputIllegalException) {
oakLegalActions.push(action);
}
}
}
assign(data, {
oakLegalActions,
});
} */
this.setData(data);
}
},
async addNode(path, options) {
await features.runningNode.addNode((0, lodash_1.assign)({
parent: path ? `${this.data.oakFullpath}.${path}` : this.data.oakFullpath
}, options));
async onPropsChanged(options) {
const path2 = options.hasOwnProperty('path') ? options.path : this.data.oakPath;
const parent2 = options.hasOwnProperty('parent') ? options.parent : this.data.oakParent;
if (path2 && parent2) {
const oakFullpath2 = `${parent2}.${path2}`;
if (oakFullpath2 !== this.data.oakFullpath) {
this.data.oakFullpath = oakFullpath2;
this.reRender();
}
}
},
pushNode(path, options) {
const path2 = path ? `${this.data.oakFullpath}.${path}` : this.data.oakFullpath;
features.runningTree.pushNode(path2, options || {});
},
removeNode(parent, path) {
features.runningTree.removeNode(parent, path);
},
async getFilters() {
const namedFilters = await features.runningNode.getNamedFilters(this.data.oakFullpath);
const namedFilters = features.runningTree.getNamedFilters(this.data.oakFullpath);
const filters = await Promise.all(namedFilters.map(({ filter }) => {
if (typeof filter === 'function') {
return filter();
@ -483,7 +495,7 @@ function createComponentOptions(options, features, exceptionRouterDict) {
return filters;
},
async getFilterByName(name) {
const filter = await features.runningNode.getNamedFilterByName(this.data.oakFullpath, name);
const filter = features.runningTree.getNamedFilterByName(this.data.oakFullpath, name);
if (filter?.filter) {
if (typeof filter.filter === 'function') {
return filter.filter();
@ -493,19 +505,19 @@ function createComponentOptions(options, features, exceptionRouterDict) {
return;
},
addNamedFilter(namedFilter, refresh = false) {
return features.runningNode.addNamedFilter(this.data.oakFullpath, namedFilter, refresh);
return features.runningTree.addNamedFilter(this.data.oakFullpath, namedFilter, refresh);
},
removeNamedFilter(namedFilter, refresh = false) {
return features.runningNode.removeNamedFilter(this.data.oakFullpath, namedFilter, refresh);
return features.runningTree.removeNamedFilter(this.data.oakFullpath, namedFilter, refresh);
},
removeNamedFilterByName(name, refresh = false) {
return features.runningNode.removeNamedFilterByName(this.data.oakFullpath, name, refresh);
return features.runningTree.removeNamedFilterByName(this.data.oakFullpath, name, refresh);
},
setNamedSorters(namedSorters) {
return features.runningNode.setNamedSorters(this.data.oakFullpath, namedSorters);
return features.runningTree.setNamedSorters(this.data.oakFullpath, namedSorters);
},
async getSorters() {
const namedSorters = await features.runningNode.getNamedSorters(this.data.oakFullpath);
const namedSorters = features.runningTree.getNamedSorters(this.data.oakFullpath);
const sorters = await Promise.all(namedSorters.map(({ sorter }) => {
if (typeof sorter === 'function') {
return sorter();
@ -515,7 +527,7 @@ function createComponentOptions(options, features, exceptionRouterDict) {
return sorters;
},
async getSorterByName(name) {
const sorter = await features.runningNode.getNamedSorterByName(this.data.oakFullpath, name);
const sorter = features.runningTree.getNamedSorterByName(this.data.oakFullpath, name);
if (sorter?.sorter) {
if (typeof sorter.sorter === 'function') {
return sorter.sorter();
@ -525,19 +537,19 @@ function createComponentOptions(options, features, exceptionRouterDict) {
return;
},
addNamedSorter(namedSorter, refresh = false) {
return features.runningNode.addNamedSorter(this.data.oakFullpath, namedSorter, refresh);
return features.runningTree.addNamedSorter(this.data.oakFullpath, namedSorter, refresh);
},
removeNamedSorter(namedSorter, refresh = false) {
return features.runningNode.removeNamedSorter(this.data.oakFullpath, namedSorter, refresh);
return features.runningTree.removeNamedSorter(this.data.oakFullpath, namedSorter, refresh);
},
removeNamedSorterByName(name, refresh = false) {
return features.runningNode.removeNamedSorterByName(this.data.oakFullpath, name, refresh);
return features.runningTree.removeNamedSorterByName(this.data.oakFullpath, name, refresh);
},
setUpdateData(attr, value) {
if (this.data.oakExecuting) {
return;
}
return features.runningNode.setUpdateData(this.data.oakFullpath, attr, value);
return features.runningTree.setUpdateData(this.data.oakFullpath, attr, value);
},
callPicker(attr, params) {
if (this.data.oakExecuting) {
@ -546,87 +558,8 @@ function createComponentOptions(options, features, exceptionRouterDict) {
return callPicker(features, attr, params, this.data.oakEntity, this.data.oakFullpath);
},
setFilters(filters) {
return features.runningNode.setNamedFilters(this.data.oakFullpath, filters);
return features.runningTree.setNamedFilters(this.data.oakFullpath, filters);
},
/* async execute(action, afterExecuted) {
if (this.data.oakExecuting) {
return;
}
this.setData({
oakExecuting: true,
oakFocused: {},
});
try {
await execute(features, this.data.oakFullpath, action);
this.setData({ oakExecuting: false });
afterExecuted && afterExecuted();
}
catch (err) {
if (err instanceof OakException) {
if (err instanceof OakInputIllegalException) {
const attr = err.getAttributes()[0];
this.setData({
oakFocused: {
},
[attr]: true,
oakExecuting: false,
oakError: {
level: 'warning',
msg: err.message,
},
});
}
else {
const { name } = err.constructor;
const handler = exceptionRouterDict[name];
if (handler) {
const { hidden, level, handler: fn, router } = handler;
if (fn) {
this.setData({
oakExecuting: false,
});
fn(err);
}
else if (router) {
this.setData({
oakExecuting: false,
});
this.navigateTo({
url: router,
});
}
else if (!hidden) {
this.setData({
oakExecuting: false,
oakError: {
level: level!,
msg: err.message,
},
});
}
}
else {
this.setData({
oakExecuting: false,
oakError: {
level: 'warning',
msg: err.message,
},
});
}
}
}
else {
this.setData({
oakExecuting: false,
oakError: {
level: 'error',
msg: (err as Error).message,
},
});
}
}
}, */
navigateTo(options) {
const { url } = options;
const url2 = url.includes('?') ? url.concat(`&oakFrom=${this.data.oakFullpath}`) : url.concat(`?oakFrom=${this.data.oakFullpath}`);
@ -641,35 +574,27 @@ function createComponentOptions(options, features, exceptionRouterDict) {
this.features = features;
},
async ready() {
const { oakPath, oakParent, oakValue } = this.data;
const $rows = oakValue instanceof Array ? oakValue : [oakValue];
const data = await formData.call(this, $rows, features);
for (const k in data) {
if (data[k] === undefined) {
(0, lodash_1.assign)(data, {
[k]: null,
});
}
}
if (oakParent) {
// 小程序component ready的时候父组件还未构造完成
const oakFullpath = `${oakParent}.${oakPath}`;
const node = features.runningNode.createNode({
path: oakPath,
parent: oakParent,
});
this.setData((0, lodash_1.assign)(data, {
oakFullpath,
oakEntity: node.getEntity,
}));
}
else {
this.setData(data);
const { oakPath, oakParent } = this.data;
if (oakParent && oakPath) {
this.data.oakFullpath = `${oakParent}.${oakPath}`;
this.reRender();
}
},
async attached() {
this.subscribe();
},
async detached() {
console.log('component detached');
await features.runningNode.destroyNode(this.data.oakFullpath);
this.unsubscribe();
// await context.rollback();
},
},
pageLifetimes: {
show() {
this.reRender();
this.subscribe();
},
hide() {
this.unsubscribe();
}
},
};
@ -796,7 +721,7 @@ function initialize(storageSchema, createFeatures, createContext, exceptionRoute
});
},
OakComponent: (options, componentOptions = {}) => {
const oakOptions = createComponentOptions(options, features, exceptionRouterDict);
const oakOptions = createComponentOptions(options, features, subscribe, exceptionRouterDict);
const { properties, pageLifetimes, lifetimes, methods, data, observers } = oakOptions;
const { properties: p2, pageLifetimes: pl2, lifetimes: l2, methods: m2, data: d2, observers: o2, ...restOptions } = componentOptions;
const pls = [pageLifetimes, pl2].filter(ele => !!ele);

View File

@ -3,7 +3,7 @@ import { Aspect, Checker, Context, EntityDict, RowStore } from 'oak-domain/lib/t
import { Cache } from './cache';
import { Location } from './location';
import { RunningNode } from './node';
import { Upload } from './uplpad';
import { Upload } from './upload';
import { StorageSchema } from 'oak-domain/lib/types/Storage';
import { RunningTree } from './runningTree';

View File

@ -230,8 +230,15 @@ class ListNode<ED extends EntityDict,
getChild(path: string): SingleNode<ED, T, Cxt, AD> {
const idx = parseInt(path, 10);
assert(typeof idx === 'number');
if (idx < this.children.length) {
return this.children[idx];
}
else {
const idx2 = idx - this.children.length;
// assert(idx2 < this.newBorn.length); // 在删除结点时可能还是会跑到
return this.newBorn[idx2];
}
}
getChildren() {
return this.children;
@ -253,17 +260,13 @@ class ListNode<ED extends EntityDict,
}
setValue(value: SelectRowShape<ED[T]['OpSchema'], ED[T]['Selection']['data']>[]) {
this.children = [];
value.forEach(
(ele, idx) => {
if (this.children[idx]) {
this.children[idx].setValue(ele);
}
else {
const node = new SingleNode(this.entity, this.schema, this.cache, this.projection, this.projectionShape, this);
this.children[idx] = node;
node.setValue(ele);
}
}
);
}

View File

@ -9,3 +9,4 @@ export * from './types/Feature';
export * from './types/ExceptionRoute';
export { BasicFeatures } from './features';
export * from './features/cache';
export * from './features/upload';

View File

@ -89,7 +89,7 @@ type OakComponentMethods<ED extends EntityDict, T extends keyof ED> = {
subscribed?: () => void;
subscribe: () => void;
unsubscribe: () => void;
reRender: (extra?: any) => Promise<void>;
reRender: (extra?: Record<string, any>) => Promise<void>;
pushNode: (path?: string, options?: Pick<CreateNodeOptions<ED, keyof ED>, 'updateData' | 'beforeExecute' | 'afterExecute'>) => void;
removeNode: (parent: string, path: string) => void;
setUpdateData: (attr: string, input: any) => void;
@ -223,7 +223,7 @@ function createPageOptions<ED extends EntityDict,
newOakActions: Array,
},
methods: {
async reRender() {
async reRender(extra) {
if (this.data.oakFullpath) {
const $rows = await features.runningTree.getFreshValue(this.data.oakFullpath);
const data = await formData.call(this, $rows as any, features);
@ -254,6 +254,9 @@ function createPageOptions<ED extends EntityDict,
oakLegalActions,
});
}
if (extra) {
assign(data, extra);
}
this.setData(data);
}
@ -679,7 +682,7 @@ function createComponentOptions<ED extends EntityDict,
}
},
async reRender() {
async reRender(extra) {
if (this.data.oakFullpath) {
const $rows = await features.runningTree.getFreshValue(this.data.oakFullpath);
const data = await formData.call(this, $rows as any, features);
@ -711,6 +714,9 @@ function createComponentOptions<ED extends EntityDict,
});
} */
if (extra) {
assign(data, extra);
}
this.setData(data);
}
},
@ -721,7 +727,9 @@ function createComponentOptions<ED extends EntityDict,
if (path2 && parent2) {
const oakFullpath2 = `${parent2}.${path2}`;
if (oakFullpath2 !== this.data.oakFullpath) {
this.data.oakFullpath = oakFullpath2;
this.setData({
oakFullpath: oakFullpath2,
});
this.reRender();
}
}
@ -852,7 +860,10 @@ function createComponentOptions<ED extends EntityDict,
async ready() {
const { oakPath, oakParent } = this.data;
if (oakParent && oakPath) {
this.data.oakFullpath = `${oakParent}.${oakPath}`;
const oakFullpath = `${oakParent}.${oakPath}`;
this.setData({
oakFullpath,
});
this.reRender();
}
},