I want to use Nestjs and Typeorm to manage transactions

139 views Asked by At

`Since I'm using a custom repository, my code looks like this

feed.repository.ts

import { FeedEntity } from '@/models/entities/feed.entity';
import { ICreateFeedArgs, IUpdateFeedArgs } from '@/types/args/feed';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { v4 as uuidv4 } from 'uuid';
import { FeedByIdResDto } from '../dto/feed/res/feed-by-id-res.dto';

@Injectable()
export class FeedsRepository extends Repository<FeedEntity> {
    constructor(
        @InjectRepository(FeedEntity)
        private readonly repository: Repository<FeedEntity>,
    ) {
        super(repository.target, repository.manager, repository.queryRunner);
    }

    
    ...

    async deleteFeed(feedId: string): Promise<boolean> {
        const { affected } = await this.delete({
            id: feedId,
        });

        return !!affected;
    }

        ...
    
}

feeds.module.ts

import { Module } from '@nestjs/common';
import { FeedsController } from './feeds.controller';
import { FeedsService } from './feeds.service';
import { FeedsRepository } from '@/models/repositories/feeds.repository';
import { TypeOrmModule } from '@nestjs/typeorm';
import { FeedEntity } from '@/models/entities/feed.entity';
import { MediasModule } from '../medias/medias.module';

@Module({
    imports: [TypeOrmModule.forFeature([FeedEntity]), MediasModule],
    controllers: [FeedsController],
    providers: [FeedsService, FeedsRepository],
    exports: [],
})
export class FeedsModule {}

feeds.service.ts

@Injectable()
export class FeedsService {
    constructor(
        private readonly feedsRepository: FeedsRepository,
        private readonly mediasService: MediasService,
        private dataSource: DataSource,
    ) {}

         ...

         async deleteFeed(feedId: string) {
        const queryRunner = this.dataSource.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction();

        try {
            

            const result = queryRunner.manager
                .withRepository(this.feedsRepository)
                .deleteFeed(feedId);

            await queryRunner.commitTransaction();
            
        } catch (error) {
            await queryRunner.rollbackTransaction();
            throw error;
        } finally {
            await queryRunner.release();
        }
    }

         ...
}

I realized that I needed withRepository to use a custom function in a custom repository with queryRunner, so I tried it, but I got the following error.

 | query: START TRANSACTION
 | query: COMMIT
 | 
 | /app/src/repository/Repository.ts:404
 |         return this.manager.delete(this.metadata.target as any, criteria as any)
 |                             ^
 | TypeError: Cannot read properties of undefined (reading 'delete')
 |     at FeedsRepository.delete (/app/src/repository/Repository.ts:404:29)
 |     at FeedsRepository.deleteFeed (/app/src/models/repositories/feeds.repository.ts:70:41)
 |     at FeedsService.deleteFeed (/app/src/api/feeds/feeds.service.ts:77:6)
 |     at processTicksAndRejections (node:internal/process/task_queues:95:5)
 |     at FeedsController.deleteFeed (/app/src/api/feeds/feeds.controller.ts:100:3)

Please help me, thank you!

no customrepository

    ...
@InjectRepository(FeedEntity)
private readonly feedRepository: Repository<FeedEntity>
    ...

console.log(queryRunner.manager.withRepository(this.feedRepository))

Repository {
     |   target: [class FeedEntity extends DefaultEntity],
     |   manager: <ref *1> EntityManager {
     |     '@instanceof': Symbol(EntityManager),
     |     repositories: Map(0) {},
     |     treeRepositories: [],
     |     plainObjectToEntityTransformer: PlainObjectToNewEntityTransformer {},
     |     connection: DataSource {
     |       '@instanceof': Symbol(DataSource),
     |       migrations: [],
     |       subscribers: [],
     |       entityMetadatas: [Array],
     |       entityMetadatasMap: [Map],
     |       name: 'default',
     |       options: [Object],
     |       logger: [AdvancedConsoleLogger],
     |       driver: [PostgresDriver],
     |       manager: [EntityManager],
     |       namingStrategy: [DefaultNamingStrategy],
     |       metadataTableName: 'typeorm_metadata',
     |       queryResultCache: undefined,
     |       relationLoader: [RelationLoader],
     |       relationIdLoader: [RelationIdLoader],
     |       isInitialized: true
     |     },
     |     queryRunner: PostgresQueryRunner {
     |       isReleased: false,
     |       isTransactionActive: true,
     |       data: {},
     |       loadedTables: [],
     |       loadedViews: [],
     |       sqlMemoryMode: false,
     |       sqlInMemory: [SqlInMemory],
     |       transactionDepth: 1,
     |       cachedTablePaths: {},
     |       driver: [PostgresDriver],
     |       connection: [DataSource],
     |       mode: 'master',
     |       broadcaster: [Broadcaster],
     |       manager: [Circular *1],
     |       databaseConnectionPromise: [Promise],
     |       databaseConnection: [Client],
     |       releaseCallback: [Function (anonymous)]
     |     }
     |   },
     |   queryRunner: undefined
     | }
     | query: COMMIT

customrepository

    ...
private readonly feedsRepository: FeedsRepository,
    ...

console.log(queryRunner.manager.withRepository(this.feedRepository))

query: START TRANSACTION
     | FeedsRepository {
     |   target: undefined,
     |   manager: undefined,
     |   queryRunner: undefined,
     |   repository: Repository {
     |     target: [class FeedEntity extends DefaultEntity],
     |     manager: EntityManager {
     |       '@instanceof': Symbol(EntityManager),
     |       repositories: [Map],
     |       treeRepositories: [],
     |       plainObjectToEntityTransformer: PlainObjectToNewEntityTransformer {},
     |       connection: [DataSource]
     |     },
     |     queryRunner: undefined
     |   }
     | }
     | query: COMMIT
0

There are 0 answers