Skip to content

Instantly share code, notes, and snippets.

@timrijckaert
Last active March 22, 2021 11:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timrijckaert/fbe90cf9b3d3f4c75116a06217da6cdb to your computer and use it in GitHub Desktop.
Save timrijckaert/fbe90cf9b3d3f4c75116a06217da6cdb to your computer and use it in GitHub Desktop.
package com.example.sample
import arrow.core.Either
import arrow.core.NonEmptyList
import arrow.core.computations.either
import arrow.core.flatMap
import arrow.core.nonEmptyListOf
import arrow.core.right
import arrow.core.traverseEither
import arrow.core.zip
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: Db, public val db: Nw)
public val appModule: AppModule = AppModule(Db(), Nw())
//</editor-fold>
//<editor-fold desc="News List">
public interface NewsRepository {
public suspend fun headlines(): Either<Failure, NonEmptyList<NewsItem>>
}
public class NewsRepositoryImpl(private val newsDataSource: NewsDataSource) : NewsRepository {
override suspend fun headlines(): Either<Failure, NonEmptyList<NewsItem>> =
newsDataSource.fetchNwHeadlines().zip(newsDataSource.fetchDbHeadlines()) { nw, db -> nw + db }
}
public interface HttpNewsDataSource {
public suspend fun fetchNwHeadlines(): Either<Failure, NonEmptyList<NewsItem>>
}
public interface DbNewsDataSource {
public suspend fun fetchDbHeadlines(): Either<Failure, NonEmptyList<NewsItem>>
}
public interface NewsDataSource : HttpNewsDataSource, DbNewsDataSource
public class NewsDataSourceImpl(
private val retroFit: Db,
private val db: Nw
) : NewsDataSource {
override suspend fun fetchNwHeadlines(): Either<Failure, NonEmptyList<NewsItem>> =
nonEmptyListOf(
NewsItem("1"),
NewsItem("2"),
NewsItem("3"),
).right()
override suspend fun fetchDbHeadlines(): Either<Failure, NonEmptyList<NewsItem>> =
nonEmptyListOf(
NewsItem("4"),
NewsItem("5"),
NewsItem("6"),
).right()
}
public interface ListModule {
public val newsRepository: NewsRepository
}
public suspend fun ListModule.headlines(): Either<Failure, NonEmptyList<NewsItem>> = newsRepository.headlines()
public fun newsListModule(appModule: AppModule): ListModule =
object : ListModule {
override val newsRepository: NewsRepository
get() = NewsRepositoryImpl(NewsDataSourceImpl(appModule.retrofit, appModule.db))
}
//</editor-fold>
//<editor-fold desc="Detail">
public interface DetailRepository {
public suspend fun detail(newsItem: NewsItem): Either<Failure, Detail>
}
public class DetailRepositoryImpl(private val detailDataSource: DetailDataSource) : DetailRepository {
override suspend fun detail(newsItem: NewsItem): Either<Failure, Detail> =
either {
raceN(
{ detailDataSource.fetchNwDetail(newsItem).bind() },
{ detailDataSource.fetchDbDetail(newsItem).bind() }
).mapLeft { Failure }.bind()
}
}
public interface HttpDetailDataSource {
public suspend fun fetchNwDetail(newsItem: NewsItem): Either<Failure, Detail>
}
public interface DbDetailDataSource {
public suspend fun fetchDbDetail(newsItem: NewsItem): Either<Failure, Detail>
}
public interface DetailDataSource : HttpDetailDataSource, DbDetailDataSource
public class DetailDataSourceImpl(private val retrofit: Db, private val db: Nw) : DetailDataSource {
override suspend fun fetchNwDetail(newsItem: NewsItem): Either<Failure, Detail> =
Detail(newsItem.id, "Nw: Content of $newsItem").right()
override suspend fun fetchDbDetail(newsItem: NewsItem): Either<Failure, Detail> =
Detail(newsItem.id, "Db: Content of $newsItem").right()
}
public interface DetailModule {
public val detailRepository: DetailRepository
}
public suspend fun DetailModule.detail(newsItem: NewsItem): Either<Failure, Detail> = detailRepository.detail(newsItem)
public fun detailModule(appModule: AppModule): DetailModule =
object : DetailModule {
override val detailRepository: DetailRepository =
DetailRepositoryImpl(DetailDataSourceImpl(appModule.retrofit, appModule.db))
}
//</editor-fold>
public suspend fun main() {
val newsList = newsListModule(appModule)
val detailModule = detailModule(appModule)
val detailPages =
newsList.headlines()
.flatMap {
it.traverseEither { newsItem -> detailModule.detail(newsItem) }
}
println(detailPages)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment