Installations
npm install typeorm-transactional-cls-hooked
Releases
Unable to fetch releases
Developer
odavid
Developer Guide
Module System
CommonJS
Min. Node Version
>=8.0.0
Typescript Support
Yes
Node Version
12.22.1
NPM Version
6.14.12
Statistics
524 Stars
100 Commits
86 Forks
14 Watching
12 Branches
11 Contributors
Updated on 19 Nov 2024
Languages
TypeScript (99.69%)
JavaScript (0.31%)
Total Downloads
Cumulative downloads
Total Downloads
5,382,560
Last day
-4.6%
4,182
Compared to previous day
Last week
1%
20,990
Compared to previous week
Last month
30%
82,256
Compared to previous month
Last year
-28.6%
956,347
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
typeorm-transactional-cls-hooked
A Transactional
Method Decorator for typeorm that uses cls-hooked to handle and propagate transactions between different repositories and service methods.
Inspired by Spring Transactional Annotation and Sequelize CLS
See Changelog
Installation
1npm install --save typeorm-transactional-cls-hooked 2## Needed dependencies 3npm install --save typeorm reflect-metadata
Or
1yarn add typeorm-transactional-cls-hooked 2## Needed dependencies 3yarn add typeorm reflect-metadata
Note: You will need to import
reflect-metadata
somewhere in the global place of your app - https://github.com/typeorm/typeorm#installation
Initialization
In order to use it, you will first need to initialize the cls-hooked namespace before your application is started
1import { initializeTransactionalContext } from 'typeorm-transactional-cls-hooked'; 2 3initializeTransactionalContext() // Initialize cls-hooked 4... 5app = express() 6...
BaseRepository
Since this is an external library, all your typeorm repositories will need to be a custom repository extending either the BaseRepository
(when using TypeORM's Entity
) or the BaseTreeRepository
class (when using TypeORM's TreeEntity
).
1// Post.entity.ts 2@Entity() 3export class Post{ 4 @PrimaryGeneratedColumn() 5 id: number 6 7 @Column 8 message: string 9 ... 10} 11 12// Post.repository.ts 13import { EntityRepository } from 'typeorm'; 14import { BaseRepository } from 'typeorm-transactional-cls-hooked'; 15 16@EntityRepository(Post) 17export class PostRepository extends BaseRepository<Post> {}
The only purpose of the BaseRepository
class is to make sure the manager
property of the repository will always be the right one. In cases where inheritance is not possible, you can always Patch the Repository/TreeRepository to enable the same functionality as the BaseRepository
Patching TypeORM Repository
Sometimes there is a need to keep using the TypeORM Repository instead of using the BaseRepository
.
For this cases, you will need to "mixin/patch" the original Repository
with the BaseRepository
.
By doing so, you will be able to use the original Repository
and not change the code or use BaseRepository
.
This method was taken from https://gist.github.com/Diluka/87efbd9169cae96a012a43d1e5695667 (Thanks @Diluka)
In order to do that, the following should be done during initialization:
1import { initializeTransactionalContext, patchTypeORMRepositoryWithBaseRepository } from 'typeorm-transactional-cls-hooked'; 2 3initializeTransactionalContext() // Initialize cls-hooked 4patchTypeORMRepositoryWithBaseRepository() // patch Repository with BaseRepository.
If there is a need to keep using the TypeORM TreeRepository
instead of using BaseTreeRepository
, use patchTypeORMTreeRepositoryWithBaseTreeRepository
.
IMPORTANT NOTE
Calling initializeTransactionalContext and patchTypeORMRepositoryWithBaseRepository must happen BEFORE any application context is initialized!
Using Transactional Decorator
- Every service method that needs to be transactional, need to use the
@Transactional()
decorator - The decorator can take a
connectionName
as argument (by default it isdefault
)- In some cases, where the connectionName should be dynamically evaluated, the value of connectionName can be a function that returns a string.
- The decorator can take an optional
propagation
as argument to define the propagation behaviour - The decorator can take an optional
isolationLevel
as argument to define the isolation level (by default it will use your database driver's default isolation level.)
1export class PostService { 2 constructor(readonly repository: PostRepository) 3 4 @Transactional() // Will open a transaction if one doesn't already exist 5 async createPost(id, message): Promise<Post> { 6 const post = this.repository.create({ id, message }) 7 return this.repository.save(post) 8 } 9}
Transaction Propagation
The following propagation options can be specified:
MANDATORY
- Support a current transaction, throw an exception if none exists.NESTED
- Execute within a nested transaction if a current transaction exists, behave likeREQUIRED
else.NEVER
- Execute non-transactionally, throw an exception if a transaction exists.NOT_SUPPORTED
- Execute non-transactionally, suspend the current transaction if one exists.REQUIRED
(default behaviour) - Support a current transaction, create a new one if none exists.REQUIRES_NEW
- Create a new transaction, and suspend the current transaction if one exists.SUPPORTS
- Support a current transaction, execute non-transactionally if none exists.
Isolation Levels
The following isolation level options can be specified:
READ_UNCOMMITTED
- A constant indicating that dirty reads, non-repeatable reads and phantom reads can occur.READ_COMMITTED
- A constant indicating that dirty reads are prevented; non-repeatable reads and phantom reads can occur.REPEATABLE_READ
- A constant indicating that dirty reads and non-repeatable reads are prevented; phantom reads can occur.SERIALIZABLE
= A constant indicating that dirty reads, non-repeatable reads and phantom reads are prevented.
NOTE: If a transaction already exist and a method is decorated with @Transactional
and propagation
does not equal to REQUIRES_NEW
, then the declared isolationLevel
value will not be taken into account.
Hooks
Because you hand over control of the transaction creation to this library, there is no way for you to know whether or not the current transaction was sucessfully persisted to the database.
To circumvent that, we expose three helper methods that allow you to hook into the transaction lifecycle and take appropriate action after a commit/rollback.
runOnTransactionCommit(cb)
takes a callback to be executed after the current transaction was sucessfully committedrunOnTransactionRollback(cb)
takes a callback to be executed after the current transaction rolls back. The callback gets the error that initiated the roolback as a parameter.runOnTransactionComplete(cb)
takes a callback to be executed at the completion of the current transactional context. If there was an error, it gets passed as an argument.
1export class PostService { 2 constructor(readonly repository: PostRepository, readonly events: EventService) {} 3 4 @Transactional() 5 async createPost(id, message): Promise<Post> { 6 const post = this.repository.create({ id, message }) 7 const result = await this.repository.save(post) 8 runOnTransactionCommit(() => this.events.emit('post created')) 9 return result 10 } 11}
Unit Test Mocking
@Transactional
and BaseRepository
can be mocked to prevent running any of the transactional code in unit tests.
This can be accomplished in Jest with:
1jest.mock('typeorm-transactional-cls-hooked', () => ({ 2 Transactional: () => () => ({}), 3 BaseRepository: class {}, 4}));
Repositories, services, etc. can be mocked as usual.
Logging / Debug
The Transactional
uses the Typeorm Connection logger to emit log
messages.
In order to enable logs, you should set logging: ["log"]
or logging: ["all"]
to your typeorm logging configuration.
The Transactional log message structure looks as follows:
Transactional@UNIQ_ID|CONNECTION_NAME|METHOD_NAME|ISOLATION|PROPAGATION - MESSAGE
- UNIQ_ID - a timestamp taken at the begining of the Transactional call
- CONNECTION_NAME - The typeorm connection name passed to the Transactional decorator
- METHOD_NAME - The decorated method in action
- ISOLATION - The Isolation Level passed to the Transactional decorator
- PROPAGATION - The Propagation value passed to the Transactional decorator
During initialization and patching repositories, the Typeorm Connection logger is not available yet.
For this reason, the console.log()
is being used, but only if TRANSACTIONAL_CONSOLE_DEBUG
environment variable is defined.
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
- Info: project has a license file: LICENSE.txt:0
- Info: FSF or OSI recognized license: MIT License: LICENSE.txt:0
Reason
Found 3/27 approved changesets -- score normalized to 1
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Warn: no topLevel permission defined: .github/workflows/main.yml:1
- Info: no jobLevel write permissions found
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:7: update your workflow using https://app.stepsecurity.io/secureworkflow/odavid/typeorm-transactional-cls-hooked/main.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/odavid/typeorm-transactional-cls-hooked/main.yml/master?enable=pin
- Warn: npmCommand not pinned by hash: .github/workflows/main.yml:23
- Info: 0 out of 2 GitHub-owned GitHubAction dependencies pinned
- Info: 0 out of 1 npmCommand dependencies pinned
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 13 are checked with a SAST tool
Reason
34 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92
- Warn: Project is vulnerable to: GHSA-4jpv-8r57-pv7j
- Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw
- Warn: Project is vulnerable to: GHSA-cph5-m8f7-6c5x
- Warn: Project is vulnerable to: GHSA-wf5p-g6vw-rhxx
- Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg
- Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275
- Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq
- Warn: Project is vulnerable to: GHSA-74fj-2j2h-c42q
- Warn: Project is vulnerable to: GHSA-pw2r-vq6v-hr8c
- Warn: Project is vulnerable to: GHSA-jchw-25xp-jwwc
- Warn: Project is vulnerable to: GHSA-cxjh-pqwp-8mfp
- Warn: Project is vulnerable to: GHSA-896r-f27r-55mw
- Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h
- Warn: Project is vulnerable to: GHSA-5v2h-r2cx-5xgj
- Warn: Project is vulnerable to: GHSA-rrrm-qjm4-v8hf
- Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv
- Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3
- Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h
- Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g
- Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9
- Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j
- Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp
- Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6
- Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw
- Warn: Project is vulnerable to: GHSA-4rq4-32rv-6wp6
- Warn: Project is vulnerable to: GHSA-64g7-mvw6-v9qj
- Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v
- Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3
- Warn: Project is vulnerable to: GHSA-fx4w-v43j-vc45
- Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7
- Warn: Project is vulnerable to: GHSA-6fc8-4gx4-v693
- Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q
- Warn: Project is vulnerable to: GHSA-776f-qx25-q3cc
Score
2.9
/10
Last Scanned on 2024-11-18
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn MoreOther packages similar to typeorm-transactional-cls-hooked
typeorm-transactional
A Transactional Method Decorator for typeorm that uses cls-hooked to handle and propagate transactions between different repositories and service methods. Inpired by Spring Trasnactional Annotation and Sequelize CLS
typeorm-test-transactions
A transactional wrapper for tests that use TypeORM that automatically rolls back the transaction at the end of the test.
@types/cls-hooked
TypeScript definitions for cls-hooked
cls-hooked
CLS using AsynWrap instead of async-listener - Node >= 4.7.0