Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial attempt to refactor datasets (now datasources) and repository… #3

Merged
merged 1 commit into from
Mar 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ import com.antonioleiva.bandhookkotlin.data.mapper.AlbumMapper
import com.antonioleiva.bandhookkotlin.domain.entity.Album
import com.antonioleiva.bandhookkotlin.domain.entity.BizException.AlbumNotFound
import com.antonioleiva.bandhookkotlin.left
import com.antonioleiva.bandhookkotlin.repository.dataset.AlbumDataSet
import com.antonioleiva.bandhookkotlin.repository.datasource.AlbumDataSource
import com.antonioleiva.bandhookkotlin.right

class CloudAlbumDataSet(val lastFmService: LastFmService) : AlbumDataSet {
class CloudAlbumDataSource(val lastFmService: LastFmService) : AlbumDataSource {

override fun requestAlbum(mbid: String): Result<AlbumNotFound, Album> {
return lastFmService.requestAlbum(mbid).asResult<AlbumNotFound, LastFmResponse, Album> {
override fun get(id: String): Result<AlbumNotFound, Album> {
return lastFmService.requestAlbum(id).asResult<AlbumNotFound, LastFmResponse, Album> {
AlbumMapper().transform(album).fold(
{ AlbumNotFound(mbid).left<AlbumNotFound, Album>() },
{ AlbumNotFound(id).left<AlbumNotFound, Album>() },
{ it.right<AlbumNotFound, Album>() }
)
}
Expand All @@ -49,4 +49,5 @@ class CloudAlbumDataSet(val lastFmService: LastFmService) : AlbumDataSet {

return emptyList()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@ import com.antonioleiva.bandhookkotlin.data.mapper.ArtistMapper
import com.antonioleiva.bandhookkotlin.domain.entity.Artist
import com.antonioleiva.bandhookkotlin.domain.entity.BizException.ArtistNotFound
import com.antonioleiva.bandhookkotlin.left
import com.antonioleiva.bandhookkotlin.repository.dataset.ArtistDataSet
import com.antonioleiva.bandhookkotlin.repository.datasource.ArtistDataSource
import com.antonioleiva.bandhookkotlin.right

class CloudArtistDataSet(val language: String, val lastFmService: LastFmService) : ArtistDataSet {
class CloudArtistDataSource(val language: String, val lastFmService: LastFmService) : ArtistDataSource {

val coldplayMbid = "cc197bad-dc9c-440d-a5b5-d52ba2e14234"

override fun requestArtist(mbid: String): Result<ArtistNotFound, Artist> {
return lastFmService.requestArtistInfo(mbid, language).asResult<ArtistNotFound,
override fun get(id: String): Result<ArtistNotFound, Artist> {
return lastFmService.requestArtistInfo(id, language).asResult<ArtistNotFound,
LastFmResponse, Artist> {
ArtistMapper().transform(artist).fold(
{ ArtistNotFound(mbid).left<ArtistNotFound, Artist>() },
{ ArtistNotFound(id).left<ArtistNotFound, Artist>() },
{ it.right<ArtistNotFound, Artist>() }
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.antonioleiva.bandhookkotlin.di

import com.antonioleiva.bandhookkotlin.data.CloudAlbumDataSet
import com.antonioleiva.bandhookkotlin.data.CloudArtistDataSet
import com.antonioleiva.bandhookkotlin.data.CloudAlbumDataSource
import com.antonioleiva.bandhookkotlin.data.CloudArtistDataSource
import com.antonioleiva.bandhookkotlin.data.lastfm.LastFmService
import com.antonioleiva.bandhookkotlin.di.qualifier.LanguageSelection
import com.antonioleiva.bandhookkotlin.domain.repository.AlbumRepository
import com.antonioleiva.bandhookkotlin.domain.repository.ArtistRepository
import com.antonioleiva.bandhookkotlin.repository.AlbumRepositoryImpl
import com.antonioleiva.bandhookkotlin.repository.ArtistRepositoryImp
import com.antonioleiva.bandhookkotlin.repository.ArtistRepositoryImpl
import dagger.Module
import dagger.Provides
import javax.inject.Singleton
Expand All @@ -17,9 +17,9 @@ class RepositoryModule {

@Provides @Singleton
fun provideArtistRepo(@LanguageSelection language: String, lastFmService: LastFmService): ArtistRepository
= ArtistRepositoryImp(listOf(CloudArtistDataSet(language, lastFmService)))
= ArtistRepositoryImpl(listOf(CloudArtistDataSource(language, lastFmService)))

@Provides @Singleton
fun provideAlbumRepo(lastFmService: LastFmService): AlbumRepository
= AlbumRepositoryImpl(listOf(CloudAlbumDataSet(lastFmService)))
= AlbumRepositoryImpl(listOf(CloudAlbumDataSource(lastFmService)))
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ import com.antonioleiva.bandhookkotlin.domain.repository.AlbumRepository

class GetAlbumDetailInteractor(val albumRepository: AlbumRepository) {

fun getAlbum(albumId: String) = albumRepository.getAlbum(albumId)
fun getAlbum(albumId: String) = albumRepository.get(albumId)

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ import com.antonioleiva.bandhookkotlin.domain.repository.ArtistRepository

class GetArtistDetailInteractor(val artistRepository: ArtistRepository) {

fun getArtist(artistId: String) = artistRepository.getArtist(artistId)
fun getArtist(artistId: String) = artistRepository.get(artistId)

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@

package com.antonioleiva.bandhookkotlin.domain.repository

import com.antonioleiva.bandhookkotlin.Result
import com.antonioleiva.bandhookkotlin.domain.entity.Album
import com.antonioleiva.bandhookkotlin.domain.entity.BizException.AlbumNotFound

interface AlbumRepository {
interface AlbumRepository : Repository<AlbumNotFound, Album, String> {
fun getTopAlbums(artistId: String?, artistName: String?): List<Album>
fun getAlbum(id: String): Result<AlbumNotFound, Album>
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@

package com.antonioleiva.bandhookkotlin.domain.repository

import com.antonioleiva.bandhookkotlin.Result
import com.antonioleiva.bandhookkotlin.domain.entity.Artist
import com.antonioleiva.bandhookkotlin.domain.entity.BizException.ArtistNotFound

interface ArtistRepository {
interface ArtistRepository : Repository<ArtistNotFound, Artist, String> {
fun getRecommendedArtists(): List<Artist>
fun getArtist(id: String): Result<ArtistNotFound, Artist>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.antonioleiva.bandhookkotlin.domain.repository

import com.antonioleiva.bandhookkotlin.Result
import com.antonioleiva.bandhookkotlin.recoverWith
import com.antonioleiva.bandhookkotlin.repository.datasource.DataSource
import org.funktionale.collections.tail

/**
*
*/
interface Repository<E, A, ID> {
val dataSources: List<DataSource<E, A, ID>>

/**
* Trampolined (async) recursion until all DataSources are exhausted or a right result is found
*/
fun recurseDataSources(currentDataSources: List<DataSource<E, A, ID>>,
acc: Result<E, A>, f:
(DataSource<E, A, ID>) -> Result<E, A>): Result<E, A> =
if (currentDataSources.isEmpty()) {
acc
} else {
val current = currentDataSources.get(0)
f(current).recoverWith {
recurseDataSources(currentDataSources.tail(), f(current), f)
}
}

// TODO: The only missing bit to provide a default implementation for get is a constructor /
// factory for the error
fun get(id: ID): Result<E, A>
// = recurseDataSources(
// currentDataSources = dataSources,
// acc = ResultT.raiseError<E, A>(E(id)),
// f = { it.get(id) }
// )

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,35 +21,20 @@ import com.antonioleiva.bandhookkotlin.ResultT
import com.antonioleiva.bandhookkotlin.domain.entity.Album
import com.antonioleiva.bandhookkotlin.domain.entity.BizException.AlbumNotFound
import com.antonioleiva.bandhookkotlin.domain.repository.AlbumRepository
import com.antonioleiva.bandhookkotlin.recoverWith
import com.antonioleiva.bandhookkotlin.repository.dataset.AlbumDataSet
import org.funktionale.collections.tail
import com.antonioleiva.bandhookkotlin.repository.datasource.AlbumDataSource

class AlbumRepositoryImpl(val albumDataSets: List<AlbumDataSet>) : AlbumRepository {
class AlbumRepositoryImpl(override val dataSources: List<AlbumDataSource>) : AlbumRepository {

/** Trampolined (async) recursion until all DataSets are exhausted or a right result is found */
fun <E, A> recurseDataSets(currentDataSets: List<AlbumDataSet>, acc: Result<E, A>, f: (AlbumDataSet) -> Result<E, A>): Result<E, A> =
if (currentDataSets.isEmpty()) {
acc
} else {
val current = currentDataSets.get(0)
f(current).recoverWith {
recurseDataSets(currentDataSets.tail(), f(current), f)
}
}


override fun getAlbum(id: String): Result<AlbumNotFound, Album> =
recurseDataSets(
currentDataSets = albumDataSets,
override fun get(id: String): Result<AlbumNotFound, Album> =
recurseDataSources(
currentDataSources = dataSources,
acc = ResultT.raiseError<AlbumNotFound, Album>(AlbumNotFound(id)),
f = { it.requestAlbum(id) }
f = { it.get(id) }
)


override fun getTopAlbums(artistId: String?, artistName: String?): List<Album> {
for (dataSet in albumDataSets) {
val result = dataSet.requestTopAlbums(artistId, artistName)
for (dataSource in dataSources) {
val result = dataSource.requestTopAlbums(artistId, artistName)
if (result.isNotEmpty()) {
return result
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,20 @@ import com.antonioleiva.bandhookkotlin.ResultT
import com.antonioleiva.bandhookkotlin.domain.entity.Artist
import com.antonioleiva.bandhookkotlin.domain.entity.BizException.ArtistNotFound
import com.antonioleiva.bandhookkotlin.domain.repository.ArtistRepository
import com.antonioleiva.bandhookkotlin.recoverWith
import com.antonioleiva.bandhookkotlin.repository.dataset.ArtistDataSet
import org.funktionale.collections.tail
import com.antonioleiva.bandhookkotlin.repository.datasource.ArtistDataSource

class ArtistRepositoryImp(val artistDataSets: List<ArtistDataSet>) : ArtistRepository {
class ArtistRepositoryImpl(override val dataSources: List<ArtistDataSource>) : ArtistRepository {

/** Trampolined (async) recursion until all DataSets are exhausted or a right result is found */
fun <E, A> recurseDataSets(currentDataSets: List<ArtistDataSet>, acc: Result<E, A>, f:
(ArtistDataSet) -> Result<E, A>): Result<E, A> =
if (currentDataSets.isEmpty()) {
acc
} else {
val current = currentDataSets.get(0)
f(current).recoverWith {
recurseDataSets(currentDataSets.tail(), f(current), f)
}
}

override fun getArtist(id: String): Result<ArtistNotFound, Artist> =
recurseDataSets(
currentDataSets = artistDataSets,
override fun get(id: String): Result<ArtistNotFound, Artist> =
recurseDataSources(
currentDataSources = dataSources,
acc = ResultT.raiseError<ArtistNotFound, Artist>(ArtistNotFound(id)),
f = { it.requestArtist(id) }
f = { it.get(id) }
)

override fun getRecommendedArtists(): List<Artist> {
for (dataSet in artistDataSets) {
val result = dataSet.requestRecommendedArtists()
for (dataSource in dataSources) {
val result = dataSource.requestRecommendedArtists()
if (result.isNotEmpty()) {
return result
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,13 @@
* limitations under the License.
*/

package com.antonioleiva.bandhookkotlin.repository.dataset
package com.antonioleiva.bandhookkotlin.repository.datasource

import com.antonioleiva.bandhookkotlin.Result
import com.antonioleiva.bandhookkotlin.domain.entity.Album
import com.antonioleiva.bandhookkotlin.domain.entity.BizException.AlbumNotFound

interface AlbumDataSet {
interface AlbumDataSource : DataSource<AlbumNotFound, Album, String> {

fun requestTopAlbums(artistId: String?, artistName: String?): List<Album>
fun requestAlbum(mbid: String): Result<AlbumNotFound, Album>

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,13 @@
* limitations under the License.
*/

package com.antonioleiva.bandhookkotlin.repository.dataset
package com.antonioleiva.bandhookkotlin.repository.datasource

import com.antonioleiva.bandhookkotlin.Result
import com.antonioleiva.bandhookkotlin.domain.entity.Artist
import com.antonioleiva.bandhookkotlin.domain.entity.BizException.ArtistNotFound

interface ArtistDataSet {
interface ArtistDataSource : DataSource<ArtistNotFound, Artist, String> {

fun requestRecommendedArtists(): List<Artist>
fun requestArtist(mbid: String): Result<ArtistNotFound, Artist>

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.antonioleiva.bandhookkotlin.repository.datasource

import com.antonioleiva.bandhookkotlin.Result

/**
*
*/
interface DataSource<E, A, ID> {
fun get(id: ID): Result<E, A>
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,23 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.*
import org.mockito.runners.MockitoJUnitRunner
import org.mockito.junit.MockitoJUnitRunner
import retrofit2.Response

@RunWith(MockitoJUnitRunner::class)
class CloudAlbumDataSetTest {
class CloudAlbumDataSourceTest {

@Mock
lateinit var lastFmService: LastFmService

lateinit var cloudAlbumDataSet: CloudAlbumDataSet
lateinit var cloudAlbumDataSource: CloudAlbumDataSource
lateinit var lastFmResponse: LastFmResponse
lateinit var knownAlbumDetail: LastFmAlbumDetail
lateinit var unknownAlbumDetail: LastFmAlbumDetail
lateinit var album: LastFmAlbum
lateinit var artist: LastFmArtist
lateinit var topAlbums: LastFmTopAlbums
lateinit var albums: List<LastFmAlbum>
lateinit var albums: List<LastFmAlbum>

private val albumMapper = AlbumMapper()
private val albumMbid = "album mbid"
Expand All @@ -51,7 +51,7 @@ class CloudAlbumDataSetTest {

@Before
fun setUp() {
cloudAlbumDataSet = CloudAlbumDataSet(lastFmService)
cloudAlbumDataSource = CloudAlbumDataSource(lastFmService)

artist = LastFmArtist(artistName, artistMbid, "artist url", emptyList(), null, null)
album = LastFmAlbum("album name", albumMbid, "album url",
Expand All @@ -73,7 +73,7 @@ class CloudAlbumDataSetTest {
@Test
fun testRequestAlbum_knownAlbum() {
// When
val album = cloudAlbumDataSet.requestAlbum(albumMbid)
val album = cloudAlbumDataSource.get(albumMbid)

// Then
verify(lastFmService).requestAlbum(albumMbid)
Expand All @@ -88,7 +88,7 @@ class CloudAlbumDataSetTest {
`when`(lastFmService.requestAlbum(albumMbid)).thenReturn(FakeCall(Response.success(unknownAlbumResponse), null))

// When
val album = cloudAlbumDataSet.requestAlbum(albumMbid)
val album = cloudAlbumDataSource.get(albumMbid)

// Then
verify(lastFmService).requestAlbum(albumMbid)
Expand All @@ -98,7 +98,7 @@ class CloudAlbumDataSetTest {
@Test
fun testRequestTopAlbums_byArtistMbid() {
// When
val albums = cloudAlbumDataSet.requestTopAlbums(artistMbid, null)
val albums = cloudAlbumDataSource.requestTopAlbums(artistMbid, null)

// Then
verify(lastFmService).requestAlbums(artistMbid, "")
Expand All @@ -108,7 +108,7 @@ class CloudAlbumDataSetTest {
@Test
fun testRequestTopAlbums_byArtistName() {
// When
val albums = cloudAlbumDataSet.requestTopAlbums(null, artistName)
val albums = cloudAlbumDataSource.requestTopAlbums(null, artistName)

// Then
verify(lastFmService).requestAlbums("", artistName)
Expand All @@ -118,7 +118,7 @@ class CloudAlbumDataSetTest {
@Test
fun testRequestTopAlbums_byArtistNameAndMbid() {
// When
val albums = cloudAlbumDataSet.requestTopAlbums(artistMbid, artistName)
val albums = cloudAlbumDataSource.requestTopAlbums(artistMbid, artistName)

// Then
verify(lastFmService).requestAlbums(artistMbid, artistName)
Expand All @@ -128,10 +128,10 @@ class CloudAlbumDataSetTest {
@Test
fun testRequestTopAlbums_noArguments() {
// When
val albums = cloudAlbumDataSet.requestTopAlbums(null, null)
val albums = cloudAlbumDataSource.requestTopAlbums(null, null)

// Then
verify(lastFmService, never()).requestAlbums(anyString(), anyString())
assertTrue(albums.isEmpty())
}
}
}
Loading