
commonMain.com.paoapps.blockedcache.CacheResult.kt Maven / Gradle / Ivy
package com.paoapps.blockedcache
/**
* Represents the various states and outcomes of a cache operation.
* This sealed class encapsulates different result states like success, loading, error, and others.
*
* @param T The type of data involved in the cache operation.
*/
sealed class CacheResult {
/**
* Represents an empty result, indicating no data is present.
*/
object Empty: CacheResult()
/**
* Represents an offline state with potential stale data.
*
* @property staleData Optionally holds stale data if available.
* @property creationTimeStaleData The creation time of the stale data, if available.
*/
data class Offline(val staleData: T? = null, val creationTimeStaleData: Long? = null): CacheResult()
/**
* Represents a loading state, potentially with stale data.
*
* @property staleData Optionally holds stale data if available.
* @property creationTimeStaleData The creation time of the stale data, if available.
*/
data class Loading(val staleData: T? = null, val creationTimeStaleData: Long? = null) : CacheResult()
/**
* Represents a successful result with data.
*
* @property data The actual data fetched or retrieved from the cache.
*/
data class Success(val data: T) : CacheResult()
/**
* Provides either the actual data in case of success, or the stale data in other states.
* Returns null for the Empty state.
*/
val actualOrStaleData: T?
get() = when (this) {
is Success -> this.data
is Loading -> this.staleData
is Error -> this.staleData
is Offline -> this.staleData
is Empty -> null
}
/**
* Indicates whether the cache result is currently in the loading state.
*/
val isLoading: Boolean get() = this is Loading
/**
* Transforms the data within the cache result to a different type.
*
* @param D The type to which the data is to be transformed.
* @param transform A transformation function applied to the data.
* @return A new [CacheResult] instance with the transformed data.
*/
fun map(transform: (T) -> (D)): CacheResult = when(this) {
is Loading -> Loading(staleData?.let(transform), creationTimeStaleData)
is Success -> Success(transform(data))
is Error -> Error(failure.map(), staleData?.let(transform), creationTimeStaleData)
is Empty -> Empty
is Offline -> Offline(staleData?.let(transform), creationTimeStaleData)
}
/**
* Transforms the data within the cache result to a different type, encapsulated within another [CacheResult].
*
* @param D The type to which the data is to be transformed.
* @param transform A transformation function that returns a new [CacheResult] instance.
* @return A new [CacheResult] instance based on the transformation applied.
*/
fun flatMap(transform: (T) -> (CacheResult)): CacheResult = when(this) {
is Loading -> Loading(staleData?.let(transform)?.actualOrStaleData, creationTimeStaleData)
is Success -> transform(data)
is Error -> Error(failure.map(), staleData?.let(transform)?.actualOrStaleData, creationTimeStaleData)
is Empty -> Empty
is Offline -> Offline(staleData?.let(transform)?.actualOrStaleData, creationTimeStaleData)
}
/**
* Transforms the data within the cache result to a different type, ignoring null transformations.
*
* @param D The type to which the data is to be transformed.
* @param transform A transformation function that returns a nullable result.
* @return A new [CacheResult] instance with the transformed data, or Empty if the transformation result is null.
*/
fun mapNotNull(transform: (T) -> (D?)): CacheResult = when(this) {
is Loading -> Loading(staleData?.let(transform), creationTimeStaleData)
is Success -> transform(data)?.let { Success(it) } ?: Empty
is Error -> Error(failure.map(), staleData?.let(transform), creationTimeStaleData)
is Empty -> Empty
is Offline -> Offline(staleData?.let(transform), creationTimeStaleData)
}
/**
* Indicates whether the cache result represents a successful state.
*/
val isSuccess: Boolean get() = this is Success
/**
* Indicates whether the cache result represents an error state.
*/
val isFailure: Boolean get() = this is Error
/**
* Combines this cache result with another, creating a pair of their data.
*
* @param X The type of data in the other cache result.
* @param other Another cache result to be combined with this one.
* @return A new [CacheResult] instance holding a pair of data from both cache results.
*/
operator fun plus(other: CacheResult): CacheResult> {
return when {
this is Error -> Error(failure = failure.map(), staleData = Pair(staleData, other.actualOrStaleData), creationTimeStaleData = creationTimeStaleData)
other is Error -> Error(other.failure.map(), Pair(this.actualOrStaleData, other.staleData), other.creationTimeStaleData)
this is Loading || other is Loading -> Loading(
null,
0
)
this is Empty && other is Empty -> Empty
else -> Success(
Pair(
this.actualOrStaleData,
other.actualOrStaleData
)
)
}
}
/**
* Combines this cache result with another, creating a pair of their data, while handling null values distinctly.
*
* This function differs from the 'plus' function in its treatment of null values in stale data.
* When combining two 'Error' results, it attempts to pair non-null stale data from both.
* For 'Loading' states, it combines the actual or stale data if both are non-null.
* Only when both cache results are 'Success' does it pair their data directly.
*
* @param X The type of data in the other cache result.
* @param other Another cache result to be combined with this one.
* @return A new [CacheResult] instance holding a pair of data from both cache results, handling nulls as described.
*/
fun plusHandlingNulls(other: CacheResult): CacheResult> {
return when {
this is Error -> Error(failure = failure.map(), staleData = staleData?.let { first -> other.actualOrStaleData?.let { Pair(first, it) } }, creationTimeStaleData = creationTimeStaleData)
other is Error -> Error(failure = other.failure.map(), staleData = other.staleData?.let { second -> actualOrStaleData?.let { Pair(it, second) } }, other.creationTimeStaleData)
this is Loading || other is Loading -> Loading(
actualOrStaleData?.let { first -> other.actualOrStaleData?.let { Pair(first, it) } },
0
)
this is Success && other is Success -> Success(
Pair(
this.data,
other.data
)
)
else -> Empty
}
}
/**
* Represents an error state in a cache operation.
*
* @property failure The error that occurred during the cache operation.
* @property staleData Optionally holds stale data if available.
* @property creationTimeStaleData The creation time of the stale data, if available.
*/
data class Error(
val failure: FetcherResult.Error,
val staleData: T? = null,
val creationTimeStaleData: Long? = null
) : CacheResult() {
override fun toString(): String {
return "Response failure: $failure"
}
}
}
/**
* Converts a [FetcherResult] to a corresponding [CacheResult].
*
* @param T The type of data involved in the operation.
* @return The corresponding [CacheResult] based on the [FetcherResult].
*/
fun FetcherResult.asCacheResult(): CacheResult = when (this) {
is FetcherResult.Data -> {
CacheResult.Success(value)
}
is FetcherResult.Error -> {
CacheResult.Error(this)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy