oak-backend-base/src/DbStore.ts

141 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { MysqlStore, MySqlSelectOption, MysqlOperateOption } from 'oak-db';
import { EntityDict, Context, StorageSchema, Trigger, Checker, AuthDeduceRelationMap, SelectOption, AuthCascadePath } from 'oak-domain/lib/types';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
import { TriggerExecutor } from 'oak-domain/lib/store/TriggerExecutor';
import { MySQLConfiguration, } from 'oak-db/lib/MySQL/types/Configuration';
import { AsyncContext, AsyncRowStore } from 'oak-domain/lib/store/AsyncRowStore';
import { RelationAuth } from 'oak-domain/lib/store/RelationAuth';
export class DbStore<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> extends MysqlStore<ED, Cxt> implements AsyncRowStore<ED, Cxt> {
private executor: TriggerExecutor<ED>;
private relationAuth: RelationAuth<ED>;
constructor(
storageSchema: StorageSchema<ED>,
contextBuilder: (scene?: string) => (store: DbStore<ED, Cxt>) => Promise<Cxt>,
mysqlConfiguration: MySQLConfiguration,
actionCascadeGraph: AuthCascadePath<ED>[],
relationCascadeGraph: AuthCascadePath<ED>[],
authDeduceRelationMap: AuthDeduceRelationMap<ED>,
selectFreeEntities: (keyof ED)[]) {
super(storageSchema, mysqlConfiguration);
this.executor = new TriggerExecutor((scene) => contextBuilder(scene)(this));
this.relationAuth = new RelationAuth(storageSchema, actionCascadeGraph, relationCascadeGraph, authDeduceRelationMap, selectFreeEntities);
}
protected async cascadeUpdateAsync<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: AsyncContext<ED>, option: MysqlOperateOption) {
if (!option.blockTrigger) {
await this.executor.preOperation(entity, operation, context, option);
}
await this.relationAuth.checkRelationAsync(entity, operation, context);
const result = await super.cascadeUpdateAsync(entity, operation, context, option);
if (!option.blockTrigger) {
await this.executor.postOperation(entity, operation, context, option);
}
return result;
}
async operate<T extends keyof ED>(
entity: T,
operation: ED[T]['Operation'],
context: Cxt,
option: MysqlOperateOption
) {
const autoCommit = !context.getCurrentTxnId();
let result;
if (autoCommit) {
await context.begin();
}
try {
result = await super.operate(entity, operation, context, option);
}
catch (err) {
await context.rollback();
throw err;
}
if (autoCommit) {
await context.commit();
}
return result;
}
async select<T extends keyof ED>(
entity: T,
selection: ED[T]['Selection'],
context: Cxt,
option: MySqlSelectOption
) {
const autoCommit = !context.getCurrentTxnId();
if (autoCommit) {
await context.begin();
}
let result: Partial<ED[T]['Schema']>[];
// select的trigger应加在根select之前cascade的select不加处理
Object.assign(selection, {
action: 'select',
});
if (!option.blockTrigger) {
await this.executor.preOperation(entity, selection as ED[T]['Operation'], context, option);
}
if (!option.dontCollect) {
await this.relationAuth.checkRelationAsync(entity, selection, context);
}
try {
result = await super.select(entity, selection, context, option);
if (!option.blockTrigger) {
await this.executor.postOperation(entity, selection as ED[T]['Operation']
, context, option, result);
}
}
catch (err) {
await context.rollback();
throw err;
}
if (autoCommit) {
await context.commit();
}
return result;
}
async count<T extends keyof ED>(entity: T, selection: Pick<ED[T]['Selection'], 'filter' | 'count'>, context: Cxt, option: SelectOption): Promise<number> {
const autoCommit = !context.getCurrentTxnId();
let result;
if (autoCommit) {
await context.begin();
}
try {
const selection2 = Object.assign({
action: 'select',
}, selection) as ED[T]['Operation'];
await this.relationAuth.checkRelationAsync(entity, selection2, context);
if (!option.blockTrigger) {
await this.executor.preOperation(entity, selection2, context, option);
}
result = await super.count(entity, selection, context, option);
/* count应该不存在后trigger吧
if (!option.blockTrigger) {
await this.executor.postOperation(entity, selection2, context, option);
} */
}
catch (err) {
await context.rollback();
throw err;
}
if (autoCommit) {
await context.commit();
}
return result;
}
registerTrigger<T extends keyof ED>(trigger: Trigger<ED, T, Cxt>) {
this.executor.registerTrigger(trigger);
}
registerChecker<T extends keyof ED>(checker: Checker<ED, T, Cxt>) {
this.executor.registerChecker(checker);
}
}