-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: impl transaction decorator (#124)
--------- Co-authored-by: ximin.cxm <[email protected]>
- Loading branch information
Showing
13 changed files
with
292 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Change Log | ||
|
||
All notable changes to this project will be documented in this file. | ||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# @eggjs/tegg-transaction-decorator | ||
|
||
事务注解 | ||
|
||
## Usage | ||
```ts | ||
export class Foo { | ||
|
||
@Transactional({ propagation: PropagationType.ALWAYS_NEW }) | ||
async bar() { | ||
await this.foo(); | ||
} | ||
|
||
@Transactional({ propagation: PropagationType.REQUIRED }) | ||
async foo(msg) { | ||
console.log('has msg: ', msg); | ||
} | ||
|
||
} | ||
|
||
``` | ||
|
||
Foo.bar 始终会在一个独立的事务中执行,而 Foo.foo 会在 Foo.bar 的事务中执行 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export * from './src/decorator/Transactional'; | ||
export * from './src/Common'; | ||
export * from './src/model/TransactionMetadata'; | ||
export * from './src/builder/TransactionMetaBuilder'; | ||
export * from './src/util/TransactionMetadataUtil'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
{ | ||
"name": "@eggjs/tegg-transaction-decorator", | ||
"version": "3.9.0", | ||
"description": "tegg transaction decorator", | ||
"keywords": [ | ||
"egg", | ||
"typescript", | ||
"decorator", | ||
"transaction", | ||
"tegg" | ||
], | ||
"author": "qile222 <[email protected]>", | ||
"homepage": "https://github.com/eggjs/tegg", | ||
"repository": { | ||
"type": "git", | ||
"url": "[email protected]:eggjs/tegg.git", | ||
"directory": "core/transaction-decorator" | ||
}, | ||
"dependencies": { | ||
"@eggjs/core-decorator": "^3.8.0", | ||
"@eggjs/tegg-common-util": "^3.8.0", | ||
"@eggjs/tegg-metadata": "^3.8.0" | ||
}, | ||
"scripts": { | ||
"test": "cross-env NODE_ENV=test NODE_OPTIONS='--no-deprecation' mocha", | ||
"clean": "tsc -b --clean", | ||
"tsc": "npm run clean && tsc -p ./tsconfig.json", | ||
"tsc:pub": "npm run clean && tsc -p ./tsconfig.pub.json", | ||
"prepublishOnly": "npm run tsc:pub" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"engines": { | ||
"node": ">=14.0.0" | ||
}, | ||
"license": "MIT", | ||
"main": "dist/index.js", | ||
"files": [ | ||
"dist/**/*.js", | ||
"dist/**/*.d.ts" | ||
], | ||
"bugs": { | ||
"url": "https://github.com/eggjs/tegg/issues" | ||
}, | ||
"devDependencies": { | ||
"@types/mocha": "^10.0.1", | ||
"@types/node": "^20.2.4", | ||
"cross-env": "^7.0.3", | ||
"mocha": "^10.2.0", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^5.0.4" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
export enum PropagationType { | ||
/** 不管是当前调用栈是否存在事务,始终让当前函数在新的事务中执行 */ | ||
ALWAYS_NEW = 'ALWAYS_NEW', | ||
/** 如果当前调用栈存在事务则复用,否则创建一个 */ | ||
REQUIRED = 'REQUIRED', | ||
} | ||
|
||
export interface TransactionalParams { | ||
/** 事务传播方式,默认 REQUIRED */ | ||
propagation?: PropagationType; | ||
} |
18 changes: 18 additions & 0 deletions
18
core/transaction-decorator/src/builder/TransactionMetaBuilder.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { EggProtoImplClass } from '@eggjs/tegg'; | ||
import { TransactionMetadata } from '../model/TransactionMetadata'; | ||
import { TransactionMetadataUtil } from '../util/TransactionMetadataUtil'; | ||
|
||
export class TransactionMetaBuilder { | ||
private readonly clazz: EggProtoImplClass; | ||
|
||
constructor(clazz: EggProtoImplClass) { | ||
this.clazz = clazz; | ||
} | ||
|
||
build(): TransactionMetadata[] { | ||
if (!TransactionMetadataUtil.isTransactionClazz(this.clazz)) { | ||
return []; | ||
} | ||
return TransactionMetadataUtil.getTransactionMetadataList(this.clazz); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { EggProtoImplClass } from '@eggjs/tegg'; | ||
import { TransactionalParams, PropagationType } from '../Common'; | ||
import { TransactionMetadataUtil } from '../util/TransactionMetadataUtil'; | ||
|
||
export function Transactional(params?: TransactionalParams) { | ||
const propagation = params?.propagation || PropagationType.REQUIRED; | ||
if (!Object.values(PropagationType).includes(propagation)) { | ||
throw new Error(`unknown propagation type ${propagation}`); | ||
} | ||
|
||
return function(target: any, propertyKey: PropertyKey) { | ||
const constructor: EggProtoImplClass = target.constructor; | ||
TransactionMetadataUtil.setIsTransactionClazz(constructor); | ||
TransactionMetadataUtil.addTransactionMetadata(constructor, { | ||
propagation, | ||
method: propertyKey, | ||
}); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { PropagationType } from '../Common'; | ||
|
||
export interface TransactionMetadata { | ||
propagation: PropagationType; | ||
method: PropertyKey; | ||
} |
26 changes: 26 additions & 0 deletions
26
core/transaction-decorator/src/util/TransactionMetadataUtil.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { EggProtoImplClass, MetadataUtil } from '@eggjs/tegg'; | ||
import { TransactionMetadata } from '../model/TransactionMetadata'; | ||
|
||
export const TRANSACTION_META_DATA = Symbol.for('EggPrototype#transaction#metaData'); | ||
export const IS_TRANSACTION_CLAZZ = Symbol.for('EggPrototype#IS_TRANSACTION_CLAZZ'); | ||
|
||
export class TransactionMetadataUtil { | ||
|
||
static setIsTransactionClazz(clazz: EggProtoImplClass) { | ||
MetadataUtil.defineMetaData(IS_TRANSACTION_CLAZZ, true, clazz); | ||
} | ||
|
||
static isTransactionClazz(clazz: EggProtoImplClass): boolean { | ||
return MetadataUtil.getBooleanMetaData(IS_TRANSACTION_CLAZZ, clazz); | ||
} | ||
|
||
static addTransactionMetadata(clazz: EggProtoImplClass, data: TransactionMetadata) { | ||
const list = MetadataUtil.initOwnArrayMetaData<TransactionMetadata>(TRANSACTION_META_DATA, clazz, []); | ||
list.push(data); | ||
} | ||
|
||
static getTransactionMetadataList(clazz: EggProtoImplClass): TransactionMetadata[] { | ||
return MetadataUtil.getArrayMetaData<TransactionMetadata>(TRANSACTION_META_DATA, clazz); | ||
} | ||
|
||
} |
51 changes: 51 additions & 0 deletions
51
core/transaction-decorator/test/builder/TransactionMetaBuilder.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import assert from 'assert'; | ||
import { TransactionMetadataUtil } from '../../src/util/TransactionMetadataUtil'; | ||
import { TransactionMetaBuilder } from '../../src/builder/TransactionMetaBuilder'; | ||
import { PropagationType } from '../../src/Common'; | ||
import { Foo, Bar, FooBar, BarFoo } from '../fixtures/transaction'; | ||
import { Transactional } from '../../src/decorator/Transactional'; | ||
|
||
describe('test/builder/TransactionMetaBuilder.test.ts', () => { | ||
|
||
it('should build meta data success', () => { | ||
assert.ok(TransactionMetadataUtil.isTransactionClazz(Foo)); | ||
|
||
const fooBuilder = new TransactionMetaBuilder(Foo); | ||
assert.deepStrictEqual(fooBuilder.build(), [{ | ||
propagation: PropagationType.REQUIRED, | ||
method: 'defaultPropagation', | ||
}, { | ||
propagation: PropagationType.REQUIRED, | ||
method: 'requiredPropagation', | ||
}, { | ||
propagation: PropagationType.ALWAYS_NEW, | ||
method: 'alwaysNewPropagation', | ||
}]); | ||
|
||
assert.ok(TransactionMetadataUtil.isTransactionClazz(Bar)); | ||
const barBuilder = new TransactionMetaBuilder(Bar); | ||
assert.deepStrictEqual(barBuilder.build(), [{ | ||
propagation: PropagationType.REQUIRED, | ||
method: 'foo', | ||
}, { | ||
propagation: PropagationType.ALWAYS_NEW, | ||
method: 'bar', | ||
}]); | ||
|
||
assert.ok(TransactionMetadataUtil.isTransactionClazz(FooBar)); | ||
const fooBarBuilder = new TransactionMetaBuilder(FooBar); | ||
assert.deepStrictEqual(fooBarBuilder.build(), [{ | ||
propagation: PropagationType.ALWAYS_NEW, | ||
method: 'foo', | ||
}]); | ||
|
||
const barFooBuilder = new TransactionMetaBuilder(BarFoo); | ||
assert.ok(!TransactionMetadataUtil.isTransactionClazz(BarFoo)); | ||
assert.deepStrictEqual(barFooBuilder.build(), []); | ||
|
||
assert.throws(() => { | ||
Transactional({ propagation: 'xx' as PropagationType }); | ||
}, new Error('unknown propagation type xx')); | ||
}); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { Transactional } from '../../src/decorator/Transactional'; | ||
import { PropagationType } from '../../src/Common'; | ||
|
||
export class Foo { | ||
|
||
@Transactional() | ||
async defaultPropagation(msg) { | ||
console.log('msg: ', msg); | ||
} | ||
|
||
@Transactional({}) | ||
async requiredPropagation(msg) { | ||
console.log('msg: ', msg); | ||
} | ||
|
||
@Transactional({ propagation: PropagationType.ALWAYS_NEW }) | ||
async alwaysNewPropagation(msg) { | ||
console.log('msg: ', msg); | ||
} | ||
|
||
} | ||
|
||
export class Bar { | ||
|
||
@Transactional() | ||
async foo(msg) { | ||
console.log('msg: ', msg); | ||
} | ||
|
||
@Transactional({ propagation: PropagationType.ALWAYS_NEW }) | ||
async bar(msg) { | ||
console.log('msg: ', msg); | ||
} | ||
|
||
} | ||
|
||
export class FooBar { | ||
|
||
@Transactional({ propagation: PropagationType.ALWAYS_NEW }) | ||
async foo(msg) { | ||
console.log('msg: ', msg); | ||
} | ||
|
||
} | ||
|
||
export class BarFoo { | ||
|
||
async foo(msg) { | ||
console.log('msg: ', msg); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"extends": "../../tsconfig.json", | ||
"compilerOptions": { | ||
"outDir": "dist", | ||
"baseUrl": "./" | ||
}, | ||
"exclude": [ | ||
"dist", | ||
"node_modules" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"extends": "../../tsconfig.json", | ||
"compilerOptions": { | ||
"outDir": "dist", | ||
"baseUrl": "./" | ||
}, | ||
"exclude": [ | ||
"dist", | ||
"node_modules", | ||
"test" | ||
] | ||
} |