일단 유저 모델에 이메일 키, 추가
import { IsEmail , IsNotEmpty } from 'class-validator' ;
import {
BaseEntity ,
Column ,
Entity ,
PrimaryGeneratedColumn ,
Unique ,
} from 'typeorm' ;
export enum UserRole {
ADMIN = 'admin' ,
User = 'user' ,
}
@ Entity ()
@ Unique ([ 'username' ])
export class User extends BaseEntity {
@ PrimaryGeneratedColumn ()
id : number ;
@ Column ()
username : string ;
@ Column ()
@ IsNotEmpty ()
password : string ;
@ Column ({
type : 'enum' ,
enum : UserRole ,
default : UserRole . User ,
})
role : UserRole ;
@ Column ()
@ IsEmail ()
@ IsNotEmpty ()
email : string ;
}
그에 따른 dto 파일에 이메일 키 추가
import {
IsEmail ,
IsString ,
Matches ,
MaxLength ,
MinLength ,
} from 'class-validator' ;
export class AuthCredentialsDto {
@ IsString ()
@ MinLength ( 4 )
@ MaxLength ( 20 )
username : string ;
@ IsString ()
@ MinLength ( 6 )
@ MaxLength ( 20 )
@ Matches ( / ^ [ a-zA-Z0-9 ] * $ / , {
message : 'password only accepts english and number' ,
})
password : string ;
@ IsString ()
@ MaxLength ( 60 )
@ IsEmail ()
email : string ;
}
레포지토리에 이메일 추가 + 코드리뷰 반영해서 save 간략하게 변경
import { DataSource , Repository } from 'typeorm' ;
import { User } from './user.entity' ;
import { InjectRepository } from '@nestjs/typeorm' ;
import { AuthCredentialsDto } from './dto/auth-credential.dto' ;
import {
ConflictException ,
InternalServerErrorException ,
} from '@nestjs/common' ;
import * as bcrypt from 'bcryptjs' ;
export class UserRepository extends Repository < User > {
constructor (@ InjectRepository ( User ) private dataSource : DataSource ) {
super ( User , dataSource . manager );
}
async createUser ( authCredentialsDto : AuthCredentialsDto ) : Promise < User > {
const { username , password , email } = authCredentialsDto ;
const salt = await bcrypt . genSalt ();
const hashedPassword = await bcrypt . hash ( password , salt );
const user = this . create ({ username , password : hashedPassword , email });
try {
return await this . save ( user );
} catch ( error ) {
if ( error . code === 'ER_DUP_ENTRY' ) {
throw new ConflictException ( 'Duplicate error' );
} else {
throw new InternalServerErrorException ();
} // 유효성 검사 중 문제 발생 -> 500에러 처리방법
}
}
}
관계 설정
@JoinColumn() - fk임을 명시해 관계 형성함 > 해당 엔티티에서 fk키를 통해 join할 수 있도록 해줌
>>다른 모델로 조인할 때 기준이 되는 모델에 해당 데코레이션 설정하기
1:1
@OneToOne(() => 관계를 맺는 모델 이름) //인수로 익명함수를 작성해 넘겨줌
해당모델: 해당모델;
1:m
@ManyToOne(() => 해당 모델) //many에 해당하는 테이블에 joincolumn 생략 가능
해당 모델에는 1 의 관계에 해당하는 모델을 적어줌
n:m
@ManyToMany(() => 해당모델, (해당모델) => 해당모델.기준모델)
해당모델: 해당모델[];
m에 해당하는 모델에는 @ManyToMany 를 적되 해당 모델을 반대로 적음
@joinTable()은기준이 되는 한 테이블에만 적으면 됨 / 중간 테이블을 자동으로 작성해줌
유저 - 레시피와 1:n관계 하위카테고리 - 레시피와 n:1관계 > 카테고리 하나당 상품 여러개 상위카테고리 - 하위 카테고리와 1:n관계 > 상위 하나당 하위 여러개 스페셜카테고리 - 리뷰 - 유저랑 1:n관계 찜 - 유저랑 1:n관계 / 레시피와 1:n 관계 파일 - 사진과 1:n관계 사진 - 파일과 n:1 관계 / 레시피와 n:m 관계
레시피 모델
<레시피 모듈>
import { Module } from '@nestjs/common' ;
import { RecipeController } from './recipe.controller' ;
import { RecipeService } from './recipe.service' ;
import { TypeOrmModule } from '@nestjs/typeorm' ;
import { Recipe } from './recipe.entity' ;
import { AuthModule } from 'src/auth/auth.module' ;
import { RecipeRepository } from './recipe.repository' ;
@ Module ({
imports : [ TypeOrmModule . forFeature ([ Recipe ]), AuthModule ],
controllers : [ RecipeController ],
providers : [ RecipeService , RecipeRepository ],
})
export class RecipeModule {}
<레시피 레포지터리>
import { DataSource , Repository } from 'typeorm' ;
import { Recipe } from './recipe.entity' ;
import { InjectRepository } from '@nestjs/typeorm' ;
import { CreateRecipeDto } from './dto/create-recipe.dto' ;
export class RecipeRepository extends Repository < Recipe > {
constructor (@ InjectRepository ( Recipe ) private dataSource : DataSource ) {
super ( Recipe , dataSource . manager );
}
async createRecipe ( createRecipeDto : CreateRecipeDto ) : Promise < Recipe > {
const {
recipeName ,
img ,
portion ,
leadTime ,
level ,
ingredient ,
ingredientUnit ,
aveStar ,
} = createRecipeDto ;
const recipe = this . create ({
recipeName ,
img ,
portion ,
leadTime ,
level ,
ingredient ,
ingredientUnit ,
aveStar ,
});
await this . save ( recipe );
return recipe ;
}
}
<레시피 dto>
import { IsNumber , IsString } from 'class-validator' ;
export class CreateRecipeDto {
@ IsString ()
recipeName : string ;
@ IsString ()
img : string ;
@ IsNumber ()
portion : number ;
@ IsNumber ()
leadTime : number ;
@ IsNumber ()
level : number ;
@ IsString ()
ingredient : string ;
@ IsString ()
ingredientUnit : string ;
@ IsNumber ()
aveStar : number ;
}
<레시피 엔티티>
import { IsNotEmpty , IsString } from 'class-validator' ;
import { User } from 'src/auth/user.entity' ;
import {
BaseEntity ,
Column ,
Entity ,
ManyToMany ,
PrimaryGeneratedColumn ,
} from 'typeorm' ;
@ Entity ()
export class Recipe extends BaseEntity {
@ PrimaryGeneratedColumn ()
recipeId : number ;
@ Column ()
@ IsNotEmpty ()
@ IsString ()
recipeName : string ;
@ Column ()
img : string ;
@ Column ()
portion : number ;
@ Column ()
leadTime : number ;
@ Column ()
level : number ;
@ Column ()
ingredient : string ; //배열
@ Column ()
ingredientUnit : string ; //g, 개
@ Column ()
aveStar : number ;
@ ManyToMany (() => User , ( user ) => user . recipes )
user : User ;
}
<레시피 컨트롤러>
import {
Body ,
Controller ,
Get ,
Param ,
ParseIntPipe ,
Post ,
Delete ,
} from '@nestjs/common' ;
import { RecipeService } from './recipe.service' ;
import { Recipe } from './recipe.entity' ;
import { CreateRecipeDto } from './dto/create-recipe.dto' ;
@ Controller ( 'recipe' )
export class RecipeController {
constructor ( private recipeService : RecipeService ) {}
@ Get ( '/' )
getAllTask () : Promise < Recipe []> {
return this . recipeService . getAllRecipe ();
}
@ Post ()
createRecipe (@ Body () createRecipeDto : CreateRecipeDto ) : Promise < Recipe > {
return this . recipeService . createRecipe ( createRecipeDto );
}
@ Get ( '/:recipeId' )
getRecipeById (@ Param ( 'recipeId' ) recipeId : number ) : Promise < Recipe > {
return this . recipeService . getRecipeById ( recipeId );
}
@ Delete ( '/:recipeId' )
deleteRecipe (@ Param ( 'recipeId' , ParseIntPipe ) recipeId ) : Promise < void > {
return this . recipeService . deleteRecipe ( recipeId );
}
}
<레시피 서비스>
import { Injectable , NotFoundException } from '@nestjs/common' ;
import { RecipeRepository } from './recipe.repository' ;
import { Recipe } from './recipe.entity' ;
import { CreateRecipeDto } from './dto/create-recipe.dto' ;
@ Injectable ()
export class RecipeService {
constructor ( private recipeRepository : RecipeRepository ) {}
async getAllRecipe () : Promise < Recipe []> {
return this . recipeRepository . find ();
}
createRecipe ( createRecipeDto : CreateRecipeDto ) : Promise < Recipe > {
return this . recipeRepository . createRecipe ( createRecipeDto );
}
async getRecipeById ( recipeId : number ) : Promise < Recipe > {
const found = await this . recipeRepository . findOneBy ({ recipeId });
if ( ! found ) {
throw new NotFoundException (
`recipeId가 ${ recipeId } 인 레시피를 찾을 수 없습니다` ,
);
}
return found ;
}
async deleteRecipe ( recipeId : number ) : Promise < void > {
const result = await this . recipeRepository . delete ( recipeId );
if ( result . affected === 0 ) {
throw new NotFoundException ( `Can't find Recipe with id ${ recipeId } ` );
}
}
}
내일 update쪽 > @Path 만들기
#엘리스트랙 #엘리스트랙후기 #리액트네이티브강좌 #온라인코딩부트캠프 #온라인코딩학원 #프론트엔드학원 #개발자국비지원 #개발자부트캠프 #국비지원부트캠프 #프론트엔드국비지원 #React #Styledcomponent #React Router Dom #Redux #Typescript #Javascript