修正了cache和feature的一些问题

This commit is contained in:
Xu Chang 2022-03-31 18:36:37 +08:00
parent 3fd4965b28
commit 9365aaf780
5 changed files with 96 additions and 55 deletions

View File

@ -4,7 +4,8 @@
"description": "oak框架中前端与平台无关的逻辑部分",
"dependencies": {
"@reduxjs/toolkit": "^1.7.2",
"lodash": "^4.17.21"
"lodash": "^4.17.21",
"uuid": "^8.3.2"
},
"devDependencies": {
"@babel/cli": "^7.12.13",
@ -27,15 +28,15 @@
"mocha": "^8.2.1",
"oak-debug-store": "file:../oak-debug-store",
"oak-domain": "file:../oak-domain",
"oak-general-business": "file:../oak-general-business",
"oak-memory-tree-store": "file:../oak-memory-tree-store",
"oak-trigger-executor": "file:../oak-trigger-executor",
"oak-general-business": "file:../oak-general-business",
"ts-node": "^9.1.1",
"typescript": "^4.5.2"
},
"scripts": {
"build": "tsc",
"make-domain": "ts-node ./test/build-test-domain.ts"
"make-domain": "ts-node ./test/build-test-domain.ts"
},
"main": "src/index"
}

View File

@ -1,4 +1,4 @@
import { DeduceSelection, EntityDict, OpRecord } from 'oak-domain/lib/types/Entity';
import { DeduceSelection, EntityDict, OperateParams, OpRecord } from 'oak-domain/lib/types/Entity';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-domain/EntityDict';
import { Aspect } from 'oak-domain/lib/types/Aspect';
import { Feature } from '../types/Feature';
@ -18,8 +18,17 @@ type SyncAction<ED extends EntityDict> = {
payload: OpRecord<ED>[];
}
type OperateAction<ED extends EntityDict, T extends keyof ED> = {
type: 'operate';
payload: {
entity: T;
operation: ED[T]['Operation'];
params?: OperateParams;
};
};
export class Cache<ED extends EntityDict, AD extends Record<string, Aspect<ED>>> extends Feature<ED, AD> {
action<T extends keyof ED>(context: FrontContext<ED>, action: RefreshAction<ED, T> | SyncAction<ED>) {
action<T extends keyof ED>(context: FrontContext<ED>, action: RefreshAction<ED, T> | SyncAction<ED> | OperateAction<ED, T>) {
const { type, payload } = action;
if (type === 'refresh') {
@ -30,7 +39,11 @@ export class Cache<ED extends EntityDict, AD extends Record<string, Aspect<ED>>>
params,
}, context);
}
return context.rowStore.sync(payload as SyncAction<ED>['payload'], context);
else if (type === 'sync') {
return context.rowStore.sync(payload as SyncAction<ED>['payload'], context);
}
const { entity, operation, params } = payload as OperateAction<ED, T>['payload'];
return context.rowStore.operate(entity, operation, context, params);
}
async get<T extends keyof ED>(context: FrontContext<ED>, options: { entity: T, selection: ED[T]['Selection'], params?: object }) {
const { entity, selection, params } = options;

View File

@ -1,9 +1,10 @@
import { DeduceFilter, DeduceUpdateOperation, EntityDict, EntityShape, OperationResult, OpRecord, SelectionResult } from 'oak-domain/lib/types/Entity';
import { DeduceFilter, DeduceUpdateOperation, EntityDict, EntityShape, FormCreateData, OperationResult, OpRecord, SelectionResult } from 'oak-domain/lib/types/Entity';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-domain/EntityDict';
import { Aspect } from 'oak-domain/lib/types/Aspect';
import { combineFilters } from 'oak-domain/lib/schema/filter';
import { Feature } from '../types/Feature';
import { Cache } from './cache';
import { v4 } from 'uuid';
import assert from 'assert';
import { FrontContext } from '../FrontContext';
import { assign } from 'lodash';
@ -62,7 +63,7 @@ class ListNode<ED extends EntityDict, AD extends Record<string, Aspect<ED>>, T e
this.sorter = sorter || [];
}
addChild(path: number, node: Node<ED, AD, T>) {
const { children } = this;
children[path] = node;
@ -76,7 +77,7 @@ class ListNode<ED extends EntityDict, AD extends Record<string, Aspect<ED>>, T e
this.indexFrom = 0;
this.hasMore = ids.length === count;
}
async getData(context: FrontContext<ED>, projection: ED[T]['Selection']['data']) {
const { entity, ids } = this;
if (ids) {
@ -94,7 +95,7 @@ class ListNode<ED extends EntityDict, AD extends Record<string, Aspect<ED>>, T e
});
}
}
async nextPage() {
}
@ -120,7 +121,7 @@ class SingleNode<ED extends EntityDict, AD extends Record<string, Aspect<ED>>, T
async refresh(context: FrontContext<ED>) {
const { entity, projection, id } = this;
assert (id);
assert(id);
await super.doRefresh(context, { id });
}
@ -135,7 +136,7 @@ class SingleNode<ED extends EntityDict, AD extends Record<string, Aspect<ED>>, T
const { entity, id } = this;
assert(id);
const filter: Partial<AttrFilter<ED[T]["Schema"]>> = {
id,
id,
} as any;
return (await this.cache.get(context, {
entity,
@ -160,7 +161,15 @@ type InitNodeAction<ED extends EntityDict, AD extends Record<string, Aspect<ED>>
sorter?: ED[T]['Selection']['sorter'];
append?: boolean
},
}
};
type SetValueAction<ED extends EntityDict, T extends keyof ED> = {
type: 'setValue',
payload: {
path: string;
value: any;
};
};
type GetData<ED extends EntityDict, AD extends Record<string, Aspect<ED>>, T extends keyof ED> = {
@ -196,33 +205,50 @@ export class RunningNode<ED extends EntityDict, AD extends Record<string, Aspect
}
}
action<T extends keyof ED>(context: FrontContext<ED>, action: InitNodeAction<ED, AD, T>) {
async action<T extends keyof ED>(context: FrontContext<ED>, action: SetValueAction<ED, T>) {
const { type, payload } = action;
switch (type) {
case 'init': {
const { path, parent, entity, isList, id, projection, filters, sorter, append } = payload;
const node = isList ? new ListNode<ED, AD, T>(entity, this.cache, projection, parent, filters, sorter, append):
new SingleNode<ED, AD, T>(entity, this.cache, projection, parent, id);
if (parent) {
assert(path);
const { addChild } = node;
if (id) {
assert(typeof path === 'string');
(<SingleNode<ED, AD, T>>node).addChild(path, node);
}
else {
assert(typeof path === 'number');
(<ListNode<ED, AD, T>>node).addChild(path ,node);
}
}
return node;
case 'setValue': {
}
default: {
break;
}
}
throw new Error('Method not implemented.');
}
}
async init<T extends keyof ED>(context: FrontContext<ED>, params: InitNodeAction<ED, AD, T>['payload']) {
const { path, parent, entity, isList, id, projection, filters, sorter, append } = params;
let node: Node<ED, AD, T>;
if (isList) {
node = new ListNode<ED, AD, T>(entity, this.cache, projection, parent, filters, sorter, append);
}
else {
let id2: string = id || v4({ random: await getRandomValues(16) });
if (!id) {
// 如果!isList并且没有id说明是create在这里先插入cache
await context.rowStore.operate(entity, {
action: 'create',
data: {
id: id2,
} as FormCreateData<ED[T]['OpSchema']>,
}, context);
}
node = new SingleNode<ED, AD, T>(entity, this.cache, projection, parent, id2);
}
if (parent) {
assert(path);
if (typeof path === 'number') {
(<ListNode<ED, AD, T>>parent).addChild(path, node);
}
else {
assert(typeof path === 'string');
(<SingleNode<ED, AD, T>>parent).addChild(path, node);
}
}
return node;
}
}

