修改了框架的大量语法

This commit is contained in:
Xu Chang 2022-04-25 11:06:47 +08:00
parent ba073f572d
commit 8198b81479
22 changed files with 368 additions and 300 deletions

View File

@ -42,6 +42,7 @@ const ActionImportStatements = () => [
factory.createImportDeclaration(undefined, undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("GenericAction"))])), factory.createStringLiteral((0, env_1.ACTION_CONSTANT_IN_OAK_DOMAIN)()), undefined)
];
const ActionAsts = {};
const SchemaAsts = {};
function addRelationship(many, one, key) {
const { [many]: manySet } = ManyToOne;
const one2 = one === 'Schema' ? many : one;
@ -83,6 +84,19 @@ function pushStatementIntoActionAst(moduleName, node, sourceFile) {
});
}
}
function pushStatementIntoSchemaAst(moduleName, statement, sourceFile) {
if (SchemaAsts[moduleName]) {
SchemaAsts[moduleName].statements.push(statement);
}
else {
(0, lodash_1.assign)(SchemaAsts, {
[moduleName]: {
statements: [statement],
sourceFile,
}
});
}
}
/**
* 检查ActionDef是否满足合法的定义
* 1ActionDef, Action, State三者命名是否一致
@ -220,6 +234,7 @@ function analyzeEntity(filename, path, program) {
const schemaAttrs = [];
let hasFulltextIndex = false;
let indexes;
let beforeSchema = true;
ts.forEachChild(sourceFile, (node) => {
if (ts.isImportDeclaration(node)) {
const entityImported = getEntityImported(node, filename);
@ -309,6 +324,11 @@ function analyzeEntity(filename, path, program) {
[moduleName]: 1,
});
}
beforeSchema = false;
}
else if (beforeSchema) {
// 本地规定的一些形状定义,直接使用
pushStatementIntoSchemaAst(moduleName, node, sourceFile);
}
}
if (ts.isTypeAliasDeclaration(node)) {
@ -322,7 +342,7 @@ function analyzeEntity(filename, path, program) {
])), sourceFile);
dealWithActions(moduleName, filename, node.type, program, schemaAttrs);
}
if (node.name.text === 'Relation') {
else if (node.name.text === 'Relation') {
// 增加userXXX对象的描述
if (ts.isLiteralTypeNode(node.type)) {
(0, assert_1.default)(ts.isStringLiteral(node.type.literal));
@ -351,6 +371,10 @@ function analyzeEntity(filename, path, program) {
addRelationship(relationEntityName, 'User', 'user');
addRelationship(relationEntityName, moduleName, entityLc);
}
else if (beforeSchema) {
// 本地规定的一些形状定义,直接使用
pushStatementIntoSchemaAst(moduleName, node, sourceFile);
}
}
if (ts.isVariableStatement(node)) {
const { declarationList: { declarations } } = node;
@ -633,6 +657,10 @@ function constructSchema(statements, entity) {
statements.push(factory.createImportDeclaration(undefined, undefined, factory.createImportClause(false, undefined, factory.createNamespaceImport(factory.createIdentifier(ele))), factory.createStringLiteral(`../${ele}/Schema`)));
}
});
// 在这里把需要直接拷贝过来的语句写入
if (SchemaAsts[entity]) {
statements.push(...SchemaAsts[entity].statements);
}
// if (keys(foreignKeySet).length > 0) {
// for (const fkItem in foreignKeySet) {
// const entityLc = fkItem.slice(0, 1).toLowerCase().concat(fkItem.slice(1));
@ -770,12 +798,14 @@ function constructFilter(statements, entity) {
}
}
}
else {
(0, assert_1.default)(ts.isUnionTypeNode(type) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type));
else if (ts.isUnionTypeNode(type) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type)) {
members.push(factory.createPropertySignature(undefined, name, undefined, factory.createTypeReferenceNode(factory.createIdentifier('Q_EnumValue'), [
type
])));
}
else {
// 此时应当是引用本地定义的shape
}
}
// type AttrFilter = {};
const eumUnionTypeNode = ReversePointerRelations[entity] && ReversePointerRelations[entity].map(ele => factory.createLiteralTypeNode(factory.createStringLiteral((0, utils_1.firstLetterLowerCase)(ele))));
@ -876,7 +906,8 @@ function constructProjection(statements, entity) {
}
}
else {
(0, assert_1.default)(ts.isUnionTypeNode(type) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type));
// 增加了本身object的shape定义
// assert(ts.isUnionTypeNode(type!) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type!));
properties.push([name, false, undefined]);
}
}
@ -1128,10 +1159,12 @@ function constructSorter(statements, entity) {
}
}
}
else {
(0, assert_1.default)(ts.isUnionTypeNode(type) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type));
else if (ts.isUnionTypeNode(type) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type)) {
members.push(factory.createPropertySignature(undefined, name, undefined, factory.createLiteralTypeNode(factory.createNumericLiteral("1"))));
}
else {
// 本地规定的shape非结构化属性不参与排序
}
}
if (ReversePointerRelations[entity]) {
ReversePointerRelations[entity].forEach((one) => {
@ -1862,29 +1895,39 @@ function constructAttributes(entity) {
}
else {
if (ts.isUnionTypeNode(type)) {
(0, assert_1.default)(ts.isLiteralTypeNode(type.types[0]));
if (ts.isStringLiteral(type.types[0].literal)) {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("varchar")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([factory.createPropertyAssignment(factory.createIdentifier("length"), factory.createNumericLiteral(env_1.STRING_LITERAL_MAX_LENGTH))], true)));
if (ts.isLiteralTypeNode(type.types[0])) {
if (ts.isStringLiteral(type.types[0].literal)) {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("varchar")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([factory.createPropertyAssignment(factory.createIdentifier("length"), factory.createNumericLiteral(env_1.STRING_LITERAL_MAX_LENGTH))], true)));
}
else {
(0, assert_1.default)(ts.isNumericLiteral(type.types[0].literal));
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("int")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier("precision"), factory.createNumericLiteral(env_1.NUMERICAL_LITERL_DEFAULT_PRECISION)),
factory.createPropertyAssignment(factory.createIdentifier("scale"), factory.createNumericLiteral(env_1.NUMERICAL_LITERL_DEFAULT_SCALE))
], true)));
}
}
else {
(0, assert_1.default)(ts.isNumericLiteral(type.types[0].literal));
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("int")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier("precision"), factory.createNumericLiteral(env_1.NUMERICAL_LITERL_DEFAULT_PRECISION)),
factory.createPropertyAssignment(factory.createIdentifier("scale"), factory.createNumericLiteral(env_1.NUMERICAL_LITERL_DEFAULT_SCALE))
], true)));
// 否则是本地规定的shape直接用object
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("object")));
}
}
else {
(0, assert_1.default)(ts.isLiteralTypeNode(type), `${entity}中的属性${name.text}有非法的属性类型定义`);
if (ts.isStringLiteral(type.literal)) {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("varchar")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([factory.createPropertyAssignment(factory.createIdentifier("length"), factory.createNumericLiteral(env_1.STRING_LITERAL_MAX_LENGTH))], true)));
if (ts.isLiteralTypeNode(type)) {
if (ts.isStringLiteral(type.literal)) {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("varchar")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([factory.createPropertyAssignment(factory.createIdentifier("length"), factory.createNumericLiteral(env_1.STRING_LITERAL_MAX_LENGTH))], true)));
}
else {
(0, assert_1.default)(ts.isNumericLiteral(type.literal));
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("precision")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier("precision"), factory.createNumericLiteral(env_1.NUMERICAL_LITERL_DEFAULT_PRECISION)),
factory.createPropertyAssignment(factory.createIdentifier("scale"), factory.createNumericLiteral(env_1.NUMERICAL_LITERL_DEFAULT_SCALE))
], true)));
}
}
else {
(0, assert_1.default)(ts.isNumericLiteral(type.literal));
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("precision")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier("precision"), factory.createNumericLiteral(env_1.NUMERICAL_LITERL_DEFAULT_PRECISION)),
factory.createPropertyAssignment(factory.createIdentifier("scale"), factory.createNumericLiteral(env_1.NUMERICAL_LITERL_DEFAULT_SCALE))
], true)));
// 否则是本地规定的shape直接用object
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("object")));
}
}
}

View File

@ -1,15 +1,13 @@
import { Context } from '../types/Context';
import { DeduceCreateOperation, DeduceCreateSingleOperation, DeduceRemoveOperation, DeduceUpdateOperation, EntityDef, OperateParams } from "../types/Entity";
import { DeduceCreateOperation, DeduceCreateSingleOperation, DeduceRemoveOperation, DeduceUpdateOperation, EntityDict, OperateParams } from "../types/Entity";
import { RowStore } from '../types/RowStore';
import { StorageSchema } from '../types/Storage';
/**这个用来处理级联的select和update对不同能力的 */
export declare abstract class CascadeStore<ED extends {
[E: string]: EntityDef;
}> extends RowStore<ED> {
export declare abstract class CascadeStore<ED extends EntityDict, Cxt extends Context<ED>> extends RowStore<ED, Cxt> {
constructor(storageSchema: StorageSchema<ED>);
protected abstract selectAbjointRow<T extends keyof ED>(entity: T, selection: Omit<ED[T]['Selection'], 'indexFrom' | 'count' | 'data' | 'sorter'>, context: Context<ED>, params?: OperateParams): Promise<Array<ED[T]['OpSchema']>>;
protected abstract updateAbjointRow<T extends keyof ED>(entity: T, operation: DeduceCreateSingleOperation<ED[T]['Schema']> | DeduceUpdateOperation<ED[T]['Schema']> | DeduceRemoveOperation<ED[T]['Schema']>, context: Context<ED>, params?: OperateParams): Promise<void>;
protected cascadeSelect<T extends keyof ED>(entity: T, selection: ED[T]['Selection'], context: Context<ED>, params?: OperateParams): Promise<Array<ED[T]['Schema']>>;
protected abstract selectAbjointRow<T extends keyof ED>(entity: T, selection: Omit<ED[T]['Selection'], 'indexFrom' | 'count' | 'data' | 'sorter'>, context: Cxt, params?: OperateParams): Promise<Array<ED[T]['OpSchema']>>;
protected abstract updateAbjointRow<T extends keyof ED>(entity: T, operation: DeduceCreateSingleOperation<ED[T]['Schema']> | DeduceUpdateOperation<ED[T]['Schema']> | DeduceRemoveOperation<ED[T]['Schema']>, context: Cxt, params?: OperateParams): Promise<void>;
protected cascadeSelect<T extends keyof ED>(entity: T, selection: ED[T]['Selection'], context: Cxt, params?: OperateParams): Promise<Array<ED[T]['Schema']>>;
/**
*
* A --> B
@ -33,6 +31,6 @@ export declare abstract class CascadeStore<ED extends {
* @param context
* @param params
*/
protected cascadeUpdate<T extends keyof ED>(entity: T, operation: DeduceCreateOperation<ED[T]['Schema']> | DeduceUpdateOperation<ED[T]['Schema']> | DeduceRemoveOperation<ED[T]['Schema']>, context: Context<ED>, params?: OperateParams): Promise<void>;
protected cascadeUpdate<T extends keyof ED>(entity: T, operation: DeduceCreateOperation<ED[T]['Schema']> | DeduceUpdateOperation<ED[T]['Schema']> | DeduceRemoveOperation<ED[T]['Schema']>, context: Cxt, params?: OperateParams): Promise<void>;
judgeRelation(entity: keyof ED, attr: string): string | string[] | 1 | 0 | 2;
}

View File

@ -6,19 +6,20 @@ import { Trigger, Executor } from "../types/Trigger";
/**
* update可能会传入多种不同的actionupdate trigger
*/
export declare class TriggerExecutor<ED extends EntityDict> extends Executor<ED> {
export declare class TriggerExecutor<ED extends EntityDict, Cxt extends Context<ED>> extends Executor<ED, Cxt> {
private triggerMap;
private triggerNameMap;
private volatileEntities;
private logger;
constructor(logger?: Logger);
registerChecker<T extends keyof ED>(checker: Checker<ED, T>): void;
registerTrigger<T extends keyof ED>(trigger: Trigger<ED, T>): void;
unregisterTrigger<T extends keyof ED>(trigger: Trigger<ED, T>): void;
private contextBuilder;
constructor(contextBuilder: () => Cxt, logger?: Logger);
registerChecker<T extends keyof ED>(checker: Checker<ED, T, Cxt>): void;
registerTrigger<T extends keyof ED>(trigger: Trigger<ED, T, Cxt>): void;
unregisterTrigger<T extends keyof ED>(trigger: Trigger<ED, T, Cxt>): void;
private preCommitTrigger;
preOperation<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Context<ED>): Promise<void>;
preOperation<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Cxt): Promise<void>;
private onCommit;
private postCommitTrigger;
postOperation<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Context<ED>): Promise<void>;
checkpoint(context: Context<ED>, timestamp: number): Promise<number>;
postOperation<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Cxt): Promise<void>;
checkpoint(context: Cxt, timestamp: number): Promise<number>;
}

