mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-11-04 06:00:22 +00:00 
			
		
		
		
	kv rework, fixes in map keyvalue repo, tests
This commit is contained in:
		@@ -37,17 +37,24 @@ kt-serialization-cbor = { module = "org.jetbrains.kotlinx:kotlinx-serialization-
 | 
			
		||||
 | 
			
		||||
kt-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kt-coroutines" }
 | 
			
		||||
kt-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kt-coroutines" }
 | 
			
		||||
kt-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kt-coroutines" }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ktor-io = { module = "io.ktor:ktor-io", version.ref = "ktor" }
 | 
			
		||||
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
 | 
			
		||||
ktor-client = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
 | 
			
		||||
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
 | 
			
		||||
ktor-client-java = { module = "io.ktor:ktor-client-java", version.ref = "ktor" }
 | 
			
		||||
ktor-client-websockets = { module = "io.ktor:ktor-client-websockets", version.ref = "ktor" }
 | 
			
		||||
ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" }
 | 
			
		||||
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
 | 
			
		||||
ktor-server = { module = "io.ktor:ktor-server", version.ref = "ktor" }
 | 
			
		||||
ktor-server-cio = { module = "io.ktor:ktor-server-cio", version.ref = "ktor" }
 | 
			
		||||
ktor-server-host-common = { module = "io.ktor:ktor-server-host-common", version.ref = "ktor" }
 | 
			
		||||
ktor-websockets = { module = "io.ktor:ktor-websockets", version.ref = "ktor" }
 | 
			
		||||
ktor-server-websockets = { module = "io.ktor:ktor-server-websockets", version.ref = "ktor" }
 | 
			
		||||
ktor-server-statusPages = { module = "io.ktor:ktor-server-status-pages", version.ref = "ktor" }
 | 
			
		||||
ktor-server-content-negotiation = { module = "io.ktor:ktor-server-content-negotiation", version.ref = "ktor" }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "klock" }
 | 
			
		||||
 
 | 
			
		||||
@@ -50,3 +50,10 @@ interface StandardKeyValueRepo<Key, Value> : ReadStandardKeyValueRepo<Key, Value
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
typealias KeyValueRepo<Key,Value> = StandardKeyValueRepo<Key, Value>
 | 
			
		||||
 | 
			
		||||
class DelegateBasedStandardKeyValueRepo<Key, Value>(
 | 
			
		||||
    readDelegate: ReadStandardKeyValueRepo<Key, Value>,
 | 
			
		||||
    writeDelegate: WriteStandardKeyValueRepo<Key, Value>
 | 
			
		||||
) : StandardKeyValueRepo<Key, Value>,
 | 
			
		||||
    ReadStandardKeyValueRepo<Key, Value> by readDelegate,
 | 
			
		||||
    WriteStandardKeyValueRepo<Key, Value> by writeDelegate
 | 
			
		||||
 
 | 
			
		||||
