πŸŽ‰ berenickt λΈ”λ‘œκ·Έμ— 온 κ±Έ ν™˜μ˜ν•©λ‹ˆλ‹€. πŸŽ‰
Back
NestJs
37-Follower Comment Count

1. Follower Count 증가 & κ°μ†Œ - 1

user 엔티티에 νŒ”λ‘œμš°, νŒ”λ‘œμ›Œ 수 μ»¬λŸΌμ„ μΆ”κ°€ν•΄μ€€λ‹€.

users.entity.ts
1
@Column({ default: 0 })
2
followerCount: number
3
4
@Column({ default: 0 })
5
followeeCount: number

users 컨트둀러

users/users.controller.ts
1
import { QueryRunner as QR } from 'typeorm'
2
// λ‚˜λ¨Έμ§€ import μƒλž΅
3
4
// **** νŒ”λ‘œμš° μš”μ²­ 승인
5
@Patch('follow/:id/confirm')
6
@UseInterceptors(TransactionInterceptor)
7
async patchFollowConfirm(
8
@User() user: UsersModel, //
9
@Param('id', ParseIntPipe) followerId: number,
10
@QueryRunner() qr: QR,
11
) {
12
await this.usersService.confirmFollow(followerId, user.id, qr)
13
await this.usersService.incrementFollowerCount(user.id, qr)
14
return true
15
}
16
17
// **** νŒ”λ‘œμš° μš”μ²­ μ‚­μ œ
18
@Delete('follow/:id')
19
async deleteFollow(
20
@User() user: UsersModel, //
21
@Param('id', ParseIntPipe) followeeId: number,
22
@QueryRunner() qr: QR,
23
) {
24
await this.usersService.deleteFollow(user.id, followeeId, qr)
25
await this.usersService.decrementFollowerCount(followeeId, qr)
26
return true
27
}

users μ„œλΉ„μŠ€

users/users.service.ts
1
@Injectable()
2
export class UsersService {
3
// μƒλž΅
4
5
getUsersRepository(qr?: QueryRunner) {
6
return qr //
7
? qr.manager.getRepository<UsersModel>(UsersModel)
8
: this.usersRepository
9
}
10
11
getUserFollowRepository(qr?: QueryRunner) {
12
return qr //
13
? qr.manager.getRepository<UserFollowersModel>(UserFollowersModel)
14
: this.userFollowersRepository
15
}
16
17
// μƒλž΅
18
19
// **** 4) νŒ”λ‘œμš° μš”μ²­
20
async followUser(followerId: number, followeeId: number, qr?: QueryRunner) {
21
const userFollowersRepository = this.getUserFollowRepository(qr)
22
23
await userFollowersRepository.save({
24
follower: { id: followerId },
25
followee: { id: followeeId },
26
})
27
28
return true
29
}
30
31
// **** 5) νŒ”λ‘œμ›Œλ“€ 쑰회
32
// μƒλž΅
33
34
// **** νŒ”λ‘œμš° μš”μ²­ 승인
35
async confirmFollow(followerId: number, followeeId: number, qr?: QueryRunner) {
36
const userFollowersRepository = this.getUserFollowRepository(qr)
37
38
const existing = await userFollowersRepository.findOne({
39
where: {
40
follower: { id: followerId },
41
followee: { id: followeeId },
42
},
43
relations: {
44
follower: true,
45
followee: true,
46
},
47
})
48
49
if (!existing) {
50
throw new BadRequestException('μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” νŒ”λ‘œμš° μš”μ²­μž…λ‹ˆλ‹€!')
51
}
52
53
await userFollowersRepository.save({
54
...existing,
55
isConfirmed: true,
56
})
57
58
return true
59
}
60
61
// **** νŒ”λ‘œμš° μš”μ²­ μ‚­μ œ
62
async deleteFollow(followerId: number, followeeId: number, qr?: QueryRunner) {
63
const userFollowersRepository = this.getUserFollowRepository(qr)
64
65
await userFollowersRepository.delete({
66
follower: {
67
id: followerId,
68
},
69
followee: {
70
id: followeeId,
71
},
72
})
73
74
return true
75
}
76
77
async incrementFollowerCount(userId: number, qr?: QueryRunner) {
78
const userRepository = this.getUsersRepository(qr)
79
80
await userRepository.increment(
81
{ id: userId }, //
82
'followerCount',
83
1,
84
)
85
}
86
87
async decrementFollowerCount(userId: number, qr?: QueryRunner) {
88
const userRepository = this.getUsersRepository(qr)
89
90
await userRepository.decrement(
91
{ id: userId }, //
92
'followerCount',
93
1,
94
)
95
}
96
}

