mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-09-18 14:59:24 +00:00
Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
e3ff1b9609 | |||
70c31966ca | |||
0e4188882f | |||
6bf0ce92ba | |||
d51bdc5086 | |||
e5dd4363f1 | |||
a3a48bbaac | |||
5e716fb9a8 | |||
11a36153cc | |||
8bee354f04 | |||
f7dd2b5ce7 | |||
8ca10c00bb | |||
905c7e8eda | |||
d4c5e849bf | |||
8250a2a021 | |||
01b3df7b8c | |||
daa6e4aff5 | |||
23bcb26a58 | |||
e55f60c30b | |||
0d0c16e16d | |||
540d5cce7c | |||
a548b00979 | |||
4b7ca6d565 | |||
0473fa238c | |||
cfc7119697 | |||
22a6520d3e | |||
fb25e91191 | |||
c116b270b6 | |||
aa2d598689 | |||
5ef3bb746b | |||
037616e271 | |||
abbea906f1 | |||
9132e216c9 | |||
12a7e3c4af | |||
b40c093917 | |||
7ac12455c8 | |||
5043eec7a2 | |||
cf31f53e01 |
2
.github/workflows/dokka_push.yml
vendored
2
.github/workflows/dokka_push.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: cd /usr/local/lib/android/sdk/build-tools/32.0.0/ && mv d8 dx && cd lib && mv d8.jar dx.jar
|
run: cd /usr/local/lib/android/sdk/build-tools/32.0.0/ && mv d8 dx && cd lib && mv d8.jar dx.jar
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./gradlew dokkaHtml
|
run: ./gradlew build && ./gradlew dokkaHtml
|
||||||
- name: Publish KDocs
|
- name: Publish KDocs
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
with:
|
with:
|
||||||
|
57
CHANGELOG.md
57
CHANGELOG.md
@@ -1,5 +1,62 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.11.13
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Coroutines`: `1.6.3` -> `1.6.4`
|
||||||
|
* `Compose`: `1.2.0-alpha01-dev629` -> `1.2.0-alpha01-dev731`
|
||||||
|
|
||||||
|
## 0.11.12
|
||||||
|
|
||||||
|
* `Repos`:
|
||||||
|
* `Common`:
|
||||||
|
* `JVM`:
|
||||||
|
* Fixes in `ReadFileKeyValueRepo` methods (`values`/`keys`)
|
||||||
|
|
||||||
|
## 0.11.11
|
||||||
|
|
||||||
|
* `Crypto`:
|
||||||
|
* `hmacSha256` has been deprecated
|
||||||
|
* `Ktor`:
|
||||||
|
* `Client`:
|
||||||
|
* `BodyPair` has been deprecated
|
||||||
|
* `Repos`:
|
||||||
|
* `Cache`:
|
||||||
|
* New interface `CacheRepo`
|
||||||
|
* New interface `FullCacheRepo`
|
||||||
|
* `actualize*` methods inside of full cache repos now open for overriding
|
||||||
|
|
||||||
|
## 0.11.10
|
||||||
|
|
||||||
|
* `Repos`:
|
||||||
|
* `Cache`:
|
||||||
|
* `KVCache` has been replaced to the package `dev.inmo.micro_utils.repos.cache`
|
||||||
|
* `SimpleKVCache` has been replaced to the package `dev.inmo.micro_utils.repos.cache`
|
||||||
|
* New `KVCache` subtype - `FullKVCache`
|
||||||
|
* Add `Full*` variants of standard repos
|
||||||
|
* Add `cached`/`caching` (for write repos) extensions for all standard types of repos
|
||||||
|
|
||||||
|
## 0.11.9
|
||||||
|
|
||||||
|
* `Versions`
|
||||||
|
* `Coroutines`: `1.6.1` -> `1.6.3`
|
||||||
|
* `Ktor`: `2.0.2` -> `2.0.3`
|
||||||
|
* `Compose`: `1.2.0-alpha01-dev686` -> `1.2.0-alpha01-dev729`
|
||||||
|
|
||||||
|
## 0.11.8
|
||||||
|
|
||||||
|
* `Repos`:
|
||||||
|
* `Common`:
|
||||||
|
* Fixes in `FileKeyValueRepo`
|
||||||
|
|
||||||
|
## 0.11.7
|
||||||
|
|
||||||
|
* `Common`:
|
||||||
|
* New abstractions `SimpleMapper` and `SimpleSuspendableMapper`
|
||||||
|
* `Repos`:
|
||||||
|
* `Common`:
|
||||||
|
* Add mappers for `CRUDRepo`
|
||||||
|
|
||||||
## 0.11.6
|
## 0.11.6
|
||||||
|
|
||||||
* `FSM`:
|
* `FSM`:
|
||||||
|
@@ -0,0 +1,53 @@
|
|||||||
|
package dev.inmo.micro_utils.common
|
||||||
|
|
||||||
|
import kotlin.jvm.JvmName
|
||||||
|
|
||||||
|
interface SimpleMapper<T1, T2> {
|
||||||
|
fun convertToT1(from: T2): T1
|
||||||
|
fun convertToT2(from: T1): T2
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmName("convertFromT2")
|
||||||
|
fun <T1, T2> SimpleMapper<T1, T2>.convert(from: T2) = convertToT1(from)
|
||||||
|
@JvmName("convertFromT1")
|
||||||
|
fun <T1, T2> SimpleMapper<T1, T2>.convert(from: T1) = convertToT2(from)
|
||||||
|
|
||||||
|
class SimpleMapperImpl<T1, T2>(
|
||||||
|
private val t1: (T2) -> T1,
|
||||||
|
private val t2: (T1) -> T2,
|
||||||
|
) : SimpleMapper<T1, T2> {
|
||||||
|
override fun convertToT1(from: T2): T1 = t1.invoke(from)
|
||||||
|
|
||||||
|
override fun convertToT2(from: T1): T2 = t2.invoke(from)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <T1, T2> simpleMapper(
|
||||||
|
noinline t1: (T2) -> T1,
|
||||||
|
noinline t2: (T1) -> T2,
|
||||||
|
) = SimpleMapperImpl(t1, t2)
|
||||||
|
|
||||||
|
interface SimpleSuspendableMapper<T1, T2> {
|
||||||
|
suspend fun convertToT1(from: T2): T1
|
||||||
|
suspend fun convertToT2(from: T1): T2
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmName("convertFromT2")
|
||||||
|
suspend fun <T1, T2> SimpleSuspendableMapper<T1, T2>.convert(from: T2) = convertToT1(from)
|
||||||
|
@JvmName("convertFromT1")
|
||||||
|
suspend fun <T1, T2> SimpleSuspendableMapper<T1, T2>.convert(from: T1) = convertToT2(from)
|
||||||
|
|
||||||
|
class SimpleSuspendableMapperImpl<T1, T2>(
|
||||||
|
private val t1: suspend (T2) -> T1,
|
||||||
|
private val t2: suspend (T1) -> T2,
|
||||||
|
) : SimpleSuspendableMapper<T1, T2> {
|
||||||
|
override suspend fun convertToT1(from: T2): T1 = t1.invoke(from)
|
||||||
|
|
||||||
|
override suspend fun convertToT2(from: T1): T2 = t2.invoke(from)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <T1, T2> simpleSuspendableMapper(
|
||||||
|
noinline t1: suspend (T2) -> T1,
|
||||||
|
noinline t2: suspend (T1) -> T2,
|
||||||
|
) = SimpleSuspendableMapperImpl(t1, t2)
|
@@ -41,6 +41,13 @@ data class Optional<T> internal constructor(
|
|||||||
inline val <T> T.optional
|
inline val <T> T.optional
|
||||||
get() = Optional.presented(this)
|
get() = Optional.presented(this)
|
||||||
|
|
||||||
|
inline val <T : Any> T?.optionalOrAbsentIfNull
|
||||||
|
get() = if (this == null) {
|
||||||
|
Optional.absent<T>()
|
||||||
|
} else {
|
||||||
|
Optional.presented(this)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will call [block] when data presented ([Optional.dataPresented] == true)
|
* Will call [block] when data presented ([Optional.dataPresented] == true)
|
||||||
*/
|
*/
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
package dev.inmo.micro_utils.crypto
|
package dev.inmo.micro_utils.crypto
|
||||||
|
|
||||||
|
@Deprecated("Deprecated due to incorrect of work sometimes and redundancy. Can be replaced by korlibs krypto")
|
||||||
expect fun SourceString.hmacSha256(key: String): String
|
expect fun SourceString.hmacSha256(key: String): String
|
||||||
|
@@ -8,6 +8,7 @@ external interface CryptoJs {
|
|||||||
@JsNonModule
|
@JsNonModule
|
||||||
external val CryptoJS: CryptoJs
|
external val CryptoJS: CryptoJs
|
||||||
|
|
||||||
|
@Deprecated("Deprecated due to incorrect of work sometimes and redundancy. Can be replaced by korlibs krypto")
|
||||||
actual fun SourceString.hmacSha256(key: String): String {
|
actual fun SourceString.hmacSha256(key: String): String {
|
||||||
return CryptoJS.asDynamic().HmacSHA256(this, key).toString().unsafeCast<String>()
|
return CryptoJS.asDynamic().HmacSHA256(this, key).toString().unsafeCast<String>()
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ package dev.inmo.micro_utils.crypto
|
|||||||
import javax.crypto.Mac
|
import javax.crypto.Mac
|
||||||
import javax.crypto.spec.SecretKeySpec
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
|
||||||
|
@Deprecated("Deprecated due to incorrect of work sometimes and redundancy. Can be replaced by korlibs krypto")
|
||||||
actual fun SourceString.hmacSha256(key: String): String {
|
actual fun SourceString.hmacSha256(key: String): String {
|
||||||
val mac = Mac.getInstance("HmacSHA256")
|
val mac = Mac.getInstance("HmacSHA256")
|
||||||
|
|
||||||
|
@@ -21,7 +21,7 @@ if (new File(projectDir, "secret.gradle").exists()) {
|
|||||||
owner "InsanusMokrassar"
|
owner "InsanusMokrassar"
|
||||||
repo "MicroUtils"
|
repo "MicroUtils"
|
||||||
|
|
||||||
tagName "${project.version}"
|
tagName "v${project.version}"
|
||||||
releaseName "${project.version}"
|
releaseName "${project.version}"
|
||||||
targetCommitish "${project.version}"
|
targetCommitish "${project.version}"
|
||||||
|
|
||||||
|
@@ -14,5 +14,5 @@ crypto_js_version=4.1.1
|
|||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.11.6
|
version=0.11.13
|
||||||
android_code_version=130
|
android_code_version=137
|
||||||
|
@@ -2,18 +2,18 @@
|
|||||||
|
|
||||||
kt = "1.6.21"
|
kt = "1.6.21"
|
||||||
kt-serialization = "1.3.3"
|
kt-serialization = "1.3.3"
|
||||||
kt-coroutines = "1.6.1"
|
kt-coroutines = "1.6.4"
|
||||||
|
|
||||||
jb-compose = "1.2.0-alpha01-dev686"
|
jb-compose = "1.2.0-alpha01-dev731"
|
||||||
jb-exposed = "0.38.2"
|
jb-exposed = "0.38.2"
|
||||||
jb-dokka = "1.6.21"
|
jb-dokka = "1.6.21"
|
||||||
|
|
||||||
klock = "2.7.0"
|
klock = "2.7.0"
|
||||||
uuid = "0.4.1"
|
uuid = "0.4.1"
|
||||||
|
|
||||||
ktor = "2.0.2"
|
ktor = "2.0.3"
|
||||||
|
|
||||||
gh-release = "2.3.7"
|
gh-release = "2.4.1"
|
||||||
|
|
||||||
android-gradle = "7.0.4"
|
android-gradle = "7.0.4"
|
||||||
dexcount = "3.1.0"
|
dexcount = "3.1.0"
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
@@ -12,6 +12,7 @@ import io.ktor.http.*
|
|||||||
import io.ktor.utils.io.core.ByteReadPacket
|
import io.ktor.utils.io.core.ByteReadPacket
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
|
|
||||||
|
@Deprecated("This class will be removed in next")
|
||||||
typealias BodyPair<T> = Pair<SerializationStrategy<T>, T>
|
typealias BodyPair<T> = Pair<SerializationStrategy<T>, T>
|
||||||
|
|
||||||
class UnifiedRequester(
|
class UnifiedRequester(
|
||||||
@@ -33,7 +34,7 @@ class UnifiedRequester(
|
|||||||
|
|
||||||
suspend fun <BodyType, ResultType> unipost(
|
suspend fun <BodyType, ResultType> unipost(
|
||||||
url: String,
|
url: String,
|
||||||
bodyInfo: BodyPair<BodyType>,
|
bodyInfo: Pair<SerializationStrategy<BodyType>, BodyType>,
|
||||||
resultDeserializer: DeserializationStrategy<ResultType>
|
resultDeserializer: DeserializationStrategy<ResultType>
|
||||||
) = client.unipost(url, bodyInfo, resultDeserializer, serialFormat)
|
) = client.unipost(url, bodyInfo, resultDeserializer, serialFormat)
|
||||||
|
|
||||||
@@ -52,7 +53,7 @@ class UnifiedRequester(
|
|||||||
url: String,
|
url: String,
|
||||||
filename: String,
|
filename: String,
|
||||||
inputProvider: InputProvider,
|
inputProvider: InputProvider,
|
||||||
otherData: BodyPair<BodyType>,
|
otherData: Pair<SerializationStrategy<BodyType>, BodyType>,
|
||||||
resultDeserializer: DeserializationStrategy<ResultType>,
|
resultDeserializer: DeserializationStrategy<ResultType>,
|
||||||
mimetype: String = "*/*",
|
mimetype: String = "*/*",
|
||||||
additionalParametersBuilder: FormBuilder.() -> Unit = {},
|
additionalParametersBuilder: FormBuilder.() -> Unit = {},
|
||||||
@@ -75,7 +76,7 @@ class UnifiedRequester(
|
|||||||
suspend fun <BodyType, ResultType> unimultipart(
|
suspend fun <BodyType, ResultType> unimultipart(
|
||||||
url: String,
|
url: String,
|
||||||
mppFile: MPPFile,
|
mppFile: MPPFile,
|
||||||
otherData: BodyPair<BodyType>,
|
otherData: Pair<SerializationStrategy<BodyType>, BodyType>,
|
||||||
resultDeserializer: DeserializationStrategy<ResultType>,
|
resultDeserializer: DeserializationStrategy<ResultType>,
|
||||||
mimetype: String = "*/*",
|
mimetype: String = "*/*",
|
||||||
additionalParametersBuilder: FormBuilder.() -> Unit = {},
|
additionalParametersBuilder: FormBuilder.() -> Unit = {},
|
||||||
@@ -120,7 +121,7 @@ fun <T> SerializationStrategy<T>.encodeUrlQueryValue(
|
|||||||
|
|
||||||
suspend fun <BodyType, ResultType> HttpClient.unipost(
|
suspend fun <BodyType, ResultType> HttpClient.unipost(
|
||||||
url: String,
|
url: String,
|
||||||
bodyInfo: BodyPair<BodyType>,
|
bodyInfo: Pair<SerializationStrategy<BodyType>, BodyType>,
|
||||||
resultDeserializer: DeserializationStrategy<ResultType>,
|
resultDeserializer: DeserializationStrategy<ResultType>,
|
||||||
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
||||||
) = post(url) {
|
) = post(url) {
|
||||||
@@ -162,7 +163,7 @@ suspend fun <ResultType> HttpClient.unimultipart(
|
|||||||
suspend fun <BodyType, ResultType> HttpClient.unimultipart(
|
suspend fun <BodyType, ResultType> HttpClient.unimultipart(
|
||||||
url: String,
|
url: String,
|
||||||
filename: String,
|
filename: String,
|
||||||
otherData: BodyPair<BodyType>,
|
otherData: Pair<SerializationStrategy<BodyType>, BodyType>,
|
||||||
inputProvider: InputProvider,
|
inputProvider: InputProvider,
|
||||||
resultDeserializer: DeserializationStrategy<ResultType>,
|
resultDeserializer: DeserializationStrategy<ResultType>,
|
||||||
mimetype: String = "*/*",
|
mimetype: String = "*/*",
|
||||||
@@ -220,7 +221,7 @@ suspend fun <ResultType> HttpClient.unimultipart(
|
|||||||
suspend fun <BodyType, ResultType> HttpClient.unimultipart(
|
suspend fun <BodyType, ResultType> HttpClient.unimultipart(
|
||||||
url: String,
|
url: String,
|
||||||
mppFile: MPPFile,
|
mppFile: MPPFile,
|
||||||
otherData: BodyPair<BodyType>,
|
otherData: Pair<SerializationStrategy<BodyType>, BodyType>,
|
||||||
resultDeserializer: DeserializationStrategy<ResultType>,
|
resultDeserializer: DeserializationStrategy<ResultType>,
|
||||||
mimetype: String = "*/*",
|
mimetype: String = "*/*",
|
||||||
additionalParametersBuilder: FormBuilder.() -> Unit = {},
|
additionalParametersBuilder: FormBuilder.() -> Unit = {},
|
||||||
|
2
repos/cache/build.gradle
vendored
2
repos/cache/build.gradle
vendored
@@ -15,4 +15,4 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +1,16 @@
|
|||||||
package dev.inmo.micro_utils.repos.cache
|
package dev.inmo.micro_utils.repos.cache
|
||||||
|
|
||||||
import dev.inmo.micro_utils.repos.*
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import dev.inmo.micro_utils.repos.cache.cache.KVCache
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
|
|
||||||
open class ReadCRUDCacheRepo<ObjectType, IdType>(
|
open class ReadCRUDCacheRepo<ObjectType, IdType>(
|
||||||
protected val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
|
protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
|
||||||
protected val kvCache: KVCache<IdType, ObjectType>,
|
protected open val kvCache: KVCache<IdType, ObjectType>,
|
||||||
protected val idGetter: (ObjectType) -> IdType
|
protected open val idGetter: (ObjectType) -> IdType
|
||||||
) : ReadCRUDRepo<ObjectType, IdType> by parentRepo {
|
) : ReadCRUDRepo<ObjectType, IdType> by parentRepo, CacheRepo {
|
||||||
override suspend fun getById(id: IdType): ObjectType? = kvCache.get(id) ?: (parentRepo.getById(id) ?.also {
|
override suspend fun getById(id: IdType): ObjectType? = kvCache.get(id) ?: (parentRepo.getById(id) ?.also {
|
||||||
kvCache.set(id, it)
|
kvCache.set(id, it)
|
||||||
})
|
})
|
||||||
@@ -18,8 +18,63 @@ open class ReadCRUDCacheRepo<ObjectType, IdType>(
|
|||||||
override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id)
|
override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
|
||||||
|
kvCache: KVCache<IdType, ObjectType>,
|
||||||
|
idGetter: (ObjectType) -> IdType
|
||||||
|
) = ReadCRUDCacheRepo(this, kvCache, idGetter)
|
||||||
|
|
||||||
|
open class WriteCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||||
|
protected open val parentRepo: WriteCRUDRepo<ObjectType, IdType, InputValueType>,
|
||||||
|
protected open val kvCache: KVCache<IdType, ObjectType>,
|
||||||
|
protected open val scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||||
|
protected open val idGetter: (ObjectType) -> IdType
|
||||||
|
) : WriteCRUDRepo<ObjectType, IdType, InputValueType>, CacheRepo {
|
||||||
|
override val newObjectsFlow: Flow<ObjectType> by parentRepo::newObjectsFlow
|
||||||
|
override val updatedObjectsFlow: Flow<ObjectType> by parentRepo::updatedObjectsFlow
|
||||||
|
override val deletedObjectsIdsFlow: Flow<IdType> by parentRepo::deletedObjectsIdsFlow
|
||||||
|
|
||||||
|
val deletedObjectsFlowJob = parentRepo.deletedObjectsIdsFlow.onEach {
|
||||||
|
kvCache.unset(it)
|
||||||
|
}.launchIn(scope)
|
||||||
|
|
||||||
|
override suspend fun deleteById(ids: List<IdType>) = parentRepo.deleteById(ids)
|
||||||
|
|
||||||
|
override suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType> {
|
||||||
|
val updated = parentRepo.update(values)
|
||||||
|
|
||||||
|
kvCache.unset(values.map { it.id })
|
||||||
|
kvCache.set(updated.associateBy { idGetter(it) })
|
||||||
|
|
||||||
|
return updated
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun update(id: IdType, value: InputValueType): ObjectType? {
|
||||||
|
return parentRepo.update(id, value) ?.also {
|
||||||
|
kvCache.unset(id)
|
||||||
|
kvCache.set(idGetter(it), it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun create(values: List<InputValueType>): List<ObjectType> {
|
||||||
|
val created = parentRepo.create(values)
|
||||||
|
|
||||||
|
kvCache.set(
|
||||||
|
created.associateBy { idGetter(it) }
|
||||||
|
)
|
||||||
|
|
||||||
|
return created
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <ObjectType, IdType, InputType> WriteCRUDRepo<ObjectType, IdType, InputType>.caching(
|
||||||
|
kvCache: KVCache<IdType, ObjectType>,
|
||||||
|
scope: CoroutineScope,
|
||||||
|
idGetter: (ObjectType) -> IdType
|
||||||
|
) = WriteCRUDCacheRepo(this, kvCache, scope, idGetter)
|
||||||
|
|
||||||
|
|
||||||
open class CRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
open class CRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||||
parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
|
override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
|
||||||
kvCache: KVCache<IdType, ObjectType>,
|
kvCache: KVCache<IdType, ObjectType>,
|
||||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||||
idGetter: (ObjectType) -> IdType
|
idGetter: (ObjectType) -> IdType
|
||||||
@@ -27,8 +82,17 @@ open class CRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
|||||||
parentRepo,
|
parentRepo,
|
||||||
kvCache,
|
kvCache,
|
||||||
idGetter
|
idGetter
|
||||||
), CRUDRepo<ObjectType, IdType, InputValueType>, WriteCRUDRepo<ObjectType, IdType, InputValueType> by parentRepo {
|
),
|
||||||
protected val onNewJob = parentRepo.newObjectsFlow.onEach { kvCache.set(idGetter(it), it) }.launchIn(scope)
|
WriteCRUDRepo<ObjectType, IdType, InputValueType> by WriteCRUDCacheRepo(
|
||||||
protected val onUpdatedJob = parentRepo.updatedObjectsFlow.onEach { kvCache.set(idGetter(it), it) }.launchIn(scope)
|
parentRepo,
|
||||||
protected val onRemoveJob = parentRepo.deletedObjectsIdsFlow.onEach { kvCache.unset(it) }.launchIn(scope)
|
kvCache,
|
||||||
}
|
scope,
|
||||||
|
idGetter
|
||||||
|
),
|
||||||
|
CRUDRepo<ObjectType, IdType, InputValueType>
|
||||||
|
|
||||||
|
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
|
||||||
|
kvCache: KVCache<IdType, ObjectType>,
|
||||||
|
scope: CoroutineScope,
|
||||||
|
idGetter: (ObjectType) -> IdType
|
||||||
|
) = CRUDCacheRepo(this, kvCache, scope, idGetter)
|
||||||
|
3
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/CacheRepo.kt
vendored
Normal file
3
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/CacheRepo.kt
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.cache
|
||||||
|
|
||||||
|
interface CacheRepo
|
@@ -1,41 +1,6 @@
|
|||||||
package dev.inmo.micro_utils.repos.cache
|
package dev.inmo.micro_utils.repos.cache
|
||||||
|
|
||||||
import dev.inmo.micro_utils.repos.*
|
@Deprecated("Replaced", ReplaceWith("KVCache", "dev.inmo.micro_utils.repos.cache.cache.KVCache"))
|
||||||
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
|
typealias KVCache<K, V> = dev.inmo.micro_utils.repos.cache.cache.KVCache<K, V>
|
||||||
import kotlinx.coroutines.sync.Mutex
|
@Deprecated("Replaced", ReplaceWith("SimpleKVCache", "dev.inmo.micro_utils.repos.cache.cache.SimpleKVCache"))
|
||||||
import kotlinx.coroutines.sync.withLock
|
typealias SimpleKVCache<K, V> = dev.inmo.micro_utils.repos.cache.cache.SimpleKVCache<K, V>
|
||||||
|
|
||||||
interface KVCache<K, V> : KeyValueRepo<K, V>
|
|
||||||
|
|
||||||
open class SimpleKVCache<K, V>(
|
|
||||||
protected val cachedValuesCount: Int,
|
|
||||||
private val kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
|
|
||||||
) : KVCache<K, V>, KeyValueRepo<K, V> by kvParent {
|
|
||||||
protected open val cacheStack = ArrayList<K>(cachedValuesCount)
|
|
||||||
protected val syncMutex = Mutex()
|
|
||||||
|
|
||||||
protected suspend fun makeUnset(toUnset: List<K>) {
|
|
||||||
cacheStack.removeAll(toUnset)
|
|
||||||
kvParent.unset(toUnset)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun set(toSet: Map<K, V>) {
|
|
||||||
syncMutex.withLock {
|
|
||||||
if (toSet.size > cachedValuesCount) {
|
|
||||||
cacheStack.clear()
|
|
||||||
|
|
||||||
kvParent.unset(getAllWithNextPaging { kvParent.keys(it) })
|
|
||||||
val keysToInclude = toSet.keys.drop(toSet.size - cachedValuesCount)
|
|
||||||
|
|
||||||
cacheStack.addAll(keysToInclude)
|
|
||||||
kvParent.set(keysToInclude.associateWith { toSet.getValue(it) })
|
|
||||||
} else {
|
|
||||||
makeUnset(cacheStack.take(toSet.size))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun unset(toUnset: List<K>) {
|
|
||||||
syncMutex.withLock { makeUnset(toUnset) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,23 +1,35 @@
|
|||||||
package dev.inmo.micro_utils.repos.cache
|
package dev.inmo.micro_utils.repos.cache
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.pagination.Pagination
|
||||||
|
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||||
import dev.inmo.micro_utils.repos.*
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import dev.inmo.micro_utils.repos.cache.cache.KVCache
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
||||||
open class ReadKeyValueCacheRepo<Key,Value>(
|
open class ReadKeyValueCacheRepo<Key,Value>(
|
||||||
protected val parentRepo: ReadKeyValueRepo<Key, Value>,
|
protected open val parentRepo: ReadKeyValueRepo<Key, Value>,
|
||||||
protected val kvCache: KVCache<Key, Value>,
|
protected open val kvCache: KVCache<Key, Value>,
|
||||||
) : ReadKeyValueRepo<Key,Value> by parentRepo {
|
) : ReadKeyValueRepo<Key,Value> by parentRepo, CacheRepo {
|
||||||
override suspend fun get(k: Key): Value? = kvCache.get(k) ?: parentRepo.get(k) ?.also { kvCache.set(k, it) }
|
override suspend fun get(k: Key): Value? = kvCache.get(k) ?: parentRepo.get(k) ?.also { kvCache.set(k, it) }
|
||||||
override suspend fun contains(key: Key): Boolean = kvCache.contains(key) || parentRepo.contains(key)
|
override suspend fun contains(key: Key): Boolean = kvCache.contains(key) || parentRepo.contains(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
|
||||||
|
kvCache: KVCache<Key, Value>
|
||||||
|
) = ReadKeyValueCacheRepo(this, kvCache)
|
||||||
|
|
||||||
open class KeyValueCacheRepo<Key,Value>(
|
open class KeyValueCacheRepo<Key,Value>(
|
||||||
parentRepo: KeyValueRepo<Key, Value>,
|
parentRepo: KeyValueRepo<Key, Value>,
|
||||||
kvCache: KVCache<Key, Value>,
|
kvCache: KVCache<Key, Value>,
|
||||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
) : ReadKeyValueCacheRepo<Key,Value>(parentRepo, kvCache), KeyValueRepo<Key,Value>, WriteKeyValueRepo<Key, Value> by parentRepo {
|
) : ReadKeyValueCacheRepo<Key,Value>(parentRepo, kvCache), KeyValueRepo<Key,Value>, WriteKeyValueRepo<Key, Value> by parentRepo, CacheRepo {
|
||||||
protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope)
|
protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope)
|
||||||
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope)
|
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <Key, Value> KeyValueRepo<Key, Value>.cached(
|
||||||
|
kvCache: KVCache<Key, Value>,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
) = KeyValueCacheRepo(this, kvCache, scope)
|
||||||
|
@@ -5,14 +5,15 @@ import dev.inmo.micro_utils.pagination.PaginationResult
|
|||||||
import dev.inmo.micro_utils.pagination.utils.paginate
|
import dev.inmo.micro_utils.pagination.utils.paginate
|
||||||
import dev.inmo.micro_utils.pagination.utils.reverse
|
import dev.inmo.micro_utils.pagination.utils.reverse
|
||||||
import dev.inmo.micro_utils.repos.*
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import dev.inmo.micro_utils.repos.cache.cache.KVCache
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
||||||
open class ReadKeyValuesCacheRepo<Key,Value>(
|
open class ReadKeyValuesCacheRepo<Key,Value>(
|
||||||
protected val parentRepo: ReadKeyValuesRepo<Key, Value>,
|
protected open val parentRepo: ReadKeyValuesRepo<Key, Value>,
|
||||||
protected val kvCache: KVCache<Key, List<Value>>
|
protected open val kvCache: KVCache<Key, List<Value>>
|
||||||
) : ReadKeyValuesRepo<Key,Value> by parentRepo {
|
) : ReadKeyValuesRepo<Key,Value> by parentRepo, CacheRepo {
|
||||||
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
|
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
|
||||||
return kvCache.get(k) ?.paginate(
|
return kvCache.get(k) ?.paginate(
|
||||||
pagination.let { if (reversed) it.reverse(count(k)) else it }
|
pagination.let { if (reversed) it.reverse(count(k)) else it }
|
||||||
@@ -29,12 +30,21 @@ open class ReadKeyValuesCacheRepo<Key,Value>(
|
|||||||
override suspend fun contains(k: Key): Boolean = kvCache.contains(k) || parentRepo.contains(k)
|
override suspend fun contains(k: Key): Boolean = kvCache.contains(k) || parentRepo.contains(k)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
|
||||||
|
kvCache: KVCache<Key, List<Value>>
|
||||||
|
) = ReadKeyValuesCacheRepo(this, kvCache)
|
||||||
|
|
||||||
open class KeyValuesCacheRepo<Key,Value>(
|
open class KeyValuesCacheRepo<Key,Value>(
|
||||||
parentRepo: KeyValuesRepo<Key, Value>,
|
parentRepo: KeyValuesRepo<Key, Value>,
|
||||||
kvCache: KVCache<Key, List<Value>>,
|
kvCache: KVCache<Key, List<Value>>,
|
||||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
) : ReadKeyValuesCacheRepo<Key,Value>(parentRepo, kvCache), KeyValuesRepo<Key,Value>, WriteKeyValuesRepo<Key,Value> by parentRepo {
|
) : ReadKeyValuesCacheRepo<Key,Value>(parentRepo, kvCache), KeyValuesRepo<Key,Value>, WriteKeyValuesRepo<Key,Value> by parentRepo, CacheRepo {
|
||||||
protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, kvCache.get(it.first) ?.plus(it.second) ?: listOf(it.second)) }.launchIn(scope)
|
protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, kvCache.get(it.first) ?.plus(it.second) ?: listOf(it.second)) }.launchIn(scope)
|
||||||
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.set(it.first, kvCache.get(it.first) ?.minus(it.second) ?: return@onEach) }.launchIn(scope)
|
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.set(it.first, kvCache.get(it.first) ?.minus(it.second) ?: return@onEach) }.launchIn(scope)
|
||||||
protected val onDataClearedJob = parentRepo.onDataCleared.onEach { kvCache.unset(it) }.launchIn(scope)
|
protected val onDataClearedJob = parentRepo.onDataCleared.onEach { kvCache.unset(it) }.launchIn(scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <Key, Value> KeyValuesRepo<Key, Value>.cached(
|
||||||
|
kvCache: KVCache<Key, List<Value>>,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
) = KeyValuesCacheRepo(this, kvCache, scope)
|
||||||
|
8
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/FullKVCache.kt
vendored
Normal file
8
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/FullKVCache.kt
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.cache.cache
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface declares that current type of [KVCache] will contains all the data all the time of its life
|
||||||
|
*/
|
||||||
|
interface FullKVCache<K, V> : KVCache<K, V> {
|
||||||
|
companion object
|
||||||
|
}
|
7
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/KVCache.kt
vendored
Normal file
7
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/KVCache.kt
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.cache.cache
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
|
||||||
|
interface KVCache<K, V> : KeyValueRepo<K, V> {
|
||||||
|
companion object
|
||||||
|
}
|
28
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleFullKVCache.kt
vendored
Normal file
28
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleFullKVCache.kt
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.cache.cache
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.repos.KeyValueRepo
|
||||||
|
import dev.inmo.micro_utils.repos.MapKeyValueRepo
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
|
||||||
|
open class SimpleFullKVCache<K, V>(
|
||||||
|
private val kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
|
||||||
|
) : FullKVCache<K, V>, KeyValueRepo<K, V> by kvParent {
|
||||||
|
protected val syncMutex = Mutex()
|
||||||
|
|
||||||
|
override suspend fun set(toSet: Map<K, V>) {
|
||||||
|
syncMutex.withLock {
|
||||||
|
kvParent.set(toSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun unset(toUnset: List<K>) {
|
||||||
|
syncMutex.withLock {
|
||||||
|
kvParent.unset(toUnset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <K, V> FullKVCache(
|
||||||
|
kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
|
||||||
|
) = SimpleFullKVCache<K, V>(kvParent)
|
42
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleKVCache.kt
vendored
Normal file
42
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/cache/SimpleKVCache.kt
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.cache.cache
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
|
||||||
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
|
||||||
|
open class SimpleKVCache<K, V>(
|
||||||
|
protected val cachedValuesCount: Int,
|
||||||
|
private val kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
|
||||||
|
) : KVCache<K, V>, KeyValueRepo<K, V> by kvParent {
|
||||||
|
protected open val cacheQueue = ArrayDeque<K>(cachedValuesCount)
|
||||||
|
protected val syncMutex = Mutex()
|
||||||
|
|
||||||
|
protected suspend fun makeUnset(toUnset: List<K>) {
|
||||||
|
cacheQueue.removeAll(toUnset)
|
||||||
|
kvParent.unset(toUnset)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun set(toSet: Map<K, V>) {
|
||||||
|
syncMutex.withLock {
|
||||||
|
for ((k, v) in toSet) {
|
||||||
|
if (cacheQueue.size >= cachedValuesCount) {
|
||||||
|
cacheQueue.removeFirstOrNull() ?.let {
|
||||||
|
kvParent.unset(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cacheQueue.addLast(k)
|
||||||
|
kvParent.set(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun unset(toUnset: List<K>) {
|
||||||
|
syncMutex.withLock { makeUnset(toUnset) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <K, V> KVCache(
|
||||||
|
cachedValuesCount: Int,
|
||||||
|
kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
|
||||||
|
) = SimpleKVCache<K, V>(cachedValuesCount, kvParent)
|
95
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullCRUDCacheRepo.kt
vendored
Normal file
95
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullCRUDCacheRepo.kt
vendored
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.cache.full
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.*
|
||||||
|
import dev.inmo.micro_utils.pagination.Pagination
|
||||||
|
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||||
|
import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
|
||||||
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import dev.inmo.micro_utils.repos.cache.*
|
||||||
|
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||||
|
import dev.inmo.micro_utils.repos.cache.cache.KVCache
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
|
||||||
|
open class FullReadCRUDCacheRepo<ObjectType, IdType>(
|
||||||
|
protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
|
||||||
|
protected open val kvCache: FullKVCache<IdType, ObjectType>,
|
||||||
|
protected open val idGetter: (ObjectType) -> IdType
|
||||||
|
) : ReadCRUDRepo<ObjectType, IdType>, FullCacheRepo {
|
||||||
|
protected inline fun <T> doOrTakeAndActualize(
|
||||||
|
action: FullKVCache<IdType, ObjectType>.() -> Optional<T>,
|
||||||
|
actionElse: ReadCRUDRepo<ObjectType, IdType>.() -> T,
|
||||||
|
actualize: FullKVCache<IdType, ObjectType>.(T) -> Unit
|
||||||
|
): T {
|
||||||
|
kvCache.action().onPresented {
|
||||||
|
return it
|
||||||
|
}.onAbsent {
|
||||||
|
return parentRepo.actionElse().also {
|
||||||
|
kvCache.actualize(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error("The result should be returned above")
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open suspend fun actualizeAll() {
|
||||||
|
kvCache.clear()
|
||||||
|
doForAllWithNextPaging {
|
||||||
|
parentRepo.getByPagination(it).also {
|
||||||
|
kvCache.set(it.results.associateBy { idGetter(it) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = doOrTakeAndActualize(
|
||||||
|
{ values(pagination).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull },
|
||||||
|
{ getByPagination(pagination) },
|
||||||
|
{ if (it.results.isNotEmpty()) actualizeAll() }
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun count(): Long = doOrTakeAndActualize(
|
||||||
|
{ count().takeIf { it != 0L }.optionalOrAbsentIfNull },
|
||||||
|
{ count() },
|
||||||
|
{ if (it != 0L) actualizeAll() }
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun contains(id: IdType): Boolean = doOrTakeAndActualize(
|
||||||
|
{ contains(id).takeIf { it }.optionalOrAbsentIfNull },
|
||||||
|
{ contains(id) },
|
||||||
|
{ if (it) parentRepo.getById(id) ?.let { set(id, it) } }
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun getById(id: IdType): ObjectType? = doOrTakeAndActualize(
|
||||||
|
{ get(id) ?.optional ?: Optional.absent() },
|
||||||
|
{ getById(id) },
|
||||||
|
{ it ?.let { set(idGetter(it), it) } }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
|
||||||
|
kvCache: FullKVCache<IdType, ObjectType>,
|
||||||
|
idGetter: (ObjectType) -> IdType
|
||||||
|
) = FullReadCRUDCacheRepo(this, kvCache, idGetter)
|
||||||
|
|
||||||
|
open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||||
|
override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
|
||||||
|
kvCache: FullKVCache<IdType, ObjectType>,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||||
|
idGetter: (ObjectType) -> IdType
|
||||||
|
) : FullReadCRUDCacheRepo<ObjectType, IdType>(
|
||||||
|
parentRepo,
|
||||||
|
kvCache,
|
||||||
|
idGetter
|
||||||
|
),
|
||||||
|
WriteCRUDRepo<ObjectType, IdType, InputValueType> by WriteCRUDCacheRepo(
|
||||||
|
parentRepo,
|
||||||
|
kvCache,
|
||||||
|
scope,
|
||||||
|
idGetter
|
||||||
|
),
|
||||||
|
CRUDRepo<ObjectType, IdType, InputValueType>
|
||||||
|
|
||||||
|
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
|
||||||
|
kvCache: FullKVCache<IdType, ObjectType>,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||||
|
idGetter: (ObjectType) -> IdType
|
||||||
|
) = FullCRUDCacheRepo(this, kvCache, scope, idGetter)
|
5
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullCacheRepo.kt
vendored
Normal file
5
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullCacheRepo.kt
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.cache.full
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.repos.cache.CacheRepo
|
||||||
|
|
||||||
|
interface FullCacheRepo : CacheRepo
|
104
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullKeyValueCacheRepo.kt
vendored
Normal file
104
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullKeyValueCacheRepo.kt
vendored
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.cache.full
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.*
|
||||||
|
import dev.inmo.micro_utils.pagination.Pagination
|
||||||
|
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||||
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||||
|
import dev.inmo.micro_utils.repos.pagination.getAll
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
||||||
|
open class FullReadKeyValueCacheRepo<Key,Value>(
|
||||||
|
protected open val parentRepo: ReadKeyValueRepo<Key, Value>,
|
||||||
|
protected open val kvCache: FullKVCache<Key, Value>,
|
||||||
|
) : ReadKeyValueRepo<Key, Value>, FullCacheRepo {
|
||||||
|
protected inline fun <T> doOrTakeAndActualize(
|
||||||
|
action: FullKVCache<Key, Value>.() -> Optional<T>,
|
||||||
|
actionElse: ReadKeyValueRepo<Key, Value>.() -> T,
|
||||||
|
actualize: FullKVCache<Key, Value>.(T) -> Unit
|
||||||
|
): T {
|
||||||
|
kvCache.action().onPresented {
|
||||||
|
return it
|
||||||
|
}.onAbsent {
|
||||||
|
return parentRepo.actionElse().also {
|
||||||
|
kvCache.actualize(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error("The result should be returned above")
|
||||||
|
}
|
||||||
|
protected open suspend fun actualizeAll() {
|
||||||
|
kvCache.clear()
|
||||||
|
kvCache.set(parentRepo.getAll { keys(it) }.toMap())
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun get(k: Key): Value? = doOrTakeAndActualize(
|
||||||
|
{ get(k) ?.optional ?: Optional.absent() },
|
||||||
|
{ get(k) },
|
||||||
|
{ set(k, it ?: return@doOrTakeAndActualize) }
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<Value> = doOrTakeAndActualize(
|
||||||
|
{ values(pagination, reversed).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull },
|
||||||
|
{ values(pagination, reversed) },
|
||||||
|
{ if (it.results.isNotEmpty()) actualizeAll() }
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun count(): Long = doOrTakeAndActualize(
|
||||||
|
{ count().takeIf { it != 0L }.optionalOrAbsentIfNull },
|
||||||
|
{ count() },
|
||||||
|
{ if (it != 0L) actualizeAll() }
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun contains(key: Key): Boolean = doOrTakeAndActualize(
|
||||||
|
{ contains(key).takeIf { it }.optionalOrAbsentIfNull },
|
||||||
|
{ contains(key) },
|
||||||
|
{ if (it) parentRepo.get(key) ?.also { kvCache.set(key, it) } }
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = doOrTakeAndActualize(
|
||||||
|
{ keys(pagination, reversed).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull },
|
||||||
|
{ keys(pagination, reversed) },
|
||||||
|
{ if (it.results.isNotEmpty()) actualizeAll() }
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean): PaginationResult<Key> = doOrTakeAndActualize(
|
||||||
|
{ keys(v, pagination, reversed).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull },
|
||||||
|
{ parentRepo.keys(v, pagination, reversed) },
|
||||||
|
{ if (it.results.isNotEmpty()) actualizeAll() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
|
||||||
|
kvCache: FullKVCache<Key, Value>
|
||||||
|
) = FullReadKeyValueCacheRepo(this, kvCache)
|
||||||
|
|
||||||
|
open class FullWriteKeyValueCacheRepo<Key,Value>(
|
||||||
|
protected open val parentRepo: WriteKeyValueRepo<Key, Value>,
|
||||||
|
protected open val kvCache: FullKVCache<Key, Value>,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
) : WriteKeyValueRepo<Key, Value> by parentRepo, FullCacheRepo {
|
||||||
|
protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope)
|
||||||
|
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <Key, Value> WriteKeyValueRepo<Key, Value>.caching(
|
||||||
|
kvCache: FullKVCache<Key, Value>,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
) = FullWriteKeyValueCacheRepo(this, kvCache, scope)
|
||||||
|
|
||||||
|
open class FullKeyValueCacheRepo<Key,Value>(
|
||||||
|
parentRepo: KeyValueRepo<Key, Value>,
|
||||||
|
kvCache: FullKVCache<Key, Value>,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
) : FullWriteKeyValueCacheRepo<Key,Value>(parentRepo, kvCache, scope),
|
||||||
|
KeyValueRepo<Key,Value>,
|
||||||
|
ReadKeyValueRepo<Key, Value> by FullReadKeyValueCacheRepo(parentRepo, kvCache) {
|
||||||
|
override suspend fun unsetWithValues(toUnset: List<Value>) = parentRepo.unsetWithValues(toUnset)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <Key, Value> KeyValueRepo<Key, Value>.cached(
|
||||||
|
kvCache: FullKVCache<Key, Value>,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
) = FullKeyValueCacheRepo(this, kvCache, scope)
|
154
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullKeyValuesCacheRepo.kt
vendored
Normal file
154
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/full/FullKeyValuesCacheRepo.kt
vendored
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.cache.full
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.*
|
||||||
|
import dev.inmo.micro_utils.pagination.*
|
||||||
|
import dev.inmo.micro_utils.pagination.utils.*
|
||||||
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
||||||
|
open class FullReadKeyValuesCacheRepo<Key,Value>(
|
||||||
|
protected open val parentRepo: ReadKeyValuesRepo<Key, Value>,
|
||||||
|
protected open val kvCache: FullKVCache<Key, List<Value>>,
|
||||||
|
) : ReadKeyValuesRepo<Key, Value>, FullCacheRepo {
|
||||||
|
protected inline fun <T> doOrTakeAndActualize(
|
||||||
|
action: FullKVCache<Key, List<Value>>.() -> Optional<T>,
|
||||||
|
actionElse: ReadKeyValuesRepo<Key, Value>.() -> T,
|
||||||
|
actualize: FullKVCache<Key, List<Value>>.(T) -> Unit
|
||||||
|
): T {
|
||||||
|
kvCache.action().onPresented {
|
||||||
|
return it
|
||||||
|
}.onAbsent {
|
||||||
|
return parentRepo.actionElse().also {
|
||||||
|
kvCache.actualize(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error("The result should be returned above")
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open suspend fun actualizeKey(k: Key) {
|
||||||
|
kvCache.set(k, parentRepo.getAll(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open suspend fun actualizeAll() {
|
||||||
|
doAllWithCurrentPaging { kvCache.keys(it).also { kvCache.unset(it.results) } }
|
||||||
|
kvCache.set(parentRepo.getAll())
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
|
||||||
|
return doOrTakeAndActualize(
|
||||||
|
{
|
||||||
|
get(k) ?.paginate(
|
||||||
|
pagination.let { if (reversed) it.reverse(count(k)) else it }
|
||||||
|
) ?.let {
|
||||||
|
if (reversed) it.copy(results = it.results.reversed()) else it
|
||||||
|
}.optionalOrAbsentIfNull
|
||||||
|
},
|
||||||
|
{ get(k, pagination, reversed) },
|
||||||
|
{ actualizeKey(k) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> {
|
||||||
|
return doOrTakeAndActualize(
|
||||||
|
{
|
||||||
|
kvCache.keys(pagination, reversed).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull
|
||||||
|
},
|
||||||
|
{ parentRepo.keys(pagination, reversed) },
|
||||||
|
{ actualizeAll() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun count(): Long = doOrTakeAndActualize(
|
||||||
|
{ count().takeIf { it != 0L }.optionalOrAbsentIfNull },
|
||||||
|
{ count() },
|
||||||
|
{ if (it != 0L) actualizeAll() }
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun count(k: Key): Long = doOrTakeAndActualize(
|
||||||
|
{ count().takeIf { it != 0L }.optionalOrAbsentIfNull },
|
||||||
|
{ count() },
|
||||||
|
{ if (it != 0L) actualizeKey(k) }
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun contains(k: Key, v: Value): Boolean = doOrTakeAndActualize(
|
||||||
|
{ get(k) ?.contains(v).takeIf { it == true }.optionalOrAbsentIfNull },
|
||||||
|
{ contains(k, v) },
|
||||||
|
{ if (it) actualizeKey(k) }
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun contains(k: Key): Boolean = doOrTakeAndActualize(
|
||||||
|
{ contains(k).takeIf { it }.optionalOrAbsentIfNull },
|
||||||
|
{ contains(k) },
|
||||||
|
{ if (it) actualizeKey(k) }
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun keys(
|
||||||
|
v: Value,
|
||||||
|
pagination: Pagination,
|
||||||
|
reversed: Boolean
|
||||||
|
): PaginationResult<Key> = doOrTakeAndActualize(
|
||||||
|
{
|
||||||
|
val keys = getAllWithNextPaging { keys(it) }.filter { get(it) ?.contains(v) == true }.optionallyReverse(reversed)
|
||||||
|
if (keys.isNotEmpty()) {
|
||||||
|
keys.paginate(pagination.optionallyReverse(keys.size, reversed)).takeIf { it.results.isNotEmpty() }.optionalOrAbsentIfNull
|
||||||
|
} else {
|
||||||
|
Optional.absent()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ parentRepo.keys(v, pagination, reversed) },
|
||||||
|
{ if (it.results.isNotEmpty()) actualizeAll() }
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
|
||||||
|
kvCache: FullKVCache<Key, List<Value>>
|
||||||
|
) = FullReadKeyValuesCacheRepo(this, kvCache)
|
||||||
|
|
||||||
|
open class FullWriteKeyValuesCacheRepo<Key,Value>(
|
||||||
|
protected open val parentRepo: WriteKeyValuesRepo<Key, Value>,
|
||||||
|
protected open val kvCache: FullKVCache<Key, List<Value>>,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
) : WriteKeyValuesRepo<Key, Value> by parentRepo, FullCacheRepo {
|
||||||
|
protected val onNewJob = parentRepo.onNewValue.onEach {
|
||||||
|
kvCache.set(
|
||||||
|
it.first,
|
||||||
|
kvCache.get(it.first) ?.plus(it.second) ?: listOf(it.second)
|
||||||
|
)
|
||||||
|
}.launchIn(scope)
|
||||||
|
protected val onRemoveJob = parentRepo.onValueRemoved.onEach {
|
||||||
|
kvCache.set(
|
||||||
|
it.first,
|
||||||
|
kvCache.get(it.first) ?.minus(it.second) ?: return@onEach
|
||||||
|
)
|
||||||
|
}.launchIn(scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <Key, Value> WriteKeyValuesRepo<Key, Value>.caching(
|
||||||
|
kvCache: FullKVCache<Key, List<Value>>,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
) = FullWriteKeyValuesCacheRepo(this, kvCache, scope)
|
||||||
|
|
||||||
|
open class FullKeyValuesCacheRepo<Key,Value>(
|
||||||
|
parentRepo: KeyValuesRepo<Key, Value>,
|
||||||
|
kvCache: FullKVCache<Key, List<Value>>,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
) : FullWriteKeyValuesCacheRepo<Key, Value>(parentRepo, kvCache, scope),
|
||||||
|
KeyValuesRepo<Key, Value>,
|
||||||
|
ReadKeyValuesRepo<Key, Value> by FullReadKeyValuesCacheRepo(parentRepo, kvCache) {
|
||||||
|
override suspend fun clearWithValue(v: Value) {
|
||||||
|
doAllWithCurrentPaging {
|
||||||
|
keys(v, it).also {
|
||||||
|
remove(it.results.associateWith { listOf(v) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <Key, Value> KeyValuesRepo<Key, Value>.caching(
|
||||||
|
kvCache: FullKVCache<Key, List<Value>>,
|
||||||
|
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
) = FullKeyValuesCacheRepo(this, kvCache, scope)
|
@@ -1,22 +1,51 @@
|
|||||||
package dev.inmo.micro_utils.repos
|
package dev.inmo.micro_utils.repos
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.*
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
interface MapperRepo<FromKey, FromValue, ToKey, ToValue> {
|
interface MapperRepo<FromKey, FromValue, ToKey, ToValue> {
|
||||||
|
val keyMapper: SimpleSuspendableMapper<FromKey, ToKey>
|
||||||
|
get() = simpleSuspendableMapper(
|
||||||
|
{ it.toInnerKey() },
|
||||||
|
{ it.toOutKey() }
|
||||||
|
)
|
||||||
|
val valueMapper: SimpleSuspendableMapper<FromValue, ToValue>
|
||||||
|
get() = simpleSuspendableMapper(
|
||||||
|
{ it.toInnerValue() },
|
||||||
|
{ it.toOutValue() }
|
||||||
|
)
|
||||||
|
|
||||||
suspend fun FromKey.toOutKey() = this as ToKey
|
suspend fun FromKey.toOutKey() = this as ToKey
|
||||||
suspend fun FromValue.toOutValue() = this as ToValue
|
suspend fun FromValue.toOutValue() = this as ToValue
|
||||||
|
|
||||||
suspend fun ToKey.toInnerKey() = this as FromKey
|
suspend fun ToKey.toInnerKey() = this as FromKey
|
||||||
suspend fun ToValue.toInnerValue() = this as FromValue
|
suspend fun ToValue.toInnerValue() = this as FromValue
|
||||||
|
|
||||||
|
companion object
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> mapper(
|
class SimpleMapperRepo<FromKey, FromValue, ToKey, ToValue>(
|
||||||
crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
private val keyFromToTo: suspend FromKey.() -> ToKey,
|
||||||
crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
private val valueFromToTo: suspend FromValue.() -> ToValue,
|
||||||
crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
private val keyToToFrom: suspend ToKey.() -> FromKey,
|
||||||
crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
private val valueToToFrom: suspend ToValue.() -> FromValue
|
||||||
) = object : MapperRepo<FromKey, FromValue, ToKey, ToValue> {
|
) : MapperRepo<FromKey, FromValue, ToKey, ToValue> {
|
||||||
override suspend fun FromKey.toOutKey(): ToKey = keyFromToTo()
|
override suspend fun FromKey.toOutKey(): ToKey = keyFromToTo()
|
||||||
override suspend fun FromValue.toOutValue(): ToValue = valueFromToTo()
|
override suspend fun FromValue.toOutValue(): ToValue = valueFromToTo()
|
||||||
override suspend fun ToKey.toInnerKey(): FromKey = keyToToFrom()
|
override suspend fun ToKey.toInnerKey(): FromKey = keyToToFrom()
|
||||||
override suspend fun ToValue.toInnerValue(): FromValue = valueToToFrom()
|
override suspend fun ToValue.toInnerValue(): FromValue = valueToToFrom()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator fun <FromKey, FromValue, ToKey, ToValue> MapperRepo.Companion.invoke(
|
||||||
|
keyFromToTo: suspend FromKey.() -> ToKey,
|
||||||
|
valueFromToTo: suspend FromValue.() -> ToValue,
|
||||||
|
keyToToFrom: suspend ToKey.() -> FromKey,
|
||||||
|
valueToToFrom: suspend ToValue.() -> FromValue
|
||||||
|
) = SimpleMapperRepo(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
|
|
||||||
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> mapper(
|
||||||
|
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
||||||
|
noinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
||||||
|
noinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
||||||
|
noinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
||||||
|
) = MapperRepo(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
|
@@ -48,6 +48,10 @@ interface KeyValueRepo<Key, Value> : ReadKeyValueRepo<Key, Value>, WriteKeyValue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun clear() {
|
||||||
|
doAllWithCurrentPaging { keys(it).also { unset(it.results) } }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
typealias StandardKeyValueRepo<Key,Value> = KeyValueRepo<Key, Value>
|
typealias StandardKeyValueRepo<Key,Value> = KeyValueRepo<Key, Value>
|
||||||
|
|
||||||
|
@@ -0,0 +1,130 @@
|
|||||||
|
package dev.inmo.micro_utils.repos.mappers
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.common.*
|
||||||
|
import dev.inmo.micro_utils.pagination.*
|
||||||
|
import dev.inmo.micro_utils.repos.*
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
|
open class MapperReadCRUDRepo<FromId, FromRegistered, ToId, ToRegistered>(
|
||||||
|
private val to: ReadCRUDRepo<ToRegistered, ToId>,
|
||||||
|
mapper: MapperRepo<FromId, FromRegistered, ToId, ToRegistered>
|
||||||
|
) : ReadCRUDRepo<FromRegistered, FromId>, MapperRepo<FromId, FromRegistered, ToId, ToRegistered> by mapper {
|
||||||
|
override suspend fun getByPagination(
|
||||||
|
pagination: Pagination
|
||||||
|
): PaginationResult<FromRegistered> = to.getByPagination(
|
||||||
|
pagination
|
||||||
|
).let {
|
||||||
|
it.changeResultsUnchecked(
|
||||||
|
it.results.map { it.toInnerValue() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun count(): Long = to.count()
|
||||||
|
|
||||||
|
override suspend fun contains(id: FromId): Boolean = to.contains(id.toOutKey())
|
||||||
|
|
||||||
|
override suspend fun getById(id: FromId): FromRegistered? = to.getById(
|
||||||
|
id.toOutKey()
|
||||||
|
) ?.toInnerValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <FromKey, FromValue, ToKey, ToValue> ReadCRUDRepo<ToValue, ToKey>.withMapper(
|
||||||
|
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
|
||||||
|
): ReadCRUDRepo<FromValue, FromKey> = MapperReadCRUDRepo(this, mapper)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadCRUDRepo<ToValue, ToKey>.withMapper(
|
||||||
|
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
||||||
|
noinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
||||||
|
noinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
||||||
|
noinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
||||||
|
): ReadCRUDRepo<FromValue, FromKey> = withMapper(
|
||||||
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
|
)
|
||||||
|
|
||||||
|
open class MapperWriteCRUDRepo<FromId, FromRegistered, FromInput, ToId, ToRegistered, ToInput>(
|
||||||
|
private val to: WriteCRUDRepo<ToRegistered, ToId, ToInput>,
|
||||||
|
mapper: MapperRepo<FromId, FromRegistered, ToId, ToRegistered>,
|
||||||
|
inputMapper: SimpleSuspendableMapper<FromInput, ToInput>
|
||||||
|
) : WriteCRUDRepo<FromRegistered, FromId, FromInput>,
|
||||||
|
MapperRepo<FromId, FromRegistered, ToId, ToRegistered> by mapper,
|
||||||
|
SimpleSuspendableMapper<FromInput, ToInput> by inputMapper {
|
||||||
|
override val newObjectsFlow: Flow<FromRegistered> = to.newObjectsFlow.map { it.toInnerValue() }
|
||||||
|
override val updatedObjectsFlow: Flow<FromRegistered> = to.updatedObjectsFlow.map { it.toInnerValue() }
|
||||||
|
override val deletedObjectsIdsFlow: Flow<FromId> = to.deletedObjectsIdsFlow.map { it.toInnerKey() }
|
||||||
|
|
||||||
|
override suspend fun deleteById(ids: List<FromId>) = to.deleteById(ids.map { it.toOutKey() })
|
||||||
|
|
||||||
|
override suspend fun update(
|
||||||
|
values: List<UpdatedValuePair<FromId, FromInput>>
|
||||||
|
): List<FromRegistered> = to.update(
|
||||||
|
values.map {
|
||||||
|
it.first.toOutKey() to convert(it.second)
|
||||||
|
}
|
||||||
|
).map { it.toInnerValue() }
|
||||||
|
|
||||||
|
override suspend fun update(
|
||||||
|
id: FromId,
|
||||||
|
value: FromInput
|
||||||
|
): FromRegistered? = to.update(id.toOutKey(), convert(value)) ?.toInnerValue()
|
||||||
|
|
||||||
|
override suspend fun create(values: List<FromInput>): List<FromRegistered> = to.create(
|
||||||
|
values.map {
|
||||||
|
convert(it)
|
||||||
|
}
|
||||||
|
).map {
|
||||||
|
it.toInnerValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <FromKey, FromValue, FromInput, ToKey, ToValue, ToInput> WriteCRUDRepo<ToValue, ToKey, ToInput>.withMapper(
|
||||||
|
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>,
|
||||||
|
simpleSuspendableMapper: SimpleSuspendableMapper<FromInput, ToInput>
|
||||||
|
): WriteCRUDRepo<FromValue, FromKey, FromInput> = MapperWriteCRUDRepo(this, mapper, simpleSuspendableMapper)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <reified FromKey, reified FromValue, reified FromInput, reified ToKey, reified ToValue, reified ToInput> WriteCRUDRepo<ToValue, ToKey, ToInput>.withMapper(
|
||||||
|
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
||||||
|
noinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
||||||
|
noinline inputFromToTo: suspend FromInput.() -> ToInput = { this as ToInput },
|
||||||
|
noinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
||||||
|
noinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
||||||
|
noinline inputToToFrom: suspend ToInput.() -> FromInput = { this as FromInput },
|
||||||
|
): WriteCRUDRepo<FromValue, FromKey, FromInput> = withMapper(
|
||||||
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom),
|
||||||
|
simpleSuspendableMapper({ inputToToFrom(it) }, { inputFromToTo(it) })
|
||||||
|
)
|
||||||
|
|
||||||
|
@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
|
||||||
|
open class MapperCRUDRepo<FromId, FromRegistered, FromInput, ToId, ToRegistered, ToInput>(
|
||||||
|
private val to: CRUDRepo<ToRegistered, ToId, ToInput>,
|
||||||
|
private val mapper: MapperRepo<FromId, FromRegistered, ToId, ToRegistered>,
|
||||||
|
private val inputMapper: SimpleSuspendableMapper<FromInput, ToInput>
|
||||||
|
) : CRUDRepo<FromRegistered, FromId, FromInput>,
|
||||||
|
MapperRepo<FromId, FromRegistered, ToId, ToRegistered> by mapper,
|
||||||
|
ReadCRUDRepo<FromRegistered, FromId> by MapperReadCRUDRepo(to, mapper),
|
||||||
|
WriteCRUDRepo<FromRegistered, FromId, FromInput> by MapperWriteCRUDRepo(to, mapper, inputMapper)
|
||||||
|
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <FromKey, FromValue, FromInput, ToKey, ToValue, ToInput> CRUDRepo<ToValue, ToKey, ToInput>.withMapper(
|
||||||
|
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>,
|
||||||
|
simpleSuspendableMapper: SimpleSuspendableMapper<FromInput, ToInput>
|
||||||
|
): CRUDRepo<FromValue, FromKey, FromInput> = MapperCRUDRepo(this, mapper, simpleSuspendableMapper)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun <reified FromKey, reified FromValue, reified FromInput, reified ToKey, reified ToValue, reified ToInput> CRUDRepo<ToValue, ToKey, ToInput>.withMapper(
|
||||||
|
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
||||||
|
noinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
||||||
|
noinline inputFromToTo: suspend FromInput.() -> ToInput = { this as ToInput },
|
||||||
|
noinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
||||||
|
noinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
||||||
|
noinline inputToToFrom: suspend ToInput.() -> FromInput = { this as FromInput },
|
||||||
|
): CRUDRepo<FromValue, FromKey, FromInput> = withMapper(
|
||||||
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom),
|
||||||
|
simpleSuspendableMapper({ inputToToFrom(it) }, { inputFromToTo(it) })
|
||||||
|
)
|
@@ -77,10 +77,10 @@ inline fun <FromKey, FromValue, ToKey, ToValue> ReadKeyValueRepo<ToKey, ToValue>
|
|||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadKeyValueRepo<ToKey, ToValue>.withMapper(
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadKeyValueRepo<ToKey, ToValue>.withMapper(
|
||||||
crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
||||||
crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
noinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
||||||
crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
noinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
||||||
crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
noinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
||||||
): ReadKeyValueRepo<FromKey, FromValue> = withMapper(
|
): ReadKeyValueRepo<FromKey, FromValue> = withMapper(
|
||||||
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
)
|
)
|
||||||
@@ -122,10 +122,10 @@ inline fun <FromKey, FromValue, ToKey, ToValue> WriteKeyValueRepo<ToKey, ToValue
|
|||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteKeyValueRepo<ToKey, ToValue>.withMapper(
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteKeyValueRepo<ToKey, ToValue>.withMapper(
|
||||||
crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
||||||
crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
noinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
||||||
crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
noinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
||||||
crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
noinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
||||||
): WriteKeyValueRepo<FromKey, FromValue> = withMapper(
|
): WriteKeyValueRepo<FromKey, FromValue> = withMapper(
|
||||||
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
)
|
)
|
||||||
@@ -148,10 +148,10 @@ inline fun <FromKey, FromValue, ToKey, ToValue> KeyValueRepo<ToKey, ToValue>.wit
|
|||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> KeyValueRepo<ToKey, ToValue>.withMapper(
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> KeyValueRepo<ToKey, ToValue>.withMapper(
|
||||||
crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
||||||
crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
noinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
||||||
crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
noinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
||||||
crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
noinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
||||||
): KeyValueRepo<FromKey, FromValue> = withMapper(
|
): KeyValueRepo<FromKey, FromValue> = withMapper(
|
||||||
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
)
|
)
|
||||||
|
@@ -75,10 +75,10 @@ inline fun <FromKey, FromValue, ToKey, ToValue> ReadKeyValuesRepo<ToKey, ToValue
|
|||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadKeyValuesRepo<ToKey, ToValue>.withMapper(
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadKeyValuesRepo<ToKey, ToValue>.withMapper(
|
||||||
crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
||||||
crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
noinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
||||||
crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
noinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
||||||
crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
noinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
||||||
): ReadKeyValuesRepo<FromKey, FromValue> = withMapper(
|
): ReadKeyValuesRepo<FromKey, FromValue> = withMapper(
|
||||||
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
)
|
)
|
||||||
@@ -128,10 +128,10 @@ inline fun <FromKey, FromValue, ToKey, ToValue> WriteKeyValuesRepo<ToKey, ToValu
|
|||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteKeyValuesRepo<ToKey, ToValue>.withMapper(
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteKeyValuesRepo<ToKey, ToValue>.withMapper(
|
||||||
crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
||||||
crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
noinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
||||||
crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
noinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
||||||
crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
noinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
||||||
): WriteKeyValuesRepo<FromKey, FromValue> = withMapper(
|
): WriteKeyValuesRepo<FromKey, FromValue> = withMapper(
|
||||||
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
)
|
)
|
||||||
@@ -154,10 +154,10 @@ inline fun <FromKey, FromValue, ToKey, ToValue> KeyValuesRepo<ToKey, ToValue>.wi
|
|||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> KeyValuesRepo<ToKey, ToValue>.withMapper(
|
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> KeyValuesRepo<ToKey, ToValue>.withMapper(
|
||||||
crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
|
||||||
crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
noinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue },
|
||||||
crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
noinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey },
|
||||||
crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
noinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue },
|
||||||
): KeyValuesRepo<FromKey, FromValue> = withMapper(
|
): KeyValuesRepo<FromKey, FromValue> = withMapper(
|
||||||
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
|
||||||
)
|
)
|
||||||
|
@@ -34,7 +34,7 @@ class FileReadKeyValueRepo(
|
|||||||
override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<File> {
|
override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<File> {
|
||||||
val count = count()
|
val count = count()
|
||||||
val resultPagination = if (reversed) pagination.reverse(count) else pagination
|
val resultPagination = if (reversed) pagination.reverse(count) else pagination
|
||||||
val filesPaths = folder.list() ?.copyOfRange(resultPagination.firstIndex, resultPagination.lastIndex) ?: return emptyPaginationResult()
|
val filesPaths = folder.list() ?.copyOfRange(resultPagination.firstIndex, resultPagination.lastIndexExclusive) ?: return emptyPaginationResult()
|
||||||
if (reversed) {
|
if (reversed) {
|
||||||
filesPaths.reverse()
|
filesPaths.reverse()
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ class FileReadKeyValueRepo(
|
|||||||
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<String> {
|
override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<String> {
|
||||||
val count = count()
|
val count = count()
|
||||||
val resultPagination = if (reversed) pagination.reverse(count) else pagination
|
val resultPagination = if (reversed) pagination.reverse(count) else pagination
|
||||||
val filesPaths = folder.list() ?.copyOfRange(resultPagination.firstIndex, resultPagination.lastIndex) ?: return emptyPaginationResult()
|
val filesPaths = folder.list() ?.copyOfRange(resultPagination.firstIndex, resultPagination.lastIndexExclusive) ?: return emptyPaginationResult()
|
||||||
if (reversed) {
|
if (reversed) {
|
||||||
filesPaths.reverse()
|
filesPaths.reverse()
|
||||||
}
|
}
|
||||||
@@ -99,7 +99,9 @@ class FileWriteKeyValueRepo(
|
|||||||
override val onValueRemoved: Flow<String> = _onValueRemoved.asSharedFlow()
|
override val onValueRemoved: Flow<String> = _onValueRemoved.asSharedFlow()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
folder.mkdirs()
|
if (!folder.mkdirs() && !folder.exists()) {
|
||||||
|
error("Unable to create folder ${folder.absolutePath}")
|
||||||
|
}
|
||||||
filesChangedProcessingScope ?.let {
|
filesChangedProcessingScope ?.let {
|
||||||
it.launch {
|
it.launch {
|
||||||
try {
|
try {
|
||||||
@@ -144,15 +146,17 @@ class FileWriteKeyValueRepo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun set(toSet: Map<String, File>) {
|
override suspend fun set(toSet: Map<String, File>) {
|
||||||
supervisorScope {
|
val scope = CoroutineScope(currentCoroutineContext())
|
||||||
toSet.map { (filename, fileSource) ->
|
toSet.map { (filename, fileSource) ->
|
||||||
launch {
|
scope.launch {
|
||||||
val file = File(folder, filename)
|
val file = File(folder, filename)
|
||||||
|
|
||||||
file.delete()
|
file.delete()
|
||||||
fileSource.copyTo(file, overwrite = true)
|
fileSource.copyTo(file, overwrite = true)
|
||||||
_onNewValue.emit(filename to file)
|
if (!file.exists()) {
|
||||||
|
error("Can't create file $file with new content")
|
||||||
}
|
}
|
||||||
|
_onNewValue.emit(filename to file)
|
||||||
}
|
}
|
||||||
}.joinAll()
|
}.joinAll()
|
||||||
}
|
}
|
||||||
|
@@ -56,25 +56,25 @@ class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> (
|
|||||||
|
|
||||||
override suspend fun create(values: List<InputValue>): List<ObjectType> = unifiedRequester.unipost(
|
override suspend fun create(values: List<InputValue>): List<ObjectType> = unifiedRequester.unipost(
|
||||||
buildStandardUrl(baseUrl, createRouting),
|
buildStandardUrl(baseUrl, createRouting),
|
||||||
BodyPair(listInputSerializer, values),
|
Pair(listInputSerializer, values),
|
||||||
listObjectsSerializer
|
listObjectsSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun update(id: IdType, value: InputValue): ObjectType? = unifiedRequester.unipost(
|
override suspend fun update(id: IdType, value: InputValue): ObjectType? = unifiedRequester.unipost(
|
||||||
buildStandardUrl(baseUrl, updateRouting),
|
buildStandardUrl(baseUrl, updateRouting),
|
||||||
BodyPair(inputUpdateSerializer, id to value),
|
Pair(inputUpdateSerializer, id to value),
|
||||||
objectsNullableSerializer
|
objectsNullableSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun update(values: List<UpdatedValuePair<IdType, InputValue>>): List<ObjectType> = unifiedRequester.unipost(
|
override suspend fun update(values: List<UpdatedValuePair<IdType, InputValue>>): List<ObjectType> = unifiedRequester.unipost(
|
||||||
buildStandardUrl(baseUrl, updateManyRouting),
|
buildStandardUrl(baseUrl, updateManyRouting),
|
||||||
BodyPair(listInputUpdateSerializer, values),
|
Pair(listInputUpdateSerializer, values),
|
||||||
listObjectsSerializer
|
listObjectsSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun deleteById(ids: List<IdType>) = unifiedRequester.unipost(
|
override suspend fun deleteById(ids: List<IdType>) = unifiedRequester.unipost(
|
||||||
buildStandardUrl(baseUrl, deleteByIdRouting),
|
buildStandardUrl(baseUrl, deleteByIdRouting),
|
||||||
BodyPair(listIdsSerializer, ids),
|
Pair(listIdsSerializer, ids),
|
||||||
Unit.serializer()
|
Unit.serializer()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -45,7 +45,7 @@ class KtorWriteStandardKeyValueRepo<K, V> (
|
|||||||
baseUrl,
|
baseUrl,
|
||||||
setRoute
|
setRoute
|
||||||
),
|
),
|
||||||
BodyPair(keyValueMapSerializer, toSet),
|
Pair(keyValueMapSerializer, toSet),
|
||||||
Unit.serializer()
|
Unit.serializer()
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ class KtorWriteStandardKeyValueRepo<K, V> (
|
|||||||
baseUrl,
|
baseUrl,
|
||||||
unsetRoute,
|
unsetRoute,
|
||||||
),
|
),
|
||||||
BodyPair(keysListSerializer, toUnset),
|
Pair(keysListSerializer, toUnset),
|
||||||
Unit.serializer()
|
Unit.serializer()
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ class KtorWriteStandardKeyValueRepo<K, V> (
|
|||||||
baseUrl,
|
baseUrl,
|
||||||
unsetWithValuesRoute,
|
unsetWithValuesRoute,
|
||||||
),
|
),
|
||||||
BodyPair(valuesListSerializer, toUnset),
|
Pair(valuesListSerializer, toUnset),
|
||||||
Unit.serializer()
|
Unit.serializer()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -47,7 +47,7 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
|||||||
baseUrl,
|
baseUrl,
|
||||||
removeRoute,
|
removeRoute,
|
||||||
),
|
),
|
||||||
BodyPair(keyValueMapSerializer, toRemove),
|
Pair(keyValueMapSerializer, toRemove),
|
||||||
Unit.serializer(),
|
Unit.serializer(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
|||||||
baseUrl,
|
baseUrl,
|
||||||
addRoute,
|
addRoute,
|
||||||
),
|
),
|
||||||
BodyPair(keyValueMapSerializer, toAdd),
|
Pair(keyValueMapSerializer, toAdd),
|
||||||
Unit.serializer(),
|
Unit.serializer(),
|
||||||
)
|
)
|
||||||
override suspend fun clear(k: Key) = unifiedRequester.unipost(
|
override suspend fun clear(k: Key) = unifiedRequester.unipost(
|
||||||
@@ -64,7 +64,7 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
|||||||
baseUrl,
|
baseUrl,
|
||||||
clearRoute,
|
clearRoute,
|
||||||
),
|
),
|
||||||
BodyPair(keySerializer, k),
|
Pair(keySerializer, k),
|
||||||
Unit.serializer(),
|
Unit.serializer(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
|||||||
baseUrl,
|
baseUrl,
|
||||||
clearWithValueRoute,
|
clearWithValueRoute,
|
||||||
),
|
),
|
||||||
BodyPair(valueSerializer, v),
|
Pair(valueSerializer, v),
|
||||||
Unit.serializer(),
|
Unit.serializer(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ class KtorWriteOneToManyKeyValueRepo<Key, Value> (
|
|||||||
baseUrl,
|
baseUrl,
|
||||||
setRoute,
|
setRoute,
|
||||||
),
|
),
|
||||||
BodyPair(keyValueMapSerializer, toSet),
|
Pair(keyValueMapSerializer, toSet),
|
||||||
Unit.serializer(),
|
Unit.serializer(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user