Coverage Summary for Class: GetGoalsUseCaseKt (com.georgeci.moneysurfer.domain.usecase)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| GetGoalsUseCaseKt |
100%
(2/2)
|
25%
(2/8)
|
62.5%
(5/8)
|
100%
(11/11)
|
| GetGoalsUseCaseKt$special$$inlined$compareBy$1 |
0%
(0/1)
|
|
| GetGoalsUseCaseKt$special$$inlined$thenByDescending$1 |
0%
(0/1)
|
|
| GetGoalsUseCaseKt$WhenMappings |
|
| Total |
50%
(2/4)
|
25%
(2/8)
|
62.5%
(5/8)
|
100%
(11/11)
|
package com.georgeci.moneysurfer.domain.usecase
import com.georgeci.moneysurfer.domain.auth.SessionPointers
import com.georgeci.moneysurfer.domain.model.GoalProgress
import com.georgeci.moneysurfer.domain.model.GoalStatus
import com.georgeci.moneysurfer.domain.model.SavingsGoal
import com.georgeci.moneysurfer.domain.model.SavingsGoalSummary
import com.georgeci.moneysurfer.domain.primitives.Money
import com.georgeci.moneysurfer.domain.repositories.GoalContributionRepository
import com.georgeci.moneysurfer.domain.repositories.SavingsGoalRepository
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import org.koin.core.annotation.Single
/**
* Goals of the current workspace with their saved amounts folded in. Contributions are
* read once per workspace rather than once per goal — the list would otherwise open a
* `SUM` flow per row.
*
* ARCHIVED goals are hidden; v1 has no list filter to bring them back (md/goals.md).
*/
@Single
@OptIn(ExperimentalCoroutinesApi::class)
class GetGoalsUseCase(
private val goalRepository: SavingsGoalRepository,
private val contributionRepository: GoalContributionRepository,
private val session: SessionPointers,
) {
operator fun invoke(includeArchived: Boolean = false): Flow<List<SavingsGoalSummary>> =
session.currentWorkspaceId.flatMapLatest { workspaceId ->
workspaceId ?: return@flatMapLatest flowOf(emptyList())
combine(
goalRepository.getByWorkspaceId(workspaceId),
contributionRepository.getByWorkspaceId(workspaceId),
) { goals, contributions ->
val savedByGoal = contributions
.groupBy { it.goalId }
.mapValues { (_, rows) -> rows.fold(Money.zero()) { acc, row -> acc + row.amount } }
goals
.filter { includeArchived || it.status != GoalStatus.ARCHIVED }
.sortedWith(goalOrder)
.map { goal ->
SavingsGoalSummary(
goal = goal,
progress = GoalProgress.of(goal, savedByGoal[goal.id] ?: Money.zero()),
)
}
}
}
}
/** Goals you are still saving for float to the top; newest first inside a status. */
private val goalOrder = compareBy<SavingsGoal> { goal ->
when (goal.status) {
GoalStatus.ACTIVE -> 0
GoalStatus.COMPLETED -> 1
GoalStatus.PAUSED -> 2
GoalStatus.ARCHIVED -> 3
}
}.thenByDescending { it.createdAt }