View File

@ -24,8 +24,10 @@ class TriggerExecutor extends Trigger_1.Executor {
triggerNameMap;
volatileEntities;
logger;
constructor(logger = console) {
contextBuilder;
constructor(contextBuilder, logger = console) {
super();
this.contextBuilder = contextBuilder;
this.logger = logger;
this.triggerMap = {};
this.triggerNameMap = {};
@ -166,7 +168,8 @@ class TriggerExecutor extends Trigger_1.Executor {
}
}
onCommit(trigger, operation) {
return async (context) => {
return async () => {
const context = this.contextBuilder();
await context.begin();
const number = await trigger.fn({
operation: operation,
@ -243,7 +246,7 @@ class TriggerExecutor extends Trigger_1.Executor {
const { $$triggerData$$ } = row;
const { name, operation } = $$triggerData$$;
const trigger = this.triggerNameMap[name];
await this.onCommit(trigger, operation)(context);
await this.onCommit(trigger, operation)();
}
}
return result;

View File

@ -1,15 +1,15 @@
import { EntityDict, OpRecord, RowStore, TxnOption, Context } from "../types";
export declare class UniversalContext<ED extends EntityDict> implements Context<ED> {
rowStore: RowStore<ED>;
rowStore: RowStore<ED, this>;
uuid?: string;
opRecords: OpRecord<ED>[];
events: {
commit: Array<(context: UniversalContext<ED>) => Promise<void>>;
rollback: Array<(context: UniversalContext<ED>) => Promise<void>>;
commit: Array<() => Promise<void>>;
rollback: Array<() => Promise<void>>;
};
constructor(store: RowStore<ED>);
constructor(store: RowStore<ED, UniversalContext<ED>>);
private resetEvents;
on(event: 'commit' | 'rollback', callback: (context: UniversalContext<ED>) => Promise<void>): void;
on(event: 'commit' | 'rollback', callback: () => Promise<void>): void;
begin(options?: TxnOption): Promise<void>;
commit(): Promise<void>;
rollback(): Promise<void>;

View File

@ -30,27 +30,21 @@ class UniversalContext {
}
async commit() {
if (this.uuid) {
/**
* todo 这里应该等到提交成功了再做 by Xc
*/
for (const e of this.events.commit) {
await e(this);
}
await this.rowStore.commit(this.uuid);
this.uuid = undefined;
for (const e of this.events.commit) {
await e();
}
this.resetEvents();
}
}
async rollback() {
if (this.uuid) {
/**
* todo 这里应该等到回滚成功了再做 by Xc
*/
for (const e of this.events.rollback) {
await e(this);
}
await this.rowStore.rollback(this.uuid);
this.uuid = undefined;
for (const e of this.events.rollback) {
await e();
}
this.resetEvents();
}
}

22
lib/types/Auth.d.ts vendored
View File

@ -1,23 +1,19 @@
import { EntityDict } from "../types/Entity";
import { Context } from "./Context";
import { CreateTriggerBase, RemoveTriggerBase, UpdateTriggerBase } from "./Trigger";
export declare class AttrIllegalError extends Error {
private attributes;
constructor(attributes: string[], message?: string);
getAttributes(): string[];
}
export declare type CreateChecker<ED extends EntityDict, T extends keyof ED> = {
export declare type CreateChecker<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = {
action: 'create';
entity: T;
checker: CreateTriggerBase<ED, T>['fn'];
checker: CreateTriggerBase<ED, T, Cxt>['fn'];
};
export declare type UpdateChecker<ED extends EntityDict, T extends keyof ED> = {
action: UpdateTriggerBase<ED, T>['action'];
export declare type UpdateChecker<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = {
action: UpdateTriggerBase<ED, T, Cxt>['action'];
entity: T;
checker: UpdateTriggerBase<ED, T>['fn'];
checker: UpdateTriggerBase<ED, T, Cxt>['fn'];
};
export declare type RemoveChecker<ED extends EntityDict, T extends keyof ED> = {
export declare type RemoveChecker<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = {
action: 'remove';
entity: T;
checker: RemoveTriggerBase<ED, T>['fn'];
checker: RemoveTriggerBase<ED, T, Cxt>['fn'];
};
export declare type Checker<ED extends EntityDict, T extends keyof ED> = CreateChecker<ED, T> | UpdateChecker<ED, T> | RemoveChecker<ED, T>;
export declare type Checker<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = CreateChecker<ED, T, Cxt> | UpdateChecker<ED, T, Cxt> | RemoveChecker<ED, T, Cxt>;

View File

@ -1,15 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AttrIllegalError = void 0;
class AttrIllegalError extends Error {
attributes;
constructor(attributes, message) {
super(message);
this.attributes = attributes;
}
getAttributes() {
return this.attributes;
}
}
exports.AttrIllegalError = AttrIllegalError;
;

View File

@ -2,10 +2,10 @@ import { EntityDict, OpRecord } from './Entity';
import { RowStore } from './RowStore';
export interface Context<ED extends EntityDict> {
opRecords: OpRecord<ED>[];
rowStore: RowStore<ED>;
rowStore: RowStore<ED, this>;
begin(options?: object): Promise<void>;
commit(): Promise<void>;
rollback(): Promise<void>;
getCurrentTxnId(): string | undefined;
on(event: 'commit' | 'rollback', callback: (context: Context<ED>) => Promise<void>): void;
on(event: 'commit' | 'rollback', callback: () => Promise<void>): void;
}

View File

@ -5,13 +5,13 @@ import { OakErrorDefDict } from '../OakError';
export declare type TxnOption = {
isolationLevel: 'repeatable read' | 'serializable';
};
export declare abstract class RowStore<ED extends EntityDict> {
export declare abstract class RowStore<ED extends EntityDict, Cxt extends Context<ED>> {
static $$LEVEL: string;
static $$CODES: OakErrorDefDict;
protected storageSchema: StorageSchema<ED>;
abstract operate<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Context<ED>, params?: OperateParams): Promise<OperationResult>;
abstract select<T extends keyof ED, S extends ED[T]['Selection']>(entity: T, selection: S, context: Context<ED>, params?: Object): Promise<SelectionResult<ED[T]['Schema'], S['data']>>;
abstract count<T extends keyof ED>(entity: T, selection: Omit<ED[T]['Selection'], 'data' | 'sorter' | 'action'>, context: Context<ED>, params?: Object): Promise<number>;
abstract operate<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Cxt, params?: OperateParams): Promise<OperationResult>;
abstract select<T extends keyof ED, S extends ED[T]['Selection']>(entity: T, selection: S, context: Cxt, params?: Object): Promise<SelectionResult<ED[T]['Schema'], S['data']>>;
abstract count<T extends keyof ED>(entity: T, selection: Omit<ED[T]['Selection'], 'data' | 'sorter' | 'action'>, context: Cxt, params?: Object): Promise<number>;
constructor(storageSchema: StorageSchema<ED>);
abstract begin(option?: TxnOption): Promise<string>;
abstract commit(txnId: string): Promise<void>;

View File

@ -2,7 +2,7 @@ import { GenericAction } from "../actions/action";
import { DeduceCreateOperation, DeduceRemoveOperation, DeduceSelection, DeduceUpdateOperation, EntityDict } from "../types/Entity";
import { EntityShape, SelectionResult, TriggerDataAttribute, TriggerTimestampAttribute } from "../types/Entity";
import { Context } from "./Context";
export interface CreateTriggerBase<ED extends EntityDict, T extends keyof ED> {
export interface CreateTriggerBase<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> {
entity: T;
name: string;
action: 'create';
@ -11,15 +11,15 @@ export interface CreateTriggerBase<ED extends EntityDict, T extends keyof ED> {
operation: DeduceCreateOperation<ED[T]['Schema']>;
}, context: Context<ED>, params?: Object) => Promise<number>;
}
export interface CreateTriggerInTxn<ED extends EntityDict, T extends keyof ED> extends CreateTriggerBase<ED, T> {
export interface CreateTriggerInTxn<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends CreateTriggerBase<ED, T, Cxt> {
when: 'before' | 'after';
}
export interface CreateTriggerCrossTxn<ED extends EntityDict, T extends keyof ED> extends CreateTriggerBase<ED, T> {
export interface CreateTriggerCrossTxn<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends CreateTriggerBase<ED, T, Cxt> {
when: 'commit';
strict?: 'takeEasy' | 'makeSure';
}
export declare type CreateTrigger<ED extends EntityDict, T extends keyof ED> = CreateTriggerInTxn<ED, T> | CreateTriggerCrossTxn<ED, T>;
export interface UpdateTriggerBase<ED extends EntityDict, T extends keyof ED> {
export declare type CreateTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = CreateTriggerInTxn<ED, T, Cxt> | CreateTriggerCrossTxn<ED, T, Cxt>;
export interface UpdateTriggerBase<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> {
entity: T;
name: string;
action: Exclude<ED[T]['Action'], GenericAction> | 'update' | Array<Exclude<ED[T]['Action'], GenericAction> | 'update'>;
@ -27,33 +27,33 @@ export interface UpdateTriggerBase<ED extends EntityDict, T extends keyof ED> {
check?: (operation: DeduceUpdateOperation<ED[T]['Schema']>) => boolean;
fn: (event: {
operation: DeduceUpdateOperation<ED[T]['Schema']>;
}, context: Context<ED>, params?: Object) => Promise<number>;
}, context: Cxt, params?: Object) => Promise<number>;
}
export interface UpdateTriggerInTxn<ED extends EntityDict, T extends keyof ED> extends UpdateTriggerBase<ED, T> {
export interface UpdateTriggerInTxn<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends UpdateTriggerBase<ED, T, Cxt> {
when: 'before' | 'after';
}
export interface UpdateTriggerCrossTxn<ED extends EntityDict, T extends keyof ED> extends UpdateTriggerBase<ED, T> {
export interface UpdateTriggerCrossTxn<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends UpdateTriggerBase<ED, T, Cxt> {
when: 'commit';
strict?: 'takeEasy' | 'makeSure';
}
export declare type UpdateTrigger<ED extends EntityDict, T extends keyof ED> = UpdateTriggerInTxn<ED, T> | UpdateTriggerCrossTxn<ED, T>;
export interface RemoveTriggerBase<ED extends EntityDict, T extends keyof ED> {
export declare type UpdateTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = UpdateTriggerInTxn<ED, T, Cxt> | UpdateTriggerCrossTxn<ED, T, Cxt>;
export interface RemoveTriggerBase<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> {
entity: T;
name: string;
action: 'remove';
check?: (operation: DeduceRemoveOperation<ED[T]['Schema']>) => boolean;
fn: (event: {
operation: DeduceRemoveOperation<ED[T]['Schema']>;
}, context: Context<ED>, params?: Object) => Promise<number>;
}, context: Cxt, params?: Object) => Promise<number>;
}
export interface RemoveTriggerInTxn<ED extends EntityDict, T extends keyof ED> extends RemoveTriggerBase<ED, T> {
export interface RemoveTriggerInTxn<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends RemoveTriggerBase<ED, T, Cxt> {
when: 'before' | 'after';
}
export interface RemoveTriggerCrossTxn<ED extends EntityDict, T extends keyof ED> extends RemoveTriggerBase<ED, T> {
export interface RemoveTriggerCrossTxn<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends RemoveTriggerBase<ED, T, Cxt> {
when: 'commit';
strict?: 'takeEasy' | 'makeSure';
}
export declare type RemoveTrigger<ED extends EntityDict, T extends keyof ED> = RemoveTriggerInTxn<ED, T> | RemoveTriggerCrossTxn<ED, T>;
export declare type RemoveTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = RemoveTriggerInTxn<ED, T, Cxt> | RemoveTriggerCrossTxn<ED, T, Cxt>;
export interface SelectTriggerBase<ED extends EntityDict, T extends keyof ED> {
entity: T;
name: string;
@ -63,21 +63,21 @@ export interface SelectTriggerBase<ED extends EntityDict, T extends keyof ED> {
* selection似乎不需要支持跨事务
* todo by Xc
*/
export interface SelectTriggerBefore<ED extends EntityDict, T extends keyof ED> extends SelectTriggerBase<ED, T> {
export interface SelectTriggerBefore<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends SelectTriggerBase<ED, T> {
when: 'before';
fn: (event: {
operation: DeduceSelection<ED[T]['Schema']>;
}, context: Context<ED>, params?: Object) => Promise<number>;
}, context: Cxt, params?: Object) => Promise<number>;
}
export interface SelectTriggerAfter<ED extends EntityDict, T extends keyof ED> extends SelectTriggerBase<ED, T> {
export interface SelectTriggerAfter<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends SelectTriggerBase<ED, T> {
when: 'after';
fn: <S extends ED[T]['Selection']>(event: {
operation: S;
result: SelectionResult<ED[T]['Schema'], S['data']>;
}, context: Context<ED>, params?: Object) => Promise<number>;
}, context: Cxt, params?: Object) => Promise<number>;
}
export declare type SelectTrigger<ED extends EntityDict, T extends keyof ED> = SelectTriggerBefore<ED, T> | SelectTriggerAfter<ED, T>;
export declare type Trigger<ED extends EntityDict, T extends keyof ED> = CreateTrigger<ED, T> | UpdateTrigger<ED, T> | RemoveTrigger<ED, T> | SelectTrigger<ED, T>;
export declare type SelectTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = SelectTriggerBefore<ED, T, Cxt> | SelectTriggerAfter<ED, T, Cxt>;
export declare type Trigger<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = CreateTrigger<ED, T, Cxt> | UpdateTrigger<ED, T, Cxt> | RemoveTrigger<ED, T, Cxt> | SelectTrigger<ED, T, Cxt>;
export interface TriggerEntityShape extends EntityShape {
$$triggerData$$?: {
name: string;
@ -85,11 +85,11 @@ export interface TriggerEntityShape extends EntityShape {
};
$$triggerTimestamp$$?: number;
}
export declare abstract class Executor<ED extends EntityDict> {
export declare abstract class Executor<ED extends EntityDict, Cxt extends Context<ED>> {
static dataAttr: TriggerDataAttribute;
static timestampAttr: TriggerTimestampAttribute;
abstract registerTrigger<T extends keyof ED>(trigger: Trigger<ED, T>): void;
abstract preOperation<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Context<ED>): Promise<void>;
abstract postOperation<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Context<ED>): Promise<void>;
abstract checkpoint(context: Context<ED>, timestamp: number): Promise<number>;
abstract registerTrigger<T extends keyof ED>(trigger: Trigger<ED, T, Cxt>): void;
abstract preOperation<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Cxt): Promise<void>;
abstract postOperation<T extends keyof ED>(entity: T, operation: ED[T]['Operation'], context: Cxt): Promise<void>;
abstract checkpoint(context: Cxt, timestamp: number): Promise<number>;
}

View File

@ -12,3 +12,4 @@ export * from './Polyfill';
export * from './RowStore';
export * from './Storage';
export * from './Trigger';
export * from './Exception';

View File

@ -24,3 +24,4 @@ __exportStar(require("./Polyfill"), exports);
__exportStar(require("./RowStore"), exports);
__exportStar(require("./Storage"), exports);
__exportStar(require("./Trigger"), exports);
__exportStar(require("./Exception"), exports);

View File

@ -70,6 +70,13 @@ const ActionAsts: {
};
} = {};
const SchemaAsts: {
[module: string]: {
statements: Array<ts.Statement>;
sourceFile: ts.SourceFile;
};
} = {};
function addRelationship(many: string, one: string, key: string) {
const { [many]: manySet } = ManyToOne;
const one2 = one === 'Schema' ? many : one;
@ -105,7 +112,7 @@ function createForeignRef(entity: string, foreignKey: string, ref: string) {
function pushStatementIntoActionAst(
moduleName: string,
node: ts.TypeAliasDeclaration | ts.VariableStatement,
node: ts.Statement,
sourceFile: ts.SourceFile) {
if (ActionAsts[moduleName]) {
ActionAsts[moduleName].statements.push(node);
@ -121,6 +128,20 @@ function pushStatementIntoActionAst(
}
}
function pushStatementIntoSchemaAst(moduleName: string, statement: ts.Statement, sourceFile: ts.SourceFile) {
if (SchemaAsts[moduleName]) {
SchemaAsts[moduleName].statements.push(statement);
}
else {
assign(SchemaAsts, {
[moduleName]: {
statements: [statement],
sourceFile,
}
});
}
}
/**
* ActionDef是否满足合法的定义
* 1ActionDef, Action, State三者命名是否一致
@ -303,6 +324,7 @@ function analyzeEntity(filename: string, path: string, program: ts.Program) {
const schemaAttrs: ts.TypeElement[] = [];
let hasFulltextIndex: boolean = false;
let indexes: ts.ArrayLiteralExpression;
let beforeSchema = true;
ts.forEachChild(sourceFile!, (node) => {
if (ts.isImportDeclaration(node)) {
const entityImported = getEntityImported(node, filename);
@ -398,6 +420,11 @@ function analyzeEntity(filename: string, path: string, program: ts.Program) {
[moduleName]: 1,
});
}
beforeSchema = false;
}
else if (beforeSchema) {
// 本地规定的一些形状定义,直接使用
pushStatementIntoSchemaAst(moduleName, node, sourceFile!);
}
}
@ -439,8 +466,7 @@ function analyzeEntity(filename: string, path: string, program: ts.Program) {
);
dealWithActions(moduleName, filename, node.type, program, schemaAttrs);
}
if (node.name.text === 'Relation') {
else if (node.name.text === 'Relation') {
// 增加userXXX对象的描述
if (ts.isLiteralTypeNode(node.type)) {
assert(ts.isStringLiteral(node.type.literal));
@ -492,6 +518,10 @@ function analyzeEntity(filename: string, path: string, program: ts.Program) {
addRelationship(relationEntityName, 'User', 'user');
addRelationship(relationEntityName, moduleName, entityLc);
}
else if (beforeSchema) {
// 本地规定的一些形状定义,直接使用
pushStatementIntoSchemaAst(moduleName, node, sourceFile!);
}
}
if (ts.isVariableStatement(node)) {
@ -958,6 +988,11 @@ function constructSchema(statements: Array<ts.Statement>, entity: string) {
}
);
// 在这里把需要直接拷贝过来的语句写入
if (SchemaAsts[entity]) {
statements.push(...SchemaAsts[entity].statements);
}
// if (keys(foreignKeySet).length > 0) {
// for (const fkItem in foreignKeySet) {
// const entityLc = fkItem.slice(0, 1).toLowerCase().concat(fkItem.slice(1));
@ -1212,9 +1247,7 @@ function constructFilter(statements: Array<ts.Statement>, entity: string) {
}
}
}
else {
assert(ts.isUnionTypeNode(type!) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type!));
else if (ts.isUnionTypeNode(type!) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type!)) {
members.push(
factory.createPropertySignature(
undefined,
@ -1229,6 +1262,9 @@ function constructFilter(statements: Array<ts.Statement>, entity: string) {
)
);
}
else {
// 此时应当是引用本地定义的shape
}
}
// type AttrFilter = {};
@ -1398,7 +1434,8 @@ function constructProjection(statements: Array<ts.Statement>, entity: string) {
}
}
else {
assert(ts.isUnionTypeNode(type!) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type!));
// 增加了本身object的shape定义
// assert(ts.isUnionTypeNode(type!) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type!));
properties.push(
[name, false, undefined]
)
@ -1840,8 +1877,7 @@ function constructSorter(statements: Array<ts.Statement>, entity: string) {
}
}
}
else {
assert(ts.isUnionTypeNode(type!) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type!));
else if (ts.isUnionTypeNode(type!) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type!)) {
members.push(
factory.createPropertySignature(
undefined,
@ -1851,6 +1887,9 @@ function constructSorter(statements: Array<ts.Statement>, entity: string) {
)
);
}
else {
// 本地规定的shape非结构化属性不参与排序
}
}
if (ReversePointerRelations[entity]) {
@ -4118,94 +4157,114 @@ function constructAttributes(entity: string): ts.PropertyAssignment[] {
}
else {
if (ts.isUnionTypeNode(type!)) {
assert(ts.isLiteralTypeNode(type.types[0]));
if (ts.isStringLiteral(type.types[0].literal)) {
attrAssignments.push(
factory.createPropertyAssignment(
factory.createIdentifier("type"),
factory.createStringLiteral("varchar")
),
factory.createPropertyAssignment(
factory.createIdentifier("params"),
factory.createObjectLiteralExpression(
[factory.createPropertyAssignment(
factory.createIdentifier("length"),
factory.createNumericLiteral(STRING_LITERAL_MAX_LENGTH)
)],
true
if (ts.isLiteralTypeNode(type.types[0])) {
if (ts.isStringLiteral(type.types[0].literal)) {
attrAssignments.push(
factory.createPropertyAssignment(
factory.createIdentifier("type"),
factory.createStringLiteral("varchar")
),
factory.createPropertyAssignment(
factory.createIdentifier("params"),
factory.createObjectLiteralExpression(
[factory.createPropertyAssignment(
factory.createIdentifier("length"),
factory.createNumericLiteral(STRING_LITERAL_MAX_LENGTH)
)],
true
)
)
)
);
);
}
else {
assert(ts.isNumericLiteral(type.types[0].literal));
attrAssignments.push(
factory.createPropertyAssignment(
factory.createIdentifier("type"),
factory.createStringLiteral("int")
),
factory.createPropertyAssignment(
factory.createIdentifier("params"),
factory.createObjectLiteralExpression(
[
factory.createPropertyAssignment(
factory.createIdentifier("precision"),
factory.createNumericLiteral(NUMERICAL_LITERL_DEFAULT_PRECISION)
),
factory.createPropertyAssignment(
factory.createIdentifier("scale"),
factory.createNumericLiteral(NUMERICAL_LITERL_DEFAULT_SCALE)
)
],
true
)
)
);
}
}
else {
assert(ts.isNumericLiteral(type.types[0].literal));
// 否则是本地规定的shape直接用object
attrAssignments.push(
factory.createPropertyAssignment(
factory.createIdentifier("type"),
factory.createStringLiteral("int")
factory.createStringLiteral("object")
),
factory.createPropertyAssignment(
factory.createIdentifier("params"),
factory.createObjectLiteralExpression(
[
factory.createPropertyAssignment(
factory.createIdentifier("precision"),
factory.createNumericLiteral(NUMERICAL_LITERL_DEFAULT_PRECISION)
),
factory.createPropertyAssignment(
factory.createIdentifier("scale"),
factory.createNumericLiteral(NUMERICAL_LITERL_DEFAULT_SCALE)
)
],
true
)
)
);
}
}
else {
assert(ts.isLiteralTypeNode(type!), `${entity}中的属性${(<ts.Identifier>name).text}有非法的属性类型定义`);
if (ts.isStringLiteral(type.literal)) {
attrAssignments.push(
factory.createPropertyAssignment(
factory.createIdentifier("type"),
factory.createStringLiteral("varchar")
),
factory.createPropertyAssignment(
factory.createIdentifier("params"),
factory.createObjectLiteralExpression(
[factory.createPropertyAssignment(
factory.createIdentifier("length"),
factory.createNumericLiteral(STRING_LITERAL_MAX_LENGTH)
)],
true
if (ts.isLiteralTypeNode(type!)) {
if (ts.isStringLiteral(type.literal)) {
attrAssignments.push(
factory.createPropertyAssignment(
factory.createIdentifier("type"),
factory.createStringLiteral("varchar")
),
factory.createPropertyAssignment(
factory.createIdentifier("params"),
factory.createObjectLiteralExpression(
[factory.createPropertyAssignment(
factory.createIdentifier("length"),
factory.createNumericLiteral(STRING_LITERAL_MAX_LENGTH)
)],
true
)
)
)
);
);
}
else {
assert(ts.isNumericLiteral(type.literal));
attrAssignments.push(
factory.createPropertyAssignment(
factory.createIdentifier("type"),
factory.createStringLiteral("precision")
),
factory.createPropertyAssignment(
factory.createIdentifier("params"),
factory.createObjectLiteralExpression(
[
factory.createPropertyAssignment(
factory.createIdentifier("precision"),
factory.createNumericLiteral(NUMERICAL_LITERL_DEFAULT_PRECISION)
),
factory.createPropertyAssignment(
factory.createIdentifier("scale"),
factory.createNumericLiteral(NUMERICAL_LITERL_DEFAULT_SCALE)
)
],
true
)
)
);
}
}
else {
assert(ts.isNumericLiteral(type.literal));
// 否则是本地规定的shape直接用object
attrAssignments.push(
factory.createPropertyAssignment(
factory.createIdentifier("type"),
factory.createStringLiteral("precision")
factory.createStringLiteral("object")
),
factory.createPropertyAssignment(
factory.createIdentifier("params"),
factory.createObjectLiteralExpression(
[
factory.createPropertyAssignment(
factory.createIdentifier("precision"),
factory.createNumericLiteral(NUMERICAL_LITERL_DEFAULT_PRECISION)
),
factory.createPropertyAssignment(
factory.createIdentifier("scale"),
factory.createNumericLiteral(NUMERICAL_LITERL_DEFAULT_SCALE)
)
],
true
)
)
);
}
}
@ -4489,6 +4548,6 @@ export function buildSchema(outputDir: string): void {
outputStorage(outputDir, printer);
//if (!process.env.COMPLING_BASE_ENTITY_DICT) {
outputPackageJson(outputDir);
outputPackageJson(outputDir);
//}
}

View File

@ -2,35 +2,33 @@ import assert from "assert";
import { assign } from "lodash";
import { Context } from '../types/Context';
import { DeduceCreateOperation, DeduceCreateSingleOperation, DeduceFilter, DeduceRemoveOperation, DeduceSelection,
DeduceUpdateOperation, EntityDef, EntityShape, OperateParams, SelectionResult } from "../types/Entity";
DeduceUpdateOperation, EntityDict, EntityShape, OperateParams, SelectionResult } from "../types/Entity";
import { RowStore } from '../types/RowStore';
import { StorageSchema } from '../types/Storage';
import { addFilterSegment } from "./filter";
import { judgeRelation } from "./relation";
/**这个用来处理级联的select和update对不同能力的 */
export abstract class CascadeStore<ED extends {
[E: string]: EntityDef;
}> extends RowStore<ED> {
export abstract class CascadeStore<ED extends EntityDict, Cxt extends Context<ED>> extends RowStore<ED, Cxt> {
constructor(storageSchema: StorageSchema<ED>) {
super(storageSchema);
}
protected abstract selectAbjointRow<T extends keyof ED>(
entity: T,
selection: Omit<ED[T]['Selection'], 'indexFrom' | 'count' | 'data' | 'sorter'>,
context: Context<ED>,
context: Cxt,
params?: OperateParams): Promise<Array<ED[T]['OpSchema']>>;
protected abstract updateAbjointRow<T extends keyof ED>(
entity: T,
operation: DeduceCreateSingleOperation<ED[T]['Schema']> | DeduceUpdateOperation<ED[T]['Schema']> | DeduceRemoveOperation<ED[T]['Schema']>,
context: Context<ED>,
context: Cxt,
params?: OperateParams): Promise<void>;
protected async cascadeSelect<T extends keyof ED>(
entity: T,
selection: ED[T]['Selection'],
context: Context<ED>, params?: OperateParams): Promise<Array<ED[T]['Schema']>> {
context: Cxt, params?: OperateParams): Promise<Array<ED[T]['Schema']>> {
const { data } = selection;
const projection: ED[T]['Selection']['data'] = {};
@ -166,7 +164,7 @@ export abstract class CascadeStore<ED extends {
protected async cascadeUpdate<T extends keyof ED>(
entity: T,
operation: DeduceCreateOperation<ED[T]['Schema']> | DeduceUpdateOperation<ED[T]['Schema']> | DeduceRemoveOperation<ED[T]['Schema']>,
context: Context<ED>,
context: Cxt,
params?: OperateParams): Promise<void> {
const { action, data, filter } = operation;
const opData = {};

View File

@ -19,28 +19,30 @@ import { Trigger, Executor, CreateTriggerCrossTxn, CreateTrigger, CreateTriggerI
'stat': 'select',
}; */
export class TriggerExecutor<ED extends EntityDict> extends Executor<ED> {
export class TriggerExecutor<ED extends EntityDict, Cxt extends Context<ED>> extends Executor<ED, Cxt> {
private triggerMap: {
[T in keyof ED]?: {
[A: string]: Array<Trigger<ED, T>>;
[A: string]: Array<Trigger<ED, T, Cxt>>;
};
};
private triggerNameMap: {
[N: string]: Trigger<ED, keyof ED>;
[N: string]: Trigger<ED, keyof ED, Cxt>;
};
private volatileEntities: Array<keyof ED>;
private logger: Logger;
private contextBuilder: () => Cxt;
constructor(logger: Logger = console) {
constructor(contextBuilder: () => Cxt, logger: Logger = console) {
super();
this.contextBuilder = contextBuilder;
this.logger = logger;
this.triggerMap = {};
this.triggerNameMap = {};
this.volatileEntities = [];
}
registerChecker<T extends keyof ED>(checker: Checker<ED, T>): void {
registerChecker<T extends keyof ED>(checker: Checker<ED, T, Cxt>): void {
const { entity, action, checker: checkFn } = checker;
const ActionNameMatrix: Record<string, string> = {
'create': '创建',
@ -55,11 +57,11 @@ export class TriggerExecutor<ED extends EntityDict> extends Executor<ED> {
action,
fn: checkFn,
when: 'before',
} as CreateTriggerInTxn<ED, T>;
} as CreateTriggerInTxn<ED, T, Cxt>;
this.registerTrigger(trigger);
}
registerTrigger<T extends keyof ED>(trigger: Trigger<ED, T>): void {
registerTrigger<T extends keyof ED>(trigger: Trigger<ED, T, Cxt>): void {
// trigger的两种访问方式: by name, by entity/action
if (this.triggerNameMap.hasOwnProperty(trigger.name)) {
throw new Error(`不可有同名的触发器「${trigger.name}`);
@ -102,7 +104,7 @@ export class TriggerExecutor<ED extends EntityDict> extends Executor<ED> {
}
}
unregisterTrigger<T extends keyof ED>(trigger: Trigger<ED, T>): void {
unregisterTrigger<T extends keyof ED>(trigger: Trigger<ED, T, Cxt>): void {
assert(trigger.when !== 'commit' || trigger.strict !== 'makeSure', 'could not remove strict volatile triggers');
const removeTrigger = (action: string) => {
@ -126,11 +128,11 @@ export class TriggerExecutor<ED extends EntityDict> extends Executor<ED> {
private async preCommitTrigger<T extends keyof ED>(
entity: T,
operation: ED[T]['Operation'],
trigger: Trigger<ED, T>,
context: Context<ED>,
trigger: Trigger<ED, T, Cxt>,
context: Cxt,
) {
assert(trigger.action !== 'select');
if ((trigger as CreateTriggerCrossTxn<ED, T>).strict === 'makeSure') {
if ((trigger as CreateTriggerCrossTxn<ED, T, Cxt>).strict === 'makeSure') {
switch (operation.action) {
case 'create': {
if (operation.data.hasOwnProperty(Executor.dataAttr) || operation.data.hasOwnProperty(Executor.timestampAttr)) {
@ -179,7 +181,7 @@ export class TriggerExecutor<ED extends EntityDict> extends Executor<ED> {
async preOperation<T extends keyof ED>(
entity: T,
operation: ED[T]['Operation'],
context: Context<ED>
context: Cxt
): Promise<void> {
const { action } = operation;
const triggers = this.triggerMap[entity] && this.triggerMap[entity]![action].filter(
@ -187,18 +189,18 @@ export class TriggerExecutor<ED extends EntityDict> extends Executor<ED> {
);
if (triggers) {
const preTriggers = triggers.filter(
ele => ele.when === 'before' && (!(ele as CreateTrigger<ED, T>).check || (ele as CreateTrigger<ED, T>).check!(operation as DeduceCreateOperation<ED[T]['Schema']>))
ele => ele.when === 'before' && (!(ele as CreateTrigger<ED, T, Cxt>).check || (ele as CreateTrigger<ED, T, Cxt>).check!(operation as DeduceCreateOperation<ED[T]['Schema']>))
);
for (const trigger of preTriggers) {
const number = await (trigger as CreateTrigger<ED, T>).fn({ operation: operation as DeduceCreateOperation<ED[T]['Schema']> }, context);
const number = await (trigger as CreateTrigger<ED, T, Cxt>).fn({ operation: operation as DeduceCreateOperation<ED[T]['Schema']> }, context);
if (number > 0) {
this.logger.info(`触发器「${trigger.name}」成功触发了「${number}」行数据更改`);
}
}
const commitTriggers = triggers.filter(
ele => ele.when === 'commit' && (!(ele as CreateTrigger<ED, T>).check || (ele as CreateTrigger<ED, T>).check!(operation as DeduceCreateOperation<ED[T]['Schema']>))
ele => ele.when === 'commit' && (!(ele as CreateTrigger<ED, T, Cxt>).check || (ele as CreateTrigger<ED, T, Cxt>).check!(operation as DeduceCreateOperation<ED[T]['Schema']>))
);
for (const trigger of commitTriggers) {
@ -208,14 +210,15 @@ export class TriggerExecutor<ED extends EntityDict> extends Executor<ED> {
}
private onCommit<T extends keyof ED>(
trigger: Trigger<ED, T>, operation: ED[T]['Operation']) {
return async (context: Context<ED>) => {
trigger: Trigger<ED, T, Cxt>, operation: ED[T]['Operation']) {
return async () => {
const context = this.contextBuilder();
await context.begin();
const number = await (trigger as CreateTrigger<ED, T>).fn({
const number = await (trigger as CreateTrigger<ED, T, Cxt>).fn({
operation: operation as DeduceCreateOperation<ED[T]['Schema']>,
}, context);
const { rowStore } = context;
if ((trigger as CreateTriggerCrossTxn<ED, T>).strict === 'makeSure') {
if ((trigger as CreateTriggerCrossTxn<ED, T, Cxt>).strict === 'makeSure') {
// 如果是必须完成的trigger在完成成功后要把trigger相关的属性置null;
let filter = {};
if (operation.action === 'create') {
@ -252,8 +255,8 @@ export class TriggerExecutor<ED extends EntityDict> extends Executor<ED> {
private async postCommitTrigger<T extends keyof ED>(
operation: ED[T]['Operation'],
trigger: Trigger<ED, T>,
context: Context<ED>
trigger: Trigger<ED, T, Cxt>,
context: Cxt
) {
context.on('commit', this.onCommit(trigger, operation));
}
@ -261,23 +264,23 @@ export class TriggerExecutor<ED extends EntityDict> extends Executor<ED> {
async postOperation<T extends keyof ED>(
entity: T,
operation: ED[T]['Operation'],
context: Context<ED>
context: Cxt
): Promise<void> {
const { action } = operation;
const triggers = this.triggerMap[entity] && this.triggerMap[entity]![action];
if (triggers) {
const postTriggers = triggers.filter(
ele => ele.when === 'after' && (!(ele as CreateTrigger<ED, T>).check || (ele as CreateTrigger<ED, T>).check!(operation as DeduceCreateOperation<ED[T]['Schema']>))
ele => ele.when === 'after' && (!(ele as CreateTrigger<ED, T, Cxt>).check || (ele as CreateTrigger<ED, T, Cxt>).check!(operation as DeduceCreateOperation<ED[T]['Schema']>))
);
for (const trigger of postTriggers) {
const number = await (trigger as CreateTrigger<ED, T>).fn({ operation: operation as DeduceCreateOperation<ED[T]['Schema']> }, context);
const number = await (trigger as CreateTrigger<ED, T, Cxt>).fn({ operation: operation as DeduceCreateOperation<ED[T]['Schema']> }, context);
if (number > 0) {
this.logger.info(`触发器「${trigger.name}」成功触发了「${number}」行数据更改`);
}
}
const commitTriggers = (<Array<CreateTrigger<ED, T>>>triggers).filter(
const commitTriggers = (<Array<CreateTrigger<ED, T, Cxt>>>triggers).filter(
ele => ele.when === 'commit' && (!ele.check || ele.check(operation as DeduceCreateOperation<ED[T]['Schema']>))
);
@ -287,7 +290,7 @@ export class TriggerExecutor<ED extends EntityDict> extends Executor<ED> {
}
}
async checkpoint(context: Context<ED>, timestamp: number): Promise<number> {
async checkpoint(context: Cxt, timestamp: number): Promise<number> {
let result = 0;
const { rowStore } = context;
for (const entity of this.volatileEntities) {
@ -306,7 +309,7 @@ export class TriggerExecutor<ED extends EntityDict> extends Executor<ED> {
const { $$triggerData$$ } = row;
const { name, operation } = $$triggerData$$!;
const trigger = this.triggerNameMap[name];
await this.onCommit(trigger, operation as ED[typeof entity]['Operation'])(context);
await this.onCommit(trigger, operation as ED[typeof entity]['Operation'])();
}
}

View File

@ -1,15 +1,15 @@
import { EntityDict, OpRecord, RowStore, TxnOption, Context } from "../types";
export class UniversalContext<ED extends EntityDict> implements Context<ED> {
rowStore: RowStore<ED>;
rowStore: RowStore<ED, this>;
uuid?: string;
opRecords: OpRecord<ED>[];
events: {
commit: Array<(context: UniversalContext<ED>) => Promise<void>>;
rollback: Array<(context: UniversalContext<ED>) => Promise<void>>;
commit: Array<() => Promise<void>>;
rollback: Array<() => Promise<void>>;
}
constructor(store: RowStore<ED>) {
constructor(store: RowStore<ED, UniversalContext<ED>>) {
this.rowStore = store;
this.opRecords = [];
this.events = {
@ -25,7 +25,7 @@ export class UniversalContext<ED extends EntityDict> implements Context<ED> {
};
}
on(event: 'commit' | 'rollback', callback: (context: UniversalContext<ED>) => Promise<void>): void {
on(event: 'commit' | 'rollback', callback: () => Promise<void>): void {
this.uuid && this.events[event].push(callback);
}
@ -36,27 +36,21 @@ export class UniversalContext<ED extends EntityDict> implements Context<ED> {
}
async commit(): Promise<void> {
if (this.uuid) {
/**
* todo by Xc
*/
for(const e of this.events.commit) {
await e(this);
}
await this.rowStore.commit(this.uuid!);
this.uuid = undefined;
for(const e of this.events.commit) {
await e();
}
this.resetEvents();
}
}
async rollback(): Promise<void> {
if(this.uuid) {
/**
* todo by Xc
*/
for(const e of this.events.rollback) {
await e(this);
}
await this.rowStore.rollback(this.uuid!);
this.uuid = undefined;
for(const e of this.events.rollback) {
await e();
}
this.resetEvents();
}
}

View File

@ -1,35 +1,23 @@
import { EntityDict } from "../types/Entity";
import { Context } from "./Context";
import { CreateTriggerBase, RemoveTriggerBase, UpdateTriggerBase } from "./Trigger";
export class AttrIllegalError extends Error {
private attributes: string[];
constructor(attributes: string[], message?: string) {
super(message);
this.attributes = attributes;
}
getAttributes() {
return this.attributes;
}
};
export type CreateChecker<ED extends EntityDict, T extends keyof ED> = {
export type CreateChecker<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = {
action: 'create';
entity: T;
checker: CreateTriggerBase<ED, T>['fn'],
checker: CreateTriggerBase<ED, T, Cxt>['fn'],
};
export type UpdateChecker<ED extends EntityDict, T extends keyof ED> = {
action: UpdateTriggerBase<ED, T>['action'];
export type UpdateChecker<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = {
action: UpdateTriggerBase<ED, T, Cxt>['action'];
entity: T;
checker: UpdateTriggerBase<ED, T>['fn'],
checker: UpdateTriggerBase<ED, T, Cxt>['fn'],
};
export type RemoveChecker<ED extends EntityDict, T extends keyof ED> = {
export type RemoveChecker<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = {
action: 'remove';
entity: T;
checker: RemoveTriggerBase<ED, T>['fn'],
checker: RemoveTriggerBase<ED, T, Cxt>['fn'],
};
export type Checker<ED extends EntityDict, T extends keyof ED> = CreateChecker<ED, T> | UpdateChecker<ED, T> | RemoveChecker<ED, T>;
export type Checker<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = CreateChecker<ED, T, Cxt> | UpdateChecker<ED, T, Cxt> | RemoveChecker<ED, T, Cxt>;

View File

@ -4,11 +4,11 @@ import { RowStore } from './RowStore';
export interface Context<ED extends EntityDict>{
opRecords: OpRecord<ED>[];
rowStore: RowStore<ED>;
rowStore: RowStore<ED, this>;
begin(options?: object): Promise<void>;
commit():Promise<void>;
rollback():Promise<void>;
getCurrentTxnId(): string | undefined;
on(event: 'commit' | 'rollback', callback: (context: Context<ED>) => Promise<void>): void;
on(event: 'commit' | 'rollback', callback: () => Promise<void>): void;
};

View File

@ -7,7 +7,7 @@ export type TxnOption = {
isolationLevel: 'repeatable read' | 'serializable';
};
export abstract class RowStore<ED extends EntityDict> {
export abstract class RowStore<ED extends EntityDict, Cxt extends Context<ED>> {
static $$LEVEL = 'store';
static $$CODES: OakErrorDefDict = {
primaryKeyConfilict: [1, '主键重复'],
@ -19,21 +19,21 @@ export abstract class RowStore<ED extends EntityDict> {
abstract operate<T extends keyof ED>(
entity: T,
operation: ED[T]['Operation'],
context: Context<ED>,
context: Cxt,
params?: OperateParams
): Promise<OperationResult>;
abstract select<T extends keyof ED, S extends ED[T]['Selection']> (
entity: T,
selection: S,
context: Context<ED>,
context: Cxt,
params?: Object
): Promise<SelectionResult<ED[T]['Schema'], S['data']>>;
abstract count<T extends keyof ED> (
entity: T,
selection: Omit<ED[T]['Selection'], 'data' | 'sorter' | 'action'>,
context: Context<ED>,
context: Cxt,
params?: Object
): Promise<number>;

View File

@ -3,7 +3,7 @@ import { DeduceCreateOperation, DeduceRemoveOperation, DeduceSelection, DeduceUp
import { EntityDef, EntityShape, OperationResult, SelectionResult, TriggerDataAttribute, TriggerTimestampAttribute } from "../types/Entity";
import { Context } from "./Context";
export interface CreateTriggerBase<ED extends EntityDict, T extends keyof ED> {
export interface CreateTriggerBase<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> {
entity: T;
name: string;
action: 'create',
@ -11,57 +11,57 @@ export interface CreateTriggerBase<ED extends EntityDict, T extends keyof ED> {
fn: (event: { operation: DeduceCreateOperation<ED[T]['Schema']>; }, context: Context<ED>, params?: Object) => Promise<number>;
};
export interface CreateTriggerInTxn<ED extends EntityDict, T extends keyof ED> extends CreateTriggerBase<ED, T> {
export interface CreateTriggerInTxn<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends CreateTriggerBase<ED, T, Cxt> {
when: 'before' | 'after',
};
export interface CreateTriggerCrossTxn<ED extends EntityDict, T extends keyof ED> extends CreateTriggerBase<ED, T> {
export interface CreateTriggerCrossTxn<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends CreateTriggerBase<ED, T, Cxt> {
when: 'commit',
strict?: 'takeEasy' | 'makeSure';
};
export type CreateTrigger<ED extends EntityDict, T extends keyof ED> = CreateTriggerInTxn<ED, T> | CreateTriggerCrossTxn<ED, T>;
export type CreateTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = CreateTriggerInTxn<ED, T, Cxt> | CreateTriggerCrossTxn<ED, T, Cxt>;
export interface UpdateTriggerBase<ED extends EntityDict, T extends keyof ED> {
export interface UpdateTriggerBase<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> {
entity: T;
name: string;
action: Exclude<ED[T]['Action'], GenericAction> | 'update' | Array<Exclude<ED[T]['Action'], GenericAction> | 'update'>,
attributes?: keyof ED[T]['OpSchema'] | Array<keyof ED[T]['OpSchema']>;
check?: (operation: DeduceUpdateOperation<ED[T]['Schema']>) => boolean;
fn: (event: { operation: DeduceUpdateOperation<ED[T]['Schema']> }, context: Context<ED>, params?: Object) => Promise<number>;
fn: (event: { operation: DeduceUpdateOperation<ED[T]['Schema']> }, context: Cxt, params?: Object) => Promise<number>;
};
export interface UpdateTriggerInTxn<ED extends EntityDict, T extends keyof ED> extends UpdateTriggerBase<ED, T> {
export interface UpdateTriggerInTxn<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends UpdateTriggerBase<ED, T, Cxt> {
when: 'before' | 'after',
};
export interface UpdateTriggerCrossTxn<ED extends EntityDict, T extends keyof ED> extends UpdateTriggerBase<ED, T> {
export interface UpdateTriggerCrossTxn<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends UpdateTriggerBase<ED, T, Cxt> {
when: 'commit',
strict?: 'takeEasy' | 'makeSure';
};
export type UpdateTrigger<ED extends EntityDict, T extends keyof ED> = UpdateTriggerInTxn<ED, T> | UpdateTriggerCrossTxn<ED, T>;
export type UpdateTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = UpdateTriggerInTxn<ED, T, Cxt> | UpdateTriggerCrossTxn<ED, T, Cxt>;
export interface RemoveTriggerBase<ED extends EntityDict, T extends keyof ED> {
export interface RemoveTriggerBase<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> {
entity: T;
name: string;
action: 'remove',
check?: (operation: DeduceRemoveOperation<ED[T]['Schema']>) => boolean;
fn: (event: { operation: DeduceRemoveOperation<ED[T]['Schema']> }, context: Context<ED>, params?: Object) => Promise<number>;
fn: (event: { operation: DeduceRemoveOperation<ED[T]['Schema']> }, context: Cxt, params?: Object) => Promise<number>;
};
export interface RemoveTriggerInTxn<ED extends EntityDict, T extends keyof ED> extends RemoveTriggerBase<ED, T> {
export interface RemoveTriggerInTxn<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends RemoveTriggerBase<ED, T, Cxt> {
when: 'before' | 'after',
};
export interface RemoveTriggerCrossTxn<ED extends EntityDict, T extends keyof ED> extends RemoveTriggerBase<ED, T> {
export interface RemoveTriggerCrossTxn<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends RemoveTriggerBase<ED, T, Cxt> {
when: 'commit',
strict?: 'takeEasy' | 'makeSure';
};
export type RemoveTrigger<ED extends EntityDict, T extends keyof ED> = RemoveTriggerInTxn<ED, T> | RemoveTriggerCrossTxn<ED, T>;
export type RemoveTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = RemoveTriggerInTxn<ED, T, Cxt> | RemoveTriggerCrossTxn<ED, T, Cxt>;
export interface SelectTriggerBase<ED extends EntityDict, T extends keyof ED> {
@ -74,22 +74,23 @@ export interface SelectTriggerBase<ED extends EntityDict, T extends keyof ED> {
* selection似乎不需要支持跨事务
* todo by Xc
*/
export interface SelectTriggerBefore<ED extends EntityDict, T extends keyof ED> extends SelectTriggerBase<ED, T> {
export interface SelectTriggerBefore<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends SelectTriggerBase<ED, T> {
when: 'before';
fn: (event: { operation: DeduceSelection<ED[T]['Schema']> }, context: Context<ED>, params?: Object) => Promise<number>;
fn: (event: { operation: DeduceSelection<ED[T]['Schema']> }, context: Cxt, params?: Object) => Promise<number>;
};
export interface SelectTriggerAfter<ED extends EntityDict, T extends keyof ED> extends SelectTriggerBase<ED, T> {
export interface SelectTriggerAfter<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> extends SelectTriggerBase<ED, T> {
when: 'after',
fn: <S extends ED[T]['Selection']>(event: {
operation: S;
result: SelectionResult<ED[T]['Schema'], S['data']>;
}, context: Context<ED>, params?: Object) => Promise<number>;
}, context: Cxt, params?: Object) => Promise<number>;
};
export type SelectTrigger<ED extends EntityDict, T extends keyof ED> = SelectTriggerBefore<ED, T> | SelectTriggerAfter<ED, T>;
export type SelectTrigger<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = SelectTriggerBefore<ED, T, Cxt> | SelectTriggerAfter<ED, T, Cxt>;
export type Trigger<ED extends EntityDict, T extends keyof ED> = CreateTrigger<ED, T> | UpdateTrigger<ED, T> | RemoveTrigger<ED, T> | SelectTrigger<ED, T>;
export type Trigger<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>> = CreateTrigger<ED, T, Cxt> | UpdateTrigger<ED, T, Cxt>
| RemoveTrigger<ED, T, Cxt> | SelectTrigger<ED, T, Cxt>;
export interface TriggerEntityShape extends EntityShape {
$$triggerData$$?: {
@ -99,23 +100,23 @@ export interface TriggerEntityShape extends EntityShape {
$$triggerTimestamp$$?: number;
};
export abstract class Executor<ED extends EntityDict> {
export abstract class Executor<ED extends EntityDict, Cxt extends Context<ED>> {
static dataAttr: TriggerDataAttribute = '$$triggerData$$';
static timestampAttr: TriggerTimestampAttribute = '$$triggerTimestamp$$';
abstract registerTrigger<T extends keyof ED>(trigger: Trigger<ED, T>): void;
abstract registerTrigger<T extends keyof ED>(trigger: Trigger<ED, T, Cxt>): void;
abstract preOperation<T extends keyof ED>(
entity: T,
operation: ED[T]['Operation'],
context: Context<ED>
context: Cxt
): Promise<void>;
abstract postOperation<T extends keyof ED>(
entity: T,
operation: ED[T]['Operation'],
context: Context<ED>
context: Cxt
): Promise<void>;
abstract checkpoint(context: Context<ED>, timestamp: number): Promise<number>; // 将所有在timestamp之前存在不一致的数据进行恢复
abstract checkpoint(context: Cxt, timestamp: number): Promise<number>; // 将所有在timestamp之前存在不一致的数据进行恢复
}

View File

@ -11,4 +11,5 @@ export * from './Logger';
export * from './Polyfill';
export * from './RowStore';
export * from './Storage';
export * from './Trigger';
export * from './Trigger';
export * from './Exception';