Mapped type

김민재·2021년 11월 28일
0

Nest.JS & graphQl

목록 보기
5/7

*🔐Study Keyword :

✅:Entity가 DB Table과 GraphQLType, DTO를 모두 만들어낼 수 있도록 하는 방법에 대해서

1. Mapped type

  • base type을 바탕으로 다른 버전들을 만들 수 있게 해준다.
  1. partial type - base class를 가져다가 모든 field가 required가 아닌 class를 만들어준다.
  2. pick type - input type에서 몇가지 특정 property를 선택해서 새로운 class를 만들어준다.
  3. omit type - base class에서 class를 만드는데 몇몇 field를 제외하고 만든다.
  4. intersection Type - 두 input을 합쳐주는 역할을 한다.

2. Mapped type을 활용하기

  • Parent type과 child type이 다른 경우
    옵션 1번. entity 파일에 @InputType({ isAbstract: true }) 추가하기
    옵션 2번. Mapped type()에 두번 째 인자로 InputType을 전달하기

1. 옵션 1번

dto/create-restaurant.dto.ts

import { ArgsType, Field, InputType, OmitType } from '@nestjs/graphql';
import { Restaurant } from 'src/restaurants/entities/restaurant.entity';
@InputType()
export class CreateRestaurantDto extends OmitType(
  Restaurant,
  ['id'],
  InputType,
    // Restaurant에 있는 ObjectType이므로 결과로 나오는 class도 ObjectType 되기 때문에 InputType을 적어준다.
) {
}

2. 옵션 2번

  • isAbstract란 어떤것으로 확장한다는 것을 의미,
    따라서 스키마에 해당 InputType이 포함되지 않게된다.

entities/restaurant.entity.ts

import { Field, InputType, ObjectType } from '@nestjs/graphql';
import { IsBoolean, IsOptional, IsString, Length } from 'class-validator';
import { Column, Entity, PrimaryColumn, PrimaryGeneratedColumn } from 'typeorm';
@InputType({ isAbstract: true })
@ObjectType()
@Entity()
export class Restaurant {
  @PrimaryGeneratedColumn()
  @Field((type) => Number)
  id: number;
  @Field((type) => String)
  @Column()
  @IsString()
  @Length(5)
  name: string;
  @Field((type) => Boolean, { defaultValue: true })
  @Column()
  @IsBoolean()
  @IsOptional()
  isVegan?: boolean;
  @Field((type) => String, { defaultValue: '강남' })
  @Column()
  @IsString()
  @Length(5)
  @IsOptional()
// 해당 필드를 보내거나 보내지 않아도 된다는 것을 의미
  address: string;
}

FiedOptions) defaultValue와 nullable 차이

  • defaultValue의 값을 설정하면 DB에 특정 필드의 값의 기본 값을 넣을 수 있게된다.
  • nullable은 nullable인지 아닌지만을 나타내므로 nullable을 true를 하고 데이터를 넣지 않으면 dto에 내용이 안들간다.

3. Update

  • update에는 id가 필요한데 하나의 DTO로 전달하는 방식에 대해서
  • UpdateRestaurantInputType을 만든다.
    - PartialType()을 extends하였으며 내부에 CreateRestaurantDto을 전달한다.
  • UpdateRestaurantDto를 만든다
    - Field에 리턴값으로 생성한 UpdateRestaurantInputType을 넣어준다.
    • data: UpdateRestaurantInputType을 넣어준다.

upate-restaurant.dto

import { ArgsType, Field, InputType, PartialType } from '@nestjs/graphql';
import { CreateRestaurantDto } from './create-restaurant.dto';
@InputType()
export class UpdateRestaurantInputType extends PartialType(
  CreateRestaurantDto,
) {}
@InputType()
export class UpdateRestaurantDto {
  @Field((type) => Number)
  id: number;
  @Field((type) => UpdateRestaurantInputType)
  data: UpdateRestaurantInputType;
}

주의) InputType VS ArgsType

  • InputType의 데코레이터를 넣으면 Args() 내부에 무조건 인자를 전달해야하며
  • ArgsType의 데로레이터는 Args() 내부에 전달하지 않아도 된다.

restaurants.service.ts

  • restaurants repository에 update method를 사용하여 업데이트 시켜준다.
    - update()에 인자로 업데이트 하고 싶은 entity의 field(Ex>id), 업데이트 하고 싶은 내용을 가진 object를 넣어준다.
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { CreateRestaurantDto } from 'src/dtos/create-restaurant.dto';
import { UpdateRestaurantDto } from 'src/dtos/update-restaurant.dto';
import { In, Repository } from 'typeorm';
import { Restaurant } from './entities/restaurant.entity';
@Injectable()
export class RestaurantService {
  constructor(
    @InjectRepository(Restaurant)
    private readonly restaurants: Repository<Restaurant>,
  ) {}
  updateRestaurant({ id, data }: UpdateRestaurantDto) {
    return this.restaurants.update(id, { ...data });
  }
}

restaurants.resolver.ts

  • restaurantService에서 만든 updateRestaurant()에 생성했던 updateRestaurantDto를 넣어준다.
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { create } from 'domain';
import { CreateRestaurantDto } from 'src/dtos/create-restaurant.dto';
import { UpdateRestaurantDto } from 'src/dtos/update-restaurant.dto';
import { Restaurant } from './entities/restaurant.entity';
import { RestaurantService } from './restaurants.service';
@Resolver((of) => Restaurant)
export class RestaurantsResolver {
  constructor(private readonly restaurantService: RestaurantService) {}
  @Mutation((returns) => Boolean)
  // resolver mutation에 어떤 레스토랑을 수정할 지 알려주기 위해 id를 보내야함
  async updateRestaurant(
    @Args('data') updateRestaurantDto: UpdateRestaurantDto,
  ): Promise<boolean> {
    try {
      await this.restaurantService.updateRestaurant(updateRestaurantDto);
      return true;
    } catch (error) {
      return false;
    }
  }
}

*💡conclusion

graphql, db, validation을 위해 3번씩 테스트하는 것에 익숙해지자

#📑Study Source

  • 니꼴라스 쌤 우버이츠 강의 중
profile
자기 신뢰의 힘을 믿고 실천하는 개발자가 되고자합니다.

0개의 댓글