base的整体架构

This commit is contained in:
Xu Chang 2022-03-17 19:41:01 +08:00
parent 3f1d15e9a0
commit bd4b346135
12 changed files with 231 additions and 82 deletions

110
src/FrontContext.ts Normal file
View File

@ -0,0 +1,110 @@
import { EntityDict } 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 { Context as BaseContext } from 'oak-memory-tree-store';
import { TriggerExecutor } from "oak-trigger-executor";
import { AspectProxy } from './types/AspectProxy';
import { CacheStore } from './dataStore/CacheStore';
import BaseAspectProxy from './aspects/index';
import { assign } from 'lodash';
import { StorageSchema } from 'oak-domain/lib/types/Storage';
import { Trigger } from 'oak-domain/lib/types/Trigger';
import { RunningContext } from "oak-domain/lib/types/Context";
import { DebugStore, Context } from 'oak-debug-store';
import { Schema as Token } from 'oak-domain/lib/base-domain/Token/Schema';
import { Schema as Application } from "oak-domain/lib/base-domain/Application/Schema";
class DebugRunningContext<ED extends EntityDict> extends Context<ED> implements RunningContext<ED> {
getApplication: () => Application;
getToken: () => Token | undefined;
constructor(store: DebugStore<ED>, ga: () => Application, gt: () => Token | undefined) {
super(store);
this.getApplication = ga;
this.getToken = gt;
}
};
export async function createAspectProxy<ED extends EntityDict, AD extends Record<string, Aspect<ED>>>(
storageSchema: StorageSchema<ED>,
triggers: Array<Trigger<ED, keyof ED>>,
applicationId: string,
getTokenValue: () => string | undefined,
aspectDict?: AD,
initialData?: {
[T in keyof ED]?: Array<ED[T]['OpSchema']>;
}): Promise<AspectProxy<ED, AD & typeof BaseAspectProxy>> {
if (process.env.NODE_ENV === 'production') {
// todo 发请求到后台获取数据
throw new Error('method not implemented');
}
else {
// todo initialData
const executor = new TriggerExecutor<ED>();
const debugStore = new DebugStore<ED>(executor, storageSchema);
triggers.forEach(
(trigger) => debugStore.registerTrigger(trigger)
);
const context = new Context(debugStore);
const { result: [application] } = await (<DebugStore<BaseEntityDict>><unknown>debugStore).select('application', {
data: {
id: 1,
systemId: 1,
system: {
id: 1,
},
},
filter: {
id: applicationId,
}
}, <Context<BaseEntityDict>><unknown>context);
const getApplication = () => application as Application;
const FullAspectProxy = assign(BaseAspectProxy, aspectDict);
return async (name, params) => {
const aspect = FullAspectProxy[name];
const context2 = new Context(debugStore);
const tokenValue = getTokenValue();
let token: Token | undefined;
if (tokenValue) {
const { result } = await (<DebugStore<BaseEntityDict>><unknown>debugStore).select('token', {
data: {
id: 1,
userId: 1,
playerId: 1,
},
filter: {
id: tokenValue,
}
}, <Context<BaseEntityDict>><unknown>context2);
token = result[0] as Token;
// todo 判断 token的合法性
}
const getToken = () => token;
const runningContext = new DebugRunningContext(debugStore, getApplication, getToken);
return aspect(params, runningContext);
}
}
}
export class FrontContext<ED extends EntityDict, AD extends Record<string, Aspect<ED>>> extends BaseContext<ED> {
getAspectProxy: () => Promise<AspectProxy<ED, AD & typeof BaseAspectProxy>>;
constructor(
storageSchema: StorageSchema<ED>,
triggers: Array<Trigger<ED, keyof ED>>,
applicationId: string,
getTokenValue: () => string | undefined,
aspectDict?: AD,
initialData?: {
[T in keyof ED]?: Array<ED[T]['OpSchema']>;
}) {
super(new CacheStore<ED>(storageSchema));
const ap = createAspectProxy<ED, AD>(storageSchema, triggers, applicationId, getTokenValue, aspectDict, initialData);
this.getAspectProxy = () => ap;
}
};

View File

@ -1,42 +0,0 @@
import { DebugStore, Context } from "oak-debug-store";
import { Aspect } from "oak-domain/lib/types/Aspect";
import { RunningContext } from "oak-domain/lib/types/Context";
import { EntityDef } from "oak-domain/lib/types/Entity";
import { loginMp } from './aspects/token';
export function makeAspectDict<ED extends {
[K: string]: EntityDef;
}>(aspects: Array<Aspect<ED>>, store: DebugStore<ED>) {
if (process.env.NODE_ENV === 'production') {
// 生产环境调服务器端函数
}
else {
const runningContext: RunningContext<ED> = {
application: {
name: "",
description: "",
type: "web",
system: {
name: "",
description: "",
config: undefined
},
dd: []
},
rowStore: store,
on: function (event: "commit" | "rollback", callback: (context: Context<ED>) => Promise<void>): void {
throw new Error("Function not implemented.");
},
begin: function (options?: object): Promise<void> {
throw new Error("Function not implemented.");
},
commit: function (): Promise<void> {
throw new Error("Function not implemented.");
},
rollback: function (): Promise<void> {
throw new Error("Function not implemented.");
}
}
}
}

