🔑Entity & 🗝️Repository를 생성해보고 연결해보자
- @ObjectType()은 GraphQl에서 자동으로 스키마를 빌드하기 위해 사용하는 GraphQl decorator이다.
import { Field, ObjectType } from '@nestjs/graphql'; @ObjectType() export class Restaurants { @Field((type) => String) name: string; @Field((type) => Boolean, { nullable: true }) isVegan?: boolean; @Field((type) => String) address: string; @Field((type) => String) ownerName: string; }
- @Entity()은 TypeORM이 DB에 저장해주도록 도와준다.
-@Entity()
@Column()
데코레이터를 활용하여 클래스 하나로 GraphQl 스키마와 DB에 저장되는 실제 데이터의 형식을 만들 수 있다.Restaurants.entity.ts
import { Field, ObjectType } from '@nestjs/graphql'; import { Column, Entity } from 'typeorm'; @ObjectType() @Entity() export class Restaurants { @PrimaryGeneratedColumn() @Field((type) => Number) id: number; @Field((type) => String) @Column() name: string; @Field((type) => Boolean, { nullable: true }) @Column() isVegan?: boolean; @Field((type) => String) @Column() address: string; @Field((type) => String) @Column() ownerName: string; }
- TypeORM에 만든 Entity가 어디 있는지 알려준다.
- TypeormModule에 넣는 entities에 배열로 Entity를 넣어준다.
app.module.ts
import { Module } from '@nestjs/common'; import * as Joi from 'joi'; // 자바스크립트 패키지는 타입스크립트로 만들어있지 않기때문에 import하는 방식이 다름 import { ConfigModule } from '@nestjs/config'; import { GraphQLModule } from '@nestjs/graphql'; import { TypeOrmModule } from '@nestjs/typeorm'; import { RestaurantsModule } from './restaurants/restaurants.module'; import { Restaurants } from './restaurants/entities/restaurants.entity'; @Module({ imports: [ TypeOrmModule.forRoot({ // TypeormModule에 Restaurants라는 entity를 가지면 Restaurant이 DB가된다. entities: [Restaurants], type: 'postgres', host: process.env.DB_HOST, port: +process.env.DB_PORT, username: process.env.DB_USERNAME, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, synchronize: process.env.NODE_ENV !== 'prod', // prod 아니면 synchronize가 true logging: true, }), , ], })
-GraphQl에서 사용하는 스키마를 자동으로 생성해주고 TypeOrmModule에서 imports하는 Entity로 인해 DB에 즉시 반영된다.
-TypeOrm을 이용, TypeOrmModule에 존재하는 Repository를 이용해서 DB에 있는 테이블에 접근하기
DB와 상호작용하는데 있어서 쓰는 패턴
1번. Active Record - 소규모 앱애서 단순하게 사용하기 좋다
TyeOrm에서 이 패턴을 사용하기 위해서는 Entity를 BaseEntity로 extends해줘야한다.import {BaseEntity, Entity, PrimaryGeneratedColumn, Column} from "typeorm"; @Entity() export class User extends BaseEntity { @PrimaryGeneratedColumn() id: number; @Column() firstName: string; @Column() lastName: string; @Column() isActive: boolean; } // example how to save AR entity const user = new User(); user.firstName = "Timber"; user.lastName = "Saw"; user.isActive = true; await user.save(); // example how to remove AR entity await user.remove(); // example how to load AR entities const users = await User.find({ skip: 2, take: 5 }); const newUsers = await User.find({ isActive: true }); const timber = await User.findOne({ firstName: "Timber", lastName: "Saw" });
2번. Data Mapper - 유지 관리하는 것을 도와주고 대규모 앱에서 유용한다.
Entity와 실제 상호작용을 담당하는 Repository가 필요하다
- Nest.js+TypeOrm 개발 환경에서는 Repository를 자동으로 사용해주는 클래스, 모듈을 쓸 수 있기에 Data Mapper 패턴을 사용한다,
- TypeOrm을 이용해서 Restaurants repository를 import한다.
- TypeOrmModule.forFeature에 배열 형태로 entity 클래스들을 넣기
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { Restaurants } from './entities/restaurants.entity'; import { RestaurantsResolver } from './restaurants.resovler'; import { RestaurantService } from './restaurants.service'; @Module({ imports: [TypeOrmModule.forFeature([Restaurants])], // forFeature을 활용하면 TypeOrmModule가 특정 feature(Restaurant entity)를 import할 수 있음 providers: [RestaurantsResolver, RestaurantService], }) export class RestaurantsModule {}
- RestaurantService에서 repository를 사용하기 위해선 RestaurantService에서 RestaurantsResolver에서 import하기
-주의) Restaurantservice가 providers에 추가 되어있어야한다.import { Args, Mutation, Query, Resolver } from '@nestjs/graphql'; import { CreateRestaurantDto } from 'src/dtos/create-restaurant.dto'; import { Restaurant } from './entities/restaurant.entity'; import { RestaurantService } from './restaurants.service'; @Resolver((of) => Restaurant) export class RestaurantsResolver { //Injectable 한 RestaurantService를 RestaurantResolver에서 import하기 constructor(private readonly restaurantService: RestaurantService) {} @Query((returns) => [Restaurant]) myRestaurant(): Promise<Restaurant[]> { //RestaurantService를 import하면 restaurantService 사용할 수 있음 return this.restaurantService.getAll(); } @Mutation((returns) => Boolean) createRestaurant(@Args() createRestaurantDto: CreateRestaurantDto): boolean { console.log(createRestaurantDto); return true; } }
- Injectable 데코레이터로 서비스를 파일을 만들어준다.
주의) RestaurantService에서 repository를 사용하기 위해서 service를 resolver에서 import 하고 있어야한다.- 그리고 module에서 import한 Restaurant entity의 repository를 inject한다.
- InjectRepository()안에 entity이름, Restaurant을 넣어서 호출한다.
- 이렇게하면 this.restaurants.하면 repository에 쓸 수 있는 모든 옵션들에 접근해 사용 할수 있다.
import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { In, Repository } from 'typeorm'; import { Restaurant } from './entities/restaurant.entity'; @Injectable() export class RestaurantService { // repository는 이름이 restaurants이며 Restaurant entity(class)의 Repository이다. constructor( @InjectRepository(Restaurant) private readonly restaurants: Repository<Restaurant>, ) {} getAll(): Restaurant[] { return this.restaurants.find() } }
- TypeORM(entity)를 graphQL의 ObjectType 옆에 쓰기만하면 DB에 모델을 생성하고 자동으로 graphQL에 스키마를 작성할 수 있고 graphQL 쿼리와 뮤테이션을 사용할 수 있는 resolver도 사용할 수 있다.
- 생성한 Repository는 service에 연결되며 이 service가 DB에 접근할 수 있다.
- 니꼴라스 쌤의 우버이츠 강의 중