Skip to content

Commit

Permalink
Update to store5 to 5.0.0-beta01 (#1294)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisbanes committed May 30, 2023
1 parent ff49ee1 commit 0429edc
Show file tree
Hide file tree
Showing 22 changed files with 155 additions and 171 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import app.tivi.data.episodes.EpisodeBinds
import app.tivi.data.followedshows.FollowedShowsBinds
import app.tivi.data.popularshows.PopularShowsBinds
import app.tivi.data.recommendedshows.RecommendedShowsBinds
import app.tivi.data.relatedshows.RelatedShowsBinds
import app.tivi.data.search.SearchBinds
import app.tivi.data.showimages.ShowImagesBinds
import app.tivi.data.shows.ShowsBinds
import app.tivi.data.traktauth.RelatedShowsBinds
import app.tivi.data.traktauth.TraktAuthComponent
import app.tivi.data.traktusers.TraktUsersBinds
import app.tivi.data.trendingshows.TrendingShowsBinds
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import coil.request.ImageRequest
import coil.request.ImageResult
import coil.size.pxOrElse
import me.tatarka.inject.annotations.Inject
import org.mobilenativefoundation.store.store5.get
import org.mobilenativefoundation.store.store5.impl.extensions.get

@Inject
class ShowCoilInterceptor(
Expand All @@ -36,7 +36,7 @@ class ShowCoilInterceptor(
model: ShowImageModel,
): ImageRequest {
val entity = runCatching {
findHighestRatedForType(showImagesStore.get(model.id), model.imageType)
findHighestRatedForType(showImagesStore.get(model.id).images, model.imageType)
}.getOrNull()

return if (entity != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ abstract class EntityLastRequestStore(
return isRequestBefore(entityId, Clock.System.now() - threshold)
}

fun isRequestValid(entityId: Long, threshold: Duration): Boolean {
return !isRequestExpired(entityId, threshold)
}

fun hasBeenRequested(entityId: Long): Boolean = dao.requestCount(request, entityId) > 0

fun isRequestBefore(entityId: Long, instant: Instant): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ open class GroupLastRequestStore(
return isRequestBefore(Clock.System.now() - threshold)
}

fun isRequestValid(threshold: Duration): Boolean {
return !isRequestExpired(threshold)
}

fun isRequestBefore(instant: Instant): Boolean {
return getRequestInstant()?.let { it < instant } ?: true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ package app.tivi.data.util

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filterNot
import org.mobilenativefoundation.store.store5.Fetcher
import org.mobilenativefoundation.store.store5.SourceOfTruth
import org.mobilenativefoundation.store.store5.Store
import org.mobilenativefoundation.store.store5.StoreResponse
import org.mobilenativefoundation.store.store5.fresh
import org.mobilenativefoundation.store.store5.get
import org.mobilenativefoundation.store.store5.StoreBuilder
import org.mobilenativefoundation.store.store5.StoreReadResponse
import org.mobilenativefoundation.store.store5.impl.extensions.fresh
import org.mobilenativefoundation.store.store5.impl.extensions.get

suspend inline fun <Key : Any, Output : Any> Store<Key, Output>.fetch(
key: Key,
Expand All @@ -19,6 +22,12 @@ suspend inline fun <Key : Any, Output : Any> Store<Key, Output>.fetch(
else -> get(key)
}

fun <T> Flow<StoreResponse<T>>.filterForResult(): Flow<StoreResponse<T>> = filterNot {
it is StoreResponse.Loading || it is StoreResponse.NoNewData
fun <T> Flow<StoreReadResponse<T>>.filterForResult(): Flow<StoreReadResponse<T>> = filterNot {
it is StoreReadResponse.Loading || it is StoreReadResponse.NoNewData
}

@Suppress("NOTHING_TO_INLINE")
inline fun <Key : Any, Model : Any> storeBuilder(
fetcher: Fetcher<Key, Model>,
sourceOfTruth: SourceOfTruth<Key, Model>,
): StoreBuilder<Key, Model> = StoreBuilder.from(fetcher, sourceOfTruth)
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ package app.tivi.data.models

import app.tivi.extensions.unsafeLazy

data class ShowImages(val images: List<ShowTmdbImage>) {

data class ShowImages(
val showId: Long,
val images: List<ShowTmdbImage>,
) {
val backdrop by unsafeLazy { findHighestRatedForType(ImageType.BACKDROP) }

val poster by unsafeLazy { findHighestRatedForType(ImageType.POSTER) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import app.tivi.data.daos.getIdOrSavePlaceholder
import app.tivi.data.daos.updatePage
import app.tivi.data.db.DatabaseTransactionRunner
import app.tivi.data.models.PopularShowEntry
import app.tivi.data.util.storeBuilder
import app.tivi.inject.ApplicationScope
import kotlin.time.Duration.Companion.hours
import kotlinx.coroutines.flow.map
import me.tatarka.inject.annotations.Inject
import org.mobilenativefoundation.store.store5.Fetcher
import org.mobilenativefoundation.store.store5.SourceOfTruth
import org.mobilenativefoundation.store.store5.Store
import org.mobilenativefoundation.store.store5.StoreBuilder
import org.mobilenativefoundation.store.store5.Validator

@ApplicationScope
@Inject
Expand All @@ -26,41 +26,35 @@ class PopularShowsStore(
showDao: TiviShowDao,
lastRequestStore: PopularShowsLastRequestStore,
transactionRunner: DatabaseTransactionRunner,
) : Store<Int, List<PopularShowEntry>> by StoreBuilder.from(
) : Store<Int, List<PopularShowEntry>> by storeBuilder(
fetcher = Fetcher.of { page: Int ->
dataSource(page, 20)
.also {
if (page == 0) lastRequestStore.updateLastRequest()
dataSource(page, 20).let { response ->
transactionRunner {
if (page == 0) {
lastRequestStore.updateLastRequest()
}
response.map { (show, entry) ->
entry.copy(showId = showDao.getIdOrSavePlaceholder(show), page = page)
}
}
}
},
sourceOfTruth = SourceOfTruth.of(
reader = { page ->
popularShowsDao.entriesObservable(page).map { entries ->
when {
// Store only treats null as 'no value', so convert to null
entries.isEmpty() -> null
// If the request is expired, our data is stale
lastRequestStore.isRequestExpired(3.hours) -> null
// Otherwise, our data is fresh and valid
else -> entries
}
}
},
reader = { page -> popularShowsDao.entriesObservable(page) },
writer = { page, response ->
transactionRunner {
val entries = response.map { (show, entry) ->
entry.copy(showId = showDao.getIdOrSavePlaceholder(show), page = page)
}
if (page == 0) {
// If we've requested page 0, remove any existing entries first
popularShowsDao.deleteAll()
popularShowsDao.upsert(entries)
popularShowsDao.upsert(response)
} else {
popularShowsDao.updatePage(page, entries)
popularShowsDao.updatePage(page, response)
}
}
},
delete = popularShowsDao::deletePage,
deleteAll = popularShowsDao::deleteAll,
),
).validator(
Validator.by { lastRequestStore.isRequestValid(3.hours) },
).build()
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import app.tivi.data.daos.getIdOrSavePlaceholder
import app.tivi.data.daos.updatePage
import app.tivi.data.db.DatabaseTransactionRunner
import app.tivi.data.models.RecommendedShowEntry
import app.tivi.data.util.storeBuilder
import app.tivi.inject.ApplicationScope
import kotlin.time.Duration.Companion.days
import kotlinx.coroutines.flow.map
import me.tatarka.inject.annotations.Inject
import org.mobilenativefoundation.store.store5.Fetcher
import org.mobilenativefoundation.store.store5.SourceOfTruth
import org.mobilenativefoundation.store.store5.Store
import org.mobilenativefoundation.store.store5.StoreBuilder
import org.mobilenativefoundation.store.store5.Validator

@ApplicationScope
@Inject
Expand All @@ -26,44 +26,38 @@ class RecommendedShowsStore(
showDao: TiviShowDao,
lastRequestStore: RecommendedShowsLastRequestStore,
transactionRunner: DatabaseTransactionRunner,
) : Store<Int, List<RecommendedShowEntry>> by StoreBuilder.from(
) : Store<Int, List<RecommendedShowEntry>> by storeBuilder(
fetcher = Fetcher.of { page: Int ->
dataSource(page, 20)
.also {
dataSource(page, 20).let { response ->
transactionRunner {
if (page == 0) {
lastRequestStore.updateLastRequest()
}
response.map { show ->
RecommendedShowEntry(
showId = showDao.getIdOrSavePlaceholder(show),
page = page,
)
}
}
}
},
sourceOfTruth = SourceOfTruth.of(
reader = { page ->
recommendedDao.entriesForPage(page).map { entries ->
when {
// Store only treats null as 'no value', so convert to null
entries.isEmpty() -> null
// If the request is expired, our data is stale
lastRequestStore.isRequestExpired(3.days) -> null
// Otherwise, our data is fresh and valid
else -> entries
}
}
},
reader = { page -> recommendedDao.entriesForPage(page) },
writer = { page, response ->
transactionRunner {
val entries = response.map { show ->
val showId = showDao.getIdOrSavePlaceholder(show)
RecommendedShowEntry(showId = showId, page = page)
}
if (page == 0) {
// If we've requested page 0, remove any existing entries first
recommendedDao.deleteAll()
recommendedDao.upsert(entries)
recommendedDao.upsert(response)
} else {
recommendedDao.updatePage(page, entries)
recommendedDao.updatePage(page, response)
}
}
},
delete = recommendedDao::deletePage,
deleteAll = recommendedDao::deleteAll,
),
).validator(
Validator.by { lastRequestStore.isRequestValid(3.days) },
).build()
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
// SPDX-License-Identifier: Apache-2.0

package app.tivi.data.traktauth
package app.tivi.data.relatedshows

import app.tivi.inject.ApplicationScope
import me.tatarka.inject.annotations.Provides
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
// SPDX-License-Identifier: Apache-2.0

package app.tivi.data.traktauth
package app.tivi.data.relatedshows

import app.tivi.data.models.RelatedShowEntry
import app.tivi.data.models.TiviShow
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
// SPDX-License-Identifier: Apache-2.0

package app.tivi.data.traktauth
package app.tivi.data.relatedshows

import app.tivi.data.daos.LastRequestDao
import app.tivi.data.lastrequests.EntityLastRequestStore
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
// Copyright 2020, Google LLC, Christopher Banes and the Tivi project contributors
// SPDX-License-Identifier: Apache-2.0

package app.tivi.data.traktauth
package app.tivi.data.relatedshows

import app.tivi.data.daos.RelatedShowsDao
import app.tivi.data.daos.TiviShowDao
import app.tivi.data.daos.getIdOrSavePlaceholder
import app.tivi.data.db.DatabaseTransactionRunner
import app.tivi.data.models.RelatedShowEntry
import app.tivi.data.util.storeBuilder
import app.tivi.inject.ApplicationScope
import kotlin.time.Duration.Companion.days
import kotlinx.coroutines.flow.map
import me.tatarka.inject.annotations.Inject
import org.mobilenativefoundation.store.store5.Fetcher
import org.mobilenativefoundation.store.store5.SourceOfTruth
import org.mobilenativefoundation.store.store5.Store
import org.mobilenativefoundation.store.store5.StoreBuilder
import org.mobilenativefoundation.store.store5.Validator

@ApplicationScope
@Inject
Expand All @@ -26,46 +27,46 @@ class RelatedShowsStore(
showDao: TiviShowDao,
lastRequestStore: RelatedShowsLastRequestStore,
transactionRunner: DatabaseTransactionRunner,
) : Store<Long, List<RelatedShowEntry>> by StoreBuilder.from(
) : Store<Long, RelatedShows> by storeBuilder(
fetcher = Fetcher.of { showId: Long ->
val tmdbResult = runCatching { tmdbDataSource(showId) }
if (tmdbResult.isSuccess) {
lastRequestStore.updateLastRequest(showId)
return@of tmdbResult.getOrThrow()
}
runCatching { tmdbDataSource(showId) }
.let { tmdbResult ->
when {
tmdbResult.isSuccess -> tmdbResult
else -> runCatching { traktDataSource(showId) }
}
}
.getOrThrow()
.let { result ->
transactionRunner {
lastRequestStore.updateLastRequest(showId)

val traktResult = runCatching { traktDataSource(showId) }
if (traktResult.isSuccess) {
lastRequestStore.updateLastRequest(showId)
}
traktResult.getOrThrow()
result.map { (show, entry) ->
entry.copy(
showId = showId,
otherShowId = showDao.getIdOrSavePlaceholder(show),
)
}
}
}
.let { RelatedShows(showId, it) }
},
sourceOfTruth = SourceOfTruth.of(
reader = { showId ->
relatedShowsDao.entriesObservable(showId).map { entries ->
when {
// Store only treats null as 'no value', so convert to null
entries.isEmpty() -> null
// If the request is expired, our data is stale
lastRequestStore.isRequestExpired(showId, 28.days) -> null
// Otherwise, our data is fresh and valid
else -> entries
}
}
relatedShowsDao.entriesObservable(showId)
.map { RelatedShows(showId, it) }
},
writer = { showId, response ->
transactionRunner {
val entries = response.map { (show, entry) ->
entry.copy(
showId = showId,
otherShowId = showDao.getIdOrSavePlaceholder(show),
)
}
relatedShowsDao.deleteWithShowId(showId)
relatedShowsDao.upsert(entries)
relatedShowsDao.upsert(response.related)
}
},
delete = relatedShowsDao::deleteWithShowId,
deleteAll = relatedShowsDao::deleteAll,
),
).validator(
Validator.by { lastRequestStore.isRequestValid(it.showId, 28.days) },
).build()

data class RelatedShows(val showId: Long, val related: List<RelatedShowEntry>)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
// SPDX-License-Identifier: Apache-2.0

package app.tivi.data.traktauth
package app.tivi.data.relatedshows

import app.moviebase.tmdb.Tmdb3
import app.moviebase.tmdb.model.TmdbShow
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
// SPDX-License-Identifier: Apache-2.0

package app.tivi.data.traktauth
package app.tivi.data.relatedshows

import app.moviebase.trakt.TraktExtended
import app.moviebase.trakt.api.TraktShowsApi
Expand Down
Loading

0 comments on commit 0429edc

Please sign in to comment.