Skip to content

Commit

Permalink
Move StoreKey and StoreData to core
Browse files Browse the repository at this point in the history
Signed-off-by: mramotar_dbx <mramotar@dropbox.com>
  • Loading branch information
matt-ramotar committed Oct 18, 2023
1 parent 514cc74 commit 6b37c53
Show file tree
Hide file tree
Showing 17 changed files with 105 additions and 50 deletions.
1 change: 1 addition & 0 deletions cache/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ kotlin {
val commonMain by getting {
dependencies {
api(libs.kotlinx.atomic.fu)
api(project(":core"))
}
}
val jvmMain by getting
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.mobilenativefoundation.store.cache5

@Deprecated("Use StoreMultiCache instead of MultiCache")
interface Identifiable<Id : Any> {
val id: Id
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package org.mobilenativefoundation.store.cache5
* Stores and manages the relationship among single items and collections.
* Delegates cache storage and behavior to Guava caches.
*/
@Deprecated("Use StoreMultiCache")
class MultiCache<Key : Any, Output : Identifiable<Key>>(
cacheBuilder: CacheBuilder<Key, Output>
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,48 @@
@file:Suppress("UNCHECKED_CAST")

package org.mobilenativefoundation.store.paging5
package org.mobilenativefoundation.store.cache5

import org.mobilenativefoundation.store.cache5.Cache
import org.mobilenativefoundation.store.core5.KeyProvider
import org.mobilenativefoundation.store.core5.StoreData
import org.mobilenativefoundation.store.core5.StoreKey

/**
* A class that represents a caching system for pagination.
* A class that represents a caching system with collection decomposition.
* Manages data with utility functions to get, invalidate, and add items to the cache.
* Depends on [PagingCacheAccessor] for internal data management.
* Depends on [StoreMultiCacheAccessor] for internal data management.
* @see [Cache].
*/
class PagingCache<Id : Any, Key : StoreKey<Id>, StoreOutput : StoreData<Id>, Collection : StoreData.Collection<Id, Single>, Single : StoreData.Single<Id>>(
class StoreMultiCache<Id : Any, Key : StoreKey<Id>, Single : StoreData.Single<Id>, Collection : StoreData.Collection<Id, Single>, Output : StoreData<Id>>(
private val keyProvider: KeyProvider<Id, Single>,
) : Cache<Key, StoreOutput> {
singlesCache: Cache<StoreKey.Single<Id>, Single> = CacheBuilder<StoreKey.Single<Id>, Single>().build(),
collectionsCache: Cache<StoreKey.Collection<Id>, Collection> = CacheBuilder<StoreKey.Collection<Id>, Collection>().build(),
) : Cache<Key, Output> {

private val accessor = PagingCacheAccessor<Id, Collection, Single>()
private val accessor = StoreMultiCacheAccessor(
singlesCache = singlesCache,
collectionsCache = collectionsCache,
)

private fun Key.castSingle() = this as StoreKey.Single<Id>
private fun Key.castCollection() = this as StoreKey.Collection<Id>

private fun StoreKey.Collection<Id>.cast() = this as Key
private fun StoreKey.Single<Id>.cast() = this as Key

override fun getIfPresent(key: Key): StoreOutput? {
override fun getIfPresent(key: Key): Output? {
return when (key) {
is StoreKey.Single<*> -> accessor.getSingle(key.castSingle()) as? StoreOutput
is StoreKey.Collection<*> -> accessor.getCollection(key.castCollection()) as? StoreOutput
is StoreKey.Single<*> -> accessor.getSingle(key.castSingle()) as? Output
is StoreKey.Collection<*> -> accessor.getCollection(key.castCollection()) as? Output
else -> {
throw UnsupportedOperationException(invalidKeyErrorMessage(key))
}
}
}

override fun getOrPut(key: Key, valueProducer: () -> StoreOutput): StoreOutput {
override fun getOrPut(key: Key, valueProducer: () -> Output): Output {
return when (key) {
is StoreKey.Single<*> -> {
val single = accessor.getSingle(key.castSingle()) as? StoreOutput
val single = accessor.getSingle(key.castSingle()) as? Output
if (single != null) {
single
} else {
Expand All @@ -46,7 +53,7 @@ class PagingCache<Id : Any, Key : StoreKey<Id>, StoreOutput : StoreData<Id>, Col
}

is StoreKey.Collection<*> -> {
val collection = accessor.getCollection(key.castCollection()) as? StoreOutput
val collection = accessor.getCollection(key.castCollection()) as? Output
if (collection != null) {
collection
} else {
Expand All @@ -62,18 +69,18 @@ class PagingCache<Id : Any, Key : StoreKey<Id>, StoreOutput : StoreData<Id>, Col
}
}

override fun getAllPresent(keys: List<*>): Map<Key, StoreOutput> {
val map = mutableMapOf<Key, StoreOutput>()
override fun getAllPresent(keys: List<*>): Map<Key, Output> {
val map = mutableMapOf<Key, Output>()
keys.filterIsInstance<StoreKey<Id>>().forEach { key ->
when (key) {
is StoreKey.Collection<Id> -> {
val collection = accessor.getCollection(key)
collection?.let { map[key.cast()] = it as StoreOutput }
collection?.let { map[key.cast()] = it as Output }
}

is StoreKey.Single<Id> -> {
val single = accessor.getSingle(key)
single?.let { map[key.cast()] = it as StoreOutput }
single?.let { map[key.cast()] = it as Output }
}
}
}
Expand All @@ -92,11 +99,11 @@ class PagingCache<Id : Any, Key : StoreKey<Id>, StoreOutput : StoreData<Id>, Col
}
}

override fun putAll(map: Map<Key, StoreOutput>) {
override fun putAll(map: Map<Key, Output>) {
map.entries.forEach { (key, value) -> put(key, value) }
}

override fun put(key: Key, value: StoreOutput) {
override fun put(key: Key, value: Output) {
when (key) {
is StoreKey.Single<*> -> {
val single = value as Single
Expand Down
Original file line number Diff line number Diff line change
@@ -1,65 +1,67 @@
package org.mobilenativefoundation.store.paging5
package org.mobilenativefoundation.store.cache5

import org.mobilenativefoundation.store.cache5.CacheBuilder
import org.mobilenativefoundation.store.core5.StoreData
import org.mobilenativefoundation.store.core5.StoreKey

/**
* Intermediate data manager for a caching system supporting pagination.
* Intermediate data manager for a caching system supporting list decomposition.
* Tracks keys for rapid data retrieval and modification.
*/
class PagingCacheAccessor<Id : Any, Collection : StoreData.Collection<Id, Single>, Single : StoreData.Single<Id>> {
private val collections = CacheBuilder<StoreKey.Collection<Id>, Collection>().build()
private val singles = CacheBuilder<StoreKey.Single<Id>, Single>().build()
class StoreMultiCacheAccessor<Id : Any, Collection : StoreData.Collection<Id, Single>, Single : StoreData.Single<Id>>(
private val singlesCache: Cache<StoreKey.Single<Id>, Single>,
private val collectionsCache: Cache<StoreKey.Collection<Id>, Collection>,
) {
private val keys = mutableSetOf<StoreKey<Id>>()


/**
* Retrieves a collection of items from the cache using the provided key.
*/
fun getCollection(key: StoreKey.Collection<Id>): Collection? = collections.getIfPresent(key)
fun getCollection(key: StoreKey.Collection<Id>): Collection? = collectionsCache.getIfPresent(key)

/**
* Retrieves an individual item from the cache using the provided key.
*/
fun getSingle(key: StoreKey.Single<Id>): Single? = singles.getIfPresent(key)
fun getSingle(key: StoreKey.Single<Id>): Single? = singlesCache.getIfPresent(key)

/**
* Stores a collection of items in the cache and updates the key set.
*/
fun putCollection(key: StoreKey.Collection<Id>, collection: Collection) {
collections.put(key, collection)
collectionsCache.put(key, collection)
keys.add(key)
}

/**
* Stores an individual item in the cache and updates the key set.
*/
fun putSingle(key: StoreKey.Single<Id>, single: Single) {
singles.put(key, single)
singlesCache.put(key, single)
keys.add(key)
}

/**
* Removes all cache entries and clears the key set.
*/
fun invalidateAll() {
collections.invalidateAll()
singles.invalidateAll()
collectionsCache.invalidateAll()
singlesCache.invalidateAll()
keys.clear()
}

/**
* Removes an individual item from the cache and updates the key set.
*/
fun invalidateSingle(key: StoreKey.Single<Id>) {
singles.invalidate(key)
singlesCache.invalidate(key)
keys.remove(key)
}

/**
* Removes a collection of items from the cache and updates the key set.
*/
fun invalidateCollection(key: StoreKey.Collection<Id>) {
collections.invalidate(key)
collectionsCache.invalidate(key)
keys.remove(key)
}

Expand All @@ -73,14 +75,14 @@ class PagingCacheAccessor<Id : Any, Collection : StoreData.Collection<Id, Single
for (key in keys) {
when (key) {
is StoreKey.Single<Id> -> {
val single = singles.getIfPresent(key)
val single = singlesCache.getIfPresent(key)
if (single != null) {
count++
}
}

is StoreKey.Collection<Id> -> {
val collection = collections.getIfPresent(key)
val collection = collectionsCache.getIfPresent(key)
if (collection != null) {
count += collection.items.size
}
Expand Down
40 changes: 40 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

plugins {
kotlin("multiplatform")
kotlin("plugin.serialization")
id("com.android.library")
id("com.vanniktech.maven.publish")
id("org.jetbrains.dokka")
id("org.jetbrains.kotlinx.kover")
`maven-publish`
id("kotlinx-atomicfu")
id("org.jetbrains.compose") version("1.5.1")
}

kotlin {
androidTarget()
jvm()
iosArm64()
iosX64()
linuxX64()
iosSimulatorArm64()
js {
browser()
nodejs()
}

sourceSets {
val commonMain by getting {
dependencies {
implementation(libs.kotlin.stdlib)
}
}
}
}

android {

compileSdk = 33

sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.mobilenativefoundation.store.paging5
package org.mobilenativefoundation.store.core5

enum class InsertionStrategy {
APPEND,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.mobilenativefoundation.store.paging5
package org.mobilenativefoundation.store.core5

interface KeyProvider<Id : Any, Single : StoreData.Single<Id>> {
fun from(key: StoreKey.Collection<Id>, value: Single): StoreKey.Single<Id>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.mobilenativefoundation.store.paging5
package org.mobilenativefoundation.store.core5


/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.mobilenativefoundation.store.paging5
package org.mobilenativefoundation.store.core5

/**
* An interface that defines keys used by Store for data-fetching operations.
Expand Down
3 changes: 1 addition & 2 deletions paging/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ kotlin {
implementation(compose.ui)
implementation(compose.foundation)
implementation(compose.material)


api(project(":core"))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ package org.mobilenativefoundation.store.paging5
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import org.mobilenativefoundation.store.core5.StoreData
import org.mobilenativefoundation.store.core5.StoreKey
import org.mobilenativefoundation.store.store5.*

private class StopProcessingException : Exception()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.mobilenativefoundation.store.paging5.util

import org.mobilenativefoundation.store.paging5.InsertionStrategy
import org.mobilenativefoundation.store.paging5.StoreData
import org.mobilenativefoundation.store.core5.InsertionStrategy
import org.mobilenativefoundation.store.core5.StoreData

sealed class PostData : StoreData<String> {
data class Post(val postId: String, val title: String) : StoreData.Single<String>, PostData() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.mobilenativefoundation.store.paging5.util

import org.mobilenativefoundation.store.paging5.InsertionStrategy
import org.mobilenativefoundation.store.paging5.StoreKey
import org.mobilenativefoundation.store.core5.InsertionStrategy
import org.mobilenativefoundation.store.core5.StoreKey

sealed class PostKey : StoreKey<String> {
data class Cursor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ package org.mobilenativefoundation.store.paging5.util

import kotlinx.coroutines.flow.flow
import org.mobilenativefoundation.store.cache5.Cache
import org.mobilenativefoundation.store.paging5.KeyProvider
import org.mobilenativefoundation.store.paging5.PagingCache
import org.mobilenativefoundation.store.paging5.StoreKey
import org.mobilenativefoundation.store.core5.KeyProvider
import org.mobilenativefoundation.store.cache5.StoreMultiCache
import org.mobilenativefoundation.store.core5.StoreKey
import org.mobilenativefoundation.store.store5.*
import kotlin.math.floor

Expand Down Expand Up @@ -115,7 +115,7 @@ class PostStoreFactory(private val api: PostApi, private val db: PostDatabase) {
}

private fun createMemoryCache(): Cache<PostKey, PostData> =
PagingCache(createPagingCacheKeyProvider())
StoreMultiCache(createPagingCacheKeyProvider())

fun create(): MutableStore<PostKey, PostData> = StoreBuilder.from(
fetcher = createFetcher(),
Expand Down
3 changes: 2 additions & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ include ':store'
include ':cache'
include ':multicast'
include ':rx2'
include ':paging'
include ':paging'
include ':core'
1 change: 1 addition & 0 deletions store/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ kotlin {
implementation(libs.touchlab.kermit)
implementation(project(":multicast"))
implementation(project(":cache"))
api(project(":core"))
}
}

Expand Down

0 comments on commit 6b37c53

Please sign in to comment.