관리 메뉴

Mini

[Next] 연관관계 매핑, ImageModel 생성 구현 본문

JS/Nest.js

[Next] 연관관계 매핑, ImageModel 생성 구현

Mini_96 2024. 9. 22. 20:08

* 설계

  • 이미지가 생성되고
  • post 생성되고 를 묶어서
  • all or nothing으로 만들고자 함.

 

* image table 생성

  • post 는 여러개의 image를 가진다.
import { BaseModel } from "./base.entity";
import { IsEnum, IsInt, IsOptional, IsString } from "class-validator";
import { Column, Entity, ManyToOne } from "typeorm";
import { Transform } from "class-transformer";
import { join } from "path";
import { POST_PUBLIC_IMAGE_PATH } from "../const/path.const";
import { PostsModel } from "../../posts/entities/posts.entity";

export enum ImageModelType{
  POST_IMAGE,
}

@Entity()
export class ImageModel extends BaseModel{
  @Column({
    default: 0,
  })
  @IsInt()
  @IsOptional()
  order: number; //이미지 보여줄 순서

  // usersMode -> 사용자 프로필 이미지
  // postModel -> 포스트 이미지
  @Column({
    enum: ImageModelType,
  })
  @IsEnum(ImageModelType)
  @IsString()
  type: ImageModelType;

  @Column()
  @IsString()
  @Transform(({value, obj}) => { //value == img이름, 현재객체(image객체)
    if(value && obj.type === ImageModelType.POST_IMAGE){
      return join(
        POST_PUBLIC_IMAGE_PATH,
        value,
      )
    }
    else{
      return value;
    }
  })
  path: String;

  //연동될타입, 어떤 속성과 연동될건지
  @ManyToOne((type) => PostsModel, (post) => post.images)
  post?: PostsModel;

}
@Entity() //테이블생성해줘
export class PostsModel extends BaseModel{

 ...

  @OneToMany((type)=> ImageModel, (image)=> image.post)
  images?: ImageModel[];
  • app.module에서 typeOrm entities에 추가도 빼먹지 말것.
TypeOrmModule.forRoot({
  type: 'postgres',
  host: process.env[ENV_DB_HOST_KEY],
  port: +process.env[ENV_DB_PORT_KEY],
  username: process.env[ENV_DB_USERNAME_KEY],
  password: process.env[ENV_DB_PASSWORD_KEY],
  database: process.env[ENV_DB_DATABASE_KEY],
  entities: [
    PostsModel,
    UsersModel,
    ImageModel,
  ], //생성할 모델들

 

 

* 서비스 구현

  • dto 수정
export class CreatePostDto extends PickType(PostsModel, ['title', 'content']){

  @IsString({
    each:true, //배열의 모든 요소 검증
  })
  @IsOptional()
  images?: string[] = [];

}
  • 의존성 주입
@Injectable()
export class PostsService {
  constructor(
    @InjectRepository(PostsModel)
    private readonly postsRepository: Repository<PostsModel>,

    @InjectRepository(ImageModel)
    private readonly imageRepository : Repository<ImageModel>,
  • 모델만 주입받을때는 TypeOrm에 import 할것 주의!!
@Module({
  imports:[
    TypeOrmModule.forFeature([
      PostsModel,
      ImageModel, //Repository만 import할때는 여기!
    ]),
    AuthModule,
    UsersModule,
    CommonModule,
  ],
  controllers: [PostsController],
  providers: [PostsService],
})
export class PostsModule {}

 

  • 이미지 등록 dto 생성
import { PickType } from "@nestjs/mapped-types";
import { ImageModel } from "../../../common/entity/image.entity";

// 이미지 1개에 대한 정보
export class CreatePostImageDto extends PickType(ImageModel, ['path','post','order','type']){

}
  • 컨트롤러
    • body의 image들에 대해 하나씩 돌면서 imageTable에 넣어주기
@Post()
@UseGuards(AccessTokenGuard)
async postPost(
  @User('id') userId : number,
  @Body() body : CreatePostDto,
  ){

  const post = await this.postsService.createPost(userId ,body);

  /**
   * body의 image 이름들에대해
   * 각각 정보들을 넣어서 이미지를 만듬(db에 저장)
   * 주인은 post
   */
  for(let i=0;i<body.images.length;i++){
    await this.postsService.createPostImage({
      post,
      order:i,
      path:body.images[i],
      type:ImageModelType.POST_IMAGE,
    });
  }

  return this.postsService.getPostById(post.id);

}

 

 

* post조회시 외래키 표시 속성 일반화

import { FindManyOptions } from "typeorm";
import { PostsModel } from "../entities/posts.entity";

export const DEFAULT_POST_FIND_OPTIONS: FindManyOptions<PostsModel> ={
  relations:{
    author: true,
    images: true,
  }

}
  • 사용
async getPostById(id:number) {
   const post = await this.postsRepository.findOne({
    where:{
      id,
    },
     ...DEFAULT_POST_FIND_OPTIONS,
  });

한 게시물에 여러 이미지 생성된 모습