Skip to content

[Startup MVP recipes #5.2] A simple resource generated by nest-cli then configured (part 2)

Warning: we are using typeorm 0.3 and postgres for this tutorial

This tutorial continues where we left in

And let’s fill in the rest of generated boilerplate by nest-cli.

The Read of CRUD

Find queries are pretty straightforward:

// users.resolver.ts

@Query(() => [User], { name: 'users' })
async findAll(): Promise<User[]> {
  return this.usersService.findAll();
}

@Query(() => User, { name: 'user' })
async findOne(
  @Args('uuid', { type: () => String }) uuid: string,
): Promise<User> {
  return this.usersService.findOne(uuid);
}
TypeScript
// users.service.ts

async findAll() {
  return this.userRepo.find();
}

async findOne(uuid: string) {
  return this.userRepo.findOneBy({ uuid });
}
TypeScript

The Update of CRUD

Define update DTO first, note that it can leverage PartialType of the create DTO. For detailed tutorial of PartialType and OmitType check official doc at https://docs.nestjs.com/openapi/mapped-types

// update-user.input.ts

@InputType()
export default class UpdateUserInput extends PartialType(CreateUserInput) {
  @Field(() => String)
  uuid: string;
}
TypeScript

For update mutation, for a minimal version we can just return the count of affected rows:

// users.resolver.ts

@Mutation(() => Int)
async updateUser(
  @Args('updateUserInput') updateUserInput: UpdateUserInput,
): Promise<number> {
  return this.usersService.update(updateUserInput.uuid, updateUserInput);
}
TypeScript
// users.service.ts

async update(uuid: string, updateUserInput: UpdateUserInput) {
    return (await this.userRepo.update({ uuid }, updateUserInput)).affected;
}
TypeScript

Alternatively, we may want to return the updated User from the update mutation, the code may not look elegant but it works:

// users.service.ts

import * as _ from 'lodash';

async update(uuid: string, updateUserInput: UpdateUserInput) {
  const result = await this.userRepo
    .createQueryBuilder()
    .update(User)
    .set(updateUserInput)
    .where({ uuid })
    .returning('*')
    .execute();
  return result.raw[0]
    ? _.mapKeys(result.raw[0], (_v: any, k: any) => _.camelCase(k))
    : null;
 }
TypeScript

Since we are using snake case naming strategy for postgres to keep it consistent with postgres standard we need to map the object names back to camel case.

Here returning('*') enforces the user entity to be returned.

The Delete of CRUD

Similarly if we just want to return affected Rows count:

// users.resolver.ts

@Mutation(() => Int)
async removeUser(@Args('uuid', { type: () => String }) uuid: string) {
  return this.usersService.remove(uuid);
}
TypeScript
// users.service.ts

async remove(uuid: string) {
  return (await this.userRepo.delete(uuid)).affected;
}
TypeScript

To return the deleted users entities + affected rows count together we will have another in-depth tutorial on that in the future.

Leave a Reply

Your email address will not be published. Required fields are marked *