0

I'm wondering if there's a way to wait for a flow to be complete and return the result inside a suspend function. transactionRepository.getAll(accountId) returns a flow of transactions

override suspend fun getAccount(accountId: Int): Account {
    val account = Account(accountRepository.get(accountId))
    transactionRepository.getAll(accountId).mapIterable {
        val transaction = Transaction(it)
        val category = Category(categoryRepository.get(it.categoryId))
        transaction.category = category
        transaction.account = account
        return@mapIterable transaction
    }.collect {
        account.transactions = it
     }

    //TODO: How can i return an account after the flow has been executed?
}

getAll function defined in my repository:

fun getAll(accountId: Int): Flow<List<DatabaseTransaction>>
General Grievance
  • 4,555
  • 31
  • 31
  • 45
DennisVA
  • 2,068
  • 1
  • 25
  • 35

2 Answers2

0

Assuming you want just the first value returned by the flow, and it's a List<Transaction>, you can use first(). But I'm only guessing because I don't know what getAll() returns and I'm not familiar with mapIterable.

override suspend fun getAccount(accountId: Int): Account {
    val account = Account(accountRepository.get(accountId))
    val transactionsFlow: Flow<List<Transaction>> = transactionRepository.getAll(accountId).mapIterable {
        val transaction = Transaction(it)
        val category = Category(categoryRepository.get(it.categoryId))
        transaction.category = category
        transaction.account = account
        return@mapIterable transaction
    }
    account.transactions = transactionsFlow.first()
    return account
}
Tenfour04
  • 83,111
  • 11
  • 94
  • 154
0

You could do two things

First one would be to use the .toList() on the flow which I think gives you the list you want then you can just do a normal for loop on that list to set the data

val transactions = transactionRepository.getAll(accountId).toList()

transactions.forEach{
    val transaction = Transaction(it)
    val category = Category(categoryRepository.get(it.categoryId))
    transaction.category = category
    transaction.account = account
}

account.transactions = transactions 

Second would be to just return the account after the collect like you normally would.

val account = Account(accountRepository.get(accountId))
transactionRepository.getAll(accountId).mapIterable {
    val transaction = Transaction(it)
    val category = Category(categoryRepository.get(it.categoryId))
    transaction.category = category
    transaction.account = account
    return@mapIterable transaction
}.collect {
    account.transactions = it
 }

return account

See this example I made

https://pl.kotl.in/wWmLiqBtz

tyczj
  • 71,600
  • 54
  • 194
  • 296
  • 1
    If the source flow is one that never completes, like one from a database that monitors the database indefinitely for changes, then `toList()` and `collect()` will never return. – Tenfour04 Sep 01 '21 at 14:06
  • @Tenfour04 that is a good caveat for these cases – tyczj Sep 01 '21 at 14:08
  • @Tenfour04 have collects on flows from the database in other places in my code and they seem to be working great though – DennisVA Sep 01 '21 at 14:40
  • but ur definitly right about toList() not returning anything – DennisVA Sep 01 '21 at 14:59
  • `collect` does serve a purpose. When I say it doesn’t return, I mean the code under it is never reached. The lambda passed to `collect` will run for each item that is emitted, but the function call itself will suspend forever. – Tenfour04 Sep 01 '21 at 17:22