Gathering detailed insights and metrics for nest-transact
Gathering detailed insights and metrics for nest-transact
Gathering detailed insights and metrics for nest-transact
Gathering detailed insights and metrics for nest-transact
npm install nest-transact
Typescript
Module System
Node Version
NPM Version
TypeScript (94.93%)
Shell (3.08%)
JavaScript (1.9%)
Dockerfile (0.09%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
118 Stars
48 Commits
20 Forks
3 Watchers
8 Branches
3 Contributors
Updated on Jun 19, 2025
Latest Version
9.1.2
Package Id
nest-transact@9.1.2
Unpacked Size
181.25 kB
Size
59.25 kB
File Count
9
NPM Version
6.14.17
Node Version
14.20.0
Published on
Apr 25, 2023
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
1
5
The major version of this package will always match the major version of Nest.js, so if you see nest-transact v9.x.x
it means that this version of the package is compatible with Nest.js ^9.x.x
.
This package takes the use of transactions in Nest.js with TypeORM to the next level. The easiest and fastest way to keep your data intact.
Since v9.0.0
of @nestjs/typeorm
and v0.3.0
of typeorm
you can not create custom repositories with class style, like it showed below:
1/** 2 * Unfortunatelly, this is a deprecated method of creation of custom repositories, since typeorm ^0.3.0 was released 3 * For additional information see: https://github.com/typeorm/typeorm/pull/8616 4 * and https://typeorm.io/changelog under the 0.3.0 version changelog (search by "Old ways of custom repository creation were dropped.") 5 */ 6@EntityRepository(Purse) 7export class PurseRepository extends Repository<Purse> { 8 async findPurseById(purseId: number): Promise<Maybe<Purse>> { 9 return await this.findOne({ where: { id: purseId } }); 10 } 11}
Because of that your custom repositories, created in that way will be broken, if you update typeorm or will use @nestjs/typeorm v9.0.0
or newer. Also, that means that those repositories can't be used in transactions too.
The modern way to create a custom repo, by opinion of typeorm-developers should look like this:
1/**
2 * This is a new way (from typeorm creators -_-) for creation of custom repositories, which might be helpful
3 */
4export const NewPurseRepository = new DataSource(Config.typeOrmConfig as DataSourceOptions).getRepository(Purse).extend({
5 async findPurseById(purseId: number): Promise<Maybe<Purse>> {
6 return await this.findOne({ where: { id: purseId } });
7 },
8});
and here is an official example:
1export const UserRepository = myDataSource.getRepository(UserEntity).extend({ 2 findUsersWithPhotos() { 3 return this.find({ 4 relations: { 5 photos: true, 6 }, 7 }); 8 }, 9});
If you don't agree with that decision, please write your comment here.
1// ./example/src/transfer/transfer.controller.ts 2 3import { Body, Controller, Post } from '@nestjs/common'; 4import { ApiResponse, ApiTags } from '@nestjs/swagger'; 5import { TransferOperationResultDto } from './dto/transfer-operation-result.dto'; 6import { TransferParamsDTO } from './dto/transfer-params.dto'; 7import { TransferService } from './transfer.service'; 8import { DataSource } from 'typeorm'; 9 10@Controller('transfer') 11@ApiTags('transfer') 12export class TransferController { 13 constructor( 14 private readonly transferService: TransferService, 15 /** 16 * DataSource instance needed to us to start a transaction 17 */ 18 private readonly dataSource: DataSource, 19 ) { 20 } 21 22 @Post() 23 @ApiResponse({ 24 type: TransferOperationResultDto, 25 }) 26 async makeRemittanceWithTransaction(@Body() dto: TransferParamsDTO) { 27 return this.dataSource.transaction(manager => { 28 /** 29 * [withTransaction] - is the new method, which provided by [TransactionFor<T>] class 30 * and its allow us to start transaction with [transferService] and all its dependencies 31 */ 32 return this.transferService.withTransaction(manager).makeTransfer( 33 dto.userIdFrom, 34 dto.userIdTo, 35 dto.sum, 36 dto.withError, 37 ); 38 }); 39 } 40 41 @Post('without-transaction') 42 @ApiResponse({ 43 type: TransferOperationResultDto, 44 }) 45 async makeRemittanceWithoutTransaction(@Body() dto: TransferParamsDTO) { 46 return this.transferService.makeTransfer( 47 dto.userIdFrom, 48 dto.userIdTo, 49 dto.sum, 50 dto.withError, 51 ); 52 } 53}
All the services shown below will make database calls within a single transaction initiated by a controller method launched in a transaction - transferController.makeRemittanceWithTransaction
.
1// ./example/src/transfer/transfer.service.ts 2 3import { HttpException, Injectable } from '@nestjs/common'; 4import { ModuleRef } from '@nestjs/core'; 5import { TransactionFor } from 'nest-transact'; 6import { isNotDefined } from '../tools'; 7import { constants } from 'http2'; 8import { TransferOperationResultDto } from './dto/transfer-operation-result.dto'; 9import { UserService } from '../user/user.service'; 10import { PurseService } from './purse.service'; 11 12@Injectable() 13export class TransferService extends TransactionFor<TransferService> { 14 constructor( 15 /** 16 * All these services will be recreated and be a participants of the same transaction 17 */ 18 private readonly purseService: PurseService, 19 private readonly userService: UserService, 20 /** 21 * This is the needed thing for [TransactionFor<T>] logic working 22 */ 23 moduleRef: ModuleRef, 24 ) { 25 super(moduleRef); 26 } 27 28 async makeTransfer(fromId: number, toId: number, sum: number, withError = false): Promise<TransferOperationResultDto> { 29 if (fromId === toId) { 30 throw new HttpException('USERS MUST HAVE DIFFERENT IDS', 400); 31 } 32 const fromUser = await this.userService.findUserById(fromId); 33 const toUser = await this.userService.findUserById(toId); 34 if (isNotDefined(fromUser.defaultPurseId)) { 35 throw new HttpException(`USER "${fromId}" DON NOT HAVE A DEFAULT PURSE`, 500); 36 } 37 if (isNotDefined(toUser.defaultPurseId)) { 38 throw new HttpException(`USER "${toId}" DON NOT HAVE A DEFAULT PURSE`, 500); 39 } 40 const fromPurse = await this.purseService.findPurseById(fromUser.defaultPurseId); 41 const toPurse = await this.purseService.findPurseById(toUser.defaultPurseId); 42 const modalSum = Math.abs(sum); 43 if (fromPurse.balance < modalSum) { 44 throw new HttpException(`USER "${fromId}" NOT ENOUGH MONEY: "${fromPurse.balance} < ${modalSum}"`, 400); 45 } 46 fromPurse.balance -= sum; 47 toPurse.balance += sum; 48 await this.purseService.savePurse(fromPurse); 49 if (withError) { 50 throw new HttpException('UNEXPECTED ERROR WAS THROWN WHILE TRANSFER WAS IN PROGRESS', constants.HTTP_STATUS_TEAPOT); 51 } 52 await this.purseService.savePurse(toPurse); 53 return new TransferOperationResultDto({ 54 sum, 55 fromId, 56 toId, 57 fromBalance: fromPurse.balance, 58 toBalance: toPurse.balance, 59 }); 60 } 61}
1// ./example/src/transfer/purse.service.ts 2 3import { HttpException, Injectable } from '@nestjs/common'; 4import { isNotDefined } from '../tools'; 5import { Purse } from './model/purse.model'; 6import { Repository } from 'typeorm'; 7import { InjectRepository } from '@nestjs/typeorm'; 8 9@Injectable() 10export class PurseService { 11 constructor( 12 /** 13 * For now this is the only way to inject repositories into services without additional complex logic 14 * which needed for the new custom repository api from the typeorm creators 15 */ 16 @InjectRepository(Purse) 17 private readonly purePurseRepository: Repository<Purse>, 18 ) { 19 } 20 21 async findPurseById(purseId: number): Promise<Purse> { 22 const purse = await this.purePurseRepository.findOne({ where: { id: purseId } }); 23 if (isNotDefined(purse)) { 24 throw new HttpException(`NOT FOUND PURSE WITH ID "${purseId}"`, 404); 25 } 26 return purse; 27 } 28 29 async savePurse(purse: Purse): Promise<Purse> { 30 return this.purePurseRepository.save(purse); 31 } 32}
Also, you can pass some class-types into the .withTransaction(manager, { excluded: [...yourClasses] })
method to exclude them (and its dependencies) from the recreation flow. It can be, for example, some cache services, or anything, which you don't want to recreate and which is not a part of transaction logic:
1// ./example/src/transfer/info.controller.ts 2 3import { Controller, Get } from '@nestjs/common'; 4import { DataSource } from 'typeorm'; 5import { InfoService } from './info.service'; 6import { CacheService } from './cache.service'; 7 8@Controller('info') 9export class InfoController { 10 constructor( 11 private readonly infoService: InfoService, 12 private readonly dataSource: DataSource, 13 ) { 14 } 15 16 @Get() 17 async getInfo() { 18 return this.dataSource.transaction(manager => { 19 return this.infoService.withTransaction(manager, { excluded: [CacheService] }).getInfo(); 20 }); 21 } 22}
1// ./example/src/transfer/info.service.ts 2 3import { Injectable } from '@nestjs/common'; 4import { TransactionFor } from '../../../lib/with-transaction'; 5import { CacheService } from './cache.service'; 6import { ModuleRef } from '@nestjs/core'; 7 8@Injectable() 9export class InfoService extends TransactionFor<InfoService> { 10 constructor( 11 private readonly cacheService: CacheService, 12 moduleRef: ModuleRef, 13 ) { 14 super(moduleRef); 15 } 16 17 async getInfo() { 18 return []; 19 } 20}
Well, to use transactions with this package you must inject ModuleRef into your provider and extends your provider from the TransactionFor class.
Then in your controller you must create a transaction entity manager and inject this to your
providers with .withTransaction(manager)
method. This method will recreate you provider and all its dependencies and do what you want.
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
Found 4/18 approved changesets -- score normalized to 2
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
16 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-07-07
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 More