From cb6fedfb52bc639e8624da8cef2bff864f35b27b Mon Sep 17 00:00:00 2001
From: 000Sanya <000sanya.000sanya@gmail.com>
Date: Sat, 29 Aug 2020 12:33:13 +1000
Subject: [PATCH] impl client and server for KeyValueRepo

---
 .../key_value/KtorStandartKeyValueRepo.kt     | 30 ++++++++
 .../key_value/KtorStandartReadKeyValueRepo.kt | 73 ++++++++++++++++++
 .../KtorStandartWriteKeyValueRepo.kt          | 49 ++++++++++++
 .../key_value/KeyValueParameterNames.kt       |  4 +
 .../common/key_value/KeyValuePostObject.kt    |  9 +++
 .../ktor/common/key_value/KeyValueRoutes.kt   | 12 +++
 .../key_value/KtorStandartKeyValueRepo.kt     | 27 +++++++
 .../key_value/KtorStandartReadKeyValueRepo.kt | 76 +++++++++++++++++++
 .../KtorStandartWriteKeyValueRepo.kt          | 44 +++++++++++
 9 files changed, 324 insertions(+)
 create mode 100644 utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/key_value/KtorStandartKeyValueRepo.kt
 create mode 100644 utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/key_value/KtorStandartReadKeyValueRepo.kt
 create mode 100644 utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/key_value/KtorStandartWriteKeyValueRepo.kt
 create mode 100644 utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/key_value/KeyValueParameterNames.kt
 create mode 100644 utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/key_value/KeyValuePostObject.kt
 create mode 100644 utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/key_value/KeyValueRoutes.kt
 create mode 100644 utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/key_value/KtorStandartKeyValueRepo.kt
 create mode 100644 utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/key_value/KtorStandartReadKeyValueRepo.kt
 create mode 100644 utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/key_value/KtorStandartWriteKeyValueRepo.kt

diff --git a/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/key_value/KtorStandartKeyValueRepo.kt b/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/key_value/KtorStandartKeyValueRepo.kt
new file mode 100644
index 00000000..aea0e77f
--- /dev/null
+++ b/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/key_value/KtorStandartKeyValueRepo.kt
@@ -0,0 +1,30 @@
+package com.insanusmokrassar.postssystem.utils.repos.ktor.client.key_value
+
+import com.insanusmokrassar.postssystem.utils.repos.StandardKeyValueRepo
+import com.insanusmokrassar.postssystem.utils.repos.StandardReadKeyValueRepo
+import com.insanusmokrassar.postssystem.utils.repos.StandardWriteKeyValueRepo
+import io.ktor.client.*
+import kotlinx.serialization.ContextualSerializer
+import kotlinx.serialization.KSerializer
+
+class KtorStandartKeyValueRepo<K, V> (
+    baseUrl: String,
+    baseSubpart: String,
+    client: HttpClient = HttpClient(),
+    keySerializer: KSerializer<K>,
+    valueSerializer: KSerializer<V>,
+    valueNullableSerializer: KSerializer<V?>
+) : StandardKeyValueRepo<K, V>,
+    StandardReadKeyValueRepo<K, V> by KtorStandartReadKeyValueRepo(
+        "$baseUrl/$baseSubpart",
+        client,
+        keySerializer,
+        valueSerializer,
+        valueNullableSerializer
+    ),
+    StandardWriteKeyValueRepo<K, V> by KtorStandartWriteKeyValueRepo(
+        "$baseUrl/$baseSubpart",
+        client,
+        keySerializer,
+        valueSerializer
+    )
\ No newline at end of file
diff --git a/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/key_value/KtorStandartReadKeyValueRepo.kt b/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/key_value/KtorStandartReadKeyValueRepo.kt
new file mode 100644
index 00000000..0cab8c9b
--- /dev/null
+++ b/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/key_value/KtorStandartReadKeyValueRepo.kt
@@ -0,0 +1,73 @@
+package com.insanusmokrassar.postssystem.utils.repos.ktor.client.key_value
+
+import com.insanusmokrassar.postssystem.ktor.asUrlQueryParts
+import com.insanusmokrassar.postssystem.ktor.buildStandardUrl
+import com.insanusmokrassar.postssystem.ktor.client.uniget
+import com.insanusmokrassar.postssystem.ktor.toHex
+import com.insanusmokrassar.postssystem.utils.common.pagination.Pagination
+import com.insanusmokrassar.postssystem.utils.common.pagination.PaginationResult
+import com.insanusmokrassar.postssystem.utils.repos.StandardReadKeyValueRepo
+import com.insanusmokrassar.postssystem.utils.repos.ktor.common.key_value.*
+import io.ktor.client.*
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.builtins.serializer
+
+class KtorStandartReadKeyValueRepo<Key, Value> (
+    private var baseUrl: String,
+    private var client: HttpClient = HttpClient(),
+    private var keySerializer: KSerializer<Key>,
+    private var valueSerializer: KSerializer<Value>,
+    private var valueNullableSerializer: KSerializer<Value?>,
+) : StandardReadKeyValueRepo<Key, Value> {
+    override suspend fun get(k: Key): Value? = client.uniget(
+        buildStandardUrl(
+            baseUrl,
+            getRoute,
+            mapOf(
+                keyParameterName to k.toHex(keySerializer)
+            )
+        ),
+        valueNullableSerializer
+    )
+
+    override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<Value> = client.uniget(
+        buildStandardUrl(
+            baseUrl,
+            valuesRoute,
+            mapOf(
+                reversedParameterName to reversed.toHex(Boolean.serializer())
+            ) + pagination.asUrlQueryParts
+        ),
+        PaginationResult.serializer(valueSerializer)
+    )
+
+    override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult<Key> = client.uniget(
+        buildStandardUrl(
+            baseUrl,
+            keysRoute,
+            mapOf(
+                reversedParameterName to reversed.toHex(Boolean.serializer())
+            ) + pagination.asUrlQueryParts
+        ),
+        PaginationResult.serializer(keySerializer)
+    )
+
+    override suspend fun contains(key: Key): Boolean = client.uniget(
+        buildStandardUrl(
+            baseUrl,
+            containsRoute,
+            mapOf(
+                keyParameterName to key.toHex(keySerializer)
+            ),
+        ),
+        Boolean.serializer(),
+    )
+
+    override suspend fun count(): Long = client.uniget(
+        buildStandardUrl(
+            baseUrl,
+            containsRoute,
+        ),
+        Long.serializer()
+    )
+}
\ No newline at end of file
diff --git a/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/key_value/KtorStandartWriteKeyValueRepo.kt b/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/key_value/KtorStandartWriteKeyValueRepo.kt
new file mode 100644
index 00000000..918d2350
--- /dev/null
+++ b/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/key_value/KtorStandartWriteKeyValueRepo.kt
@@ -0,0 +1,49 @@
+package com.insanusmokrassar.postssystem.utils.repos.ktor.client.key_value
+
+import com.insanusmokrassar.postssystem.ktor.buildStandardUrl
+import com.insanusmokrassar.postssystem.ktor.client.BodyPair
+import com.insanusmokrassar.postssystem.ktor.client.createStandardWebsocketFlow
+import com.insanusmokrassar.postssystem.ktor.client.uniget
+import com.insanusmokrassar.postssystem.ktor.client.unipost
+import com.insanusmokrassar.postssystem.utils.repos.StandardWriteKeyValueRepo
+import com.insanusmokrassar.postssystem.utils.repos.ktor.common.key_value.*
+import io.ktor.client.*
+import kotlinx.coroutines.flow.Flow
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.builtins.PairSerializer
+import kotlinx.serialization.builtins.serializer
+
+class KtorStandartWriteKeyValueRepo<K, V> (
+    private var baseUrl: String,
+    private var client: HttpClient = HttpClient(),
+    private var keySerializer: KSerializer<K>,
+    private var valueSerializer: KSerializer<V>,
+) : StandardWriteKeyValueRepo<K, V> {
+    override val onNewValue: Flow<Pair<K, V>> = client.createStandardWebsocketFlow(
+        buildStandardUrl(baseUrl, onNewValueRoute),
+        deserializer = PairSerializer(keySerializer, valueSerializer)
+    )
+
+    override val onValueRemoved: Flow<K> = client.createStandardWebsocketFlow(
+        buildStandardUrl(baseUrl, onValueRemovedRoute),
+        deserializer = keySerializer
+    )
+
+    override suspend fun set(k: K, v: V) = client.unipost(
+        buildStandardUrl(
+            baseUrl,
+            setRoute
+        ),
+        BodyPair(KeyValuePostObject.serializer(keySerializer, valueSerializer), KeyValuePostObject(k, v)),
+        Unit.serializer()
+    )
+
+    override suspend fun unset(k: K) = client.unipost(
+        buildStandardUrl(
+            baseUrl,
+            unsetRoute,
+        ),
+        BodyPair(keySerializer, k),
+        Unit.serializer()
+    )
+}
\ No newline at end of file
diff --git a/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/key_value/KeyValueParameterNames.kt b/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/key_value/KeyValueParameterNames.kt
new file mode 100644
index 00000000..54d557ac
--- /dev/null
+++ b/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/key_value/KeyValueParameterNames.kt
@@ -0,0 +1,4 @@
+package com.insanusmokrassar.postssystem.utils.repos.ktor.common.key_value
+
+const val keyParameterName = "key"
+const val reversedParameterName = "reversed"
\ No newline at end of file
diff --git a/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/key_value/KeyValuePostObject.kt b/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/key_value/KeyValuePostObject.kt
new file mode 100644
index 00000000..720f70b4
--- /dev/null
+++ b/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/key_value/KeyValuePostObject.kt
@@ -0,0 +1,9 @@
+package com.insanusmokrassar.postssystem.utils.repos.ktor.common.key_value
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class KeyValuePostObject<K, V> (
+    val key: K,
+    val value: V,
+)
\ No newline at end of file
diff --git a/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/key_value/KeyValueRoutes.kt b/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/key_value/KeyValueRoutes.kt
new file mode 100644
index 00000000..e3c724b6
--- /dev/null
+++ b/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/key_value/KeyValueRoutes.kt
@@ -0,0 +1,12 @@
+package com.insanusmokrassar.postssystem.utils.repos.ktor.common.key_value
+
+const val getRoute = "get"
+const val valuesRoute = "values"
+const val keysRoute = "keys"
+const val containsRoute = "contains"
+const val countRoute = "count"
+
+const val onNewValueRoute = "onNewValue"
+const val onValueRemovedRoute = "onValueRemoved"
+const val setRoute = "set"
+const val unsetRoute = "unset"
\ No newline at end of file
diff --git a/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/key_value/KtorStandartKeyValueRepo.kt b/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/key_value/KtorStandartKeyValueRepo.kt
new file mode 100644
index 00000000..95401505
--- /dev/null
+++ b/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/key_value/KtorStandartKeyValueRepo.kt
@@ -0,0 +1,27 @@
+package com.insanusmokrassar.postssystem.utils.repos.ktor.server.key_value
+
+import com.insanusmokrassar.postssystem.utils.repos.StandardKeyValueRepo
+import io.ktor.routing.*
+import kotlinx.serialization.KSerializer
+
+fun <K, V> Route.configureStandartKeyValueRepoRoutes(
+    baseSubpart: String,
+    originalRepo: StandardKeyValueRepo<K, V>,
+    keySerializer: KSerializer<K>,
+    valueSerializer: KSerializer<V>,
+    valueNullableSerializer: KSerializer<V?>,
+) {
+    route(baseSubpart) {
+        configureReadStandartKeyValueRepoRoutes(
+            originalRepo,
+            keySerializer,
+            valueSerializer,
+            valueNullableSerializer,
+        )
+        configureWriteStandartKeyValueRepoRoutes(
+            originalRepo,
+            keySerializer,
+            valueSerializer,
+        )
+    }
+}
\ No newline at end of file
diff --git a/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/key_value/KtorStandartReadKeyValueRepo.kt b/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/key_value/KtorStandartReadKeyValueRepo.kt
new file mode 100644
index 00000000..f2eeafc4
--- /dev/null
+++ b/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/key_value/KtorStandartReadKeyValueRepo.kt
@@ -0,0 +1,76 @@
+package com.insanusmokrassar.postssystem.utils.repos.ktor.server.key_value
+
+import com.insanusmokrassar.postssystem.ktor.server.extractPagination
+import com.insanusmokrassar.postssystem.ktor.server.unianswer
+import com.insanusmokrassar.postssystem.ktor.server.uniloadFromQueryOrSendError
+import com.insanusmokrassar.postssystem.utils.common.pagination.PaginationResult
+import com.insanusmokrassar.postssystem.utils.repos.StandardReadKeyValueRepo
+import com.insanusmokrassar.postssystem.utils.repos.ktor.common.key_value.*
+import io.ktor.application.*
+import io.ktor.routing.*
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.builtins.serializer
+
+fun <K, V> Route.configureReadStandartKeyValueRepoRoutes (
+    originalRepo: StandardReadKeyValueRepo<K, V>,
+    keySerializer: KSerializer<K>,
+    valueSerializer: KSerializer<V>,
+    valueNullableSerializer: KSerializer<V?>,
+) {
+    get(getRoute) {
+        val key = call.uniloadFromQueryOrSendError(
+            keyParameterName,
+            keySerializer
+        ) ?: return@get
+
+        call.unianswer(
+            valueNullableSerializer,
+            originalRepo.get(key)
+        )
+    }
+
+    get(valuesRoute) {
+        val parination = call.request.queryParameters.extractPagination;
+        val reversed = call.uniloadFromQueryOrSendError(
+            reversedParameterName,
+            Boolean.serializer()
+        ) ?: return@get
+
+        call.unianswer(
+            PaginationResult.serializer(valueSerializer),
+            originalRepo.values(parination, reversed)
+        )
+    }
+
+    get(keysRoute) {
+        val parination = call.request.queryParameters.extractPagination;
+        val reversed = call.uniloadFromQueryOrSendError(
+            reversedParameterName,
+            Boolean.serializer()
+        ) ?: return@get
+
+        call.unianswer(
+            PaginationResult.serializer(keySerializer),
+            originalRepo.keys(parination, reversed)
+        )
+    }
+
+    get(containsRoute) {
+        val key = call.uniloadFromQueryOrSendError(
+            keyParameterName,
+            keySerializer
+        ) ?: return@get
+
+        call.unianswer(
+            Boolean.serializer(),
+            originalRepo.contains(key)
+        )
+    }
+
+    get(countRoute) {
+        call.unianswer(
+            Long.serializer(),
+            originalRepo.count()
+        )
+    }
+}
\ No newline at end of file
diff --git a/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/key_value/KtorStandartWriteKeyValueRepo.kt b/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/key_value/KtorStandartWriteKeyValueRepo.kt
new file mode 100644
index 00000000..f74a6296
--- /dev/null
+++ b/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/key_value/KtorStandartWriteKeyValueRepo.kt
@@ -0,0 +1,44 @@
+package com.insanusmokrassar.postssystem.utils.repos.ktor.server.key_value
+
+import com.insanusmokrassar.postssystem.ktor.server.includeWebsocketHandling
+import com.insanusmokrassar.postssystem.ktor.server.uniload
+import com.insanusmokrassar.postssystem.utils.repos.StandardWriteKeyValueRepo
+import com.insanusmokrassar.postssystem.utils.repos.ktor.common.key_value.*
+import io.ktor.application.*
+import io.ktor.routing.*
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.builtins.PairSerializer
+
+fun <K, V> Route.configureWriteStandartKeyValueRepoRoutes (
+    originalRepo: StandardWriteKeyValueRepo<K, V>,
+    keySerializer: KSerializer<K>,
+    valueSerializer: KSerializer<V>,
+) {
+    includeWebsocketHandling(
+        onNewValueRoute,
+        originalRepo.onNewValue,
+        PairSerializer(keySerializer, valueSerializer)
+    )
+
+    includeWebsocketHandling(
+        onValueRemovedRoute,
+        originalRepo.onValueRemoved,
+        keySerializer
+    )
+
+    post(setRoute) {
+        val (key, value) = call.uniload(
+            KeyValuePostObject.serializer(keySerializer, valueSerializer)
+        )
+
+        originalRepo.set(key, value)
+    }
+
+    post(unsetRoute) {
+        val key = call.uniload(
+            keySerializer
+        )
+
+        originalRepo.unset(key)
+    }
+}
\ No newline at end of file