I’m migrating a database library from `Iterable` t...
# coroutines
v
I’m migrating a database library from
Iterable
to
Flow
. To have legacy support, I’m trying to wrap all Flows into existing blocking code. Is there a way to convert a Flow to an Iterator/Iterable, similar as the
Iterable.asFlow()
function exists the other way around?
The only way I found is to collect the whole Flow to a List and expose that one. However, in the context of database queries this approach seems not to be very ideal.
s
To ensure correct resource management, a flow has to be consumed in its entirety by a single call to
collect
. So you can’t just create an iterator directly from a flow. If you really need to do this, your best bet is probably to use
produceIn
to get a channel, and then make a blocking iterator that receives from the channel. That way the resource management of the flow is handled by the coroutine in which you launch the channel producer job.
v
Thank you Sam for the pointer to
produceIn
. I wrote now those two helper functions (in case anyone else finds this conversation):
Copy code
@OptIn(FlowPreview::class, DelicateCoroutinesApi::class)
private fun <T> Flow<T>.toBlockingIterator(scope: CoroutineScope = GlobalScope): Iterator<T> {
  return this
    .produceIn(scope)
    .iterator()
    .toBlockingIterator()
}

private fun <T> ChannelIterator<T>.toBlockingIterator() = object : Iterator<T> {
  override fun hasNext(): Boolean {
    return runBlocking { this@toBlockingIterator.hasNext() }
  }

  override fun next(): T {
    return runBlocking { this@toBlockingIterator.next() }
  }
}