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

commonMain.me.aartikov.replica.keyed.KeyedPhysicalReplica.kt Maven / Gradle / Ivy

package me.aartikov.replica.keyed

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import me.aartikov.replica.common.InvalidationMode
import me.aartikov.replica.common.OptimisticUpdate
import me.aartikov.replica.common.ReplicaId
import me.aartikov.replica.common.ReplicaTag
import me.aartikov.replica.single.PhysicalReplica
import me.aartikov.replica.single.ReplicaState

/**
 * Keyed replica replicates multiple chunks of data - different chunks for different keys.
 * Internally it uses [PhysicalReplica] for individual data chunks.
 *
 * The difference between [KeyedReplica] and [KeyedPhysicalReplica] is that the latter has a richer API.
 * [KeyedReplica] has minimalistic read-only API, whereas [KeyedPhysicalReplica] allows to cancel requests, modify data, execute optimistic updates.
 */
interface KeyedPhysicalReplica : KeyedReplica {

    /**
     * Unique identifier
     */
    val id: ReplicaId

    /**
     * Human readable name, used for debugging
     */
    val name: String

    /**
     * Settings, see: [KeyedReplicaSettings]
     */
    val settings: KeyedReplicaSettings

    /**
     * Tags that can be used for bulk operations
     */
    val tags: Set

    /**
     * A coroutine scope that represents life time of a keyed replica.
     */
    val coroutineScope: CoroutineScope

    /**
     * Provides [KeyedReplicaState] as an observable value.
     */
    val stateFlow: StateFlow

    /**
     * Notifies that some [KeyedReplicaEvent] has occurred.
     */
    val eventFlow: Flow>

    /**
     * Returns current [ReplicaState] for a given [key].
     */
    fun getCurrentState(key: K): ReplicaState?

    /**
     * Replace current data with new [data] for a given [key].
     *
     * Note: It doesn't change data freshness. If previous data is missing a new data will be stale.
     */
    suspend fun setData(key: K, data: T)

    /**
     * Modifies current data with [transform] function if it is exists for a given [key].
     *
     * Note: It doesn't change data freshness.
     */
    suspend fun mutateData(key: K, transform: (T) -> T)

    /**
     * Makes data stale if it is exists for a given [key]. It also could call a refresh depending on [InvalidationMode].
     */
    suspend fun invalidate(key: K, mode: InvalidationMode = InvalidationMode.RefreshIfHasObservers)

    /**
     * Makes data fresh if it is exists for a given [key].
     */
    suspend fun makeFresh(key: K)

    /**
     * Cancels current request if it is in progress for a given [key].
     */
    fun cancel(key: K)

    /**
     * Cancels current request and clears data for a given [key].
     * @param removeFromStorage specifies if data will be removed from [KeyedStorage].
     */
    suspend fun clear(key: K, removeFromStorage: Boolean = true)

    /**
     * Clears error stored in [ReplicaState] for a given [key].
     */
    suspend fun clearError(key: K)

    /**
     * Cancels network requests and clears data in all child replicas.
     */
    suspend fun clearAll()

    /**
     * Begins optimistic update for a given [key]. Observed data will be transformed by [update] function immediately.
     *
     * Note: for simple cases it is better to use [withOptimisticUpdate] extension.
     */
    suspend fun beginOptimisticUpdate(key: K, update: OptimisticUpdate)

    /**
     * Commits optimistic update for a given [key]. Child replica forgets previous data.
     *
     * Note: for simple cases it is better to use [withOptimisticUpdate] extension.
     */
    suspend fun commitOptimisticUpdate(key: K, update: OptimisticUpdate)

    /**
     * Rollbacks optimistic update for a given [key]. Observed data will be replaced to the original one.
     *
     * Note: for simple cases it is better to use [withOptimisticUpdate] extension.
     */
    suspend fun rollbackOptimisticUpdate(key: K, update: OptimisticUpdate)

    /**
     * Executes an [action] on a [PhysicalReplica] with a given [key]. If the replica doesn't exist it is created.
     */
    suspend fun onReplica(key: K, action: suspend PhysicalReplica.() -> Unit)

    /**
     * Executes an [action] on a [PhysicalReplica] with a given [key]. If the replica doesn't exist the action is not executed.
     */
    suspend fun onExistingReplica(key: K, action: suspend PhysicalReplica.() -> Unit)

    /**
     * Executes an [action] on each child [PhysicalReplica].
     */
    suspend fun onEachReplica(action: suspend PhysicalReplica.(K) -> Unit)
}

/**
 * Returns current [KeyedReplicaState].
 */
val  KeyedPhysicalReplica.currentState get() = stateFlow.value




© 2015 - 2025 Weber Informatics LLC | Privacy Policy