-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feat/#430] 밀린 문제 ID 조회 API 추가 #433
Changes from 11 commits
e62fdc1
1d2b2da
a6567dd
d4efdff
cdfc780
a6e418d
5998748
497b8dc
f4c72ad
e1a8c2d
0fba25e
f3e338b
a5d10c4
503b6a3
6af6209
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.few.api.repo.dao.article.query | ||
|
||
data class SelectAritlceIdByWorkbookIdAndDayQuery( | ||
val workbookId: Long, | ||
val day: Int, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.few.api.repo.dao.article.record | ||
|
||
data class ArticleIdRecord( | ||
val articleIds: List<Long>, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.few.api.repo.dao.problem.query | ||
|
||
data class SelectProblemIdByArticleIdsQuery( | ||
val articleIds: Set<Long>, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.few.api.repo.dao.problem.query | ||
|
||
data class SelectSubmittedProblemIdsQuery( | ||
val memberId: Long, | ||
val problemIds: List<Long>, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.few.api.repo.dao.problem.record | ||
|
||
data class ProblemIdAndArticleIdRecord( | ||
val problemId: Long, | ||
val articleId: Long, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,4 +4,5 @@ data class SelectProblemRecord( | |
val id: Long, | ||
val title: String, | ||
val contents: String, | ||
val articleId: Long, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.few.api.repo.dao.problem.record | ||
|
||
data class SubmittedProblemIdsRecord( | ||
val problemIds: List<Long>, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.few.api.repo.dao.subscription.record | ||
|
||
data class SubscriptionProgressRecord( | ||
val workbookId: Long, | ||
val day: Int, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.few.api.domain.problem.service | ||
|
||
import com.few.api.domain.problem.service.dto.BrowseArticleIdInDto | ||
import com.few.api.repo.dao.article.ArticleDao | ||
import com.few.api.repo.dao.article.query.SelectAritlceIdByWorkbookIdAndDayQuery | ||
import org.springframework.stereotype.Service | ||
|
||
@Service | ||
class ArticleService( | ||
private val articleDao: ArticleDao, | ||
) { | ||
|
||
fun browseArticleIdByWorkbookIdLimitDay(inDto: BrowseArticleIdInDto): List<Long> { | ||
return articleDao.selectArticleIdsByWorkbookIdLimitDay( | ||
SelectAritlceIdByWorkbookIdAndDayQuery( | ||
inDto.workbookId, | ||
inDto.day | ||
) | ||
).articleIds | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.few.api.domain.problem.service | ||
|
||
import com.few.api.domain.problem.service.dto.BrowseWorkbookIdAndProgressInDto | ||
import com.few.api.domain.problem.service.dto.SubscriptionProgressOutDto | ||
import com.few.api.exception.common.NotFoundException | ||
import com.few.api.repo.dao.subscription.SubscriptionDao | ||
import com.few.api.repo.dao.subscription.query.SelectSubscriptionSendStatusQuery | ||
import org.springframework.stereotype.Component | ||
|
||
@Component | ||
class SubscriptionService( | ||
private val subscriptionDao: SubscriptionDao, | ||
) { | ||
|
||
fun browseWorkbookIdAndProgress(inDto: BrowseWorkbookIdAndProgressInDto): List<SubscriptionProgressOutDto> { | ||
val subscriptionProgresses = subscriptionDao.selectWorkbookIdAndProgressByMember( | ||
SelectSubscriptionSendStatusQuery(inDto.memberId) | ||
).takeIf { it.isNotEmpty() } ?: throw NotFoundException("subscribe.workbook.notexist") | ||
|
||
return subscriptionProgresses.map { SubscriptionProgressOutDto(it.workbookId, it.day) } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.few.api.domain.problem.service.dto | ||
|
||
data class BrowseArticleIdInDto( | ||
val workbookId: Long, | ||
val day: Int, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.few.api.domain.problem.service.dto | ||
|
||
data class BrowseWorkbookIdAndProgressInDto( | ||
val memberId: Long, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.few.api.domain.problem.service.dto | ||
|
||
data class SubscriptionProgressOutDto( | ||
val workbookId: Long, | ||
val day: Int, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package com.few.api.domain.problem.usecase | ||
|
||
import com.few.api.domain.problem.service.ArticleService | ||
import com.few.api.domain.problem.service.SubscriptionService | ||
import com.few.api.domain.problem.service.dto.BrowseArticleIdInDto | ||
import com.few.api.domain.problem.service.dto.BrowseWorkbookIdAndProgressInDto | ||
import com.few.api.domain.problem.usecase.dto.BrowseProblemsUseCaseOut | ||
import com.few.api.domain.problem.usecase.dto.BrowseUndoneProblemsUseCaseIn | ||
import com.few.api.repo.dao.problem.ProblemDao | ||
import com.few.api.repo.dao.problem.SubmitHistoryDao | ||
import com.few.api.repo.dao.problem.query.SelectProblemIdByArticleIdsQuery | ||
import com.few.api.repo.dao.problem.query.SelectSubmittedProblemIdsQuery | ||
import org.springframework.stereotype.Component | ||
import org.springframework.transaction.annotation.Transactional | ||
|
||
@Component | ||
class BrowseUndoneProblemsUseCase( | ||
private val problemDao: ProblemDao, | ||
private val subscriptionService: SubscriptionService, | ||
private val articleService: ArticleService, | ||
private val submitHistoryDao: SubmitHistoryDao, | ||
) { | ||
|
||
@Transactional(readOnly = true) | ||
fun execute(useCaseIn: BrowseUndoneProblemsUseCaseIn): BrowseProblemsUseCaseOut { | ||
/** | ||
* 유저가 구독한 워크북들에 속한 아티클 개수를 조회함 | ||
* 이때 아티클 개수는 현 시점 기준으로 이메일이 전송된 아티클 개수까지만 조회함 | ||
*/ | ||
val subscriptionProgresses = subscriptionService.browseWorkbookIdAndProgress( | ||
BrowseWorkbookIdAndProgressInDto(useCaseIn.memberId) | ||
) | ||
|
||
/** | ||
* 위에서 조회한 워크부에 속한 아티클 개수에 대해 article_id 들을 조회함 | ||
*/ | ||
val sentArticleIds = subscriptionProgresses.flatMap { subscriptionProgress -> | ||
articleService.browseArticleIdByWorkbookIdLimitDay( | ||
BrowseArticleIdInDto( | ||
subscriptionProgress.workbookId, | ||
subscriptionProgress.day | ||
) | ||
) | ||
}.toSet() | ||
|
||
/** | ||
* 위에서 구한 아티클에 속한 모든 problem_id, article_id 조합을 조회함 | ||
*/ | ||
val allProblemIdsAndArticleIdsToBeSolved = problemDao.selectProblemIdByArticleIds( | ||
SelectProblemIdByArticleIdsQuery(sentArticleIds) | ||
) | ||
|
||
/** | ||
* 위에서 구한 문제들에 대해 풀이 이력이 존재하는 problem_id만 추출 후 | ||
* 유저가 풀어야 할 전체 problem_id에 대해 여집합 연산 | ||
*/ | ||
val allProblemIdsToBeSolved = allProblemIdsAndArticleIdsToBeSolved.map { it.problemId } | ||
val submittedProblemIds = submitHistoryDao.selectProblemIdByProblemIds( | ||
SelectSubmittedProblemIdsQuery(useCaseIn.memberId, allProblemIdsToBeSolved) | ||
).problemIds | ||
|
||
val unsubmittedProblemIdAndArticleIds: Map<Long, List<Long>> = allProblemIdsAndArticleIdsToBeSolved | ||
.filter { it.problemId !in submittedProblemIds } | ||
.groupBy { it.articleId } | ||
.mapValues { entry -> entry.value.map { it.problemId } } | ||
|
||
/** | ||
* 결과를 article_id를 기준으로 랜덤화한 뒤 problem_id를 순차적으로 리턴함 | ||
*/ | ||
val randomArticleIds = unsubmittedProblemIdAndArticleIds.keys.shuffled() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오 셔풀이라는 메서드가 있구나요.! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 지피티가 알려줌ㅋㅋ 내부적으론 어떤 성능 이슈나 그런게 있을지는 모르겠는데 파악해볼게요 |
||
val problemIdsRandomizedByArticleId = mutableListOf<Long>() | ||
|
||
randomArticleIds.forEach { articleId -> | ||
unsubmittedProblemIdAndArticleIds[articleId]?.let { problemIds -> | ||
problemIdsRandomizedByArticleId.addAll(problemIds) | ||
} | ||
} | ||
|
||
Comment on lines
+47
to
+79
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. articleId를 기준으로 랜덤화한 뒤 problemId를 뽑아냅니다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 최대한 변수명이나 주석으로 표현은 해뒀는데 이해 안되시는 부분 말씀해주세요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네 이해했슴다~ |
||
return BrowseProblemsUseCaseOut(problemIdsRandomizedByArticleId) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.few.api.domain.problem.usecase.dto | ||
|
||
data class BrowseUndoneProblemsUseCaseIn( | ||
val memberId: Long, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BrowseUndoneProblemsUseCase
는 problem이 맞을까요? 아님 member로 가는게 맞을까요?제출하지 않은 문제 기록이니까 뭔가 member에 있는것도 고려할 수 있을 것 같아서요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 API가 사용되는 그 resource 차원에서 볼때, problem에 더 가까울거 같습니다. 멤버를 기준으로 조회할 뿐 그 조회하려는 resource는 문제이기 때문
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
지금 API가
~/problems/unsubmitte
로 되어 있는데만약 해당 구현이 member로 간다면
~/members/problems
로 될 것 같아요RESTful API 네이밍을 할때 명사를 사용하라는 추천이 있잖아요.
그 말을 고려하면 member로 괜찮지 않을까 생각해서 코멘트 남겼어요.
근데 problem에 있어도 괜찮을 것 같습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
명사를 사용하는게 룰이긴 한데 맨데토리는 아니고 동사가 필요할 경우앤 저 api 처럼 맨 뒤에만 위치하도록 해야 함
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아 잠만 근데 저것보다 쿼리 파람으로 두는게 잴 적절하긴 하겠네요…