Skip to content

Commit a8a82d9

Browse files
committed
2 parents 0ea9e4b + aefdbd1 commit a8a82d9

22 files changed

+1457
-62
lines changed

oodd.erd.json

+11-19
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
"settings": {
55
"width": 5000,
66
"height": 5000,
7-
"scrollTop": -350.7988,
8-
"scrollLeft": -743,
9-
"zoomLevel": 0.91,
7+
"scrollTop": -911.9711,
8+
"scrollLeft": -1208.5347,
9+
"zoomLevel": 1,
1010
"show": 511,
1111
"database": 4,
1212
"databaseName": "oodd_dev",
@@ -17,15 +17,7 @@
1717
"bracketType": 1,
1818
"relationshipDataTypeSync": true,
1919
"relationshipOptimization": false,
20-
"columnOrder": [
21-
16,
22-
8,
23-
1,
24-
2,
25-
4,
26-
32,
27-
64
28-
],
20+
"columnOrder": [16, 8, 1, 2, 4, 32, 64],
2921
"maxWidthComment": -1,
3022
"ignoreSaveSettings": 0
3123
},
@@ -359,7 +351,7 @@
359351
"color": ""
360352
},
361353
"meta": {
362-
"updateAt": 1728980695840,
354+
"updateAt": 1728840014697,
363355
"createAt": 1725423390546
364356
}
365357
},
@@ -538,15 +530,15 @@
538530
"gLA60xcIc0oDGJRREWzLC"
539531
],
540532
"ui": {
541-
"x": 682.5433,
542-
"y": 355.1232,
533+
"x": 681.4444,
534+
"y": 358.9248,
543535
"zIndex": 2,
544536
"widthName": 60,
545537
"widthComment": 60,
546538
"color": ""
547539
},
548540
"meta": {
549-
"updateAt": 1729093078702,
541+
"updateAt": 1728754878357,
550542
"createAt": 1725423390547
551543
}
552544
},
@@ -615,14 +607,14 @@
615607
],
616608
"ui": {
617609
"x": 48.8889,
618-
"y": 50,
610+
"y": 49,
619611
"zIndex": 2,
620612
"widthName": 60,
621613
"widthComment": 60,
622614
"color": ""
623615
},
624616
"meta": {
625-
"updateAt": 1725423900406,
617+
"updateAt": 1728755232306,
626618
"createAt": 1725423390548
627619
}
628620
},
@@ -4679,4 +4671,4 @@
46794671
}
46804672
]
46814673
}
4682-
}
4674+
}

src/clothing/clothing.module.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
import { Module } from '@nestjs/common';
2+
import { TypeOrmModule } from '@nestjs/typeorm';
3+
import { Clothing } from 'src/common/entities/clothing.entity';
4+
import { ClothingService } from './clothing.service';
25

3-
@Module({})
6+
@Module({
7+
imports: [TypeOrmModule.forFeature([Clothing])],
8+
providers: [ClothingService],
9+
exports: [ClothingService],
10+
})
411
export class ClothingModule {}

