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

Commit

Permalink
WIP: Composition
Browse files Browse the repository at this point in the history
  • Loading branch information
ILIYANGERMANOV committed Apr 24, 2022
1 parent 8b22a51 commit 9ad7b53
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 104 deletions.
79 changes: 1 addition & 78 deletions app/src/main/java/com/ivy/wallet/domain/action/Action.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,81 +23,4 @@ abstract class Action<in I, out O> {
withContext(Dispatchers.Main) {
return@withContext action()
}
}

infix fun <A, B, C> Action<B, C>.after(act1: Action<A, B>): Action<A, C> = object : Action<A, C>() {
override suspend fun A.willDo(): C {
val b = act1(this@willDo) //A -> B
return this@after(b) //B -> C
}
}

infix fun <A, B, C> Action<A, B>.then(act2: Action<B, C>): Action<A, C> = object : Action<A, C>() {
override suspend fun A.willDo(): C {
val b = this@then(this)
return act2(b)
}
}

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

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

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

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)
}


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)
}
}
54 changes: 54 additions & 0 deletions app/src/main/java/com/ivy/wallet/domain/action/Composition.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.ivy.wallet.domain.action


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

suspend infix fun <B, C> (suspend () -> B).then(f: suspend (B) -> C): suspend () -> C =
{
val b = this@then()
f(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 <B, C> (suspend () -> B).then(act: Action<B, C>): suspend () -> C =
{
val b = this@then()
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)
}


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)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.ivy.wallet.domain.action

suspend infix fun <A> (suspend (Any) -> List<A>).thenFilter(
predicate: (A) -> Boolean
): suspend (Any) -> List<A> =
{ a ->
val list = this(a)
list.filter(predicate)
}
4 changes: 2 additions & 2 deletions app/src/main/java/com/ivy/wallet/domain/action/FPAction.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.ivy.wallet.domain.action

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

override suspend fun I.willDo(): O {
return recipe().invoke()
return compose().invoke()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import javax.inject.Inject
class AccTrnsAct @Inject constructor(
private val transactionDao: TransactionDao
) : FPAction<AccTrnsAct.Input, List<Transaction>>() {
override suspend fun Input.recipe(): suspend () -> List<Transaction> = suspend {
override suspend fun Input.compose(): suspend () -> List<Transaction> = suspend {
io {
transactionDao.findAllByAccountAndBetween(
accountId = accountId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ 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 {
override suspend fun Unit.compose(): suspend () -> List<Account> = suspend {
io { accountDao.findAll() }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import javax.inject.Inject
class BaseCurrencyAct @Inject constructor(
private val settingsDao: SettingsDao
) : FPAction<Unit, String>() {
override suspend fun Unit.recipe(): suspend () -> String {
override suspend fun Unit.compose(): suspend () -> String {
return suspend {
io { baseCurrencyCode(settingsDao) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class CalcAccBalanceAct @Inject constructor(
private val accTrnsAct: AccTrnsAct
) : FPAction<CalcAccBalanceAct.Input, CalcAccBalanceAct.Output>() {

override suspend fun Input.recipe(): suspend () -> Output = suspend {
override suspend fun Input.compose(): suspend () -> Output = suspend {
AccTrnsAct.Input(
accountId = account.id,
range = ClosedTimeRange.allTimeIvy()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.ivy.wallet.domain.action.wallet

import arrow.core.toOption
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.fixUnit
import com.ivy.wallet.domain.action.then
import java.math.BigDecimal
import javax.inject.Inject
Expand All @@ -11,29 +12,32 @@ 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
override suspend fun Input.compose(): suspend () -> BigDecimal = recipe().fixUnit()

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

data class Input(
val currency: String
val baseCurrency: String,
val balanceCurrency: String
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class ExchangeAct @Inject constructor(
private val exchangeRateDao: ExchangeRateDao,
) : FPAction<ExchangeAct.Input, Option<BigDecimal>>() {

override suspend fun Input.recipe(): suspend () -> Option<BigDecimal> = suspend {
override suspend fun Input.compose(): suspend () -> Option<BigDecimal> = suspend {
io {
exchange(
baseCurrencyCode = baseCurrency,
Expand Down

0 comments on commit 9ad7b53

Please sign in to comment.