和trigger相关的数据结构
This commit is contained in:
parent
fe08c014f6
commit
3d1b71e02b
|
|
@ -1,18 +1,67 @@
|
|||
import assert from 'assert';
|
||||
import { EntityDict } from "oak-domain/lib/types/Entity";
|
||||
import { BaseEntityDict } from "oak-general-business/lib/base-ed/EntityDict";
|
||||
import { EntityDict } from 'oak-domain/lib/types/Entity';
|
||||
import { Context as BaseContext } from 'oak-memory-tree-store';
|
||||
import { Schema as Application } from "oak-general-business/lib/base-ed/Application/Schema";
|
||||
import { Schema as Token } from 'oak-general-business/lib/base-ed/Token/Schema';
|
||||
import { DebugStore } from './debugStore';
|
||||
import { RuntimeContext } from 'oak-general-business';
|
||||
|
||||
export class DebugContext<ED extends EntityDict> extends BaseContext<ED> {
|
||||
export class DebugContext<ED extends BaseEntityDict & EntityDict> extends BaseContext<ED> implements RuntimeContext<ED> {
|
||||
getApplication: () => Application | undefined;
|
||||
getToken: () => Token | undefined;
|
||||
|
||||
async initGetFn(applicationId?: string, tokenValue?: string) {
|
||||
if (applicationId) {
|
||||
const { result: [application] } = await this.rowStore.select('application', {
|
||||
data: {
|
||||
id: 1,
|
||||
systemId: 1,
|
||||
system: {
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
filter: {
|
||||
id: applicationId,
|
||||
}
|
||||
}, this);
|
||||
this.getApplication = () => application as Application;
|
||||
}
|
||||
|
||||
if (tokenValue) {
|
||||
const { result } = await this.rowStore.select('token', {
|
||||
data: {
|
||||
id: 1,
|
||||
userId: 1,
|
||||
playerId: 1,
|
||||
},
|
||||
filter: {
|
||||
id: tokenValue,
|
||||
}
|
||||
}, this);
|
||||
const token = result[0] as Token;
|
||||
// todo 判断 token的合法性
|
||||
this.getToken = () => token;
|
||||
}
|
||||
}
|
||||
|
||||
constructor(store: DebugStore<ED>, applicationId?: string, tokenValue?: string) {
|
||||
super(store);
|
||||
this.getApplication = () => undefined;
|
||||
this.getToken = () => undefined;
|
||||
|
||||
this.initGetFn(applicationId, tokenValue);
|
||||
}
|
||||
txn?: {
|
||||
events: {
|
||||
commit: Array<(context: DebugContext<ED>) => Promise<void>>;
|
||||
rollback: Array<(context: DebugContext<ED>) => Promise<void>>;
|
||||
}
|
||||
};
|
||||
on (event: "commit" | "rollback", callback: (context: any) => Promise<void>): void {
|
||||
on(event: "commit" | "rollback", callback: (context: any) => Promise<void>): void {
|
||||
this.txn!.events[event].push(callback);
|
||||
}
|
||||
|
||||
|
||||
async begin(options?: object): Promise<void> {
|
||||
assert(!this.txn);
|
||||
await super.begin();
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { EntityDef, EntityDict, OperationResult, SelectionResult } from "oak-domain/lib/types/Entity";
|
||||
import { BaseEntityDict } from 'oak-general-business/lib/base-ed/EntityDict';
|
||||
|
||||
import { TreeStore } from 'oak-memory-tree-store';
|
||||
import { DebugContext } from './context';
|
||||
import { TriggerExecutor } from 'oak-domain/lib/store/TriggerExecutor';
|
||||
import { Trigger, TriggerEntityShape } from "oak-domain/lib/types/Trigger";
|
||||
import { TriggerExecutor, Trigger } from 'oak-general-business';
|
||||
import { StorageSchema } from "oak-domain/lib/types/Storage";
|
||||
|
||||
export class DebugStore<ED extends EntityDict> extends TreeStore<ED> {
|
||||
export class DebugStore<ED extends EntityDict & BaseEntityDict> extends TreeStore<ED> {
|
||||
|
||||
private executor: TriggerExecutor<ED>;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,9 @@ import { assign } from 'lodash';
|
|||
import { DebugStore } from './debugStore';
|
||||
import { DebugContext } from './context';
|
||||
import { FormCreateData, Selection, EntityDict } from "oak-domain/lib/types/Entity";
|
||||
import { EntityDict as BaseEntityDict } from 'oak-general-business/lib/base-ed/EntityDict';
|
||||
import { BaseEntityDict as BaseEntityDict } from 'oak-general-business/lib/base-ed/EntityDict';
|
||||
import { StorageSchema } from 'oak-domain/lib/types/Storage';
|
||||
import { Trigger } from 'oak-domain/lib/types/Trigger';
|
||||
import { TriggerExecutor } from 'oak-domain/lib/store/TriggerExecutor';
|
||||
import { Trigger, TriggerExecutor } from 'oak-general-business';
|
||||
import { data as generalData, triggers as generalTriggers } from 'oak-general-business';
|
||||
import { FrontContext } from '../FrontContext';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { DeduceSelection, EntityDict, OperateParams, OpRecord } from 'oak-domain/lib/types/Entity';
|
||||
import { Aspect } from 'oak-general-business/lib/types/Aspect';
|
||||
import { Aspect } from 'oak-general-business';
|
||||
import { Action, Feature } from '../types/Feature';
|
||||
import { assign } from 'lodash';
|
||||
import { FrontContext } from '../FrontContext';
|
||||
|
|
@ -36,12 +36,17 @@ export class Cache<ED extends EntityDict, AD extends Record<string, Aspect<ED>>>
|
|||
}
|
||||
|
||||
@Action
|
||||
async operate<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], params?: OperateParams) {
|
||||
async operate<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], commit: boolean = true, params?: OperateParams) {
|
||||
const context = new FrontContext(this.cacheStore);
|
||||
let result: Awaited<ReturnType<typeof this.cacheStore.operate>>;
|
||||
try {
|
||||
result = await this.cacheStore.operate(entity, operation, context, params);
|
||||
await context.commit();
|
||||
if (commit) {
|
||||
await context.commit();
|
||||
}
|
||||
else {
|
||||
await context.rollback();
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
await context.rollback();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { EntityDict } from 'oak-domain/lib/types/Entity';
|
||||
import { EntityDict as BaseEntityDict } from 'oak-general-business/lib/base-ed/EntityDict';
|
||||
import { Aspect } from 'oak-general-business/lib/types/Aspect';
|
||||
import { BaseEntityDict } from 'oak-general-business/lib/base-ed/EntityDict';
|
||||
import { Aspect } from 'oak-general-business';
|
||||
|
||||
import { Cache } from './cache';
|
||||
import { Location } from './location';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { EntityDict, OpRecord } from 'oak-domain/lib/types/Entity';
|
||||
import { Aspect } from 'oak-general-business/lib/types/Aspect';
|
||||
import { Aspect } from 'oak-general-business';
|
||||
import { Action, Feature } from '../types/Feature';
|
||||
|
||||
export class Location extends Feature<EntityDict, Record<string, Aspect<EntityDict>>> {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { set, cloneDeep, pull, unset } from 'lodash';
|
||||
import { DeduceCreateOperation, DeduceFilter, DeduceOperation, DeduceSelection, DeduceUpdateOperation, EntityDict, EntityShape, FormCreateData, OperationResult, OpRecord, SelectionResult } from 'oak-domain/lib/types/Entity';
|
||||
import { Aspect } from 'oak-general-business/lib/types/Aspect';
|
||||
import { Aspect } from 'oak-general-business';
|
||||
import { combineFilters } from 'oak-domain/lib/store/filter';
|
||||
import { Action, Feature } from '../types/Feature';
|
||||
import { Cache } from './cache';
|
||||
|
|
@ -116,7 +116,7 @@ class ListNode<ED extends EntityDict, AD extends Record<string, Aspect<ED>>, T e
|
|||
this.pagination = pagination || DEFAULT_PAGINATION;
|
||||
}
|
||||
|
||||
composeAction(): DeduceOperation<ED[T]['Schema']> | DeduceOperation<ED[T]['Schema']>[] | undefined {
|
||||
composeOperation(): DeduceOperation<ED[T]['Schema']> | DeduceOperation<ED[T]['Schema']>[] | undefined {
|
||||
if (!this.isDirty()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -129,7 +129,7 @@ class ListNode<ED extends EntityDict, AD extends Record<string, Aspect<ED>>, T e
|
|||
}
|
||||
const actions = [];
|
||||
for (const node of this.children) {
|
||||
const subAction = node.composeAction();
|
||||
const subAction = node.composeOperation();
|
||||
if (subAction) {
|
||||
actions.push(subAction);
|
||||
}
|
||||
|
|
@ -266,7 +266,7 @@ class SingleNode<ED extends EntityDict, AD extends Record<string, Aspect<ED>>, T
|
|||
}
|
||||
}
|
||||
|
||||
composeAction(): DeduceOperation<ED[T]['Schema']> | undefined {
|
||||
composeOperation(): DeduceOperation<ED[T]['Schema']> | undefined {
|
||||
if (!this.isDirty()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -281,7 +281,7 @@ class SingleNode<ED extends EntityDict, AD extends Record<string, Aspect<ED>>, T
|
|||
},
|
||||
} as DeduceUpdateOperation<ED[T]['Schema']>;
|
||||
for (const attr in this.children) {
|
||||
const subAction = this.children[attr]!.composeAction();
|
||||
const subAction = this.children[attr]!.composeOperation();
|
||||
if (subAction) {
|
||||
assign(action.data, {
|
||||
[attr]: subAction,
|
||||
|
|
@ -483,7 +483,7 @@ export class RunningNode<ED extends EntityDict, AD extends Record<string, Aspect
|
|||
this.schema = schema;
|
||||
}
|
||||
|
||||
private async applyAction<T extends keyof ED>(
|
||||
private async applyOperation<T extends keyof ED>(
|
||||
entity: T, value: Partial<ED[T]['Schema']> | Partial<ED[T]['Schema']>[] | undefined,
|
||||
operation: DeduceOperation<ED[T]['Schema']> | DeduceOperation<ED[T]['Schema']>[],
|
||||
projection: DeduceSelection<ED[T]['Schema']>['data']): Promise<Partial<ED[T]['Schema']> | Partial<ED[T]['Schema']>[] | undefined> {
|
||||
|
|
@ -492,7 +492,7 @@ export class RunningNode<ED extends EntityDict, AD extends Record<string, Aspect
|
|||
for (const action of operation) {
|
||||
switch (action.action) {
|
||||
case 'create': {
|
||||
value.push(await this.applyAction(entity, undefined, action, projection) as Partial<ED[T]['Schema']>);
|
||||
value.push(await this.applyOperation(entity, undefined, action, projection) as Partial<ED[T]['Schema']>);
|
||||
}
|
||||
case 'remove': {
|
||||
const { filter } = action;
|
||||
|
|
@ -508,7 +508,7 @@ export class RunningNode<ED extends EntityDict, AD extends Record<string, Aspect
|
|||
const row = value.find(
|
||||
ele => ele.id === filter!.id
|
||||
);
|
||||
await this.applyAction(entity, row!, action, projection);
|
||||
await this.applyOperation(entity, row!, action, projection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -518,7 +518,7 @@ export class RunningNode<ED extends EntityDict, AD extends Record<string, Aspect
|
|||
if (value instanceof Array) {
|
||||
// todo 这里还有种可能不是对所有的行,只对指定id的行操作
|
||||
return (await Promise.all(value.map(
|
||||
async (row) => await this.applyAction(entity, row, operation, projection)
|
||||
async (row) => await this.applyOperation(entity, row, operation, projection)
|
||||
))).filter(
|
||||
ele => !!ele
|
||||
) as Partial<ED[T]['Schema']>[];
|
||||
|
|
@ -534,7 +534,7 @@ export class RunningNode<ED extends EntityDict, AD extends Record<string, Aspect
|
|||
else if (relation === 2) {
|
||||
// 基于entity/entityId的多对一
|
||||
if (projection[attr]) {
|
||||
set(row, attr, await this.applyAction(attr, row[attr], actionData[attr]!, projection[attr]!));
|
||||
set(row, attr, await this.applyOperation(attr, row[attr], actionData[attr]!, projection[attr]!));
|
||||
if (row[attr]) {
|
||||
assign(row, {
|
||||
entity: attr,
|
||||
|
|
@ -551,7 +551,7 @@ export class RunningNode<ED extends EntityDict, AD extends Record<string, Aspect
|
|||
}
|
||||
else if (typeof relation === 'string') {
|
||||
if (projection[attr]) {
|
||||
set(row, attr, await this.applyAction(relation, row[attr], actionData[attr]!, projection[attr]!));
|
||||
set(row, attr, await this.applyOperation(relation, row[attr], actionData[attr]!, projection[attr]!));
|
||||
if (row[attr]) {
|
||||
assign(row, {
|
||||
[`${attr}Id`]: row[attr]!['id'],
|
||||
|
|
@ -567,7 +567,7 @@ export class RunningNode<ED extends EntityDict, AD extends Record<string, Aspect
|
|||
else {
|
||||
assert(relation instanceof Array);
|
||||
if (projection[attr]) {
|
||||
set(row, attr, await this.applyAction(relation[0], row[attr], actionData[attr]!, projection[attr]!));
|
||||
set(row, attr, await this.applyOperation(relation[0], row[attr], actionData[attr]!, projection[attr]!));
|
||||
row[attr]!.forEach(
|
||||
(ele: ED[keyof ED]['Schema']) => {
|
||||
if (relation[1]) {
|
||||
|
|
@ -646,9 +646,9 @@ export class RunningNode<ED extends EntityDict, AD extends Record<string, Aspect
|
|||
const node = await this.findNode(path);
|
||||
let value = await node.getValue(this.cache);
|
||||
if (node.isDirty()) {
|
||||
const operation = node.composeAction();
|
||||
const operation = node.composeOperation();
|
||||
const projection = node.getProjection();
|
||||
value = (await this.applyAction(node.getEntity(), value, operation!, projection as any));
|
||||
value = (await this.applyOperation(node.getEntity(), value, operation!, projection as any));
|
||||
}
|
||||
|
||||
if (value instanceof Array) {
|
||||
|
|
@ -657,6 +657,11 @@ export class RunningNode<ED extends EntityDict, AD extends Record<string, Aspect
|
|||
return [value!];
|
||||
}
|
||||
|
||||
async isDirty(path: string) {
|
||||
const node = await this.findNode(path);
|
||||
return node.isDirty();
|
||||
}
|
||||
|
||||
private async findNode(path: string) {
|
||||
const paths = path.split('.');
|
||||
let node = this.root[paths[0]];
|
||||
|
|
@ -725,5 +730,30 @@ export class RunningNode<ED extends EntityDict, AD extends Record<string, Aspect
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Action
|
||||
async execute(path: string, isTry?: boolean) {
|
||||
const node = await this.findNode(path);
|
||||
const operation = node.composeOperation();
|
||||
// 先在cache中尝试能否执行,如果权限上否决了在这里就失败
|
||||
if (operation instanceof Array) {
|
||||
for (const oper of operation) {
|
||||
await this.cache.operate(node.getEntity(), oper, false);
|
||||
}
|
||||
}
|
||||
else if (operation) {
|
||||
await this.cache.operate(node.getEntity(), operation, false);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTry) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('exeucte to aspectProxy');
|
||||
// this.getAspectProxy().operate
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { EntityDict as BaseEntityDict } from 'oak-general-business/lib/base-ed/EntityDict';
|
||||
import { BaseEntityDict as BaseEntityDict } from 'oak-general-business/lib/base-ed/EntityDict';
|
||||
import { aspectDict as basicAspectDict } from 'oak-general-business';
|
||||
import { Action, Feature } from '../types/Feature';
|
||||
import { Cache } from './cache';
|
||||
|
|
|
|||
49
src/index.ts
49
src/index.ts
|
|
@ -1,9 +1,9 @@
|
|||
import { StorageSchema } from 'oak-domain/lib/types/Storage';
|
||||
import { Trigger } from "oak-domain/lib/types/Trigger";
|
||||
import { EntityDict as BaseEntityDict } from 'oak-general-business/lib/base-ed/EntityDict';
|
||||
import { Trigger } from "oak-general-business";
|
||||
import { BaseEntityDict as BaseEntityDict } from 'oak-general-business/lib/base-ed/EntityDict';
|
||||
import { aspectDict as basicAspectDict } from 'oak-general-business';
|
||||
|
||||
import { Aspect } from 'oak-general-business/lib/types/Aspect';
|
||||
import { Aspect } from 'oak-general-business';
|
||||
import { Feature, subscribe } from './types/Feature';
|
||||
import { createDebugStore } from './debugStore';
|
||||
|
||||
|
|
@ -19,17 +19,6 @@ import { Schema as Token } from 'oak-general-business/lib/base-ed/Token/Schema';
|
|||
import { AspectProxy } from './types/AspectProxy';
|
||||
import { CacheStore } from './cacheStore/CacheStore';
|
||||
|
||||
class DebugRuntimeContext<ED extends EntityDict> extends DebugContext<ED> implements RuntimeContext<ED> {
|
||||
getApplication: () => Application;
|
||||
getToken: () => Token | undefined;
|
||||
|
||||
constructor(store: DebugStore<ED>, ga: () => Application, gt: () => Token | undefined) {
|
||||
super(store);
|
||||
this.getApplication = ga;
|
||||
this.getToken = gt;
|
||||
}
|
||||
};
|
||||
|
||||
function createAspectProxy<ED extends BaseEntityDict & EntityDict,
|
||||
AD extends Record<string, Aspect<ED>>,
|
||||
FD extends Record<string, Feature<ED, AD>>>(
|
||||
|
|
@ -52,39 +41,9 @@ function createAspectProxy<ED extends BaseEntityDict & EntityDict,
|
|||
const connectAspectToDebugStore = (aspect: Aspect<ED>): (p: Parameters<typeof aspect>[0]) => ReturnType<typeof aspect> => {
|
||||
return async (params: Parameters<typeof aspect>[0]) => {
|
||||
const context2 = new DebugContext(debugStore);
|
||||
|
||||
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.getValue();
|
||||
let token: Token | undefined;
|
||||
if (tokenValue) {
|
||||
const { result } = await debugStore.select('token', {
|
||||
data: {
|
||||
id: 1,
|
||||
userId: 1,
|
||||
playerId: 1,
|
||||
},
|
||||
filter: {
|
||||
id: tokenValue,
|
||||
}
|
||||
}, context2);
|
||||
token = result[0] as Token;
|
||||
// todo 判断 token的合法性
|
||||
}
|
||||
const getToken = () => token;
|
||||
|
||||
const runningContext = new DebugRuntimeContext(debugStore, getApplication, getToken);
|
||||
const runningContext = new DebugContext(debugStore, applicationId, tokenValue);
|
||||
await runningContext.begin();
|
||||
let aspectCompeleted = false;
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Aspect } from "oak-general-business/lib/types/Aspect";
|
||||
import { Aspect } from "oak-general-business";
|
||||
import { EntityDict } from "oak-domain/lib/types/Entity";
|
||||
import { FrontContext } from "../FrontContext";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { pull } from 'lodash';
|
||||
import { Aspect } from 'oak-general-business/lib/types/Aspect';
|
||||
import { Aspect } from 'oak-general-business';
|
||||
import { EntityDict } from 'oak-domain/lib/types/Entity';
|
||||
import { aspectDict as basicAspectDict} from 'oak-general-business';
|
||||
import { FrontContext } from '../FrontContext';
|
||||
|
|
@ -8,7 +8,6 @@ import { AspectProxy } from './AspectProxy';
|
|||
|
||||
export abstract class Feature<ED extends EntityDict, AD extends Record<string, Aspect<ED>>> {
|
||||
private aspectProxy?: AspectProxy<ED, AD & typeof basicAspectDict>;
|
||||
private context?: FrontContext<ED>;
|
||||
|
||||
protected getAspectProxy() {
|
||||
return this.aspectProxy!;
|
||||
|
|
@ -17,14 +16,6 @@ export abstract class Feature<ED extends EntityDict, AD extends Record<string, A
|
|||
setAspectProxy(aspectProxy: AspectProxy<ED, AD & typeof basicAspectDict>) {
|
||||
this.aspectProxy = aspectProxy;
|
||||
}
|
||||
|
||||
protected getContext() {
|
||||
return this.context!;
|
||||
}
|
||||
|
||||
setContext(context: FrontContext<ED>) {
|
||||
this.context = context;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue