skip to Main Content

I have a question. With @EntityRepository decorator being marked as deprecated in typeorm@^0.3.6, what is now the recommended or TypeScript-friendly way to create a custom repository for an entity in NestJS? A custom repository before would look like this:

// users.repository.ts
import { EntityRepository, Repository } from 'typeorm';
import { User } from './user.entity';

@EntityRepository(User)
export class UsersRepository extends Repository<User> {
  async createUser(firstName: string, lastName: string): Promise<User> {
    const user = this.create({
      firstName,
      lastName,
    });

    await this.save(user);

    return user;
  }
}

And since NestJS is by default configured with TypeScript support, I will be able to call usersRepository.createUser() without an issue in a service like this:

// users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UsersRepository } from './users.repository';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(UsersRepository)
    private readonly usersRepository: UsersRepository,
  ) {}

  async createUser(firstName: string, lastName: string): Promise<User> {
    return this.usersRepository.createUser(firstName, lastName);
  }
}

This is how the modules would import the custom repository:

// users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersController } from './users.controller';
import { UsersRepository } from './users.repository';
import { UsersService } from './users.service';

@Module({
  imports: [TypeOrmModule.forFeature([UsersRepository])],
  controllers: [UsersController],
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}

Also the reason why I mentioned MongoDB here is because I tried using [email protected] where @EntityRepository is still supported but I receive an error when I tried to import it in the module stating Repository not found or something. Do note, if I chose postgresql as my database in TypeORM with the same changes above, I don’t have this issue. Hence I went to check the latest only to find out it is already deprecated, I also didn’t find any example in NestJS documentation.

3

Answers


  1. The way you can create a custom repository for mongo in TypeORM it with the following way:

    users.repository.ts

    Here instead of using @EntityRepository you will use the @Injectable decorator, and for inject, the schema will use MongoRepository

    // users.repository.ts
    import { Injectable } from '@nestjs/common';
    import { InjectRepository } from '@nestjs/typeorm';
    import { MongoRepository } from 'typeorm';
    import { User } from './user.entity';
    @Injectable()
    export class UsersRepository {
      constructor(
        @InjectRepository(User)
        private readonly usersRepository: MongoRepository<User>,
      ) {}
    
      async createUser(firstName: string, lastName: string): Promise<User> {
        const user = new User({
          firstName,
          lastName,
        });
    
        await this.usersRepository.save(user);
    
        return user;
      }
      
    
       //write other helpful methods here(find, delete, etc...)
    
    
    }
    

    users.service.ts

    import { Injectable } from '@nestjs/common';
    import { InjectRepository } from '@nestjs/typeorm';
    import { User } from './user.entity';
    import { UsersRepository } from './users.repository';
    
    @Injectable()
    export class UsersService {
      constructor(private readonly usersRepository: UsersRepository) {}
    
      async createUser(firstName: string, lastName: string): Promise<User> {
        return this.usersRepository.createUser(firstName, lastName);
      }
    }
    

    users.module.ts

    import { Module } from '@nestjs/common';
    import { TypeOrmModule } from '@nestjs/typeorm';
    import { UsersController } from './users.controller';
    import { UsersRepository } from './users.repository';
    import { UsersService } from './users.service';
    import { User } from './user.entity';
    import { UsersRepository } from './database/repository/UsersRepository';
    @Module({
      imports: [TypeOrmModule.forFeature([User])],
      controllers: [UsersController],
      providers: [UsersRepository, UsersService],
      exports: [UsersService],
    })
    export class UsersModule {}
    
    Login or Signup to reply.
  2. I think I found a solution to this which allows to call custom methods but also inherited ones. It seems that this "issue" is not too popular yet but there is definitely some chatter about it within the typeorm GitHub threads: https://github.com/typeorm/typeorm/issues/9013

    The following solution uses MySQL as underlying database driver but I assume it will work for MongoDB as well.

    team.repository.ts

    import {DataSource, Repository} from 'typeorm';
    import {Injectable} from '@nestjs/common';
    import {Team} from '@Domain/Team/Models/team.entity';
    
    @Injectable()
    export class TeamRepository extends Repository<Team>
    {
        constructor(private dataSource: DataSource)
        {
            super(Team, dataSource.createEntityManager());
        }
    
        /**
         * Add a basic where clause to the query and return the first result.
         */
        async firstWhere(column: string, value: string | number, operator = '='): Promise<Team | undefined>
        {
            return await this.createQueryBuilder()
                             .where(`Team.${column} ${operator} :value`, {value: value})
                             .getOne();
        }
    }
    
    

    team.service.ts

    import {Injectable} from '@nestjs/common';
    import {Team} from '@Domain/Team/Models/team.entity';
    import {TeamRepository} from '@Domain/Team/Repositories/team.repository';
    
    @Injectable()
    export class TeamService
    {
        constructor(
            private teamRepository: TeamRepository,
        )
        {
        }
    
        async create(): Promise<Team>
        {
            const team: Team = await this.teamRepository.firstWhere('id', 1);
    
            return this.teamRepository.save(team);
        }
    }
    

    team.module.ts

    import {Module} from '@nestjs/common';
    import {TeamService} from '@Domain/Team/Services/team.service';
    import {TypeOrmModule} from '@nestjs/typeorm';
    import {Team} from '@Domain/Team/Models/team.entity';
    import {TeamRepository} from '@Domain/Team/Repositories/team.repository';
    
    @Module({
                imports:   [TypeOrmModule.forFeature([Team])],
                exports:   [TeamService],
                providers: [TeamService, TeamRepository],
            })
    export class TeamModule
    {
    }
    
    Login or Signup to reply.
  3. // task.entity.ts
    import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
    
    @Entity()
    export class Task {
      @PrimaryGeneratedColumn('uuid')
      id: string;
    
      @Column()
      title: string;
    
      @Column()
      description: string;
    }
    
    // tasks.repository.ts
    import { Injectable } from '@nestjs/common';
    import { DataSource, Repository } from 'typeorm';
    import { Task } from './tast.entity';
    
    @Injectable()
    export class TasksRepository extends Repository<Task> {
      constructor(dataSource: DataSource) {
        super(Task, dataSource.createEntityManager());
      }
    }
    
    //tasks.module.ts
    import { Module } from '@nestjs/common';
    import { TypeOrmModule } from '@nestjs/typeorm';
    import { TasksController } from './tasks.controller';
    import { TasksService } from './tasks.service';
    import { Task } from './tast.entity';
    
    @Module({
      imports: [TypeOrmModule.forFeature([Task])], // NOTICE: HERE
      controllers: [TasksController], // NOTICE: HERE
      providers: [TasksService],
    })
    export class TasksModule {}
    
    @Injectable()
    export class TasksService {
      constructor(
        @InjectRepository(Task) // NOTICE: here
        private readonly tasksRepository: TasksRepository,
      ) {}
    
      async getTaskById(id: string): Promise<Task> {
        const task = this.tasksRepository.findOne({
          where: {
            id,
          },
        });
    
        if (!task) {
          throw new NotFoundException(`Task with id ${id} not found`);
        }
    
        return task;
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search