事务提交时的一些细节性处理
This commit is contained in:
parent
021774a154
commit
c5ee23175e
|
|
@ -748,11 +748,6 @@ function tryCopyPages(cwdPageDir, modulePageDir) {
|
|||
function tryCopyModuleTemplateFiles(cwd, dependencies, briefNames, printer) {
|
||||
const injectDataIndexFileDependencies = [];
|
||||
const injectDataIndexFileBriefNames = [];
|
||||
const webDir = join(cwd, 'web');
|
||||
if (!(0, fs_1.existsSync)(webDir)) {
|
||||
// 如果没有web目录,说明是module,不需要处理模块级别的文件注入
|
||||
return;
|
||||
}
|
||||
dependencies.forEach((dep, idx) => {
|
||||
const moduleDir = join(cwd, 'node_modules', dep);
|
||||
const moduleTemplateDir = join(moduleDir, 'template');
|
||||
|
|
@ -791,12 +786,47 @@ function tryCopyModuleTemplateFiles(cwd, dependencies, briefNames, printer) {
|
|||
injectDataIndexFile(join(cwd, 'src', 'data', 'index.ts'), injectDataIndexFileBriefNames, printer);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 对于module类型的项目,在feature/index.ts中注入initialize函数
|
||||
* @param cwd
|
||||
* @param dependencies
|
||||
* @param briefNames
|
||||
*/
|
||||
function injectInitializeToFeatureIndex(cwd, dependencies, briefNames, printer) {
|
||||
const featureIndexFile = join(cwd, 'src', 'features', 'index.ts');
|
||||
const sourceFile = ts.createSourceFile('index.ts', (0, fs_1.readFileSync)(featureIndexFile, 'utf-8'), ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
|
||||
const { statements } = sourceFile;
|
||||
const initializeStmt = statements.find((stmt) => ts.isFunctionDeclaration(stmt) && ts.isIdentifier(stmt.name) && stmt.name.text === 'initialize');
|
||||
if (!initializeStmt) {
|
||||
const statements2 = [
|
||||
...(dependencies.map((dep, idx) => factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, factory.createIdentifier("FeatureDict"), factory.createIdentifier(`${(0, string_1.firstLetterUpperCase)(briefNames[idx])}FeatureDict`))])), factory.createStringLiteral(dep), undefined))),
|
||||
...statements,
|
||||
factory.createFunctionDeclaration([
|
||||
factory.createToken(ts.SyntaxKind.ExportKeyword),
|
||||
factory.createToken(ts.SyntaxKind.AsyncKeyword)
|
||||
], undefined, factory.createIdentifier("initialize"), [
|
||||
factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("ED"), factory.createTypeReferenceNode(factory.createIdentifier("EntityDict"), undefined), undefined)
|
||||
], [
|
||||
factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier("features"), undefined, factory.createIntersectionTypeNode([
|
||||
factory.createTypeReferenceNode(factory.createIdentifier("FeatureDict"), [factory.createTypeReferenceNode(factory.createIdentifier("ED"), undefined)]),
|
||||
factory.createTypeReferenceNode(factory.createIdentifier("BasicFeatures"), [factory.createTypeReferenceNode(factory.createIdentifier("ED"), undefined)]),
|
||||
...briefNames.map((ele) => factory.createTypeReferenceNode(factory.createIdentifier(`${(0, string_1.firstLetterUpperCase)(ele)}FeatureDict`), [factory.createTypeReferenceNode(factory.createIdentifier("ED"), undefined)]))
|
||||
]), undefined)
|
||||
], undefined, factory.createBlock([], true))
|
||||
];
|
||||
const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(statements2), sourceFile);
|
||||
(0, fs_1.writeFileSync)(featureIndexFile, result, { flag: 'w' });
|
||||
console.log(`注入${featureIndexFile}文件成功,用户可以自己修正initialize函数的参数和逻辑`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 本函数用于构建src/initialize.dev, src/initialize.prod, src/initializeFeatures, src/context/FrontendContext, src/contextBackendContext
|
||||
* 这些和dependency相关的项目文件
|
||||
*/
|
||||
function buildDependency(rebuild) {
|
||||
const cwd = process.cwd();
|
||||
const webDir = join(cwd, 'web');
|
||||
const isModule = !(0, fs_1.existsSync)(webDir); // 如果没有web目录,说明是module,不需要处理模块级别的文件注入
|
||||
const depConfigFile = join(cwd, 'src', 'configuration', 'dependency.ts');
|
||||
if (!(0, fs_1.existsSync)(depConfigFile)) {
|
||||
console.error(`${depConfigFile}不存在,无法构建启动文件`);
|
||||
|
|
@ -816,26 +846,31 @@ function buildDependency(rebuild) {
|
|||
];
|
||||
const program = ts.createProgram(templateFileList, {});
|
||||
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
||||
const initDevFile = join(cwd, 'src', 'initialize.dev.ts');
|
||||
if ((0, fs_1.existsSync)(initDevFile) && !rebuild) {
|
||||
console.log(`[${initDevFile}]文件已经存在,无需构建启动文件`);
|
||||
if (!isModule) {
|
||||
const initDevFile = join(cwd, 'src', 'initialize.dev.ts');
|
||||
if ((0, fs_1.existsSync)(initDevFile) && !rebuild) {
|
||||
console.log(`[${initDevFile}]文件已经存在,无需构建启动文件`);
|
||||
}
|
||||
else {
|
||||
outputIntializeDev(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[0]), printer, initDevFile);
|
||||
}
|
||||
const initProdFile = join(cwd, 'src', 'initialize.prod.ts');
|
||||
if ((0, fs_1.existsSync)(initProdFile) && !rebuild) {
|
||||
console.log(`[${initProdFile}]文件已经存在,无需构建启动文件`);
|
||||
}
|
||||
else {
|
||||
outputIntializeProd(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[1]), printer, initProdFile);
|
||||
}
|
||||
const initFeaturesFile = join(cwd, 'src', 'initializeFeatures.ts');
|
||||
if ((0, fs_1.existsSync)(initFeaturesFile) && !rebuild) {
|
||||
console.log(`[${initFeaturesFile}]文件已经存在,无需构建启动文件`);
|
||||
}
|
||||
else {
|
||||
outputIntializeFeatures(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[2]), printer, initFeaturesFile);
|
||||
}
|
||||
}
|
||||
else {
|
||||
outputIntializeDev(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[0]), printer, initDevFile);
|
||||
}
|
||||
const initProdFile = join(cwd, 'src', 'initialize.prod.ts');
|
||||
if ((0, fs_1.existsSync)(initProdFile) && !rebuild) {
|
||||
console.log(`[${initProdFile}]文件已经存在,无需构建启动文件`);
|
||||
}
|
||||
else {
|
||||
outputIntializeProd(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[1]), printer, initProdFile);
|
||||
}
|
||||
const initFeaturesFile = join(cwd, 'src', 'initializeFeatures.ts');
|
||||
if ((0, fs_1.existsSync)(initFeaturesFile) && !rebuild) {
|
||||
console.log(`[${initFeaturesFile}]文件已经存在,无需构建启动文件`);
|
||||
}
|
||||
else {
|
||||
outputIntializeFeatures(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[2]), printer, initFeaturesFile);
|
||||
injectInitializeToFeatureIndex(cwd, dependencies, briefNames, printer);
|
||||
}
|
||||
const dependentContextFile = join(cwd, 'src', 'context', 'DependentContext.ts');
|
||||
if ((0, fs_1.existsSync)(dependentContextFile) && !rebuild) {
|
||||
|
|
@ -873,6 +908,8 @@ function buildDependency(rebuild) {
|
|||
outputFeatureIndex(dependencies, briefNames, program.getSourceFile(templateFileList[6]), printer, featureIndexFile);
|
||||
}
|
||||
// 把各个依赖项目的一些初始化的文件拷贝过去
|
||||
tryCopyModuleTemplateFiles(cwd, dependencies, briefNames, printer);
|
||||
if (!isModule) {
|
||||
tryCopyModuleTemplateFiles(cwd, dependencies, briefNames, printer);
|
||||
}
|
||||
}
|
||||
exports.default = buildDependency;
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ export declare abstract class AsyncContext<ED extends EntityDict> implements Con
|
|||
opResult: OperationResult<ED>;
|
||||
private message?;
|
||||
events: {
|
||||
commit: Array<() => Promise<void>>;
|
||||
rollback: Array<() => Promise<void>>;
|
||||
commit: Array<(records: OpRecord<ED>[], cxtStr: string) => Promise<void>>;
|
||||
rollback: Array<(records: OpRecord<ED>[], cxtStr: string) => Promise<void>>;
|
||||
};
|
||||
/**
|
||||
* 在返回结果前调用,对数据行进行一些预处理,比如将一些敏感的列隐藏
|
||||
|
|
@ -27,7 +27,7 @@ export declare abstract class AsyncContext<ED extends EntityDict> implements Con
|
|||
getScene(): string | undefined;
|
||||
setScene(scene?: string): void;
|
||||
private resetEvents;
|
||||
on(event: 'commit' | 'rollback', callback: () => Promise<void>): void;
|
||||
on(event: 'commit' | 'rollback', callback: (records: OpRecord<ED>[], cxtStr: string) => Promise<void>): void;
|
||||
saveOpRecord<T extends keyof ED>(entity: T, operation: ED[T]['Operation']): void;
|
||||
/**
|
||||
* 一个context中不应该有并发的事务,这里将事务串行化,使用的时候千万要注意不要自己等自己
|
||||
|
|
|
|||
|
|
@ -123,7 +123,8 @@ class AsyncContext {
|
|||
await e();
|
||||
} */
|
||||
// 提交时不能等在跨事务trigger上
|
||||
commitEvents.forEach(evt => evt());
|
||||
const cxtStr = await this.toString();
|
||||
commitEvents.forEach(evt => evt(this.opRecords, cxtStr));
|
||||
this.uuid = undefined;
|
||||
this.resetEvents();
|
||||
this.opRecords = [];
|
||||
|
|
@ -135,9 +136,9 @@ class AsyncContext {
|
|||
if (this.uuid) {
|
||||
await this.rowStore.rollback(this.uuid);
|
||||
const { rollback: rollbackEvents } = this.events;
|
||||
for (const e of rollbackEvents) {
|
||||
await e();
|
||||
}
|
||||
// 回退时不能等在跨事务trigger上
|
||||
const cxtStr = await this.toString();
|
||||
rollbackEvents.forEach(evt => evt(this.opRecords, cxtStr));
|
||||
this.uuid = undefined;
|
||||
this.opRecords = [];
|
||||
this.opResult = {};
|
||||
|
|
|
|||
|
|
@ -221,19 +221,22 @@ class TriggerExecutor {
|
|||
}
|
||||
}
|
||||
postCommitTrigger(entity, operation, trigger, context, option) {
|
||||
context.on('commit', async () => {
|
||||
context.on('commit', async (opRecords, cxtStr) => {
|
||||
let ids = [];
|
||||
let cxtStr = await context.toString();
|
||||
const { opRecords } = context;
|
||||
let cxtStr2 = cxtStr;
|
||||
const { data } = operation;
|
||||
if (operation.action === 'create') {
|
||||
if (data instanceof Array) {
|
||||
ids = data.map(ele => ele.id);
|
||||
cxtStr = data[0].$$triggerData$$?.cxtStr || await context.toString();
|
||||
if (data[0].$$triggerData$$?.cxtStr) {
|
||||
cxtStr2 = data[0].$$triggerData$$?.cxtStr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ids = [data.id];
|
||||
cxtStr = data.$$triggerData$$?.cxtStr || await context.toString();
|
||||
if (data.$$triggerData$$?.cxtStr) {
|
||||
cxtStr2 = data.$$triggerData$$?.cxtStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -242,7 +245,9 @@ class TriggerExecutor {
|
|||
* 若trigger是takeEasy,只会在事务提交时做一次,使用当前context应也无大问题
|
||||
* 暂时先这样设计,若当前提交事务中改变了cxt内容,也许会有问题。by Xc 20240319
|
||||
*/
|
||||
cxtStr = data.$$triggerData$$?.cxtStr || await context.toString();
|
||||
if (data.$$triggerData$$?.cxtStr) {
|
||||
cxtStr2 = data.$$triggerData$$?.cxtStr;
|
||||
}
|
||||
const record = opRecords.find(ele => ele.id === operation.id);
|
||||
// 目前框架在operation时,一定会将ids记录在operation当中(见CascadeStore中的doUpdateSingleRowAsync函数
|
||||
(0, assert_1.default)(record && record.a !== 'c');
|
||||
|
|
@ -250,7 +255,7 @@ class TriggerExecutor {
|
|||
ids = f.id.$in;
|
||||
}
|
||||
// 此时项目的上下文,和执行此trigger时的上下文可能不一致(rootMode),采用当时的上下文cxtStr来执行
|
||||
this.onVolatileTrigger(entity, trigger, ids, cxtStr, option);
|
||||
this.onVolatileTrigger(entity, trigger, ids, cxtStr2, option);
|
||||
});
|
||||
}
|
||||
preOperation(entity, operation, context, option) {
|
||||
|
|
|
|||
|
|
@ -1305,7 +1305,7 @@ function outputIntializeFeatures(
|
|||
function injectDataIndexFile(
|
||||
dataIndexFile: string,
|
||||
briefNames: string[],
|
||||
printer: ts.Printer,
|
||||
printer: ts.Printer
|
||||
) {
|
||||
const sourceFile = ts.createSourceFile('index.ts', readFileSync(dataIndexFile, 'utf-8'), ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
|
||||
|
||||
|
|
@ -1411,12 +1411,6 @@ function tryCopyModuleTemplateFiles(
|
|||
const injectDataIndexFileDependencies: string[] = [];
|
||||
const injectDataIndexFileBriefNames: string[] = [];
|
||||
|
||||
const webDir = join(cwd, 'web');
|
||||
if (!existsSync(webDir)) {
|
||||
// 如果没有web目录,说明是module,不需要处理模块级别的文件注入
|
||||
return;
|
||||
}
|
||||
|
||||
dependencies.forEach(
|
||||
(dep, idx) => {
|
||||
const moduleDir = join(cwd, 'node_modules', dep);
|
||||
|
|
@ -1463,6 +1457,121 @@ function tryCopyModuleTemplateFiles(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对于module类型的项目,在feature/index.ts中注入initialize函数
|
||||
* @param cwd
|
||||
* @param dependencies
|
||||
* @param briefNames
|
||||
*/
|
||||
function injectInitializeToFeatureIndex(
|
||||
cwd: string,
|
||||
dependencies: string[],
|
||||
briefNames: string[],
|
||||
printer: ts.Printer,
|
||||
) {
|
||||
const featureIndexFile = join(cwd, 'src', 'features', 'index.ts');
|
||||
|
||||
const sourceFile = ts.createSourceFile('index.ts', readFileSync(featureIndexFile, 'utf-8'), ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
|
||||
const { statements } = sourceFile;
|
||||
|
||||
const initializeStmt = statements.find(
|
||||
(stmt) => ts.isFunctionDeclaration(stmt) && ts.isIdentifier(stmt.name!) && stmt.name.text === 'initialize'
|
||||
);
|
||||
if (!initializeStmt) {
|
||||
const statements2 = [
|
||||
...(
|
||||
dependencies.map(
|
||||
(dep, idx) => factory.createImportDeclaration(
|
||||
undefined,
|
||||
factory.createImportClause(
|
||||
false,
|
||||
undefined,
|
||||
factory.createNamedImports(
|
||||
[factory.createImportSpecifier(
|
||||
false,
|
||||
factory.createIdentifier("FeatureDict"),
|
||||
factory.createIdentifier(`${firstLetterUpperCase(briefNames[idx])}FeatureDict`)
|
||||
)]
|
||||
)
|
||||
),
|
||||
factory.createStringLiteral(dep),
|
||||
undefined
|
||||
)
|
||||
|
||||
)
|
||||
),
|
||||
...statements,
|
||||
factory.createFunctionDeclaration(
|
||||
[
|
||||
factory.createToken(ts.SyntaxKind.ExportKeyword),
|
||||
factory.createToken(ts.SyntaxKind.AsyncKeyword)
|
||||
],
|
||||
undefined,
|
||||
factory.createIdentifier("initialize"),
|
||||
[
|
||||
factory.createTypeParameterDeclaration(
|
||||
undefined,
|
||||
factory.createIdentifier("ED"),
|
||||
factory.createTypeReferenceNode(
|
||||
factory.createIdentifier("EntityDict"),
|
||||
undefined
|
||||
),
|
||||
undefined
|
||||
)
|
||||
],
|
||||
[
|
||||
factory.createParameterDeclaration(
|
||||
undefined,
|
||||
undefined,
|
||||
factory.createIdentifier("features"),
|
||||
undefined,
|
||||
factory.createIntersectionTypeNode([
|
||||
factory.createTypeReferenceNode(
|
||||
factory.createIdentifier("FeatureDict"),
|
||||
[factory.createTypeReferenceNode(
|
||||
factory.createIdentifier("ED"),
|
||||
undefined
|
||||
)]
|
||||
),
|
||||
factory.createTypeReferenceNode(
|
||||
factory.createIdentifier("BasicFeatures"),
|
||||
[factory.createTypeReferenceNode(
|
||||
factory.createIdentifier("ED"),
|
||||
undefined
|
||||
)]
|
||||
),
|
||||
...briefNames.map(
|
||||
(ele) => factory.createTypeReferenceNode(
|
||||
factory.createIdentifier(`${firstLetterUpperCase(ele)}FeatureDict`),
|
||||
[factory.createTypeReferenceNode(
|
||||
factory.createIdentifier("ED"),
|
||||
undefined
|
||||
)]
|
||||
)
|
||||
)
|
||||
|
||||
]),
|
||||
undefined
|
||||
)
|
||||
],
|
||||
undefined,
|
||||
factory.createBlock(
|
||||
[],
|
||||
true
|
||||
)
|
||||
)
|
||||
];
|
||||
|
||||
const result = printer.printList(
|
||||
ts.ListFormat.SourceFileStatements,
|
||||
factory.createNodeArray(statements2),
|
||||
sourceFile);
|
||||
|
||||
writeFileSync(featureIndexFile, result, { flag: 'w' });
|
||||
console.log(`注入${featureIndexFile}文件成功,用户可以自己修正initialize函数的参数和逻辑`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 本函数用于构建src/initialize.dev, src/initialize.prod, src/initializeFeatures, src/context/FrontendContext, src/contextBackendContext
|
||||
* 这些和dependency相关的项目文件
|
||||
|
|
@ -1470,6 +1579,10 @@ function tryCopyModuleTemplateFiles(
|
|||
export default function buildDependency(rebuild?: boolean) {
|
||||
const cwd = process.cwd();
|
||||
|
||||
|
||||
const webDir = join(cwd, 'web');
|
||||
const isModule = !existsSync(webDir); // 如果没有web目录,说明是module,不需要处理模块级别的文件注入
|
||||
|
||||
const depConfigFile = join(cwd, 'src', 'configuration', 'dependency.ts');
|
||||
if (!existsSync(depConfigFile)) {
|
||||
console.error(`${depConfigFile}不存在,无法构建启动文件`);
|
||||
|
|
@ -1496,30 +1609,34 @@ export default function buildDependency(rebuild?: boolean) {
|
|||
const program = ts.createProgram(templateFileList, {});
|
||||
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
||||
|
||||
if (!isModule) {
|
||||
const initDevFile = join(cwd, 'src', 'initialize.dev.ts');
|
||||
if (existsSync(initDevFile) && !rebuild) {
|
||||
console.log(`[${initDevFile}]文件已经存在,无需构建启动文件`);
|
||||
}
|
||||
else {
|
||||
outputIntializeDev(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[0])!, printer, initDevFile);
|
||||
}
|
||||
|
||||
const initDevFile = join(cwd, 'src', 'initialize.dev.ts');
|
||||
if (existsSync(initDevFile) && !rebuild) {
|
||||
console.log(`[${initDevFile}]文件已经存在,无需构建启动文件`);
|
||||
const initProdFile = join(cwd, 'src', 'initialize.prod.ts');
|
||||
if (existsSync(initProdFile) && !rebuild) {
|
||||
console.log(`[${initProdFile}]文件已经存在,无需构建启动文件`);
|
||||
}
|
||||
else {
|
||||
outputIntializeProd(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[1])!, printer, initProdFile);
|
||||
}
|
||||
|
||||
|
||||
const initFeaturesFile = join(cwd, 'src', 'initializeFeatures.ts');
|
||||
if (existsSync(initFeaturesFile) && !rebuild) {
|
||||
console.log(`[${initFeaturesFile}]文件已经存在,无需构建启动文件`);
|
||||
}
|
||||
else {
|
||||
outputIntializeFeatures(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[2])!, printer, initFeaturesFile);
|
||||
}
|
||||
}
|
||||
else {
|
||||
outputIntializeDev(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[0])!, printer, initDevFile);
|
||||
}
|
||||
|
||||
const initProdFile = join(cwd, 'src', 'initialize.prod.ts');
|
||||
if (existsSync(initProdFile) && !rebuild) {
|
||||
console.log(`[${initProdFile}]文件已经存在,无需构建启动文件`);
|
||||
}
|
||||
else {
|
||||
outputIntializeProd(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[1])!, printer, initProdFile);
|
||||
}
|
||||
|
||||
|
||||
const initFeaturesFile = join(cwd, 'src', 'initializeFeatures.ts');
|
||||
if (existsSync(initFeaturesFile) && !rebuild) {
|
||||
console.log(`[${initFeaturesFile}]文件已经存在,无需构建启动文件`);
|
||||
}
|
||||
else {
|
||||
outputIntializeFeatures(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[2])!, printer, initFeaturesFile);
|
||||
injectInitializeToFeatureIndex(cwd, dependencies, briefNames, printer);
|
||||
}
|
||||
|
||||
const dependentContextFile = join(cwd, 'src', 'context', 'DependentContext.ts');
|
||||
|
|
@ -1563,5 +1680,7 @@ export default function buildDependency(rebuild?: boolean) {
|
|||
}
|
||||
|
||||
// 把各个依赖项目的一些初始化的文件拷贝过去
|
||||
tryCopyModuleTemplateFiles(cwd, dependencies, briefNames, printer);
|
||||
if (!isModule) {
|
||||
tryCopyModuleTemplateFiles(cwd, dependencies, briefNames, printer);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,8 +17,8 @@ export abstract class AsyncContext<ED extends EntityDict> implements Context {
|
|||
opResult: OperationResult<ED>;
|
||||
private message?: string;
|
||||
events: {
|
||||
commit: Array<() => Promise<void>>;
|
||||
rollback: Array<() => Promise<void>>;
|
||||
commit: Array<(records: OpRecord<ED>[], cxtStr: string) => Promise<void>>;
|
||||
rollback: Array<(records: OpRecord<ED>[], cxtStr: string) => Promise<void>>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -82,7 +82,7 @@ export abstract class AsyncContext<ED extends EntityDict> implements Context {
|
|||
};
|
||||
}
|
||||
|
||||
on(event: 'commit' | 'rollback', callback: () => Promise<void>): void {
|
||||
on(event: 'commit' | 'rollback', callback: (records: OpRecord<ED>[], cxtStr: string) => Promise<void>): void {
|
||||
this.uuid && this.events[event].push(callback);
|
||||
}
|
||||
|
||||
|
|
@ -141,8 +141,9 @@ export abstract class AsyncContext<ED extends EntityDict> implements Context {
|
|||
} */
|
||||
|
||||
// 提交时不能等在跨事务trigger上
|
||||
const cxtStr = await this.toString();
|
||||
commitEvents.forEach(
|
||||
evt => evt()
|
||||
evt => evt(this.opRecords, cxtStr)
|
||||
);
|
||||
this.uuid = undefined;
|
||||
this.resetEvents();
|
||||
|
|
@ -155,9 +156,12 @@ export abstract class AsyncContext<ED extends EntityDict> implements Context {
|
|||
if (this.uuid) {
|
||||
await this.rowStore.rollback(this.uuid!);
|
||||
const { rollback: rollbackEvents } = this.events;
|
||||
for (const e of rollbackEvents) {
|
||||
await e();
|
||||
}
|
||||
|
||||
// 回退时不能等在跨事务trigger上
|
||||
const cxtStr = await this.toString();
|
||||
rollbackEvents.forEach(
|
||||
evt => evt(this.opRecords, cxtStr)
|
||||
);
|
||||
this.uuid = undefined;
|
||||
this.opRecords = [];
|
||||
this.opResult = {};
|
||||
|
|
|
|||
|
|
@ -287,19 +287,22 @@ export class TriggerExecutor<ED extends EntityDict & BaseEntityDict, Cxt extends
|
|||
context: Cxt,
|
||||
option: OperateOption
|
||||
) {
|
||||
context.on('commit', async () => {
|
||||
context.on('commit', async (opRecords, cxtStr) => {
|
||||
let ids = [] as string[];
|
||||
let cxtStr = await context.toString();
|
||||
const { opRecords } = context;
|
||||
let cxtStr2 = cxtStr;
|
||||
const { data } = operation;
|
||||
if (operation.action === 'create') {
|
||||
if (data instanceof Array) {
|
||||
ids = data.map(ele => ele.id!);
|
||||
cxtStr = data[0].$$triggerData$$?.cxtStr || await context.toString();
|
||||
if (data[0].$$triggerData$$?.cxtStr) {
|
||||
cxtStr2 = data[0].$$triggerData$$?.cxtStr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ids = [data.id!];
|
||||
cxtStr = data.$$triggerData$$?.cxtStr || await context.toString();
|
||||
if (data.$$triggerData$$?.cxtStr) {
|
||||
cxtStr2 = data.$$triggerData$$?.cxtStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -308,7 +311,9 @@ export class TriggerExecutor<ED extends EntityDict & BaseEntityDict, Cxt extends
|
|||
* 若trigger是takeEasy,只会在事务提交时做一次,使用当前context应也无大问题
|
||||
* 暂时先这样设计,若当前提交事务中改变了cxt内容,也许会有问题。by Xc 20240319
|
||||
*/
|
||||
cxtStr = (<ED[T]['Update']['data']>data).$$triggerData$$?.cxtStr || await context.toString();
|
||||
if ((<ED[T]['Update']['data']>data).$$triggerData$$?.cxtStr) {
|
||||
cxtStr2 = (<ED[T]['Update']['data']>data).$$triggerData$$?.cxtStr;
|
||||
}
|
||||
const record = opRecords.find(
|
||||
ele => (ele as CreateOpResult<ED, keyof ED>).id === operation.id,
|
||||
);
|
||||
|
|
@ -318,7 +323,7 @@ export class TriggerExecutor<ED extends EntityDict & BaseEntityDict, Cxt extends
|
|||
ids = f!.id!.$in;
|
||||
}
|
||||
// 此时项目的上下文,和执行此trigger时的上下文可能不一致(rootMode),采用当时的上下文cxtStr来执行
|
||||
this.onVolatileTrigger(entity, trigger, ids, cxtStr, option);
|
||||
this.onVolatileTrigger(entity, trigger, ids, cxtStr2, option);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue