* 설계
- 이미지가 생성되고
- post 생성되고 를 묶어서
- all or nothing으로 만들고자 함.
* 구현
- 컨트롤러에서 dataSouce 를 주입받음.
- 이걸로 db와 통신할수있는 api임.
- 컨트롤러
- 주의할점은, controller, service에서 같은 qr을 사용해야 트랜잭션이 적용된다는점임
- 이를위해 서비스에서 getRepository 함수를 만듬.
@Controller('posts')
export class PostsController {
constructor(
private readonly postsService: PostsService,
private readonly dataSource: DataSource,
) {}
@Post()
@UseGuards(AccessTokenGuard)
async postPost(
@User('id') userId : number,
@Body() body : CreatePostDto,
){
const qr = this.dataSource.createQueryRunner();
await qr.connect();
//이 시점에서 같은 qr을 사용해야 트랜잭션이 묶인다!! -> 즉, qr을 인자로 전달해야한다.
await qr.startTransaction();
//로직실행
try{
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,
});
}
await qr.commitTransaction();
return this.postsService.getPostById(post.id);
}
catch (e){
await qr.rollbackTransaction();
}
finally {
await qr.release();
}
}
- 서비스
getRepository(qr? : QueryRunner){
return qr? qr.manager.getRepository<PostsModel>(PostsModel) : this.postsRepository;
}
async createPost(authorId: number, postDto : CreatePostDto, qr?: QueryRunner){
const repository = this.getRepository(qr);
const post = repository.create({
author: {
id: authorId,
},
...postDto,
images: [],
likeCount:0,
commentCount:0,
});
const newPost = await repository.save(post);
return newPost;
}
* create-image도 qr 구현
- getRepository에서 자신의 모델의 리포지토리를 받아야함
- 별도로 분리.
import { BadRequestException, Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { ImageModel } from "../../common/entity/image.entity";
import { QueryRunner, Repository } from "typeorm";
import { CreatePostImageDto } from "./dto/create-image.dto";
import { basename, join } from "path";
import { POST_IMAGE_PATH, TEMP_FOLDER_PATH } from "../../common/const/path.const";
import { promises } from "fs";
@Injectable()
export class PostsImagesService{
constructor(
@InjectRepository(ImageModel)
private readonly imageRepository : Repository<ImageModel>,
) {
}
getRepository(qr? : QueryRunner){
return qr? qr.manager.getRepository<ImageModel>(ImageModel) : this.imageRepository;
}
/**
* dto의 이미지 이름을 기반으로
* 파일의 경로 생성
* @param dto
*/
async createPostImage(dto : CreatePostImageDto, qr: QueryRunner){
const repository = this.getRepository(qr);
const tempFilePath = join(TEMP_FOLDER_PATH, dto.path);
try{
await promises.access(tempFilePath); //존재확인,
}
catch(error){
throw new BadRequestException('존재하지 않는 파일 입니다.' + error);
}
//파일 이름만 가져오기
//public/temp/aaa.jpg -> aaa.jpg
const fileName= basename(tempFilePath);
const newPath = join(POST_IMAGE_PATH, fileName);
//옮기기전에 save (rollback대비)
const result = await repository.save({
...dto,
});
// 1->2로 파일 옮김.
await promises.rename(tempFilePath, newPath);
return result;
}
}
- 생성자주입
@Controller('posts')
export class PostsController {
constructor(
private readonly postsService: PostsService,
private readonly dataSource: DataSource,
private readonly postsImagesService: PostsImagesService,
* 결과
'JS > Nest.js' 카테고리의 다른 글
[Nest] Exception Filter 구현 (0) | 2024.09.22 |
---|---|
[Nest] Interceptor => logger 구현, @Transactional 구현 (0) | 2024.09.22 |
[Next] 연관관계 매핑, ImageModel 생성 구현 (0) | 2024.09.22 |
[Nest] 이미지 업로드 구현V2 (0) | 2024.09.22 |
[Nest] 이미지 업로드 구현 V1 (0) | 2024.09.22 |