Repository pattern

Let's finally have real functionality in our service.

Now that we have a database set up and running and our entity integrated with it, let's have methods that actually interact with the database in the UsersService. We'll do this with the help of a TypeORM repository. After such we'll be able to:

  • Create a user

  • Find all users

  • Find one user

  • Update a user

  • Remove a user

Let's begin. To be able to inject a User repository in the UsersService, we first have to register the entity inside the TypeOrmModule, in the imports array of the UsersModule, like so

TypeOrmModule.forFeature([User])

We can now perform the repository injection in the UsersService. This can be done by defining a constructor and, inside it, performing the aforementioned process.

constructor(
  @InjectRepository(User)
  private readonly usersRepository: Repository<User>,
) {}

With this, let's implement each one of the CRUD methods.

  • create() - From the createUserDto, the repository creates a new user instance that is, after that, saved in the database.

create(createUserDto: CreateUserDto) {
  const user = this.usersRepository.create(createUserDto);
  return this.usersRepository.save(user);
}
  • findAll() - Here, the repository simply fetches all users from the database.

findAll() {
  return this.usersRepository.find();
}
  • findOne() - A user is searched by id and, if not found, an exception is thrown.

async findOne(id: number) {
  const user = await this.usersRepository.findOneBy({ id });
  if (!user) {
    throw new NotFoundException('User not found');
  }
  return user;
}
  • update() - Using the preload() method, a user will be searched by id. If found, it will have its fields updated according to the updateUserDto and, once again, be saved in the database. If not, an exception is thrown.

async update(id: number, updateUserDto: UpdateUserDto) {
  const user = await this.usersRepository.preload({
    id,
    ...updateUserDto,
  });
  if (!user) {
    throw new NotFoundException('User not found');
  }
  return this.usersRepository.save(user);
}
  • remove() - The findOne() method implemented previously will be used to find a user and, if found, it will be removed from the database. Remember that findOne() already throws an exception if the user is not found.

async remove(id: number) {
  const user = await this.findOne(id);
  return this.usersRepository.remove(user);
}

Some concerns related to exceptions:

  • User existence is being checked manually, which can become repetitive and error-prone

  • Some cases are left unchecked, like a user being created with an existing email

We'll learn how to solve both of these problems elegantly in the Extra module 2 - Exception filters.

Commit - Implementing user logic

Last updated