View File

@ -29,7 +29,7 @@ class DebugRunningContext<ED extends EntityDict> extends Context<ED> implements
}
};
async function createAspectProxy<ED extends BaseEntityDict & EntityDict,
function createAspectProxy<ED extends BaseEntityDict & EntityDict,
AD extends Record<string, Aspect<ED>>,
FD extends Record<string, Feature<ED, AD>>>(
cacheStore: CacheStore<ED>,
@ -41,7 +41,7 @@ async function createAspectProxy<ED extends BaseEntityDict & EntityDict,
aspectDict?: AD,
initialData?: {
[T in keyof ED]?: Array<ED[T]['OpSchema']>;
}): Promise<AspectProxy<ED, AD & typeof basicAspectDict>> {
}): AspectProxy<ED, AD & typeof basicAspectDict> {
if (process.env.NODE_ENV === 'production') {
// todo 发请求到后台获取数据
throw new Error('method not implemented');
@ -53,26 +53,24 @@ async function createAspectProxy<ED extends BaseEntityDict & EntityDict,
triggers.forEach(
(trigger) => debugStore.registerTrigger(trigger)
);
const context = new Context(debugStore, getRandomNumber);
const { result: [application] } = await debugStore.select('application', {
data: {
id: 1,
systemId: 1,
system: {
id: 1,
},
},
filter: {
id: applicationId,
}
}, context);
const getApplication = () => application as Application;
const connectAspectToDebugStore = (aspect: Aspect<ED>): (p: Parameters<typeof aspect>[0], frontContext: FrontContext<ED>) => ReturnType<typeof aspect> => {
return async (params: Parameters<typeof aspect>[0], frontContext: FrontContext<ED>) => {
const context2 = new Context(debugStore, getRandomNumber);
const { result: [application] } = await debugStore.select('application', {
data: {
id: 1,
systemId: 1,
system: {
id: 1,
},
},
filter: {
id: applicationId,
}
}, context2);
const getApplication = () => application as Application;
const tokenValue = await features.token.get(frontContext as any, 'value') as string;
let token: Token | undefined;
if (tokenValue) {
@ -106,7 +104,7 @@ async function createAspectProxy<ED extends BaseEntityDict & EntityDict,
}
}
export async function initialize<ED extends EntityDict & BaseEntityDict, AD extends Record<string, Aspect<ED>>, FD extends Record<string, Feature<ED, AD>>>(
export function initialize<ED extends EntityDict & BaseEntityDict, AD extends Record<string, Aspect<ED>>, FD extends Record<string, Feature<ED, AD>>>(
storageSchema: StorageSchema<ED>,
applicationId: string,
createFeatures: (basicFeatures: BasicFeatures<ED, AD>) => FD,
@ -128,7 +126,7 @@ export async function initialize<ED extends EntityDict & BaseEntityDict, AD exte
const cacheStore = new CacheStore<ED>(storageSchema);
// todo default triggers
const aspectProxy = await createAspectProxy<ED, AD, FD>(cacheStore, storageSchema, triggers || [],
const aspectProxy = createAspectProxy<ED, AD, FD>(cacheStore, storageSchema, triggers || [],
applicationId, features, getRandomNumber, aspectDict, initialData);
keys(features).forEach(
@ -143,7 +141,7 @@ export async function initialize<ED extends EntityDict & BaseEntityDict, AD exte
}
let result;
try {
result = originActionFn(context, params);
result = originActionFn.call(features[ele], context, params);
}
catch(e) {
context.topAction = topAction;

View File

@ -61,10 +61,13 @@
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
"typeRoots": [
"./src/typings"
]
},
"include": [
"src/**/*" ],
"src/typings/**/*.ts" ],
"exclude": [
"node_modules",
"**/*.spec.ts",