src/clothing/clothing.service.ts

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { Injectable } from '@nestjs/common';
2+
import { InjectRepository } from '@nestjs/typeorm';
3+
import { QueryRunner, Repository } from 'typeorm';
4+
import { Clothing } from 'src/common/entities/clothing.entity';
5+
import { UploadClothingDto } from 'src/post/dtos/create-post.dto';
6+
import { DataNotFoundException } from 'src/common/exception/service.exception';
7+
import { PatchClothingDto } from 'src/post/dtos/patch-Post.dto';
8+
9+
@Injectable()
10+
export class ClothingService {
11+
constructor(
12+
@InjectRepository(Clothing)
13+
private readonly clothingRepository: Repository<Clothing>,
14+
) {}
15+
16+
// Clothing 엔티티 저장
17+
async saveClothings(
18+
uploadClothingDtos: UploadClothingDto[],
19+
queryRunner: QueryRunner,
20+
): Promise<Clothing[]> {
21+
const clothingEntities = uploadClothingDtos.map(
22+
(clothing: UploadClothingDto) =>
23+
this.clothingRepository.create({
24+
imageUrl: clothing.imageUrl,
25+
brandName: clothing.brandName,
26+
modelName: clothing.modelName,
27+
modelNumber: clothing.modelNumber,
28+
url: clothing.url,
29+
}),
30+
);
31+
32+
return await queryRunner.manager.save(clothingEntities);
33+
}
34+
35+
// Clothing 수정
36+
async updateClothing(
37+
uploadClothingDto: PatchClothingDto,
38+
queryRunner: QueryRunner,
39+
): Promise<Clothing> {
40+
const existingClothing = await this.clothingRepository.findOne({
41+
where: { id: uploadClothingDto.id, status: 'activated' },
42+
});
43+
44+
if (!existingClothing) {
45+
throw DataNotFoundException(
46+
`Clothing ID ${uploadClothingDto.id}를 찾을 수 없습니다.`,
47+
);
48+
}
49+
50+
// 필드 업데이트
51+
if (uploadClothingDto.imageUrl)
52+
existingClothing.imageUrl = uploadClothingDto.imageUrl;
53+
if (uploadClothingDto.brandName)
54+
existingClothing.brandName = uploadClothingDto.brandName;
55+
if (uploadClothingDto.modelName)
56+
existingClothing.modelName = uploadClothingDto.modelName;
57+
if (uploadClothingDto.modelNumber)
58+
existingClothing.modelNumber = uploadClothingDto.modelNumber;
59+
if (uploadClothingDto.url) existingClothing.url = uploadClothingDto.url;
60+
61+
return await queryRunner.manager.save(existingClothing);
62+
}
63+
64+
// Clothing 삭제 처리
65+
async deleteClothing(
66+
clothing: Clothing,
67+
queryRunner: QueryRunner,
68+
): Promise<Clothing> {
69+
clothing.status = 'deactivated';
70+
clothing.softDelete();
71+
return await queryRunner.manager.save(clothing);
72+
}
73+
}
+6-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import { Module } from '@nestjs/common';
22
import { PostClothingController } from './post-clothing.controller';
33
import { PostClothingService } from './post-clothing.service';
4+
import { PostClothing } from 'src/common/entities/post-clothing.entity';
5+
import { TypeOrmModule } from '@nestjs/typeorm';
6+
import { ClothingModule } from 'src/clothing/clothing.module';
47

58
@Module({
9+
imports: [TypeOrmModule.forFeature([PostClothing]), ClothingModule],
610
controllers: [PostClothingController],
7-
providers: [PostClothingService]
11+
providers: [PostClothingService],
12+
exports: [PostClothingService],
813
})
914
export class PostClothingModule {}
+142-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,145 @@
11
import { Injectable } from '@nestjs/common';
2+
import { InjectRepository } from '@nestjs/typeorm';
3+
import { ClothingService } from 'src/clothing/clothing.service';
4+
import { Clothing } from 'src/common/entities/clothing.entity';
5+
import { PostClothing } from 'src/common/entities/post-clothing.entity';
6+
import { Post } from 'src/common/entities/post.entity';
7+
import { UploadClothingDto } from 'src/post/dtos/create-post.dto';
8+
import { PatchClothingDto } from 'src/post/dtos/patch-Post.dto';
9+
import { QueryRunner, Repository } from 'typeorm';
210

