Skip to content

Instantly share code, notes, and snippets.

@nomisRev
Last active November 23, 2021 08:20
Show Gist options
  • Select an option

  • Save nomisRev/4569b3035a7f2bbc51a9bee6fb27dabc to your computer and use it in GitHub Desktop.

Select an option

Save nomisRev/4569b3035a7f2bbc51a9bee6fb27dabc to your computer and use it in GitHub Desktop.
Receiver Context Dependency Injection
package com.example.sample
import arrow.core.*
import arrow.core.computations.either
import arrow.fx.coroutines.raceN
public data class NewsItem(val id: String)
public data class Detail(val id: String, val content: String)
public object Failure
public class Db
public class Nw
//<editor-fold desc="Singleton">
public class AppModule(public val retrofit: Nw, public val db: Db)
public val appModule: AppModule = AppModule(Nw(), Db())
//</editor-fold>
//<editor-fold desc="News List">
public interface NewsRepository {
public suspend fun headlines(): Either<Failure, NonEmptyList<NewsItem>>
fun zip(other: NewsRepository): NewsRepository =
object : NewsRepository {
override suspend fun headlines(): Either<Failure, NonEmptyList<NewsItem>> =
[email protected]().zip(other.headlines()) { nw, db -> nw + db }
}
}
class NewsDatabaseImpl(private val database: Db) : NewsRepository {
override suspend fun headlines(): Either<Failure, NonEmptyList<NewsItem>> =
nonEmptyListOf(
NewsItem("4"),
NewsItem("5"),
NewsItem("6"),
).right()
}
class NewsNetworkImpl(private val network: Nw) : NewsRepository {
override suspend fun headlines(): Either<Failure, NonEmptyList<NewsItem>> =
nonEmptyListOf(
NewsItem("1"),
NewsItem("2"),
NewsItem("3"),
).right()
}
//</editor-fold>
//<editor-fold desc="Detail">
public interface DetailRepository {
public suspend fun detail(newsItem: NewsItem): Either<Failure, Detail>
}
public class DetailRepositoryImpl(
private val network: DetailRepository,
private val database: DetailRepository
) : DetailRepository {
override suspend fun detail(newsItem: NewsItem): Either<Failure, Detail> =
either {
raceN(
{ network.detail(newsItem).bind() },
{ database.detail(newsItem).bind() }
).merge()
}
}
class NetworkDetailDataSource(private val retrofit: Nw): DetailRepository {
override suspend fun detail(newsItem: NewsItem): Either<Failure, Detail> =
Detail(newsItem.id, "Nw: Content of $newsItem").right()
}
class DatabaseDetailDataSource(private val db: Db): DetailRepository {
override suspend fun detail(newsItem: NewsItem): Either<Failure, Detail> =
Detail(newsItem.id, "Db: Content of $newsItem").right()
}
//</editor-fold>
interface Module: NewsRepository, DetailRepository
fun module(newsRepository: NewsRepository, detailRepository: DetailRepository): Module =
object : Module, NewsRepository by newsRepository, DetailRepository by detailRepository { }
suspend fun Module.program(): Either<Failure, NonEmptyList<Detail>> =
headlines().flatMap {
it.traverseEither { detail(it) }
}
public suspend fun main() {
val news: NewsRepository =
NewsNetworkImpl(appModule.retrofit).zip(NewsDatabaseImpl(appModule.db))
val detail: DetailRepository =
DetailRepositoryImpl(
NetworkDetailDataSource(appModule.retrofit),
DatabaseDetailDataSource(appModule.db)
)
val module = module(news, detail)
val detailPages = module.program()
println(detailPages)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment