Backend/Node.js (NestJS)


지금까지 TypeORM을 통해서 데이터베이스 연동하는 것을 다루면서 많은 기능들을 포스팅했었는데, 그 외에 알아두면 좋을 법한 기능과 데코레이더들 몇가지 소개하려고 한다. VIEW Table import { ViewColumn, ViewEntity } from 'typeorm'; @ViewEntity({ expression: ` SELECT p.id, p.name, p.description, p.price, pc.name as categoryName from product p left join product_category pc on p.productCategoryId = pc.id `, }) export class ProductView { @ViewColumn() id: number; @ViewColu..


이번엔 TypeORM에서의 트랜잭션 적용을 해보겠다. 트랜잭션 (Transaction) 하나의 로직을 처리하는 SQL 질의들을 집합으로 묶어, 도중에 예외가 발생할 경우 Rollback 처리를, 모두 성공할 경우 Commit 처리하는 실행 단위이다. 쇼핑몰에서 주문할 때의 과정을 생각해보자. (주문 요청 -> 결제 처리 -> 성공 시 주문 완료 데이터 저장) 만약에 다음 과정에서 결제는 완료되었는데 주문이 들어가지 않았다면 사용자 입장에서는 어이가 없을 것이다. 또 결제 처리는 실패되었는데 주문 완료 데이터는 저장되어있다면 해당 데이터베이스는 더이상 믿을 수 없게 된다. 즉, 성공하려면 모두 성공하고, 실패하려면 모두 실패해야 한다. 자세한 내용은 해당 포스팅을 참고해도 좋을 것 같다. https://s..


이전 포스팅에서 TypeORM을 이용해 관련 테이블들을 외래키 연결 및 생성하는 코드를 작성해보았다. 이번에는 SQL의 Join에 해당하는 TypeORM 질의를 작성해보려고 한다. Relations const result = await this.productRepository.find({ relations: ['productCategory', 'productTags'], }); 단순하게 Left Join하여 모든 컬럼들을 가져오려면 relations를 작성해주면 된다. 인수로는 Join하려는 모든 릴레이션 테이블들을 리스트로 작성한다. SELECT `Product`.`id` AS `Product_id`, `Product`.`name` AS `Product_name`, `Product`.`descripti..


이전 포스팅에서는 단일 테이블의 Select, Insert, Update, Delete에 대해서 다루어 보았었는데 이번에는 Insert와 Update 시 관계 테이블 외래키와 데이터를 포함하여 TypeORM으로 작성하는 방법을 알아보도록 하겠다. DTO 이번에는 상품을 등록할 때 함께 상품 거래 장소에 대한 정보, 이미 등록되어 있던 카테고리 ID, 등록할 해쉬태그들을 같이 Insert 할 것이다. 클라이언트로부터 관계 테이블들의 데이터를 받기 위해서 DTO를 수정하도록 하겠다. ▶ createProduct.dto.ts export class CreateProductInput { @IsString() name: string; @IsString() description: string; @IsInt() @M..


CRUD중 마지막인 Select를 TypeORM을 이용하여 작성해보려고 한다. find() : 엔티티 리스트 선택 ▶ products.service.ts async findAll(): Promise { const result = await this.productRepository.find({}); return result; } find(옵션들..) 메서드는 엔티티 모델 리스트들 반환한다. 옵션이 없다면 해당 테이블을 전체 선택한다. findOne() : 단일 엔티티 선택 ▶ products.service.ts async findOne(id: number): Promise { const result = await this.productRepository.findOne({ where: { id: id }, ..


바로 이어서 데이터베이스에서 로우를 삭제하고, 선택해보는 것까지 알아보자! Delete remove() ▶ products.service.ts async remove(id: number): Promise { const product = await this.productRepository.findOne({ where: { id: id }, }); const result = await this.productRepository.remove(product) return result } remove(삭제할 모델)는 데이터베이스 테이블에서 인수로 전달받은 모델과 일치하는 로우를 삭제한다. 해당 메서드는 삭제한 엔터티 모델을 반환한다. delete() ▶ products.service.ts async delete(i..


이제 앞서 만든 REST API를 데이터베이스와 연동해보도록 하자. 우선 1차 목표는 다른 테이블과의 연관에 상관없이 TypeORM을 이용해서 Product에 데이터를 삽입하고, 업데이트 해보는 과정을 해보겠다. Controller ▶ products.controller.ts @Controller('product') export class ProductsController { constructor(private readonly productService: ProductsService) {} @Post() createProduct(@Body() input: CreateProductInput): Promise { return this.productService.create(input); } @Put(':id..


이번 포스팅에서는 앞서 만든 REST API를 데이터베이스와 연동하기 이전에 Pipe의 개념과 클래스의 값 유효성을 검증하는 Class-Validator에 대해 간단히 포스팅하고 넘어가려고 한다. Pipe @Injectable 데코레이터에 의해 사용되는 Providers에 속하는 클래스 클라이언트의 요청 데이터 인수를 Route Handler에서 작업하기 이전에 사전에 처리해주는 역할을 한다. 파이프를 사용 시 데이터를 사용 가능한지 판별하거나 사용하기 적절하게 가공하는 과정을 거치며, 해당 과정을 통과해야 라우터에 도달하게 된다. 요청값을 원하는 형식으로 바꿔주는 Data Transformation과, 입력값의 자료형 등의 유효성을 판별하는 Data Validation의 역할을 수행한다. Validat..


이전 포스팅에서 ORM을 통해서 데이터베이스의 테이블을 생성해 보았는데, 이번에는 TypeORM을 통해 테이블 간의 관계 설정하는 방법을 포스팅하려고 한다. 데이터베이스 관계 데이터베이스의 관계는 Foreign Key(외래키)를 통해 형성되며, 종류는 크게 세가지로 나뉜다. 1 : 1 관계 중고마켓에서 사용자가 상품을 등록할 때 거래 장소를 입력하게 된다. 상품은 단 하나의 상품거래 위치를 가지게 되며, 상품거래 위치 또한 하나의 상품과만 관계를 가지게 되므로 1:1 관계이다. N : 1 관계 중고마켓에서 사용자가 상품을 등록할 때 노출될 카테고리 위치 하나를 선택하게 된다. 상품은 한개의 카테고리만을 가질 수 있으나(1), 카테고리는 여러개의 상품과 관계(N)를 가질 수 있다. (위의 그림에서 한개에서..