311
@Injectable()
4-
export class PostClothingService {}
12+
export class PostClothingService {
13+
constructor(
14+
@InjectRepository(PostClothing)
15+
private readonly postClothingRepository: Repository<PostClothing>,
16+
private readonly clothingService: ClothingService,
17+
) {}
18+
19+
// 옷 정보 저장
20+
async savePostClothings(
21+
post: Post,
22+
uploadClothingDtos: UploadClothingDto[],
23+
queryRunner?: QueryRunner,
24+
): Promise<void> {
25+
const savedClothings = await this.clothingService.saveClothings(
26+
uploadClothingDtos,
27+
queryRunner,
28+
);
29+
30+
const postClothingEntities = savedClothings.map((clothing: Clothing) =>
31+
this.postClothingRepository.create({
32+
post,
33+
clothing,
34+
}),
35+
);
36+
37+
await queryRunner.manager.save(postClothingEntities);
38+
}
39+
40+
// 옷 정보 수정
41+
async updatePostClothings(
42+
post: Post,
43+
uploadClothingDtos: PatchClothingDto[],
44+
queryRunner?: QueryRunner,
45+
): Promise<void> {
46+
const existingPostClothings = await this.postClothingRepository.find({
47+
where: { post: post, status: 'activated' },
48+
relations: ['clothing'],
49+
});
50+
51+
// 빈 배열이 들어온 경우
52+
if (uploadClothingDtos.length === 0) {
53+
const clothingsToDeactivate = existingPostClothings.filter(
54+
(existingClothing) => existingClothing.status === 'activated',
55+
);
56+
57+
await this.deletePostClothing(clothingsToDeactivate, queryRunner);
58+
return; // 함수 종료
59+
}
60+
61+
// 삭제할 PostClothing
62+
const postClothingsToRemove = existingPostClothings.filter(
63+
(existingPostClothing) =>
64+
existingPostClothing.status === 'activated' &&
65+
!uploadClothingDtos.some(
66+
(newClothing) => newClothing.id === existingPostClothing.clothing.id,
67+
),
68+
);
69+
70+
if (postClothingsToRemove.length > 0) {
71+
await this.deletePostClothing(postClothingsToRemove, queryRunner);
72+
}
73+
74+
// PostClothing 추가 및 수정
75+
const newPostClothings: PostClothing[] = [];
76+
77+
for (const newClothing of uploadClothingDtos) {
78+
const existingPostClothing = existingPostClothings.find(
79+
(postClothing) => postClothing.clothing.id === newClothing.id,
80+
);
81+
82+
if (existingPostClothing) {
83+
// Clothing 정보 수정
84+
await this.clothingService.updateClothing(newClothing, queryRunner);
85+
} else {
86+
// 새로운 Clothing 추가
87+
const newClothingEntity = await this.clothingService.saveClothings(
88+
[newClothing],
89+
queryRunner,
90+
);
91+
for (const clothing of newClothingEntity) {
92+
const newPostClothingEntity = this.postClothingRepository.create({
93+
post,
94+
clothing,
95+
});
96+
newPostClothings.push(newPostClothingEntity);
97+
}
98+
}
99+
}
100+
if (newPostClothings.length > 0) {
101+
await queryRunner.manager.save(newPostClothings);
102+
}
103+
}
104+
105+
// PostClothing 및 Clothing 삭제 처리
106+
async deletePostClothing(
107+
postClothing: PostClothing[],
108+
queryRunner: QueryRunner,
109+
): Promise<void> {
110+
await Promise.all(
111+
postClothing.map(async (postClothingItem) => {
112+
postClothingItem.status = 'deactivated';
113+
postClothingItem.softDelete();
114+
115+
await this.clothingService.deleteClothing(
116+
postClothingItem.clothing,
117+
queryRunner,
118+
);
119+
120+
await queryRunner.manager.save(postClothingItem);
121+
}),
122+
);
123+
}
124+
125+
// Post에 연결된 PostClothing 및 Clothing 삭제 처리
126+
async deletePostClothingByPostId(
127+
postId: number,
128+
queryRunner: QueryRunner,
129+
): Promise<void> {
130+
const clothingToRemove = await queryRunner.manager.find(PostClothing, {
131+
where: { post: { id: postId } },
132+
relations: ['clothing'],
133+
});
134+
135+
await Promise.all(
136+
clothingToRemove.map(async (Postclothing) => {
137+
Postclothing.status = 'deactivated';
138+
Postclothing.softDelete();
139+
await this.clothingService.deleteClothing(Postclothing.clothing, queryRunner);
140+
141+
return queryRunner.manager.save(Postclothing);
142+
}),
143+
);
144+
}
145+
}
+5-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import { Module } from '@nestjs/common';
22
import { PostCommentController } from './post-comment.controller';
33
import { PostCommentService } from './post-comment.service';
4+
import { TypeOrmModule } from '@nestjs/typeorm';
5+
import { PostComment } from 'src/common/entities/post-comment.entity';
46

57
@Module({
8+
imports: [TypeOrmModule.forFeature([PostComment])],
69
controllers: [PostCommentController],
7-
providers: [PostCommentService]
10+
providers: [PostCommentService],
11+
exports: [PostCommentService],
812
})
913
export class PostCommentModule {}
+21-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,24 @@
11
import { Injectable } from '@nestjs/common';
2+
import { PostComment } from 'src/common/entities/post-comment.entity';
3+
import { QueryRunner } from 'typeorm';
24

35
@Injectable()
4-
export class PostCommentService {}
6+
export class PostCommentService {
7+
// post와 연결된 댓글 삭제
8+
async deleteCommentsByPostId(
9+
postId: number,
10+
queryRunner: QueryRunner,
11+
): Promise<void> {
12+
const commentsToRemove = await queryRunner.manager.find(PostComment, {
13+
where: { post: { id: postId } },
14+
});
15+
16+
await Promise.all(
17+
commentsToRemove.map(async (comment) => {
18+
comment.status = 'deactivated';
19+
comment.softDelete();
20+
return queryRunner.manager.save(comment);
21+
}),
22+
);
23+
}
24+
}

0 commit comments

Comments
 (0)