View File

@ -1,6 +1,8 @@
import { loginMp, loginByPassword } from './token';
export const AspectDict = {
const AspectDict = {
loginMp,
loginByPassword,
};
};
export default AspectDict;

View File

@ -1,6 +1,8 @@
import { RunningContext } from 'oak-domain/lib/types/Context';
import { Schema as Token } from 'oak-domain/lib/entities/Token';
import { EntityDict } from 'oak-domain/lib/base-domain/EntityDict';
import { EntityDict as BaseEntityDict} from 'oak-domain/lib/base-domain/EntityDict';
import { EntityDict } from 'oak-domain/lib/types/Entity';
import { Aspect } from 'oak-domain/lib/types/Aspect';
export async function loginMp<ED extends EntityDict> (params: { code: string }, context: RunningContext<ED>): Promise<Token> {
const { rowStore } = context;

View File

@ -1,6 +1,7 @@
import { EntityDict } from "oak-domain/lib/base-domain/EntityDict";
import { EntityDict as BaseEntityDict } from "oak-domain/lib/base-domain/EntityDict";
import { EntityDict } from 'oak-domain/lib/types/Entity';
import { StorageSchema } from "oak-domain/lib/types/Storage";
import { TreeStore, Context as BaseContext } from 'oak-memory-tree-store';
import { TreeStore } from 'oak-memory-tree-store';
export class CacheStore<ED extends EntityDict> extends TreeStore<ED> {
constructor(storageSchema: StorageSchema<ED>) {
@ -9,7 +10,3 @@ export class CacheStore<ED extends EntityDict> extends TreeStore<ED> {
// todo
}
export class Context<ED extends EntityDict> extends BaseContext<ED> {
};

View File

14
src/features/data.ts Normal file
View File

@ -0,0 +1,14 @@
import { EntityDict } from 'oak-domain/lib/types/Entity';
import { Aspect } from 'oak-domain/lib/types/Aspect';
import { Feature } from '../types/Feature';
import { FrontContext } from '../FrontContext';
export class Data<ED extends EntityDict, AD extends Record<string, Aspect<ED>>> extends Feature<ED, AD> {
async get<T extends keyof ED>(context: FrontContext<ED, AD>, params: { entity: T, selection: ED[T]['Selection'] }) {
const { result } = await context.rowStore.select(params.entity, params.selection, context);
return result;
}
async action(context: FrontContext<ED, AD>, type: string, payload?: any) {
throw new Error('Method not implemented.');
}
}

View File

@ -1,14 +1,18 @@
import { EntityDict } from 'oak-domain/lib/base-domain/EntityDict';
import { EntityDict } from 'oak-domain/lib/types/Entity';
import { Aspect } from 'oak-domain/lib/types/Aspect';
import { Feature } from '../types/Feature';
import { FrontContext } from '../types/FrontContext';
import { FrontContext } from '../FrontContext';
export class Token<ED extends EntityDict> extends Feature<ED> {
get(params?: any) {
export class Token<ED extends EntityDict, AD extends Record<string, Aspect<ED>>> extends Feature<ED, AD> {
tokenValue?: string;
async get(context: FrontContext<ED, AD>) {
throw new Error('Method not implemented.');
}
action(context: FrontContext<ED>, type: string, payload?: any) {
async action(context: FrontContext<ED, AD>, type: string, payload?: any) {
throw new Error('Method not implemented.');
}
getTokenValue() {
return this.tokenValue;
}
}
console.log(Token.name);

View File

@ -1,22 +1,87 @@
import { StorageSchema } from 'oak-domain/lib/types/Storage';
import { Trigger } from "oak-domain/lib/types/Trigger";
import { EntityDict } from 'oak-domain/src/base-domain/EntityDict';
import { EntityDict as BaseEntityDict } from 'oak-domain/src/base-domain/EntityDict';
import { Aspect } from 'oak-domain/lib/types/Aspect';
import { Feature } from './types/Feature';
import { CacheStore } from './dataStore/CacheStore';
import { loginMp } from './aspects/token';
import { Token } from './features/token';
const FEATURES: Array<new <ED extends EntityDict>() => Feature<ED>> = [Token];
import { assign } from 'lodash';
import { EntityDict } from 'oak-domain/lib/types/Entity';
import { FrontContext } from './FrontContext';
export function initialize<ED extends EntityDict>(storageSchema: StorageSchema<ED>,
features?: Array<Feature<ED>>,
triggers?: Array<Trigger<ED, keyof ED>>,
initialData?: Object,
aspects?: Array<Aspect<ED>>) {
const store = new CacheStore<ED>(storageSchema);
function populateFeatures<ED extends EntityDict, AD extends Record<string, Aspect<ED>>, FD extends Record<string, new <P extends EntityDict, Q extends Record<string, Aspect<P>>>() => Feature<P, Q>>>(featureClazzDict: FD)
: {
[T in keyof FD]: InstanceType<FD[T]>;
} {
const result = {};
for (const k in featureClazzDict) {
assign(result, {
[k]: new featureClazzDict[k]<ED, AD>(),
});
}
return result as any;
}
export async function initialize<ED extends EntityDict,
AD extends Record<string, Aspect<ED>>,
FD extends Record<string, new <P extends EntityDict, Q extends Record<string, Aspect<P>>>() => Feature<P, Q>>>(
storageSchema: StorageSchema<ED>,
applicationId: string,
featureClazzDict?: FD,
triggers?: Array<Trigger<ED, keyof ED>>,
aspectDict?: AD,
initialData?: {
[T in keyof ED]? : Array<ED[T]['OpSchema']>;
}) {
const token = new Token<ED, AD>();
// todo default triggers
const frontContext = new FrontContext<ED, AD>(storageSchema, triggers!, applicationId, () => token.getTokenValue(), aspectDict, initialData);
const featureDict = {
token: Token,
};
function ppf() {
return populateFeatures<ED, AD, FD>(featureClazzDict!);
}
if (featureClazzDict) {
assign(featureDict, ppf());
}
const featureDict2 = featureDict as typeof featureDict & ReturnType<typeof ppf>;
const subscribe = <F extends keyof typeof featureDict | keyof FD>(features: F[], callback: () => void) => {
const unsubscribes = features.map(
(f) => {
const feature = featureDict2[f];
return feature.subscribe(callback);
}
);
return () => {
unsubscribes.forEach(
ele => ele()
);
};
};
const getFeature = <F extends keyof typeof featureDict | keyof FD>(f: F, params?: Parameters<InstanceType<FD[F]>['get']>[1]): ReturnType<InstanceType<FD[F]>['get']> => {
// const context = new FrontContext<ED, typeof aspectDict2>(store, aspectProxy) as any;
const feature = featureDict2[f];
return feature.get(frontContext as any, params) as any; // 这里有个类型的转换暂时写不出来因为populateFeatures没法传递generic types在返回值里
};
const actionFeature = <F extends keyof typeof featureDict | keyof FD>(f: F, t: Parameters<InstanceType<FD[F]>['action']>[1], p?: Parameters<InstanceType<FD[F]>['action']>[2]): ReturnType<InstanceType<FD[F]>['action']> => {
// const context = new FrontContext<ED, typeof aspectDict2>(store, aspectProxy) as any;
const feature = featureDict2[f];
return feature.action(frontContext as any, t, p) as any;
};
return {
subscribe,
getFeature,
actionFeature,
};
}

View File

@ -1,6 +1,7 @@
import { Aspect } from "oak-domain/lib/types/Aspect";
import { EntityDef } from "oak-domain/lib/types/Entity";
import { EntityDict } from "oak-domain/lib/types/Entity";
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-domain/EntityDict';
export interface AspectProxy<ED extends Record<string, EntityDef>, AD extends Record<string, Aspect<ED>>> {
<T extends keyof AD>(name: T, params: Parameters<AD[T]>[0]): ReturnType<AD[T]>;
export interface AspectProxy<ED extends EntityDict, AD extends Record<string, Aspect<ED>>> {
<T extends keyof AD>(name: T, params: Parameters<AD[T]>[0]): Promise<ReturnType<AD[T]>>;
};

View File

@ -1,8 +1,10 @@
import { pull } from 'lodash';
import { EntityDef } from 'oak-domain/lib/types/entity';
import { FrontContext } from './FrontContext';
import { Aspect } from 'oak-domain/lib/types/Aspect';
import { EntityDict } from 'oak-domain/lib/types/entity';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-domain/EntityDict';
import { FrontContext } from '../FrontContext';
export abstract class Feature<ED extends Record<string, EntityDef>> {
export abstract class Feature<ED extends EntityDict, AD extends Record<string, Aspect<ED>>> {
private callbackSet: Array<() => void>;
constructor() {
this.callbackSet = [];
@ -21,7 +23,7 @@ export abstract class Feature<ED extends Record<string, EntityDef>> {
);
}
abstract get(params?: any): any;
abstract get(context: FrontContext<ED, AD>, params?: any): Promise<any>;
abstract action(context: FrontContext<ED>, type: string, payload?: any): any;
abstract action(context: FrontContext<ED, AD>, type: string, payload?: any): Promise<any>;
}

View File

@ -1,6 +0,0 @@
import { EntityDef } from 'oak-domain/lib/types/entity';
import { Aspect } from 'oak-domain/lib/types/Aspect';
import { Context as BaseContext } from 'oak-memory-tree-store';
export class FrontContext<ED extends Record<string, EntityDef>> extends BaseContext<ED> {
};