fix(#2): address PR review — use row mapper, require id==0, drop ignoreCase on amount, doc drift, orphan-category note
This commit is contained in:
@@ -17,6 +17,9 @@ class GetExpenseSummary(
|
|||||||
)
|
)
|
||||||
val totalAmount = expenses.sumOf { it.amount }
|
val totalAmount = expenses.sumOf { it.amount }
|
||||||
val categoryMap = categoryDao.getAll().associate { it.id to it.toModel() }
|
val categoryMap = categoryDao.getAll().associate { it.id to it.toModel() }
|
||||||
|
// ForeignKey.RESTRICT keeps categories intact, but be defensive: if a
|
||||||
|
// category was deleted out-of-band, drop its group from byCategory
|
||||||
|
// rather than crashing. totalAmount still includes the orphan rows.
|
||||||
val byCategory = expenses
|
val byCategory = expenses
|
||||||
.groupBy { it.categoryId }
|
.groupBy { it.categoryId }
|
||||||
.mapNotNull { (categoryId, group) ->
|
.mapNotNull { (categoryId, group) ->
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package dev.achmad.ledgerr.domain.expense.interactor
|
|||||||
|
|
||||||
import dev.achmad.ledgerr.data.local.dao.CategoryDao
|
import dev.achmad.ledgerr.data.local.dao.CategoryDao
|
||||||
import dev.achmad.ledgerr.data.local.dao.ExpenseDao
|
import dev.achmad.ledgerr.data.local.dao.ExpenseDao
|
||||||
|
import dev.achmad.ledgerr.data.local.dao.ExpenseWithCategoryRow
|
||||||
import dev.achmad.ledgerr.data.local.mapper.toModel
|
import dev.achmad.ledgerr.data.local.mapper.toModel
|
||||||
import dev.achmad.ledgerr.domain.expense.model.DateRange
|
import dev.achmad.ledgerr.domain.expense.model.DateRange
|
||||||
import dev.achmad.ledgerr.domain.expense.model.ExpenseWithCategory
|
import dev.achmad.ledgerr.domain.expense.model.ExpenseWithCategory
|
||||||
@@ -24,10 +25,10 @@ class GetExpenses(
|
|||||||
suspend fun awaitOne(id: Long): ExpenseWithCategory? {
|
suspend fun awaitOne(id: Long): ExpenseWithCategory? {
|
||||||
val expense = dao.getById(id) ?: return null
|
val expense = dao.getById(id) ?: return null
|
||||||
val category = categoryDao.getById(expense.categoryId) ?: return null
|
val category = categoryDao.getById(expense.categoryId) ?: return null
|
||||||
return ExpenseWithCategory(
|
return ExpenseWithCategoryRow(
|
||||||
expense = expense.toModel(),
|
expense = expense,
|
||||||
category = category.toModel(),
|
category = category,
|
||||||
)
|
).toModel()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun awaitAll(
|
suspend fun awaitAll(
|
||||||
@@ -46,7 +47,7 @@ class GetExpenses(
|
|||||||
val amountStr = entity.amount.toString()
|
val amountStr = entity.amount.toString()
|
||||||
val categoryName = categoryMap[entity.categoryId]?.name.orEmpty()
|
val categoryName = categoryMap[entity.categoryId]?.name.orEmpty()
|
||||||
note.contains(query, ignoreCase = true) ||
|
note.contains(query, ignoreCase = true) ||
|
||||||
amountStr.contains(query, ignoreCase = true) ||
|
amountStr.contains(query) ||
|
||||||
categoryName.contains(query, ignoreCase = true)
|
categoryName.contains(query, ignoreCase = true)
|
||||||
}
|
}
|
||||||
.mapNotNull { entity ->
|
.mapNotNull { entity ->
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ class InsertExpenses(
|
|||||||
) {
|
) {
|
||||||
suspend fun awaitAll(expenses: List<Expense>) {
|
suspend fun awaitAll(expenses: List<Expense>) {
|
||||||
if (expenses.isEmpty()) return
|
if (expenses.isEmpty()) return
|
||||||
|
require(expenses.all { it.id == 0L }) {
|
||||||
|
"InsertExpenses.awaitAll requires all Expense.id == 0L (got ${expenses.filter { it.id != 0L }.map { it.id }})"
|
||||||
|
}
|
||||||
dao.insertAll(expenses.map { it.toEntity() })
|
dao.insertAll(expenses.map { it.toEntity() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ One-shot search. If `query` is blank and `range` is null, returns all expenses (
|
|||||||
## expense / UpsertExpense
|
## expense / UpsertExpense
|
||||||
|
|
||||||
### `await(expense: Expense): Long`
|
### `await(expense: Expense): Long`
|
||||||
If `expense.id == 0L`: insert and return generated id. Otherwise: update by id and return the existing id. Uses Room `@Upsert`.
|
If `expense.id == 0L`: insert and return generated id. Otherwise: update by id and return the existing id. Routes through separate `dao.insert` / `dao.update` (the DAO does not expose a `@Upsert` method).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user