
commonMain.me.aartikov.replica.single.PhysicalReplica.kt Maven / Gradle / Ivy
package me.aartikov.replica.single
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
/**
* Replica is a primitive for data replication.
* The replica's task is to represent some chunk of data from a server on a client side.
* Replica is configured by [Fetcher] and [ReplicaSettings].
* Replica loads missing data when an active observer connects (see: [Replica.observe]).
* Replica keeps track of data staleness.
* Replica refreshes stale data when an active observer is connected.
* Replica deduplicates network requests (it doesn't coll a new request if another one is in progress).
* Replica cancels network request when a last observer is disconnected.
* Replica clears data when it has no observers for a long time.
*
* The difference between [Replica] and [PhysicalReplica] is that the latter has a richer API.
* [Replica] has minimalistic read-only API, whereas [PhysicalReplica] allows to cancel requests, modify data, execute optimistic updates.
* [PhysicalReplica] extends [Replica], but not all replicas are physical replicas.
* There are lightweight virtual replicas created by combining other replicas (see: replica-algebra module for more details).
*/
interface PhysicalReplica : Replica {
/**
* Unique identifier
*/
val id: ReplicaId
/**
* Human readable name, used for debugging
*/
val name: String
/**
* Settings, see: [ReplicaSettings]
*/
val settings: ReplicaSettings
/**
* Tags that can be used for bulk operations
*/
val tags: Set
/**
* A coroutine scope that represents life time of a replica.
*/
val coroutineScope: CoroutineScope
/**
* Provides [ReplicaState] as an observable value.
*/
val stateFlow: StateFlow>
/**
* Notifies that some [ReplicaEvent] has occurred.
*/
val eventFlow: Flow>
/**
* Replace current data with new [data].
*
* Note: It doesn't change data freshness. If previous data is missing a new data will be stale.
*/
suspend fun setData(data: T)
/**
* Modifies current data with [transform] function if it is exists.
*
* Note: It doesn't change data freshness.
*/
suspend fun mutateData(transform: (T) -> T)
/**
* Makes data stale if it is exists. It also could call a refresh depending on [InvalidationMode].
*/
suspend fun invalidate(mode: InvalidationMode = InvalidationMode.RefreshIfHasObservers)
/**
* Makes data fresh if it is exists.
*/
suspend fun makeFresh()
/**
* Cancels current request if it is in progress.
*/
fun cancel()
/**
* Cancels current request and clears data.
* @param removeFromStorage specifies if data will be removed from [Storage].
*/
suspend fun clear(removeFromStorage: Boolean = true)
/**
* Clears error stored in [ReplicaState].
*/
suspend fun clearError()
/**
* Begins optimistic update. Observed data will be transformed by [update] function immediately.
*
* Note: for simple cases it is better to use [withOptimisticUpdate] extension.
*/
suspend fun beginOptimisticUpdate(update: OptimisticUpdate)
/**
* Commits optimistic update. Replica forgets previous data.
*
* Note: for simple cases it is better to use [withOptimisticUpdate] extension.
*/
suspend fun commitOptimisticUpdate(update: OptimisticUpdate)
/**
* Rollbacks optimistic update. Observed data will be replaced to the original one.
*
* Note: for simple cases it is better to use [withOptimisticUpdate] extension.
*/
suspend fun rollbackOptimisticUpdate(update: OptimisticUpdate)
}
/**
* Returns current [ReplicaState].
*/
val PhysicalReplica.currentState get() = stateFlow.value
© 2015 - 2025 Weber Informatics LLC | Privacy Policy