Skip to content
This repository has been archived by the owner on Nov 5, 2024. It is now read-only.

Commit

Permalink
WIP: Action composition (not building)
Browse files Browse the repository at this point in the history
  • Loading branch information
ILIYANGERMANOV committed Apr 24, 2022
1 parent 2cf9c52 commit 8b22a51
Show file tree
Hide file tree
Showing 12 changed files with 232 additions and 134 deletions.
65 changes: 48 additions & 17 deletions app/src/main/java/com/ivy/wallet/domain/action/Action.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ abstract class Action<in I, out O> {
}

protected suspend fun <T> computation(action: suspend () -> T): T =
withContext(Dispatchers.Default) {
return@withContext action()
}

protected suspend fun <T> ui(action: suspend () -> T): T =
withContext(Dispatchers.Main) {
return@withContext action()
}
Expand All @@ -39,11 +44,6 @@ suspend infix fun <A, B, C> Action<B, C>.after(lambda: suspend (A) -> B): suspen
this@after(b)
}

suspend infix fun <A, B, C> Action<A, B>.then(lambda: suspend (B) -> C): suspend (A) -> C = { a ->
val b = this@then(a)
lambda(b)
}

suspend infix fun <A, B, C> (suspend (B) -> C).after(lambda: suspend (A) -> B): suspend (A) -> C =
{ a ->
val b = lambda(a)
Expand All @@ -56,17 +56,48 @@ suspend infix fun <A, B, C> (suspend (A) -> B).then(lambda: suspend (B) -> C): s
lambda(b)
}

fun <A, B> Action<A, B>.lambda(): suspend (A) -> B = { a ->
this(a)
}
suspend infix fun <B, C> (suspend () -> B).then(lambda: suspend (B) -> C): suspend () -> C =
{
val b = this@then()
lambda(b)
}

suspend infix fun <B, C> (suspend () -> B).then(act: Action<B, C>): suspend () -> C =
{
val b = this@then()
act(b)
}

suspend infix fun <A, B, C> (suspend (A) -> B).then(act: Action<B, C>): suspend (A) -> C =
{ a ->
val b = this@then(a)
act(b)
}

suspend infix fun <A, B, C> (Action<A, B>).then(f: suspend (B) -> C): suspend (A) -> C =
{ a ->
val b = this@then(a)
f(b)
}


///**
// * Action composition example
// */
//suspend fun example(
// calcWalletBalance: CalcWalletBalanceAct,
// getBaseCurrency: GetBaseCurrencyAct
//): BigDecimal {
// return (calcWalletBalance after getBaseCurrency)(Unit)
//}
suspend infix fun <B, C> (() -> B).then(f: suspend (B) -> C): suspend () -> C =
{
val b = this@then()
f(b)
}

fun <C> (() -> C).fixUnit(): suspend (Unit) -> C =
{
this()
}

fun <C> (suspend () -> C).fixUnit(): suspend (Unit) -> C =
{
this()
}

fun <C> (suspend (Unit) -> C).fixUnit(): suspend () -> C =
{
this(Unit)
}
9 changes: 9 additions & 0 deletions app/src/main/java/com/ivy/wallet/domain/action/FPAction.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.ivy.wallet.domain.action

