kernl.data.repo.associativecache.BaseAssociativeCacheLiveRepository.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Kernl.Runtime Show documentation
Show all versions of Kernl.Runtime Show documentation
Kernl: A Kotlin Symbol Processing (KSP) library for automatic repository generation.
package io.github.mattshoe.shoebox.kernl.data.repo.associativecache
import io.github.mattshoe.shoebox.kernl.data.DataResult
import io.github.mattshoe.shoebox.kernl.data.source.DataSource
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.reflect.KClass
abstract class BaseAssociativeCacheLiveRepository(
private val dispatcher: CoroutineDispatcher = Dispatchers.IO
):
AssociativeMemoryCacheLiveRepository {
private data class CacheEntry(
val dataSource: DataSource
)
private val dataCacheMutex = Mutex()
private val dataCache = mutableMapOf>()
abstract val dataType: KClass
abstract suspend fun fetchData(params: TParams): TData
override fun stream(params: TParams, forceFetch: Boolean): Flow> {
return initializeNewStream(params, forceFetch)
.catch {
emit(DataResult.Error(it))
}
}
override fun latestValue(params: TParams): DataResult? {
return try {
dataCache[params]?.dataSource?.value
} catch (e: Throwable) {
null
}
}
override suspend fun refresh(params: TParams) {
withContext(dispatcher) {
with (findDataCacheEntry(params)) {
dataSource.initialize(forceFetch = true) {
fetchData(params)
}
}
}
}
override suspend fun invalidate(params: TParams) {
withContext(dispatcher) {
dataCache[params]?.dataSource?.invalidate()
}
}
override suspend fun invalidateAll() {
withContext(dispatcher) {
invalidateAllDataSources()
}
}
private fun initializeNewStream(params: TParams, forceFetch: Boolean): Flow> {
return channelFlow {
withContext(Dispatchers.IO) {
loadDataIntoCache(params, forceFetch)
getDataFromDataCache(params)
.collectLatest {
send(it)
}
}
}
}
private suspend fun loadDataIntoCache(params: TParams, forceFetch: Boolean) {
dataCacheMutex.withLock {
with (findDataCacheEntry(params)) {
dataSource.initialize(forceFetch) {
fetchData(params)
}
dataCache[params] = this
}
}
}
private suspend fun getDataFromDataCache(params: TParams): Flow> {
return dataCacheMutex.withLock {
dataCache[params]
?.dataSource
?.data
?: flowOf(
DataResult.Error(
IllegalAccessError("No data found in the network cache!")
)
)
}
}
private fun findDataCacheEntry(params: TParams): CacheEntry {
return dataCache[params]
?: CacheEntry(
DataSource.Builder
.memoryCache(dataType)
.dispatcher(dispatcher)
.build()
)
}
private suspend fun invalidateAllDataSources() {
dataCache.values.forEach {
it.dataSource.invalidate()
}
}
}