-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
65824f5
commit 4be3516
Showing
8 changed files
with
504 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 63 additions & 0 deletions
63
template/shared/data/src/commonMain/kotlin/shared/data/datasource/cache/CacheKey.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package shared.data.datasource.cache | ||
|
||
/** | ||
* Interface representing a cache key for storing and retrieving data in the cache. | ||
* | ||
* @param T The type of the cached data. | ||
*/ | ||
interface CacheKey<T> { | ||
|
||
/** | ||
* Time-to-live (TTL) for the cached data, in milliseconds. | ||
*/ | ||
val ttl: Long | ||
|
||
/** | ||
* Determines if the cached data associated with this key is considered immortal. | ||
* In terms of the API, immortality means that the cache entry initialization request | ||
* is not bound to the lifecycle of the component from which it is called. | ||
* | ||
* For example, if a cache entry initialization request is called from a View (Fragment/Activity), | ||
* it will be canceled once the view is destroyed. | ||
* When a key is immortal, the cache entry will be initialized regardless of the component lifecycle. | ||
* | ||
* This can be useful when you need to proceed with some request without interruptions. | ||
* For example, an OAuth refresh token actualization response needs to be completed and stored locally | ||
* as an atomic action, so any further calls under OAuth authorization can continue with the newly obtained token. | ||
* If such an action is processed on the server but interrupted and not stored on the client, | ||
* it is possible that the old token becomes outdated and any further request to update it will fail. | ||
* | ||
* The immortal key helps reduce such issues by ensuring that cache entries are initialized | ||
* even if the associated component lifecycle ends. | ||
* | ||
* @return {@code true} if the data associated with this key is immortal, {@code false} otherwise. | ||
*/ | ||
fun immortal(): Boolean = false | ||
|
||
companion object { | ||
const val TTL_UNLIMITED = -1L | ||
const val TTL_1_SECOND = 1_000L | ||
const val TTL_3_SECONDS = 3_000L | ||
const val TTL_5_SECONDS = 5_000L | ||
const val TTL_10_SECONDS = 10_000L | ||
const val TTL_15_SECONDS = 15_000L | ||
const val TTL_30_SECONDS = 30_000L | ||
const val TTL_60_SECONDS = 60_000L | ||
const val TTL_5_MINUTES = 5 * 60_000L | ||
|
||
/** | ||
* Creates a new CacheKey with the specified time-to-live (TTL) duration. | ||
* | ||
* @param duration The time-to-live (TTL) duration for the cache key. | ||
* @param immortal Specifies whether the cache key is immortal or not. Defaults to false. | ||
* When set to true, the cache entry will not be bound to the lifecycle of the component | ||
* from which it is initialized. | ||
* @return A new CacheKey instance with the specified TTL duration and immortality status. | ||
*/ | ||
fun <T> of(duration: Long, immortal: Boolean = false): CacheKey<T> = object : CacheKey<T> { | ||
override val ttl: Long = duration | ||
override fun immortal(): Boolean = immortal | ||
} | ||
} | ||
|
||
} |
76 changes: 76 additions & 0 deletions
76
template/shared/data/src/commonMain/kotlin/shared/data/datasource/cache/CacheSource.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package shared.data.datasource.cache | ||
|
||
import shared.data.datasource.DataSource | ||
import kotlin.reflect.KClass | ||
|
||
/** | ||
* Provides an interface for a basic thread-safe caching mechanism, serving as an L1 Cache. | ||
* | ||
* The cache allows for storing and retrieving any in-memory data efficiently. | ||
* | ||
* It supports operations such as getting, putting, removing, and invalidating cache entries. | ||
*/ | ||
interface CacheSource : DataSource { | ||
|
||
/** | ||
* Retrieves the state of a cache entry associated with the specified key. | ||
* If the entry is not found in the cache, the provided value provider function is invoked to obtain the value. | ||
* | ||
* @param key The cache key associated with the entry. | ||
* @param valueProvider A suspend function that provides the value if the cache entry is not found. | ||
* @return A CacheState object representing the state of the cache entry. | ||
*/ | ||
fun <T> getState(key: CacheKey<T>, valueProvider: suspend () -> T?): CacheState<T> | ||
|
||
/** | ||
* Retrieves the value associated with the specified key from the cache. | ||
* If the value is not found in the cache, the provided value provider function is invoked to obtain the value. | ||
* | ||
* @param key The cache key associated with the value. | ||
* @param valueProvider A suspend function that provides the value if it is not found in the cache. | ||
* @return The value associated with the key, or null if not found. | ||
*/ | ||
suspend fun <T> get(key: CacheKey<T>, valueProvider: suspend () -> T?): T? | ||
|
||
/** | ||
* Invalidates all cache entries associated with the specified key type. | ||
* | ||
* @param type The type of cache keys to invalidate. | ||
*/ | ||
fun <K : CacheKey<*>> invalidate(type: KClass<K>) | ||
|
||
/** | ||
* Invalidates the cache entry associated with the specified key. | ||
* | ||
* @param key The cache key to invalidate. | ||
*/ | ||
fun <K : CacheKey<*>> invalidate(key: K) | ||
|
||
/** | ||
* Removes all cache entries associated with the specified key type. | ||
* | ||
* @param type The type of cache keys to remove. | ||
*/ | ||
fun <K : CacheKey<*>> remove(type: KClass<K>) | ||
|
||
/** | ||
* Removes the cache entry associated with the specified key. | ||
* | ||
* @param key The cache key to remove. | ||
*/ | ||
fun <K : CacheKey<*>> remove(key: K) | ||
|
||
/** | ||
* Associates the specified value with the specified key in the cache. | ||
* | ||
*@param key The cache key to associate with the value. | ||
* @param value The value to be stored in the cache. | ||
*/ | ||
fun <T> put(key: CacheKey<T>, value: T) | ||
|
||
/** | ||
* Clears all entries from the cache. | ||
*/ | ||
fun clear() | ||
|
||
} |
69 changes: 69 additions & 0 deletions
69
template/shared/data/src/commonMain/kotlin/shared/data/datasource/cache/CacheState.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package shared.data.datasource.cache | ||
|
||
import kotlinx.coroutines.flow.Flow | ||
import kotlinx.coroutines.flow.flowOf | ||
|
||
/** | ||
* Represents the state of a cache entry. | ||
* | ||
* @param T The type of the cached item. | ||
*/ | ||
interface CacheState<T> { | ||
|
||
/** The key associated with this cache state. */ | ||
val key: CacheKey<T> | ||
|
||
/** | ||
* Retrieves the cached item. | ||
* | ||
* @return The cached item, or new one if the item is not present in the cache or expired. | ||
*/ | ||
suspend fun get(): T? | ||
|
||
/** | ||
* Retrieves the last cached item. | ||
* | ||
* @return The last cached item, or null if the item is not present in the cache. | ||
*/ | ||
suspend fun last(): T? | ||
|
||
/** | ||
* Retrieves a fresh copy of the cached item. | ||
* | ||
* @return A fresh copy of the cached item, or null if the item is not available. | ||
*/ | ||
suspend fun fresh(): T? | ||
|
||
/** | ||
* Retrieves the last cached item if available, otherwise retrieves a fresh copy of the item. | ||
* | ||
* @return The last cached item if available, or a fresh copy of the item. Returns null if the item is not present in the cache. | ||
*/ | ||
suspend fun lastOrFresh() = last() ?: fresh() | ||
|
||
/** | ||
* Emits the cached item whenever it changes. | ||
* The flow updates an item in the cache based on the expiration of the key. | ||
* | ||
* @return A flow representing the changes to the cached item. | ||
*/ | ||
suspend fun changes(): Flow<T> | ||
|
||
companion object { | ||
/** | ||
* Creates a CacheState instance representing a passed item. | ||
* | ||
* @param key The cache key associated with the item. | ||
* @param item The cached item. | ||
* @return A CacheState instance representing the single cached item. | ||
*/ | ||
fun <T> single(key: CacheKey<T>, item: T): CacheState<T> = object : CacheState<T> { | ||
override val key: CacheKey<T> = key | ||
override suspend fun get(): T? = item | ||
override suspend fun last(): T? = item | ||
override suspend fun fresh(): T? = item | ||
override suspend fun changes(): Flow<T> = flowOf(item) | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.