dave08
02/18/2024, 12:12 PMJavier
02/18/2024, 12:14 PMdave08
02/18/2024, 12:14 PMJavier
02/18/2024, 12:15 PMJavier
02/18/2024, 12:15 PMJavier
02/18/2024, 12:15 PMdave08
02/18/2024, 12:16 PMtop level factory function approachDoesn't that have to be imported every time? (I already have that problem when using the cache itself...)
Javier
02/18/2024, 12:16 PMKacheableImpl
Javier
02/18/2024, 12:16 PMdave08
02/18/2024, 12:18 PMJavier
02/18/2024, 12:18 PMimport foo.Kacheable
val cache: Kacheable = Kacheable(...)
vs
import foo.Kacheable
import foo.KacheableImpl
val cache: Kacheable = KacheableImpl(...)
Javier
02/18/2024, 12:19 PMKacheableImpl
looks internal
. How you implement it in invoke or whatever is more irrelevant, I would not expose the impldave08
02/18/2024, 12:19 PMJavier
02/18/2024, 12:20 PMMutableStateFlow
is a top-level function for example.dave08
02/18/2024, 12:22 PMimport com.github.dave08.kacheable.invoke
since I have invoke on the interface with a parameter that receives the type and a top-level inline fun to use reified to avoid passing that type...Javier
02/18/2024, 12:22 PMdave08
02/18/2024, 12:22 PMJavier
02/18/2024, 12:22 PMJavier
02/18/2024, 12:28 PMJavier
02/18/2024, 12:29 PMdave08
02/18/2024, 12:37 PMdave08
02/18/2024, 12:38 PMdave08
02/18/2024, 12:40 PMJavier
02/18/2024, 12:42 PMkotlin
package.Javier
02/18/2024, 12:43 PMJavier
02/18/2024, 12:43 PMdave08
02/18/2024, 12:43 PMdave08
02/18/2024, 12:44 PMobject NoopKacheable : Kacheable {
override suspend fun <R> invalidate(vararg keys: Pair<String, List<Any>>, block: suspend () -> R): R =
block()
override suspend fun <R> invoke(
name: String,
type: KSerializer<R>,
vararg params: Any,
saveResultIf: (R) -> Boolean,
block: suspend () -> R
): R = block()
}
dave08
02/18/2024, 12:44 PMinterface Kacheable {
suspend fun <R> invalidate(vararg keys: Pair<String, List<Any>>, block: suspend () -> R): R
suspend fun <R> invoke(
name: String,
type: KSerializer<R>,
vararg params: Any,
saveResultIf: (R) -> Boolean = { true },
block: suspend () -> R
): R
companion object {
operator fun invoke(
store: KacheableStore,
configs: Map<String, CacheConfig> = emptyMap(),
getNameStrategy: GetNameStrategy = GetNameStrategy { name, params ->
if (params.isEmpty())
name
else
"$name:${params.joinToString(",")}"
},
jsonParser: Json = Json
): Kacheable = KacheableImpl(store, configs, getNameStrategy, jsonParser)
fun noop(): Kacheable = NoopKacheable
}
}
mbonnin
02/18/2024, 12:46 PMinterface Kacheable {
//...
}
fun Kacheable(store:KacheableStore, ...): Kacheable = KacheableImpl()
dave08
02/18/2024, 12:47 PMmbonnin
02/18/2024, 12:47 PMdave08
02/18/2024, 12:50 PMJavier
02/18/2024, 12:51 PMJavier
02/18/2024, 12:51 PMdave08
02/18/2024, 12:53 PMNoopKacheable
... I could change it's name... I guess the companion object DOES have an advantage that if I start typing Kacheable and then a dot, I get to see both possibilities. I'd suppose that's why you reversed the name to KacheableNoOp -- for code completion?Javier
02/18/2024, 12:55 PM()
, the other not. Maybe for consistence it is better to use top level or invoke in both cases, even if it points to the same internal NoOp objectdave08
02/18/2024, 1:01 PMCLOVIS
02/20/2024, 2:10 PMCache
interface is exposed as part of the API, all implementations are private or internal and simply expose a top-level function to instantiate them (example).
This allows me to entirely change or even remove implementations as I want. The only thing I have to keep the same between versions are the top-level functions.dave08
02/20/2024, 2:21 PMcache(configForFooCache, param1) { // computatation }
or maybe just stick to strings (hopefully one day getting to generate a function for each annotated cached function with typed params using ksp...)dave08
02/20/2024, 2:22 PMdave08
02/20/2024, 2:23 PM