@@ -78,11 +78,11 @@ class WriteMapKeyValueRepo<Key, Value>(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun unsetWithValues(toUnset: List<Value>) {
 | 
			
		||||
        map.forEach {
 | 
			
		||||
            if (it.value in toUnset) {
 | 
			
		||||
                map.remove(it.key)
 | 
			
		||||
                _onValueRemoved.emit(it.key)
 | 
			
		||||
            }
 | 
			
		||||
        map.mapNotNull { (k, v) ->
 | 
			
		||||
            k.takeIf { v in toUnset }
 | 
			
		||||
        }.forEach {
 | 
			
		||||
            map.remove(it)
 | 
			
		||||
            _onValueRemoved.emit(it)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import dev.inmo.micro_utils.ktor.common.*
 | 
			
		||||
import dev.inmo.micro_utils.pagination.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
 | 
			
		||||
import io.ktor.client.HttpClient
 | 
			
		||||
import kotlinx.serialization.KSerializer
 | 
			
		||||
import kotlinx.serialization.builtins.serializer
 | 
			
		||||
@@ -39,9 +40,7 @@ class KtorReadStandardCrudRepo<ObjectType, IdType> (
 | 
			
		||||
        buildStandardUrl(
 | 
			
		||||
            baseUrl,
 | 
			
		||||
            getByIdRouting,
 | 
			
		||||
            mapOf(
 | 
			
		||||
                "id" to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
 | 
			
		||||
            )
 | 
			
		||||
            idParameterName to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
 | 
			
		||||
        ),
 | 
			
		||||
        objectsSerializerNullable
 | 
			
		||||
    )
 | 
			
		||||
@@ -50,9 +49,7 @@ class KtorReadStandardCrudRepo<ObjectType, IdType> (
 | 
			
		||||
        buildStandardUrl(
 | 
			
		||||
            baseUrl,
 | 
			
		||||
            containsRouting,
 | 
			
		||||
            mapOf(
 | 
			
		||||
                "id" to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
 | 
			
		||||
            )
 | 
			
		||||
            idParameterName to unifiedRequester.encodeUrlQueryValue(idsSerializer, id)
 | 
			
		||||
        ),
 | 
			
		||||
        Boolean.serializer()
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import dev.inmo.micro_utils.ktor.common.*
 | 
			
		||||
import dev.inmo.micro_utils.pagination.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
 | 
			
		||||
import io.ktor.client.HttpClient
 | 
			
		||||
import io.ktor.client.call.body
 | 
			
		||||
import io.ktor.client.request.get
 | 
			
		||||
@@ -30,7 +31,7 @@ class KtorReadStandardCrudRepoClient<ObjectType, IdType> (
 | 
			
		||||
            baseUrl,
 | 
			
		||||
            getByIdRouting,
 | 
			
		||||
            mapOf(
 | 
			
		||||
                "id" to idSerializer(id)
 | 
			
		||||
                idParameterName to idSerializer(id)
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
    ) {
 | 
			
		||||
@@ -42,7 +43,7 @@ class KtorReadStandardCrudRepoClient<ObjectType, IdType> (
 | 
			
		||||
            baseUrl,
 | 
			
		||||
            containsRouting,
 | 
			
		||||
            mapOf(
 | 
			
		||||
                "id" to idSerializer(id)
 | 
			
		||||
                idParameterName to idSerializer(id)
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
    ) {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ class KtorStandardCrudRepoClient<ObjectType, IdType, InputValue> (
 | 
			
		||||
    writeDelegate
 | 
			
		||||
) {
 | 
			
		||||
    companion object {
 | 
			
		||||
        inline operator fun <reified ObjectType, reified IdType, reified InputValue>invoke(
 | 
			
		||||
        inline operator fun <reified ObjectType, reified IdType, reified InputValue> invoke(
 | 
			
		||||
            baseUrl: String,
 | 
			
		||||
            httpClient: HttpClient,
 | 
			
		||||
            objectTypeInfo: TypeInfo,
 | 
			
		||||
@@ -38,7 +38,7 @@ class KtorStandardCrudRepoClient<ObjectType, IdType, InputValue> (
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        inline operator fun <reified ObjectType, reified IdType, reified InputValue>invoke(
 | 
			
		||||
        inline operator fun <reified ObjectType, reified IdType, reified InputValue> invoke(
 | 
			
		||||
            baseUrl: String,
 | 
			
		||||
            subpart: String,
 | 
			
		||||
            httpClient: HttpClient,
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,144 @@
 | 
			
		||||
package dev.inmo.micro_utils.repos.ktor.client.key_value
 | 
			
		||||
 | 
			
		||||
import dev.inmo.micro_utils.ktor.common.*
 | 
			
		||||
import dev.inmo.micro_utils.pagination.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.containsByKeyRoute
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName
 | 
			
		||||
import io.ktor.client.HttpClient
 | 
			
		||||
import io.ktor.client.call.body
 | 
			
		||||
import io.ktor.client.request.get
 | 
			
		||||
import io.ktor.http.*
 | 
			
		||||
import io.ktor.util.reflect.TypeInfo
 | 
			
		||||
import io.ktor.util.reflect.typeInfo
 | 
			
		||||
import kotlinx.serialization.*
 | 
			
		||||
 | 
			
		||||
class KtorReadStandardKeyValueRepoClient<Key, Value>(
 | 
			
		||||
    private val baseUrl: String,
 | 
			
		||||
    private val httpClient: HttpClient,
 | 
			
		||||
    private val contentType: ContentType,
 | 
			
		||||
    private val objectType: TypeInfo,
 | 
			
		||||
    private val paginationResultObjectsTypeInfo: TypeInfo,
 | 
			
		||||
    private val paginationResultIdsTypeInfo: TypeInfo,
 | 
			
		||||
    private val idSerializer: suspend (Key) -> String,
 | 
			
		||||
    private val valueSerializer: suspend (Value) -> String
 | 
			
		||||
) : ReadStandardKeyValueRepo<Key, Value> {
 | 
			
		||||
    override suspend fun get(k: Key): Value? = httpClient.get(
 | 
			
		||||
        buildStandardUrl(
 | 
			
		||||
            baseUrl,
 | 
			
		||||
            getRoute,
 | 
			
		||||
            mapOf(
 | 
			
		||||
                idParameterName to idSerializer(k)
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
    ) {
 | 
			
		||||
        contentType(contentType)
 | 
			
		||||
    }.takeIf { it.status != HttpStatusCode.NoContent } ?.body<Value>(objectType)
 | 
			
		||||
 | 
			
		||||
    override suspend fun contains(key: Key): Boolean = httpClient.get(
 | 
			
		||||
        buildStandardUrl(
 | 
			
		||||
            baseUrl,
 | 
			
		||||
            containsRoute,
 | 
			
		||||
            idParameterName to idSerializer(key)
 | 
			
		||||
        )
 | 
			
		||||
    ) {
 | 
			
		||||
        contentType(contentType)
 | 
			
		||||
    }.body()
 | 
			
		||||
 | 
			
		||||
    override suspend fun values(
 | 
			
		||||
        pagination: Pagination,
 | 
			
		||||
        reversed: Boolean
 | 
			
		||||
    ): PaginationResult<Value> = httpClient.get(
 | 
			
		||||
        buildStandardUrl(baseUrl, valuesRoute, pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()))
 | 
			
		||||
    ) {
 | 
			
		||||
        contentType(contentType)
 | 
			
		||||
    }.body(paginationResultObjectsTypeInfo)
 | 
			
		||||
 | 
			
		||||
    override suspend fun keys(
 | 
			
		||||
        pagination: Pagination,
 | 
			
		||||
        reversed: Boolean
 | 
			
		||||
    ): PaginationResult<Key> = httpClient.get(
 | 
			
		||||
        buildStandardUrl(baseUrl, keysRoute, pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()))
 | 
			
		||||
    ) {
 | 
			
		||||
        contentType(contentType)
 | 
			
		||||
    }.body(paginationResultIdsTypeInfo)
 | 
			
		||||
 | 
			
		||||
    override suspend fun keys(
 | 
			
		||||
        v: Value,
 | 
			
		||||
        pagination: Pagination,
 | 
			
		||||
        reversed: Boolean
 | 
			
		||||
    ): PaginationResult<Key> = httpClient.get(
 | 
			
		||||
        buildStandardUrl(
 | 
			
		||||
            baseUrl,
 | 
			
		||||
            keysRoute,
 | 
			
		||||
            pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()) + (valueParameterName to valueSerializer(v))
 | 
			
		||||
        )
 | 
			
		||||
    ) {
 | 
			
		||||
        contentType(contentType)
 | 
			
		||||
    }.body(paginationResultIdsTypeInfo)
 | 
			
		||||
 | 
			
		||||
    override suspend fun count(): Long = httpClient.get(
 | 
			
		||||
        buildStandardUrl(
 | 
			
		||||
            baseUrl,
 | 
			
		||||
            countRouting
 | 
			
		||||
        )
 | 
			
		||||
    ) {
 | 
			
		||||
        contentType(contentType)
 | 
			
		||||
    }.body()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline fun <reified Key, reified Value> KtorReadStandardKeyValueRepoClient(
 | 
			
		||||
    baseUrl: String,
 | 
			
		||||
    httpClient: HttpClient,
 | 
			
		||||
    contentType: ContentType,
 | 
			
		||||
    noinline idSerializer: suspend (Key) -> String,
 | 
			
		||||
    noinline valueSerializer: suspend (Value) -> String
 | 
			
		||||
) = KtorReadStandardKeyValueRepoClient<Key, Value>(
 | 
			
		||||
    baseUrl,
 | 
			
		||||
    httpClient,
 | 
			
		||||
    contentType,
 | 
			
		||||
    typeInfo<Value>(),
 | 
			
		||||
    typeInfo<PaginationResult<Value>>(),
 | 
			
		||||
    typeInfo<PaginationResult<Key>>(),
 | 
			
		||||
    idSerializer,
 | 
			
		||||
    valueSerializer
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
inline fun <reified Key, reified Value> KtorReadStandardKeyValueRepoClient(
 | 
			
		||||
    baseUrl: String,
 | 
			
		||||
    httpClient: HttpClient,
 | 
			
		||||
    idsSerializer: KSerializer<Key>,
 | 
			
		||||
    valueSerializer: KSerializer<Value>,
 | 
			
		||||
    serialFormat: StringFormat,
 | 
			
		||||
    contentType: ContentType,
 | 
			
		||||
) = KtorReadStandardKeyValueRepoClient<Key, Value>(
 | 
			
		||||
    baseUrl,
 | 
			
		||||
    httpClient,
 | 
			
		||||
    contentType,
 | 
			
		||||
    {
 | 
			
		||||
        serialFormat.encodeToString(idsSerializer, it).encodeURLQueryComponent()
 | 
			
		||||
    }
 | 
			
		||||
) {
 | 
			
		||||
    serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline fun <reified Key, reified Value> KtorReadStandardKeyValueRepoClient(
 | 
			
		||||
    baseUrl: String,
 | 
			
		||||
    httpClient: HttpClient,
 | 
			
		||||
    idsSerializer: KSerializer<Key>,
 | 
			
		||||
    valuesSerializer: KSerializer<Value>,
 | 
			
		||||
    serialFormat: BinaryFormat,
 | 
			
		||||
    contentType: ContentType,
 | 
			
		||||
) = KtorReadStandardKeyValueRepoClient<Key, Value>(
 | 
			
		||||
    baseUrl,
 | 
			
		||||
    httpClient,
 | 
			
		||||
    contentType,
 | 
			
		||||
    {
 | 
			
		||||
        serialFormat.encodeHex(idsSerializer, it)
 | 
			
		||||
    }
 | 
			
		||||
) {
 | 
			
		||||
    serialFormat.encodeHex(valuesSerializer, it)
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,85 @@
 | 
			
		||||
package dev.inmo.micro_utils.repos.ktor.client.key_value
 | 
			
		||||
 | 
			
		||||
import dev.inmo.micro_utils.ktor.common.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.*
 | 
			
		||||
import io.ktor.client.HttpClient
 | 
			
		||||
import io.ktor.http.ContentType
 | 
			
		||||
import io.ktor.http.encodeURLQueryComponent
 | 
			
		||||
import kotlinx.serialization.*
 | 
			
		||||
 | 
			
		||||
class KtorStandardKeyValueRepoClient<Key, Value> (
 | 
			
		||||
    readDelegate: ReadStandardKeyValueRepo<Key, Value>,
 | 
			
		||||
    writeDelegate: WriteStandardKeyValueRepo<Key, Value>
 | 
			
		||||
) : StandardKeyValueRepo<Key, Value> by DelegateBasedStandardKeyValueRepo(
 | 
			
		||||
    readDelegate,
 | 
			
		||||
    writeDelegate
 | 
			
		||||
) {
 | 
			
		||||
    companion object {
 | 
			
		||||
        inline operator fun <reified Key, reified Value> invoke(
 | 
			
		||||
            baseUrl: String,
 | 
			
		||||
            httpClient: HttpClient,
 | 
			
		||||
            contentType: ContentType,
 | 
			
		||||
            noinline idSerializer: suspend (Key) -> String,
 | 
			
		||||
            noinline valueSerializer: suspend (Value) -> String
 | 
			
		||||
        ) = KtorStandardKeyValueRepoClient(
 | 
			
		||||
            KtorReadStandardKeyValueRepoClient(
 | 
			
		||||
                baseUrl, httpClient, contentType, idSerializer, valueSerializer
 | 
			
		||||
            ),
 | 
			
		||||
            KtorWriteStandardKeyValueRepoClient(
 | 
			
		||||
                baseUrl,
 | 
			
		||||
                httpClient,
 | 
			
		||||
                contentType
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
        inline operator fun <reified Key, reified Value> invoke(
 | 
			
		||||
            baseUrl: String,
 | 
			
		||||
            subpart: String,
 | 
			
		||||
            httpClient: HttpClient,
 | 
			
		||||
            contentType: ContentType,
 | 
			
		||||
            noinline idSerializer: suspend (Key) -> String,
 | 
			
		||||
            noinline valueSerializer: suspend (Value) -> String
 | 
			
		||||
        ) = KtorStandardKeyValueRepoClient(
 | 
			
		||||
            buildStandardUrl(baseUrl, subpart),
 | 
			
		||||
            httpClient,
 | 
			
		||||
            contentType,
 | 
			
		||||
            idSerializer,
 | 
			
		||||
            valueSerializer
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline fun <reified Key, reified Value> KtorStandardKeyValueRepoClient(
 | 
			
		||||
    baseUrl: String,
 | 
			
		||||
    httpClient: HttpClient,
 | 
			
		||||
    contentType: ContentType,
 | 
			
		||||
    idSerializer: SerializationStrategy<Key>,
 | 
			
		||||
    valueSerializer: SerializationStrategy<Value>,
 | 
			
		||||
    serialFormat: StringFormat,
 | 
			
		||||
) = KtorStandardKeyValueRepoClient<Key, Value>(
 | 
			
		||||
    baseUrl,
 | 
			
		||||
    httpClient,
 | 
			
		||||
    contentType,
 | 
			
		||||
    {
 | 
			
		||||
        serialFormat.encodeToString(idSerializer, it).encodeURLQueryComponent()
 | 
			
		||||
    }
 | 
			
		||||
) {
 | 
			
		||||
    serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline fun <reified Key, reified Value> KtorStandardKeyValueRepoClient(
 | 
			
		||||
    baseUrl: String,
 | 
			
		||||
    httpClient: HttpClient,
 | 
			
		||||
    contentType: ContentType,
 | 
			
		||||
    idSerializer: SerializationStrategy<Key>,
 | 
			
		||||
    valueSerializer: SerializationStrategy<Value>,
 | 
			
		||||
    serialFormat: BinaryFormat,
 | 
			
		||||
) = KtorStandardKeyValueRepoClient<Key, Value>(
 | 
			
		||||
    baseUrl,
 | 
			
		||||
    httpClient,
 | 
			
		||||
    contentType,
 | 
			
		||||
    {
 | 
			
		||||
        serialFormat.encodeHex(idSerializer, it)
 | 
			
		||||
    }
 | 
			
		||||
) {
 | 
			
		||||
    serialFormat.encodeHex(valueSerializer, it)
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,83 @@
 | 
			
		||||
package dev.inmo.micro_utils.repos.ktor.client.key_value
 | 
			
		||||
 | 
			
		||||
import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow
 | 
			
		||||
import dev.inmo.micro_utils.ktor.common.*
 | 
			
		||||
import dev.inmo.micro_utils.pagination.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
 | 
			
		||||
import io.ktor.client.HttpClient
 | 
			
		||||
import io.ktor.client.request.get
 | 
			
		||||
import io.ktor.client.request.post
 | 
			
		||||
import io.ktor.http.*
 | 
			
		||||
import io.ktor.util.InternalAPI
 | 
			
		||||
import io.ktor.util.reflect.TypeInfo
 | 
			
		||||
import io.ktor.util.reflect.typeInfo
 | 
			
		||||
import kotlinx.coroutines.flow.Flow
 | 
			
		||||
import kotlinx.serialization.*
 | 
			
		||||
 | 
			
		||||
class KtorWriteStandardKeyValueRepoClient<Key, Value>(
 | 
			
		||||
    private val baseUrl: String,
 | 
			
		||||
    private val httpClient: HttpClient,
 | 
			
		||||
    private val contentType: ContentType,
 | 
			
		||||
    override val onNewValue: Flow<Pair<Key, Value>>,
 | 
			
		||||
    override val onValueRemoved: Flow<Key>,
 | 
			
		||||
    private val idsListTypeInfo: TypeInfo,
 | 
			
		||||
    private val objectsListTypeInfo: TypeInfo,
 | 
			
		||||
    private val idsToObjectsMapTypeInfo: TypeInfo
 | 
			
		||||
) : WriteStandardKeyValueRepo<Key, Value> {
 | 
			
		||||
    @OptIn(InternalAPI::class)
 | 
			
		||||
    override suspend fun unsetWithValues(toUnset: List<Value>) {
 | 
			
		||||
        httpClient.post(
 | 
			
		||||
            buildStandardUrl(baseUrl, unsetWithValuesRoute)
 | 
			
		||||
        ) {
 | 
			
		||||
            body = toUnset
 | 
			
		||||
            bodyType = objectsListTypeInfo
 | 
			
		||||
            contentType(contentType)
 | 
			
		||||
        }.status
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @OptIn(InternalAPI::class)
 | 
			
		||||
    override suspend fun unset(toUnset: List<Key>) {
 | 
			
		||||
        httpClient.post(
 | 
			
		||||
            buildStandardUrl(baseUrl, unsetRoute)
 | 
			
		||||
        ) {
 | 
			
		||||
            body = toUnset
 | 
			
		||||
            bodyType = idsListTypeInfo
 | 
			
		||||
            contentType(contentType)
 | 
			
		||||
        }.status
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @OptIn(InternalAPI::class)
 | 
			
		||||
    override suspend fun set(toSet: Map<Key, Value>) {
 | 
			
		||||
        httpClient.post(
 | 
			
		||||
            buildStandardUrl(baseUrl, setRoute)
 | 
			
		||||
        ) {
 | 
			
		||||
            body = toSet
 | 
			
		||||
            bodyType = idsToObjectsMapTypeInfo
 | 
			
		||||
            contentType(contentType)
 | 
			
		||||
        }.status
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        inline operator fun <reified Key, reified Value> invoke(
 | 
			
		||||
            baseUrl: String,
 | 
			
		||||
            httpClient: HttpClient,
 | 
			
		||||
            contentType: ContentType
 | 
			
		||||
        ) = KtorWriteStandardKeyValueRepoClient<Key, Value>(
 | 
			
		||||
            baseUrl,
 | 
			
		||||
            httpClient,
 | 
			
		||||
            contentType,
 | 
			
		||||
            httpClient.createStandardWebsocketFlow(
 | 
			
		||||
                buildStandardUrl(baseUrl, onNewValueRoute),
 | 
			
		||||
            ),
 | 
			
		||||
            httpClient.createStandardWebsocketFlow(
 | 
			
		||||
                buildStandardUrl(baseUrl, onValueRemovedRoute),
 | 
			
		||||
            ),
 | 
			
		||||
            typeInfo<List<Key>>(),
 | 
			
		||||
            typeInfo<List<Value>>(),
 | 
			
		||||
            typeInfo<Map<Key, Value>>()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -13,5 +13,22 @@ kotlin {
 | 
			
		||||
                api internalProject("micro_utils.repos.common")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        jvmTest {
 | 
			
		||||
            dependencies {
 | 
			
		||||
                implementation internalProject("micro_utils.repos.common")
 | 
			
		||||
                implementation internalProject("micro_utils.repos.ktor.client")
 | 
			
		||||
                implementation internalProject("micro_utils.repos.ktor.server")
 | 
			
		||||
                implementation internalProject("micro_utils.repos.inmemory")
 | 
			
		||||
                implementation libs.kt.coroutines.test
 | 
			
		||||
 | 
			
		||||
                implementation libs.ktor.server.cio
 | 
			
		||||
                implementation libs.ktor.client.cio
 | 
			
		||||
                implementation libs.ktor.server.content.negotiation
 | 
			
		||||
                implementation libs.ktor.serialization.kotlinx.json
 | 
			
		||||
                implementation libs.ktor.client.content.negotiation
 | 
			
		||||
                implementation libs.ktor.client.logging
 | 
			
		||||
                implementation libs.ktor.client.websockets
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package dev.inmo.micro_utils.repos.ktor.common
 | 
			
		||||
 | 
			
		||||
const val idParameterName = "id"
 | 
			
		||||
const val keyParameterName = "key"
 | 
			
		||||
const val valueParameterName = "value"
 | 
			
		||||
const val reversedParameterName = "reversed"
 | 
			
		||||
const val reversedParameterName = "reversed"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										89
									
								
								repos/ktor/common/src/jvmTest/kotlin/CRUDTests.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								repos/ktor/common/src/jvmTest/kotlin/CRUDTests.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
import dev.inmo.micro_utils.repos.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.client.crud.KtorStandardCrudRepoClient
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.server.crud.configureStandardCrudRepoRoutes
 | 
			
		||||
import io.ktor.client.HttpClient
 | 
			
		||||
import io.ktor.client.plugins.logging.Logging
 | 
			
		||||
import io.ktor.http.ContentType
 | 
			
		||||
import io.ktor.serialization.kotlinx.KotlinxWebsocketSerializationConverter
 | 
			
		||||
import io.ktor.serialization.kotlinx.json.json
 | 
			
		||||
import io.ktor.server.application.install
 | 
			
		||||
import io.ktor.server.cio.CIO
 | 
			
		||||
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
 | 
			
		||||
import io.ktor.server.routing.routing
 | 
			
		||||
import io.ktor.server.websocket.WebSockets
 | 
			
		||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
 | 
			
		||||
import kotlinx.coroutines.test.runTest
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import kotlin.test.Test
 | 
			
		||||
import kotlin.test.assertEquals
 | 
			
		||||
 | 
			
		||||
class CRUDTests {
 | 
			
		||||
    @OptIn(ExperimentalCoroutinesApi::class)
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testCRUDFunctions() {
 | 
			
		||||
        runTest() {
 | 
			
		||||
            val map = mutableMapOf<Int, ComplexData>()
 | 
			
		||||
            val repo = MapCRUDRepo<ComplexData, Int, SimpleData>(
 | 
			
		||||
                map,
 | 
			
		||||
                { newValue, id, oldValue ->
 | 
			
		||||
                    oldValue.copy(title = newValue.title)
 | 
			
		||||
                }
 | 
			
		||||
            ) {
 | 
			
		||||
                size to ComplexData(size, title = it.title)
 | 
			
		||||
            }
 | 
			
		||||
            val server = io.ktor.server.engine.embeddedServer(
 | 
			
		||||
                CIO,
 | 
			
		||||
                23456,
 | 
			
		||||
                "127.0.0.1"
 | 
			
		||||
            ) {
 | 
			
		||||
                install(ContentNegotiation) {
 | 
			
		||||
                    json()
 | 
			
		||||
                }
 | 
			
		||||
                install(WebSockets) {
 | 
			
		||||
                    contentConverter = KotlinxWebsocketSerializationConverter(Json)
 | 
			
		||||
                }
 | 
			
		||||
                routing {
 | 
			
		||||
                    configureStandardCrudRepoRoutes(
 | 
			
		||||
                        repo
 | 
			
		||||
                    ) {
 | 
			
		||||
                        it.toInt()
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }.start(false)
 | 
			
		||||
            val client = HttpClient {
 | 
			
		||||
                install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) {
 | 
			
		||||
                    json()
 | 
			
		||||
                }
 | 
			
		||||
                install(Logging)
 | 
			
		||||
                install(io.ktor.client.plugins.websocket.WebSockets) {
 | 
			
		||||
                    contentConverter = KotlinxWebsocketSerializationConverter(Json)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            val crudClient = KtorStandardCrudRepoClient<ComplexData, Int, SimpleData>(
 | 
			
		||||
                "http://127.0.0.1:23456",
 | 
			
		||||
                client,
 | 
			
		||||
                ContentType.Application.Json
 | 
			
		||||
            ) {
 | 
			
		||||
                it.toString()
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            val created = crudClient.create(SimpleData("Example")).single()
 | 
			
		||||
            assertEquals(map.size, 1)
 | 
			
		||||
            assertEquals(map.size.toLong(), crudClient.count())
 | 
			
		||||
            assertEquals(1, crudClient.count())
 | 
			
		||||
            assertEquals(map.getValue(map.keys.first()), created)
 | 
			
		||||
 | 
			
		||||
            val updated = crudClient.update(created.id, SimpleData("Example2"))
 | 
			
		||||
            assertEquals(map.size, 1)
 | 
			
		||||
            assertEquals(map.size.toLong(), crudClient.count())
 | 
			
		||||
            assertEquals(1, crudClient.count())
 | 
			
		||||
            assertEquals(map.getValue(map.keys.first()), updated)
 | 
			
		||||
 | 
			
		||||
            crudClient.deleteById(created.id)
 | 
			
		||||
            assertEquals(map.size, 0)
 | 
			
		||||
            assertEquals(map.size.toLong(), crudClient.count())
 | 
			
		||||
            assertEquals(0, crudClient.count())
 | 
			
		||||
            server.stop()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								repos/ktor/common/src/jvmTest/kotlin/ComplexData.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								repos/ktor/common/src/jvmTest/kotlin/ComplexData.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
import com.benasher44.uuid.uuid4
 | 
			
		||||
import kotlinx.serialization.Serializable
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class ComplexData(
 | 
			
		||||
    val id: Int,
 | 
			
		||||
    val simple: SimpleData = SimpleData(),
 | 
			
		||||
    val simples: List<SimpleData> = (0 until 100).map { SimpleData(("$it")) },
 | 
			
		||||
    val title: String = uuid4().toString()
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										139
									
								
								repos/ktor/common/src/jvmTest/kotlin/KVTests.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								repos/ktor/common/src/jvmTest/kotlin/KVTests.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,139 @@
 | 
			
		||||
import dev.inmo.micro_utils.pagination.firstPageWithOneElementPagination
 | 
			
		||||
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
 | 
			
		||||
import dev.inmo.micro_utils.repos.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.client.key_value.KtorStandardKeyValueRepoClient
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.server.key_value.configureStandardKeyValueRepoRoutes
 | 
			
		||||
import io.ktor.client.HttpClient
 | 
			
		||||
import io.ktor.client.plugins.logging.Logging
 | 
			
		||||
import io.ktor.http.ContentType
 | 
			
		||||
import io.ktor.serialization.kotlinx.KotlinxWebsocketSerializationConverter
 | 
			
		||||
import io.ktor.serialization.kotlinx.json.json
 | 
			
		||||
import io.ktor.server.application.install
 | 
			
		||||
import io.ktor.server.cio.CIO
 | 
			
		||||
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
 | 
			
		||||
import io.ktor.server.routing.routing
 | 
			
		||||
import io.ktor.server.websocket.WebSockets
 | 
			
		||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
 | 
			
		||||
import kotlinx.coroutines.test.runTest
 | 
			
		||||
import kotlinx.serialization.builtins.serializer
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import kotlin.test.*
 | 
			
		||||
 | 
			
		||||
class KVTests {
 | 
			
		||||
    @OptIn(ExperimentalCoroutinesApi::class)
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testCRUDFunctions() {
 | 
			
		||||
        runTest() {
 | 
			
		||||
            val map = mutableMapOf<Int, ComplexData>()
 | 
			
		||||
            val repo = MapKeyValueRepo<Int, ComplexData>(map)
 | 
			
		||||
            val server = io.ktor.server.engine.embeddedServer(
 | 
			
		||||
                CIO,
 | 
			
		||||
                23456,
 | 
			
		||||
                "127.0.0.1"
 | 
			
		||||
            ) {
 | 
			
		||||
                install(ContentNegotiation) {
 | 
			
		||||
                    json()
 | 
			
		||||
                }
 | 
			
		||||
                install(WebSockets) {
 | 
			
		||||
                    contentConverter = KotlinxWebsocketSerializationConverter(Json)
 | 
			
		||||
                }
 | 
			
		||||
                routing {
 | 
			
		||||
                    configureStandardKeyValueRepoRoutes(
 | 
			
		||||
                        repo,
 | 
			
		||||
                        Int.serializer(),
 | 
			
		||||
                        ComplexData.serializer(),
 | 
			
		||||
                        Json {}
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }.start(false)
 | 
			
		||||
            val client = HttpClient {
 | 
			
		||||
                install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) {
 | 
			
		||||
                    json()
 | 
			
		||||
                }
 | 
			
		||||
                install(Logging)
 | 
			
		||||
                install(io.ktor.client.plugins.websocket.WebSockets) {
 | 
			
		||||
                    contentConverter = KotlinxWebsocketSerializationConverter(Json)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            val crudClient = KtorStandardKeyValueRepoClient<Int, ComplexData>(
 | 
			
		||||
                "http://127.0.0.1:23456",
 | 
			
		||||
                client,
 | 
			
		||||
                ContentType.Application.Json,
 | 
			
		||||
                Int.serializer(),
 | 
			
		||||
                ComplexData.serializer(),
 | 
			
		||||
                Json
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            val dataInOneKey = ComplexData(1, title = "Example1")
 | 
			
		||||
            val dataInMultipleKeys = ComplexData(2, title = "Example2")
 | 
			
		||||
            val repeatCount = 3
 | 
			
		||||
 | 
			
		||||
            val dataList = listOf(
 | 
			
		||||
                1 to dataInOneKey
 | 
			
		||||
            ) + (0 until repeatCount).map {
 | 
			
		||||
                (it + 2) to dataInMultipleKeys
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            dataList.forEachIndexed { i, (id, data) ->
 | 
			
		||||
                crudClient.set(id, data)
 | 
			
		||||
                assertEquals(map.size, i + 1)
 | 
			
		||||
                assertEquals(map.size.toLong(), crudClient.count())
 | 
			
		||||
                assertEquals(i + 1L, crudClient.count())
 | 
			
		||||
                dataList.take(i + 1).forEach { (id, data) ->
 | 
			
		||||
                    assertEquals(data, map[id])
 | 
			
		||||
                    assertEquals(data, crudClient.get(id))
 | 
			
		||||
                    assertEquals(map[id], crudClient.get(id))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            dataList.forEach { (id, data) ->
 | 
			
		||||
                assertTrue(crudClient.contains(id))
 | 
			
		||||
                assertEquals(data, crudClient.get(id))
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            assertEquals(
 | 
			
		||||
                dataList.mapNotNull { if (it.second == dataInMultipleKeys) it.first else null },
 | 
			
		||||
                getAllWithNextPaging(firstPageWithOneElementPagination) {
 | 
			
		||||
                    crudClient.keys(dataInMultipleKeys, it)
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            assertEquals(
 | 
			
		||||
                dataList.mapNotNull { if (it.second == dataInOneKey) it.first else null },
 | 
			
		||||
                getAllWithNextPaging(firstPageWithOneElementPagination) {
 | 
			
		||||
                    crudClient.keys(dataInOneKey, it)
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            assertEquals(
 | 
			
		||||
                dataList.map { it.first },
 | 
			
		||||
                getAllWithNextPaging(firstPageWithOneElementPagination) {
 | 
			
		||||
                    crudClient.keys(it)
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            assertEquals(
 | 
			
		||||
                dataList.map { it.second },
 | 
			
		||||
                getAllWithNextPaging(firstPageWithOneElementPagination) {
 | 
			
		||||
                    crudClient.values(it)
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            assertEquals(dataList.size.toLong(), crudClient.count())
 | 
			
		||||
 | 
			
		||||
            crudClient.unsetWithValues(dataInMultipleKeys)
 | 
			
		||||
            assertEquals(
 | 
			
		||||
                dataList.filter { it.second == dataInOneKey }.size.toLong(),
 | 
			
		||||
                crudClient.count()
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            crudClient.unset(dataList.first { it.second == dataInOneKey }.first)
 | 
			
		||||
            assertEquals(
 | 
			
		||||
                0,
 | 
			
		||||
                crudClient.count()
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            server.stop()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								repos/ktor/common/src/jvmTest/kotlin/SimpleData.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								repos/ktor/common/src/jvmTest/kotlin/SimpleData.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
import com.benasher44.uuid.uuid4
 | 
			
		||||
import kotlinx.serialization.Serializable
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class SimpleData(
 | 
			
		||||
    val title: String = uuid4().toString()
 | 
			
		||||
)
 | 
			
		||||
@@ -5,6 +5,7 @@ import dev.inmo.micro_utils.ktor.server.*
 | 
			
		||||
import dev.inmo.micro_utils.pagination.extractPagination
 | 
			
		||||
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.crud.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
 | 
			
		||||
import io.ktor.http.ContentType
 | 
			
		||||
import io.ktor.http.HttpStatusCode
 | 
			
		||||
import io.ktor.server.application.call
 | 
			
		||||
@@ -25,7 +26,7 @@ inline fun <reified ObjectType, reified IdType> Route.configureReadStandardCrudR
 | 
			
		||||
 | 
			
		||||
    get(getByIdRouting) {
 | 
			
		||||
        val id = idDeserializer(
 | 
			
		||||
            call.getQueryParameterOrSendError("id") ?: return@get
 | 
			
		||||
            call.getQueryParameterOrSendError(idParameterName) ?: return@get
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        val result = originalRepo.getById(id)
 | 
			
		||||
@@ -39,7 +40,7 @@ inline fun <reified ObjectType, reified IdType> Route.configureReadStandardCrudR
 | 
			
		||||
 | 
			
		||||
    get(containsRouting) {
 | 
			
		||||
        val id = idDeserializer(
 | 
			
		||||
            call.getQueryParameterOrSendError("id") ?: return@get
 | 
			
		||||
            call.getQueryParameterOrSendError(idParameterName) ?: return@get
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        call.respond(
 | 
			
		||||
 
 | 
			
		||||
@@ -26,11 +26,7 @@ inline fun <reified ObjectType : Any, reified IdType : Any, reified InputValue :
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    post(createRouting) {
 | 
			
		||||
        call.respond(
 | 
			
		||||
            originalRepo.create(
 | 
			
		||||
                call.receive()
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
        call.respond(originalRepo.create(call.receive()))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    post(updateManyRouting) {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,58 @@
 | 
			
		||||
package dev.inmo.micro_utils.repos.ktor.server.key_value
 | 
			
		||||
 | 
			
		||||
import dev.inmo.micro_utils.ktor.common.*
 | 
			
		||||
import dev.inmo.micro_utils.ktor.server.*
 | 
			
		||||
import dev.inmo.micro_utils.pagination.PaginationResult
 | 
			
		||||
import dev.inmo.micro_utils.pagination.extractPagination
 | 
			
		||||
import dev.inmo.micro_utils.repos.StandardCRUDRepo
 | 
			
		||||
import dev.inmo.micro_utils.repos.StandardKeyValueRepo
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
 | 
			
		||||
import io.ktor.http.*
 | 
			
		||||
import io.ktor.server.application.call
 | 
			
		||||
import io.ktor.server.response.respond
 | 
			
		||||
import io.ktor.server.routing.Route
 | 
			
		||||
import io.ktor.server.routing.get
 | 
			
		||||
import kotlinx.serialization.*
 | 
			
		||||
import kotlinx.serialization.builtins.serializer
 | 
			
		||||
 | 
			
		||||
inline fun <reified Key : Any, reified Value : Any> Route.configureStandardKeyValueRepoRoutes (
 | 
			
		||||
    originalRepo: StandardKeyValueRepo<Key, Value>,
 | 
			
		||||
    noinline idDeserializer: suspend (String) -> Key,
 | 
			
		||||
    noinline valueDeserializer: suspend (String) -> Value
 | 
			
		||||
) {
 | 
			
		||||
    configureReadStandardKeyValueRepoRoutes(originalRepo, idDeserializer, valueDeserializer)
 | 
			
		||||
    configureWriteStandardKeyValueRepoRoutes(originalRepo)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline fun <reified Key : Any, reified Value : Any> Route.configureStandardKeyValueRepoRoutes(
 | 
			
		||||
    originalRepo: StandardKeyValueRepo<Key, Value>,
 | 
			
		||||
    idsSerializer: DeserializationStrategy<Key>,
 | 
			
		||||
    valueSerializer: DeserializationStrategy<Value>,
 | 
			
		||||
    serialFormat: StringFormat
 | 
			
		||||
) = configureStandardKeyValueRepoRoutes(
 | 
			
		||||
    originalRepo,
 | 
			
		||||
    {
 | 
			
		||||
        serialFormat.decodeFromString(idsSerializer, it.decodeURLQueryComponent())
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent())
 | 
			
		||||
    }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
inline fun <reified Key : Any, reified Value : Any> Route.configureStandardKeyValueRepoRoutes(
 | 
			
		||||
    originalRepo: StandardKeyValueRepo<Key, Value>,
 | 
			
		||||
    idsSerializer: DeserializationStrategy<Key>,
 | 
			
		||||
    valueSerializer: DeserializationStrategy<Value>,
 | 
			
		||||
    serialFormat: BinaryFormat
 | 
			
		||||
) = configureStandardKeyValueRepoRoutes(
 | 
			
		||||
    originalRepo,
 | 
			
		||||
    {
 | 
			
		||||
        serialFormat.decodeHex(idsSerializer, it)
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        serialFormat.decodeHex(valueSerializer, it)
 | 
			
		||||
    }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,104 @@
 | 
			
		||||
package dev.inmo.micro_utils.repos.ktor.server.key_value
 | 
			
		||||
 | 
			
		||||
import dev.inmo.micro_utils.ktor.common.*
 | 
			
		||||
import dev.inmo.micro_utils.ktor.server.*
 | 
			
		||||
import dev.inmo.micro_utils.pagination.PaginationResult
 | 
			
		||||
import dev.inmo.micro_utils.pagination.extractPagination
 | 
			
		||||
import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo
 | 
			
		||||
import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.idParameterName
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.valueParameterName
 | 
			
		||||
import io.ktor.http.*
 | 
			
		||||
import io.ktor.server.application.call
 | 
			
		||||
import io.ktor.server.response.respond
 | 
			
		||||
import io.ktor.server.response.responseType
 | 
			
		||||
import io.ktor.server.routing.Route
 | 
			
		||||
import io.ktor.server.routing.get
 | 
			
		||||
import io.ktor.util.InternalAPI
 | 
			
		||||
import io.ktor.util.reflect.typeInfo
 | 
			
		||||
import kotlinx.serialization.*
 | 
			
		||||
import kotlinx.serialization.builtins.serializer
 | 
			
		||||
 | 
			
		||||
@OptIn(InternalAPI::class)
 | 
			
		||||
inline fun <reified Key, reified Value> Route.configureReadStandardKeyValueRepoRoutes (
 | 
			
		||||
    originalRepo: ReadStandardKeyValueRepo<Key, Value>,
 | 
			
		||||
    noinline idDeserializer: suspend (String) -> Key,
 | 
			
		||||
    noinline valueDeserializer: suspend (String) -> Value
 | 
			
		||||
) {
 | 
			
		||||
    get(getRoute) {
 | 
			
		||||
        val key = idDeserializer(
 | 
			
		||||
            call.getQueryParameterOrSendError(idParameterName) ?: return@get
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        originalRepo.get(key) ?.let {
 | 
			
		||||
            call.respond(it)
 | 
			
		||||
        } ?: call.respond(HttpStatusCode.NoContent)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val paginationWithValuesTypeInfo = typeInfo<PaginationResult<Value>>()
 | 
			
		||||
    get(valuesRoute) {
 | 
			
		||||
        val pagination = call.request.queryParameters.extractPagination
 | 
			
		||||
        val reversed = call.getQueryParameter(reversedParameterName) ?.toBoolean() ?: false
 | 
			
		||||
 | 
			
		||||
        call.response.responseType = paginationWithValuesTypeInfo
 | 
			
		||||
        call.response.pipeline.execute(call, originalRepo.values(pagination, reversed) as Any)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get(keysRoute) {
 | 
			
		||||
        val pagination = call.request.queryParameters.extractPagination
 | 
			
		||||
        val reversed = call.getQueryParameterOrSendError(reversedParameterName) ?.toBoolean() ?: false
 | 
			
		||||
        val value = call.getQueryParameter(valueParameterName) ?.let {
 | 
			
		||||
            valueDeserializer(it)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        call.respond(
 | 
			
		||||
            value ?.let { originalRepo.keys(value, pagination, reversed) } ?: originalRepo.keys(pagination, reversed)
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get(containsRoute) {
 | 
			
		||||
        val key = idDeserializer(
 | 
			
		||||
            call.getQueryParameterOrSendError(idParameterName) ?: return@get
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        call.respond(
 | 
			
		||||
            originalRepo.contains(key)
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get(countRoute) {
 | 
			
		||||
        call.respond(originalRepo.count())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline fun <reified Key, reified Value> Route.configureReadStandardKeyValueRepoRoutes(
 | 
			
		||||
    originalRepo: ReadStandardKeyValueRepo<Key, Value>,
 | 
			
		||||
    idsSerializer: DeserializationStrategy<Key>,
 | 
			
		||||
    valueSerializer: DeserializationStrategy<Value>,
 | 
			
		||||
    serialFormat: StringFormat
 | 
			
		||||
) = configureReadStandardKeyValueRepoRoutes(
 | 
			
		||||
    originalRepo,
 | 
			
		||||
    {
 | 
			
		||||
        serialFormat.decodeFromString(idsSerializer, it.decodeURLQueryComponent())
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent())
 | 
			
		||||
    }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
inline fun <reified Key, reified Value> Route.configureReadStandardKeyValueRepoRoutes(
 | 
			
		||||
    originalRepo: ReadStandardKeyValueRepo<Key, Value>,
 | 
			
		||||
    idsSerializer: DeserializationStrategy<Key>,
 | 
			
		||||
    valueSerializer: DeserializationStrategy<Value>,
 | 
			
		||||
    serialFormat: BinaryFormat
 | 
			
		||||
) = configureReadStandardKeyValueRepoRoutes(
 | 
			
		||||
    originalRepo,
 | 
			
		||||
    {
 | 
			
		||||
        serialFormat.decodeHex(idsSerializer, it)
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        serialFormat.decodeHex(valueSerializer, it)
 | 
			
		||||
    }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,45 @@
 | 
			
		||||
package dev.inmo.micro_utils.repos.ktor.server.key_value
 | 
			
		||||
 | 
			
		||||
import dev.inmo.micro_utils.ktor.server.*
 | 
			
		||||
import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo
 | 
			
		||||
import dev.inmo.micro_utils.repos.ktor.common.key_value.*
 | 
			
		||||
import io.ktor.http.HttpStatusCode
 | 
			
		||||
import io.ktor.server.application.call
 | 
			
		||||
import io.ktor.server.request.receive
 | 
			
		||||
import io.ktor.server.response.respond
 | 
			
		||||
import io.ktor.server.routing.Route
 | 
			
		||||
import io.ktor.server.routing.post
 | 
			
		||||
import io.ktor.util.reflect.typeInfo
 | 
			
		||||
 | 
			
		||||
inline fun <reified Key : Any, reified Value : Any> Route.configureWriteStandardKeyValueRepoRoutes (
 | 
			
		||||
    originalRepo: WriteStandardKeyValueRepo<Key, Value>
 | 
			
		||||
) {
 | 
			
		||||
    includeWebsocketHandling(
 | 
			
		||||
        onNewValueRoute,
 | 
			
		||||
        originalRepo.onNewValue
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    includeWebsocketHandling(
 | 
			
		||||
        onValueRemovedRoute,
 | 
			
		||||
        originalRepo.onValueRemoved
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    val mapType = typeInfo<Map<Key, Value>>()
 | 
			
		||||
    val listKeysType = typeInfo<List<Key>>()
 | 
			
		||||
    val listValuesType = typeInfo<List<Value>>()
 | 
			
		||||
 | 
			
		||||
    post(setRoute) {
 | 
			
		||||
        originalRepo.set(call.receive(mapType))
 | 
			
		||||
        call.respond(HttpStatusCode.OK)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    post(unsetRoute) {
 | 
			
		||||
        originalRepo.unset(call.receive(listKeysType))
 | 
			
		||||
        call.respond(HttpStatusCode.OK)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    post(unsetWithValuesRoute) {
 | 
			
		||||
        originalRepo.unsetWithValues(call.receive(listValuesType))
 | 
			
		||||
        call.respond(HttpStatusCode.OK)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user