修正了cache和feature的一些问题
This commit is contained in:
parent
3fd4965b28
commit
9365aaf780
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
38
src/index.ts
38
src/index.ts
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in New Issue