Implement expense interactors #2

Closed
opened 2026-06-28 08:43:52 +00:00 by admin · 0 comments
Owner

Overview

Implements the expense feature — 6 interactors covering read, write, search, and summary. Depends on #1 (DI foundation + category interactor set).

Prerequisites

Issue #1 must be merged first. This gives you:

  • AppDatabase + CategoryDao + ExpenseDao already wired
  • Category domain model + GetCategories interactor
  • Expense, DateRange, ExpenseWithCategory, ExpenseSummary domain models already in place

What to do

1. Define signatures + TODOs

Create these 6 files under domain/expense/interactor/:

  • GetExpenses.ktsubscribeAll(), subscribeByDateRange(range), awaitOne(id), awaitAll(query, range?)
  • UpsertExpense.ktawait(expense): Long
  • InsertExpenses.ktawaitAll(expenses: List<Expense>)
  • DeleteExpense.ktawait(id)
  • ReassignExpenseCategory.ktawait(fromCategoryId, toCategoryId)
  • GetExpenseSummary.ktawait(range): ExpenseSummary

For GetExpenses.awaitOne(id): implement by calling expenseDao.getById(id) + categoryDao.getById(expense.categoryId), returning null if either is null, otherwise ExpenseWithCategory(expense.toModel(), category.toModel()). Add the appropriate TODO body.

For GetExpenses.awaitAll(query, range?): do the post-fetch filter in Kotlin. Fetch categoryDao.getAll() once, build a Map<Long, Category>, fetch expenses via expenseDao.search(range?.start?.toEpochDay(), range?.end?.toEpochDay()), filter by query against note / amount.toString() / category.name, map to ExpenseWithCategory.

2. Implement all 6 interactors (replace TODOs)

Refer to docs/03-function-todos.md for exact per-method behavior and edge cases. Highlights:

  • InsertExpenses.awaitAll: bulk insert via dao.insertAll, all id must be 0.
  • ReassignExpenseCategory.await: single SQL update.
  • GetExpenseSummary.await: fetch expenses in range, sum total, group by category, sort DESC.

3. Add to DomainModule

factory { GetExpenses(get(), get()) }
factory { UpsertExpense(get()) }
factory { InsertExpenses(get()) }
factory { DeleteExpense(get()) }
factory { ReassignExpenseCategory(get()) }
factory { GetExpenseSummary(get(), get()) }

4. Verify compilation

Run ./gradlew assembleDebug. Must succeed.

Acceptance

  • All 6 expense interactors implemented
  • DomainModule has the 6 new factories
  • ./gradlew assembleDebug succeeds

Implementation rule

Per AGENTS.md — do not start implementation without explicit user sign-off on this issue. When working, check for related issues in the remote repo first.

## Overview Implements the `expense` feature — 6 interactors covering read, write, search, and summary. Depends on #1 (DI foundation + `category` interactor set). ## Prerequisites Issue #1 must be merged first. This gives you: - `AppDatabase` + `CategoryDao` + `ExpenseDao` already wired - `Category` domain model + `GetCategories` interactor - `Expense`, `DateRange`, `ExpenseWithCategory`, `ExpenseSummary` domain models already in place ## What to do ### 1. Define signatures + TODOs Create these 6 files under `domain/expense/interactor/`: - `GetExpenses.kt` — `subscribeAll()`, `subscribeByDateRange(range)`, `awaitOne(id)`, `awaitAll(query, range?)` - `UpsertExpense.kt` — `await(expense): Long` - `InsertExpenses.kt` — `awaitAll(expenses: List<Expense>)` - `DeleteExpense.kt` — `await(id)` - `ReassignExpenseCategory.kt` — `await(fromCategoryId, toCategoryId)` - `GetExpenseSummary.kt` — `await(range): ExpenseSummary` For `GetExpenses.awaitOne(id)`: implement by calling `expenseDao.getById(id)` + `categoryDao.getById(expense.categoryId)`, returning `null` if either is null, otherwise `ExpenseWithCategory(expense.toModel(), category.toModel())`. Add the appropriate TODO body. For `GetExpenses.awaitAll(query, range?)`: do the post-fetch filter in Kotlin. Fetch `categoryDao.getAll()` once, build a `Map<Long, Category>`, fetch expenses via `expenseDao.search(range?.start?.toEpochDay(), range?.end?.toEpochDay())`, filter by `query` against `note` / `amount.toString()` / `category.name`, map to `ExpenseWithCategory`. ### 2. Implement all 6 interactors (replace TODOs) Refer to `docs/03-function-todos.md` for exact per-method behavior and edge cases. Highlights: - `InsertExpenses.awaitAll`: bulk insert via `dao.insertAll`, all `id` must be 0. - `ReassignExpenseCategory.await`: single SQL update. - `GetExpenseSummary.await`: fetch expenses in range, sum total, group by category, sort DESC. ### 3. Add to `DomainModule` ```kotlin factory { GetExpenses(get(), get()) } factory { UpsertExpense(get()) } factory { InsertExpenses(get()) } factory { DeleteExpense(get()) } factory { ReassignExpenseCategory(get()) } factory { GetExpenseSummary(get(), get()) } ``` ### 4. Verify compilation Run `./gradlew assembleDebug`. Must succeed. ## Acceptance - [ ] All 6 expense interactors implemented - [ ] `DomainModule` has the 6 new factories - [ ] `./gradlew assembleDebug` succeeds ## Implementation rule Per `AGENTS.md` — do not start implementation without explicit user sign-off on this issue. When working, check for related issues in the remote repo first.
admin closed this issue 2026-06-28 09:58:45 +00:00
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/ledgerr#2