base的整体架构
This commit is contained in:
parent
3f1d15e9a0
commit
bd4b346135
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import { loginMp, loginByPassword } from './token';
|
||||
|
||||
export const AspectDict = {
|
||||
const AspectDict = {
|
||||
loginMp,
|
||||
loginByPassword,
|
||||
};
|
||||
};
|
||||
|
||||
export default AspectDict;
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
||||
};
|
||||
|
|
@ -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.');
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
85
src/index.ts
85
src/index.ts
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]>>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
}
|
||||
|
|
@ -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> {
|
||||
};
|
||||
Loading…
Reference in New Issue