All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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