2. Follower Count 증가 & κ°μ†Œ - 2

posts μ„œλΉ„μŠ€μ— λŒ“κΈ€ 수λ₯Ό ν‘œμ‹œν•˜λŠ” κΈ°λŠ₯을 μΆ”κ°€ν•œλ‹€.

posts.service.ts
1
// **** 포슀트 λŒ“κΈ€ 수 증가
2
async incrementCommentCount(postId: number, qr?: QueryRunner) {
3
const repository = this.getRepository(qr)
4
5
await repository.increment({ id: postId }, 'commentCount', 1)
6
}
7
8
// **** 포슀트 λŒ“κΈ€ 수 κ°μ†Œ
9
async decrementCommentCount(postId: number, qr?: QueryRunner) {
10
const repository = this.getRepository(qr)
11
await repository.decrement({ id: postId }, 'commentCount', 1)
12
}

3. Comment Count

comments μ„œλΉ„μŠ€μ— queryRunnerλ₯Ό μΆ”κ°€ν•œλ‹€.

comments.service.ts
1
getRepository(qr?: QueryRunner) {
2
return qr //
3
? qr.manager.getRepository<CommentsModel>(CommentsModel)
4
: this.commentsRepository
5
}
6
7
// **** (3) λŒ“κΈ€ 생성
8
async createComment(
9
dto: CreateCommentsDto, //
10
postId: number,
11
author: UsersModel,
12
qr?: QueryRunner,
13
) {
14
const repository = this.getRepository(qr)
15
16
return repository.save({
17
...dto,
18
post: { id: postId },
19
author,
20
})
21
}
22
23
// **** (5) λŒ“κΈ€ μ‚­μ œ
24
async deleteComment(id: number, qr?: QueryRunner) {
25
const repository = this.getRepository(qr)
26
27
const comment = await repository.findOne({
28
where: { id },
29
})
30
31
if (!comment) {
32
throw new BadRequestException('μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” λŒ“κΈ€μž…λ‹ˆλ‹€.')
33
}
34
35
await repository.delete(id)
36
37
return id
38
}

comments μ»¨νŠΈλ‘€λŸ¬λ„ λ‹€μŒκ³Ό 같이 μˆ˜μ •ν•œλ‹€.

comments.controller.ts
1
@Controller('posts/:postId/comments')
2
export class CommentsController {
3
constructor(private readonly commentsService: CommentsService, private readonly postsService: PostsService) {}
4
5
// μƒλž΅
6
7
// **** (3) λŒ“κΈ€ 생성
8
@Post()
9
@UseInterceptors(TransactionInterceptor)
10
async postComment(
11
@Param('postId', ParseIntPipe) postId: number,
12
@Body() body: CreateCommentsDto,
13
@User() user: UsersModel,
14
@QueryRunner() qr: QR,
15
) {
16
const resp = await this.commentsService.createComment(body, postId, user, qr)
17
18
await this.postsService.incrementCommentCount(postId, qr)
19
20
return resp
21
}
22
23
// μƒλž΅
24
25
// **** (5) λŒ“κΈ€ μ‚­μ œ
26
@Delete(':commentId')
27
@UseGuards(IsCommentMineOrAdminGuard)
28
@UseInterceptors(TransactionInterceptor)
29
async deleteComment(
30
@Param('commentId', ParseIntPipe) commentId: number, //
31
@Param('postId', ParseIntPipe) postId: number,
32
@QueryRunner() qr: QR,
33
) {
34
const resp = await this.commentsService.deleteComment(commentId, qr)
35
36
await this.postsService.decrementCommentCount(postId, qr)
37
38
return resp
39
}
40
}