abstract class FPAction<I, O> : Action<I, O>() {
protected abstract suspend fun I.recipe(): (suspend () -> O)

override suspend fun I.willDo(): O {
return recipe().invoke()
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.ivy.wallet.domain.action.account

import com.ivy.wallet.domain.action.Action
import com.ivy.wallet.domain.action.FPAction
import com.ivy.wallet.domain.data.entity.Transaction
import com.ivy.wallet.domain.fp.data.ClosedTimeRange
import com.ivy.wallet.io.persistence.dao.TransactionDao
Expand All @@ -9,20 +9,22 @@ import javax.inject.Inject

class AccTrnsAct @Inject constructor(
private val transactionDao: TransactionDao
) : Action<AccTrnsAct.Input, List<Transaction>>() {
override suspend fun Input.willDo(): List<Transaction> = io {
transactionDao.findAllByAccountAndBetween(
accountId = accountId,
startDate = range.from,
endDate = range.to
) + transactionDao.findAllToAccountAndBetween(
toAccountId = accountId,
startDate = range.from,
endDate = range.to
)
) : FPAction<AccTrnsAct.Input, List<Transaction>>() {
override suspend fun Input.recipe(): suspend () -> List<Transaction> = suspend {
io {
transactionDao.findAllByAccountAndBetween(
accountId = accountId,
startDate = range.from,
endDate = range.to
) + transactionDao.findAllToAccountAndBetween(
toAccountId = accountId,
startDate = range.from,
endDate = range.to
)
}
}

data class Input(
class Input(
val accountId: UUID,
val range: ClosedTimeRange
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ivy.wallet.domain.action.account

import com.ivy.wallet.domain.action.FPAction
import com.ivy.wallet.domain.data.entity.Account
import com.ivy.wallet.io.persistence.dao.AccountDao
import javax.inject.Inject

class AccountsAct @Inject constructor(
private val accountDao: AccountDao
) : FPAction<Unit, List<Account>>() {
override suspend fun Unit.recipe(): suspend () -> List<Account> = suspend {
io { accountDao.findAll() }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.ivy.wallet.domain.action.settings

import com.ivy.wallet.domain.action.FPAction
import com.ivy.wallet.domain.fp.wallet.baseCurrencyCode
import com.ivy.wallet.io.persistence.dao.SettingsDao
import javax.inject.Inject

class BaseCurrencyAct @Inject constructor(
private val settingsDao: SettingsDao
) : FPAction<Unit, String>() {
override suspend fun Unit.recipe(): suspend () -> String {
return suspend {
io { baseCurrencyCode(settingsDao) }
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.ivy.wallet.domain.action.wallet

import arrow.core.nonEmptyListOf
import com.ivy.wallet.domain.action.Action
import com.ivy.wallet.domain.action.FPAction
import com.ivy.wallet.domain.action.account.AccTrnsAct
import com.ivy.wallet.domain.action.then
import com.ivy.wallet.domain.data.entity.Account
Expand All @@ -13,27 +13,24 @@ import javax.inject.Inject

class CalcAccBalanceAct @Inject constructor(
private val accTrnsAct: AccTrnsAct
) : Action<CalcAccBalanceAct.Input, CalcAccBalanceAct.Output>() {
) : FPAction<CalcAccBalanceAct.Input, CalcAccBalanceAct.Output>() {

override suspend fun Input.willDo(): Output = io {
val composition = accTrnsAct then { accTrns ->
Output(
account = account,
balance = calcAccValues(
accountId = account.id,
accountsTrns = accTrns,
valueFunctions = nonEmptyListOf(AccountValueFunctions::balance)
).head
)
}

composition(
AccTrnsAct.Input(
accountId = account.id,
range = ClosedTimeRange.allTimeIvy()
)
override suspend fun Input.recipe(): suspend () -> Output = suspend {
AccTrnsAct.Input(
accountId = account.id,
range = ClosedTimeRange.allTimeIvy()
)
} then accTrnsAct then { accTrns ->
calcAccValues(
accountId = account.id,
accountsTrns = accTrns,
valueFunctions = nonEmptyListOf(AccountValueFunctions::balance)
).head
} then { balance ->
Output(
account = account,
balance = balance
)

}

data class Input(
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.ivy.wallet.domain.action.wallet

import com.ivy.wallet.domain.action.FPAction
import com.ivy.wallet.domain.action.account.AccountsAct
import com.ivy.wallet.domain.action.settings.BaseCurrencyAct
import com.ivy.wallet.domain.action.then
import java.math.BigDecimal
import javax.inject.Inject

class CalcWalletBalanceAct @Inject constructor(
private val accountsAct: AccountsAct,
private val calcAccBalanceAct: CalcAccBalanceAct,
private val exchangeAct: ExchangeAct,
private val baseCurrencyAct: BaseCurrencyAct
) : FPAction<CalcWalletBalanceAct.Input, BigDecimal>() {

override suspend fun Input.recipe(): suspend () -> BigDecimal = (accountsAct then {
it.filter { acc -> acc.includeInBalance }
} then {
it.map { acc -> calcAccBalanceAct(CalcAccBalanceAct.Input(acc)) }
} then baseCurrencyAct then {
it.map { balanceOutput ->
exchangeAct(
ExchangeAct.Input(
baseCurrency =,
fromCurrency = balanceOutput.account.currency.toOption(),
toCurrency =,
amount = balanceOutput.balance
)
)
}
} then { balances ->
balances.sumOf { it.orNull() ?: BigDecimal.ZERO }
}).fixUnit()

data class Input(
val currency: String
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.ivy.wallet.domain.action.wallet

import arrow.core.Option
import com.ivy.wallet.domain.action.FPAction
import com.ivy.wallet.domain.fp.exchange
import com.ivy.wallet.io.persistence.dao.ExchangeRateDao
import java.math.BigDecimal
import javax.inject.Inject

class ExchangeAct @Inject constructor(
private val exchangeRateDao: ExchangeRateDao,
) : FPAction<ExchangeAct.Input, Option<BigDecimal>>() {

override suspend fun Input.recipe(): suspend () -> Option<BigDecimal> = suspend {
io {
exchange(
baseCurrencyCode = baseCurrency,
exchangeRateDao = exchangeRateDao,
fromAmount = amount,
fromCurrencyCode = fromCurrency,
toCurrencyCode = toCurrency
)
}
}


data class Input(
val baseCurrency: String,
val fromCurrency: Option<String>,
val toCurrency: String,
val amount: BigDecimal
)
}
Loading

0 comments on commit 8b22a51

Please sign in to comment.