How can i avoid long transformation functions when...
# announcements
z
How can i avoid long transformation functions when trying to map elements of flow?
Copy code
override suspend fun observeWatchedShows(): Flow<List<Show>> {
    return watchListDao.observeShows()
        //Map flow of list of Watched Shows to flow of list of Show
        .map { listOfShows ->
            entityMapper.toDomainList(
                //Map list of WatchShows to list of ShowEntity
                listOfShows.map { watchedShow -> watchedShow.show }
            )
        }

    // Mapping Flow<List<WatchedShow>> -> Flow<List<ShowEntity>> -> Flow<List<Show>>
}
d
Extract a
fun Flow<List<WatchedShow>>.mapToShowList()
out of it?
z
sounds good, where would you place this function? the original function is in the repository which does not seem like a good place for extension function
d
Controller private fun
z
Tnx
d
👍🏼
z
No, since i map the elements in the flow and not the flow itself
But flatMap might make it simpler, just emit a new type of flow, i will experiment a bit and update
d
Or zip... or similar, depending on what youre doing
a
the original function is in the repository which does not seem like a good place for extension function
Any place can be a good place for an extension function if makes sense. If it improves the readability, I see no major drawback in adding a private extension function in the same file as the repository
d
It's the transformation logic that's a bit harder to unit test in a repository
z
Thank you, I agree, and also from a testing point of view, having this extension be a private member of the repository would make testing easier as it would eliminate the need for outside players when testing the repository 👍
d
I usually tend to keep the repositories very simple, because testing against a database is harder than isolating and testing a controller
z
In my scenario, the database knows a certain object, and the view knows a different one, I use the repository to map one to the other, preventing each component from knowing about the other components models. Hence the complicated mapping function. So the repository just takes the flow of data from the database, transforms it, and provides a flow of the requested data type to the outside (the ViewModel)
d
But I have made wrappers around a repository in the past for modifying results, and used kotlin delegation for all the other functions that don't need modification.
Then the wrapper doesn't need any db queries, just an adapter that's easy to test
The wrapper implements the function needed, and the db repo gets passed to it's constructor and has a function returning the intermediary result and a noop for the real function the wrapper will implement.
implementing both from the same repo interface, and using kotlin's
by
to delegate to the db repo.
z
That sounds like a good approach, If anyone else is reading this thread, here is a general snippet from the kotlins docs, describing the pattern @dave08 was reffering:
Copy code
interface Base {
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}

class Derived(b: Base) : Base by b

fun main() {
    val b = BaseImpl(10)
    Derived(b).print()
}
d
In your case it's more like:
Copy code
interface Base {
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override fun print() = TODO("Not implemented")
    fun internalPrint() { print(x) }
}

class Derived(b: BaseImpl) : Base by b {
    override fun print() = b.internalPrint() + "---"
}

fun main() {
    val b = BaseImpl(10)
    Derived(b).print()
}
The internalPrint returns
Flow<List<WatchedShow>>
and the print returns
Flow<List<Show>>
Since the return types are different, otherwise, your example is better...