13-05-nestjs-with-graphql-docker-compose
폴더를 복사해 사본을 만들어주고 폴더명을 16-01-mysql-one-to-one
으로 변경해주세요.
board.entity.ts
파일을 보면, 우리는 게시판 클래스를 만들어놨습니다.
import { Field, Int, ObjectType } from '@nestjs/graphql';
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity() // typeorm한테 알려줌(mysql)
@ObjectType() // gql한테 알려줌
export class Board {
@PrimaryGeneratedColumn('increment')
@Field(() => Int)
number: number;
@Field(() => String)
@Column()
writer: string;
@Field(() => String)
@Column()
title: string;
@Field(() => String)
@Column()
contents: string;
}
이번에는 상품과 상품 위치에 대한 entity도 만들고, 서로 연결시켜보겠습니다.
GraphQL은 하지않고, typeorm만 해주겠습니다.
apis
폴더에 product
폴더와 productSalesloation
폴더를 새로 만들고, 각 폴더에 새 폴더 entities
를 만들고, 그 안에 새로운 파일 product.entity.ts
와 productSaleslocation.entity.ts
파일을 만들어줍니다.
productSaleslocation.entity.ts
파일 안에 ProductSaleslocation
클래스를 만들어줍니다.
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class ProductSaleslocation {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
address: string;
@Column()
lat: number;
@Column()
lng: number;
@Column({ type: 'timestamp' })
meetingTime: Date;
}
product.entity.ts
파일 안에 Product
클래스를 만들고, ProductSaleslocation
을 JoinColumn
과 OneToOne
으로 연결해줍니다.
import { ProductSaleslocation } from 'src/apis/productSaleslocation/entities/productSaleslocation.entity';
import {
Column,
Entity,
JoinColumn,
OneToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity()
export class Product {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@Column()
description: string;
@Column()
price: number;
@Column()
isSoldout: boolean;
@JoinColumn()
@OneToOne(() => ProductSaleslocation)
productSaleslocation: ProductSaleslocation;
}
@JoinColumn()
은 한쪽 테이블에만 적어야합니다.
@OneToOne()
은 한쪽에만 쓰거나, 양쪽에 써줄 수 있습니다.
여기서는 Product
에만 써주겠습니다.
app.module.ts
파일에 방금 만든 클래스를 entities
에 추가해줘야합니다.
기존의 방식대로 배열에 직접 하나씩 넣어줄 수도 있지만( entities: [Board]
), 양이 많이질수록 효율적이지 않습니다.
따라서, apis 폴더 밑에 있는 entity 파일은 다 적용되도록 다음과 같이바꿔줍니다.
entities: [__dirname + '/apis/**/*.entity.*']
현재 파일이 있는 절대경로에서 apis 폴더 안에 끝까지 들어가서, 파일명 중간에 .entity.
이 들어간 파일들을 선택한다는 뜻입니다.
// app.module.ts
import { Module } from '@nestjs/common';
import { ApolloDriverConfig, ApolloDriver } from '@nestjs/apollo';
import { GraphQLModule } from '@nestjs/graphql';
import { BoardModule } from './apis/board/board.module';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
BoardModule,
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: 'src/commons/graphql/schema.gql',
}),
TypeOrmModule.forRoot({
type: 'mysql',
host: 'database',
port: 3306,
username: 'root',
password: 'root',
database: 'myproject', // 변경
entities: [__dirname + '/apis/**/*.entity.*'], // 변경
synchronize: true,
logging: true,
}),
],
})
export class AppModule {}
docker.compose.yaml
파일에서 database
의 environment
에 MYSQL_DATABASE: 'myproject'
를 추가해주세요.
version: '3.3'
services:
backend:
build:
context: .
dockerfile: dockerfile
volumes:
- ./src:/backend/src
ports:
- 3000:3000
database:
platform: linux/x86_64
image: mysql:latest
environment:
MYSQL_DATABASE: 'myproject'
MYSQL_ROOT_PASSWORD: 'root'
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --skip-character-set-client-handshake
cap_add:
- SYS_NICE
ports:
- 3306:3306
이제 도커를 띄워보겠습니다.
터미널에서 해당 폴더로 이동해 docker compose build
후 docker compose up
을 해주세요.
그리고 테이블이 잘 만들어졌는지 DBeaver로 확인하겠습니다.
entity들이 잘 만들어져 있습니다.
💡 변화가 없어요..!!
database 우클릭 -> connection view -> Advanced 클릭 -> 다시 재연결 팝업창에서 '예' 클릭
16-01-mysql-one-to-one
폴더를 복사해서 사본을 만든 후 폴더명을 16-02-mysql-many-to-one
으로 변경해주세요.
이번에는 ProductCategory
폴더를 만들고 안에 entities
폴더를 만들어 안에 새 파일을 만들어주세요.
productCategory.entity.ts
파일을 만들고 ProductCategory
클래스를 작성해줍니다.
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class ProductCategory {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
}
마찬가지로, user
폴더를 만들고 안에 entities
폴더를 만들어 새파일을 만들어주세요.
user.entity.ts
파일을 만들고 User
클래스를 만듭니다.
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
email: string;
@Column()
password: string;
}
이렇게 만들어준 user
와 productCategory
를 Product
에 ManyToMany
로 연결하겠습니다.
product.entities.ts
파일에 추가해보겠습니다.
import { ProductCategory } from 'src/apis/productCategory/entities/productCategory.entity';
import { ProductSaleslocation } from 'src/apis/productSaleslocation/entities/productSaleslocation.entity';
import { User } from 'src/apis/user/entities/user.entity';
import {
Column,
Entity,
JoinColumn,
ManyToOne,
OneToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity()
export class Product {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@Column()
description: string;
@Column()
price: number;
@Column()
isSoldout: boolean;
@JoinColumn()
@OneToOne(() => ProductSaleslocation)
productSaleslocation: ProductSaleslocation;
// user 연결
@ManyToOne(() => User)
user: User;
// productCategory 연결
@ManyToOne(() => ProductCategory)
productCategory: ProductCategory;
}
컨테이너를 띄워보겠습니다.
터미널에서 해동 폴더로 이동해 docker compose build
와 docker compose up
명령어로 실행하겠습니다.
그리고 DBeaver를 통해 확인해보겠습니다.
16-02-mysql-many-to-one
폴더를 복사하여 사본을 만들고 폴더명을 16-03-mysql-many-to-many
로 변경해주세요.
apis
폴더 안에 productTag
폴더를 생성하고 entities
폴더 안에 productTag.entity.ts
파일을 생성해주세요.
import { Product } from 'src/apis/product/entities/product.entity';
import { Column, Entity, ManyToMany, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class ProductTag {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@ManyToMany(() => Product, (product) => product.productTags)
products: Product[];
}
products
컬럼을 ManyToMany
로 연결해주겠습니다.
import { ProductCategory } from 'src/apis/productCategory/entities/productCategory.entity';
import { ProductSaleslocation } from 'src/apis/productSaleslocation/entities/productSaleslocation.entity';
import { ProductTag } from 'src/apis/productTag/entities/productTag.entity';
import { User } from 'src/apis/user/entities/user.entity';
import {
Column,
Entity,
JoinColumn,
JoinTable,
ManyToMany,
ManyToOne,
OneToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity()
export class Product {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@Column()
description: string;
@Column()
price: number;
@Column()
isSoldout: boolean;
@JoinColumn()
@OneToOne(() => ProductSaleslocation)
productSaleslocation: ProductSaleslocation;
@ManyToOne(() => User)
user: User;
@ManyToOne(() => ProductCategory)
productCategory: ProductCategory;
// productTag 연결
@JoinTable()
@ManyToMany(() => ProductTag, (productTag) => productTag.products)
productTags: ProductTag[];
}
ManyToMany
는 둘 중 하나에 JoinTable()
을 걸어줘야하기 때문에 Product
클래스에서 해주겠습니다.
컨테이너를 띄우고 DBeaver로 접속해 엔티티 관계도를 확인해보겠습니다.
이번에는 직접 SQL 쿼리문을 작성해보겠습니다.
16-03
의 컨테이너는 계속 작동시켜주세요.
도커를 통해 직접 컨테이너 안으로 들어가, mysql에 접속해보겠습니다.
다른 터미널을 열어 16-03
폴더로 위치 후, docker ps
로 mysql이 실행되고 있는 컨테이너의 아이디를 복사합니다.
docker exec -it 컨테이너ID /bin/bash
명령어를 입력해 컨테이너 안으로 들어갑니다.
mysql -u root -p
를 입력하고 비밀번호 root
를 입력해줍니다.
show databases;
를 적고 엔터를 치면 데이터베이스 목록이 나옵니다.
use myproject;
를 하면 myproject
데이터베이스를 선택하여 이후 명령어를 수행하게 됩니다.
이후 show tables;
명령어를 입력하면 해당 데이터베이스가 가지고 있는 테이블의 목록을 보여줍니다.
이 중에서 product
테이블이 어떻게 구성되어 있나 보겠습니다.
desc product;
명령어를 통해 알 수 있습니다.
방금은 도커 컨테이너 안으로 직접 들어가 명령어를 직접 입력했습니다.
이번에는 DBeaver를 이용해서 SQL문을 작성해보겠습니다.
DBeaver에서 도커 컨테이너로 띄운 mysql 서버에 접속한 후 SQL 버튼을 누르면 스크립트 작성할 수 있는 창이 뜨게 됩니다.
열린 스크립트 창에 아래와 같이 SQL문을 적어줍니다.
show databases;
use myproject;
show tables;
desc product;
실행하는 방법은 실행하고자 하는 명령어를 한줄 드래그하고 Ctrl + Enter
를 누르면 됩니다.
각각 한줄씩 실행했을 때, 아래와 같은 결과물을 볼 수 있습니다.
이번에는 users
테이블에 SQL 문으로 데이터를 직접 넣어보겠습니다.
스크립트 창에 아래와 같이 적고 Ctrl + Enter
를 눌러 실행해주세요.
잘 들어갔는지 유저 테이블에 들어가서 새로고침하고 확인해보겠습니다.
정상적으로 들어가져 있습니다.
이번에는 쿼리문으로 조회해보겠습니다.
SELECT * FROM user;
SELECT email from user;
잘 들어가져 있네요.
상품도 추가해보겠습니다.
INSERT INTO product(id, name, description, price, isSoldout) values(uuid(), '마우스', '좋은 마우스', 1000, false);
이제 한번 조회해보겠습니다.
SELECT * FROM product;
유저와 상품에 한개씩 데이터를 넣어봤습니다.
이 두개를 연결해보겠습니다.
데이터를 업데이트해서 상품에 유저를 연결하겠습니다.
아까 생성된 유저의 아이디를 복사해주세요.
상품 데이터에 유저 아이디를 추가하도록 데이터를 업데이트할건데, 모든 상품이 바뀌면 안됩니다.
어떤 상품을 업데이트하기 원하는지 조건을 where
에 적어줍니다.
UPDATE product SET userId = 'e10b80cc-f664-11ed-a9b3-0242ac160002' WHERE name = '마우스';
상품 데이터에 유저 아이디를 넣어줬으니, 두개의 테이블을 합쳐서 한번에 조회해보겠습니다.
SELECT * FROM product, user;
정상적으로 작동했습니다.