From b94417b77dfe9ce0d0b4a9c47843d561240a6515 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 25 Aug 2020 15:55:47 +0600 Subject: [PATCH] add crud repo server and change a lot of different things --- .../content/WriteContentRepoKtorClient.kt | 15 ++-- .../client/post/WritePostsRepoKtorClient.kt | 22 ++--- .../WriteContentRepoRoutingConfigurator.kt | 8 +- .../post/WritePostsRepoRoutingConfigurator.kt | 12 +-- .../ktor/client/FlowsWebsockets.kt | 18 ++++ .../postssystem/ktor/server/FlowsWebsocket.kt | 14 +++ .../ktor/server/ServerRoutingShortcuts.kt | 10 ++- .../postssystem/ktor/tests/WebsocketsTest.kt | 11 +-- settings.gradle | 1 + .../utils/repos/StandardCRUDRepo.kt | 16 +++- .../exposed/AbstractExposedWriteCRUDRepo.kt | 22 ++--- .../ktor/client/KtorWriteStandardCrudRepo.kt | 35 ++++---- utils/repos/ktor/server/build.gradle | 64 ++++++++++++++ .../ktor/server/KtorReadStandardCrudRepo.kt | 55 ++++++++++++ .../repos/ktor/server/KtorStandardCrudRepo.kt | 27 ++++++ .../ktor/server/KtorWriteStandardCrudRepo.kt | 86 +++++++++++++++++++ 16 files changed, 339 insertions(+), 77 deletions(-) create mode 100644 utils/repos/ktor/server/build.gradle create mode 100644 utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/KtorReadStandardCrudRepo.kt create mode 100644 utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/KtorStandardCrudRepo.kt create mode 100644 utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/KtorWriteStandardCrudRepo.kt diff --git a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/WriteContentRepoKtorClient.kt b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/WriteContentRepoKtorClient.kt index b86bd1b8..822a3996 100644 --- a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/WriteContentRepoKtorClient.kt +++ b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/content/WriteContentRepoKtorClient.kt @@ -4,7 +4,6 @@ import com.insanusmokrassar.postssystem.core.content.* import com.insanusmokrassar.postssystem.core.content.api.WriteContentRepo import com.insanusmokrassar.postssystem.core.ktor.* import com.insanusmokrassar.postssystem.ktor.client.* -import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat import io.ktor.client.HttpClient import kotlinx.coroutines.flow.Flow import kotlinx.serialization.builtins.nullable @@ -15,16 +14,14 @@ class WriteContentRepoKtorClient( private val client: HttpClient = HttpClient() ) : WriteContentRepo { override val contentCreatedFlow: Flow = client.createStandardWebsocketFlow( - "$baseUrl/$contentCreatedFlowRoute" - ) { - standardKtorSerialFormat.decodeFromByteArray(RegisteredContent.serializer(), it) - } + "$baseUrl/$contentCreatedFlowRoute", + deserializer = RegisteredContent.serializer() + ) override val contentDeletedFlow: Flow = client.createStandardWebsocketFlow( - "$baseUrl/$contentDeletedFlowRoute" - ) { - standardKtorSerialFormat.decodeFromByteArray(RegisteredContent.serializer(), it) - } + "$baseUrl/$contentDeletedFlowRoute", + deserializer = RegisteredContent.serializer() + ) override suspend fun registerContent(content: Content): RegisteredContent? = client.unipost( "$baseUrl/$registerContentRoute", diff --git a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/WritePostsRepoKtorClient.kt b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/WritePostsRepoKtorClient.kt index 9ac42430..d0ff656b 100644 --- a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/WritePostsRepoKtorClient.kt +++ b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/WritePostsRepoKtorClient.kt @@ -4,7 +4,6 @@ import com.insanusmokrassar.postssystem.core.ktor.* import com.insanusmokrassar.postssystem.core.post.* import com.insanusmokrassar.postssystem.core.post.repo.WritePostsRepo import com.insanusmokrassar.postssystem.ktor.client.* -import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat import io.ktor.client.HttpClient import io.ktor.client.features.websocket.WebSockets import kotlinx.coroutines.flow.Flow @@ -18,20 +17,17 @@ class WritePostsRepoKtorClient ( } ) : WritePostsRepo { override val postCreatedFlow: Flow = client.createStandardWebsocketFlow( - "$baseUrl/$postCreatedFlowRoute" - ) { - standardKtorSerialFormat.decodeFromByteArray(RegisteredPost.serializer(), it) - } + "$baseUrl/$postCreatedFlowRoute", + deserializer = RegisteredPost.serializer() + ) override val postDeletedFlow: Flow = client.createStandardWebsocketFlow( - "$baseUrl/$postDeletedFlowRoute" - ) { - standardKtorSerialFormat.decodeFromByteArray(RegisteredPost.serializer(), it) - } + "$baseUrl/$postDeletedFlowRoute", + deserializer = RegisteredPost.serializer() + ) override val postUpdatedFlow: Flow = client.createStandardWebsocketFlow( - "$baseUrl/$postUpdatedFlowRoute" - ) { - standardKtorSerialFormat.decodeFromByteArray(RegisteredPost.serializer(), it) - } + "$baseUrl/$postUpdatedFlowRoute", + deserializer = RegisteredPost.serializer() + ) override suspend fun createPost(post: Post): RegisteredPost? = client.unipost( "$baseUrl/$createPostRoute", diff --git a/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/WriteContentRepoRoutingConfigurator.kt b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/WriteContentRepoRoutingConfigurator.kt index a40f3d4e..48ae1e53 100644 --- a/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/WriteContentRepoRoutingConfigurator.kt +++ b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/content/WriteContentRepoRoutingConfigurator.kt @@ -15,12 +15,8 @@ import kotlinx.serialization.builtins.serializer fun Route.configureWriteContentRepoRoutes( proxyTo: WriteContentRepo ) { - includeWebsocketHandling(contentCreatedFlowRoute, proxyTo.contentCreatedFlow) { - standardKtorSerialFormat.encodeToByteArray(RegisteredContent.serializer(), it) - } - includeWebsocketHandling(contentDeletedFlowRoute, proxyTo.contentDeletedFlow) { - standardKtorSerialFormat.encodeToByteArray(RegisteredContent.serializer(), it) - } + includeWebsocketHandling(contentCreatedFlowRoute, proxyTo.contentCreatedFlow, RegisteredContent.serializer()) + includeWebsocketHandling(contentDeletedFlowRoute, proxyTo.contentDeletedFlow, RegisteredContent.serializer()) post(registerContentRoute) { val content = call.uniload(Content.serializer()) val registered = proxyTo.registerContent(content) diff --git a/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/WritePostsRepoRoutingConfigurator.kt b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/WritePostsRepoRoutingConfigurator.kt index 6a82e2c3..820b6ea2 100644 --- a/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/WritePostsRepoRoutingConfigurator.kt +++ b/core/ktor/server/src/main/kotlin/com/insanusmokrassar/postssystem/core/ktor/server/post/WritePostsRepoRoutingConfigurator.kt @@ -15,15 +15,9 @@ import kotlinx.serialization.builtins.serializer fun Route.configureWritePostsRepoRoutes( proxyTo: WritePostsRepo ) { - includeWebsocketHandling(postCreatedFlowRoute, proxyTo.postCreatedFlow) { - standardKtorSerialFormat.encodeToByteArray(RegisteredPost.serializer(), it) - } - includeWebsocketHandling(postDeletedFlowRoute, proxyTo.postDeletedFlow) { - standardKtorSerialFormat.encodeToByteArray(RegisteredPost.serializer(), it) - } - includeWebsocketHandling(postUpdatedFlowRoute, proxyTo.postUpdatedFlow) { - standardKtorSerialFormat.encodeToByteArray(RegisteredPost.serializer(), it) - } + includeWebsocketHandling(postCreatedFlowRoute, proxyTo.postCreatedFlow, RegisteredPost.serializer()) + includeWebsocketHandling(postDeletedFlowRoute, proxyTo.postDeletedFlow, RegisteredPost.serializer()) + includeWebsocketHandling(postUpdatedFlowRoute, proxyTo.postUpdatedFlow, RegisteredPost.serializer()) post(createPostRoute) { call.unianswer( diff --git a/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/ktor/client/FlowsWebsockets.kt b/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/ktor/client/FlowsWebsockets.kt index 656a4abd..0ae3e0c7 100644 --- a/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/ktor/client/FlowsWebsockets.kt +++ b/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/ktor/client/FlowsWebsockets.kt @@ -1,6 +1,7 @@ package com.insanusmokrassar.postssystem.ktor.client import com.insanusmokrassar.postssystem.ktor.asCorrectWebSocketUrl +import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat import com.insanusmokrassar.postssystem.utils.common.safely import io.ktor.client.HttpClient import io.ktor.client.features.websocket.ws @@ -8,6 +9,7 @@ import io.ktor.http.cio.websocket.Frame import io.ktor.http.cio.websocket.readBytes import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.channelFlow +import kotlinx.serialization.DeserializationStrategy /** * @param checkReconnection This lambda will be called when it is required to reconnect to websocket to establish @@ -63,3 +65,19 @@ inline fun HttpClient.createStandardWebsocketFlow( } } } + +/** + * @param checkReconnection This lambda will be called when it is required to reconnect to websocket to establish + * connection. Must return true in case if must be reconnected. By default always reconnecting + */ +inline fun HttpClient.createStandardWebsocketFlow( + url: String, + crossinline checkReconnection: (Throwable?) -> Boolean = { true }, + deserializer: DeserializationStrategy +) = createStandardWebsocketFlow( + url, + checkReconnection +) { + standardKtorSerialFormat.decodeFromByteArray(deserializer, it) +} + diff --git a/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/FlowsWebsocket.kt b/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/FlowsWebsocket.kt index 8e86a864..f7c58dca 100644 --- a/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/FlowsWebsocket.kt +++ b/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/FlowsWebsocket.kt @@ -1,12 +1,15 @@ package com.insanusmokrassar.postssystem.ktor.server import com.insanusmokrassar.postssystem.ktor.CorrectCloseException +import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat import com.insanusmokrassar.postssystem.utils.common.safely import io.ktor.http.cio.websocket.* import io.ktor.routing.Route import io.ktor.websocket.webSocket import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collect +import kotlinx.serialization.DeserializationStrategy +import kotlinx.serialization.SerializationStrategy private suspend fun DefaultWebSocketSession.checkReceivedAndCloseIfExists() { if (incoming.poll() != null) { @@ -29,3 +32,14 @@ fun Route.includeWebsocketHandling( } } } + +fun Route.includeWebsocketHandling( + suburl: String, + flow: Flow, + serializer: SerializationStrategy +) = includeWebsocketHandling( + suburl, + flow +) { + standardKtorSerialFormat.encodeToByteArray(serializer, it) +} diff --git a/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/ServerRoutingShortcuts.kt b/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/ServerRoutingShortcuts.kt index 5948ac49..59e10dbb 100644 --- a/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/ServerRoutingShortcuts.kt +++ b/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/ktor/server/ServerRoutingShortcuts.kt @@ -30,6 +30,14 @@ suspend fun ApplicationCall.getParameterOrSendError( field: String ) = parameters[field].also { if (it == null) { - respond(HttpStatusCode.BadRequest, "request must contains $field") + respond(HttpStatusCode.BadRequest, "Request must contains $field") + } +} + +suspend fun ApplicationCall.getQueryParameterOrSendError( + field: String +) = request.queryParameters[field].also { + if (it == null) { + respond(HttpStatusCode.BadRequest, "Request query parametersmust contains $field") } } diff --git a/ktor/tests/src/test/kotlin/com/insanusmokrassar/postssystem/ktor/tests/WebsocketsTest.kt b/ktor/tests/src/test/kotlin/com/insanusmokrassar/postssystem/ktor/tests/WebsocketsTest.kt index c7278418..618f4e57 100644 --- a/ktor/tests/src/test/kotlin/com/insanusmokrassar/postssystem/ktor/tests/WebsocketsTest.kt +++ b/ktor/tests/src/test/kotlin/com/insanusmokrassar/postssystem/ktor/tests/WebsocketsTest.kt @@ -27,9 +27,7 @@ class WebsocketsTest { val server = createKtorServer(host = "127.0.0.1", port = port) { install(WebSockets) routing { - includeWebsocketHandling(suburl, dataFlow) { - standardKtorSerialFormat.encodeToByteArray(Int.serializer(), it) - } + includeWebsocketHandling(suburl, dataFlow, Int.serializer()) } }.also { it.start(false) @@ -42,10 +40,9 @@ class WebsocketsTest { } val incomingWebsocketFlow = client.createStandardWebsocketFlow( "$serverUrl/$suburl", - { false } // always skip reconnection - ) { - standardKtorSerialFormat.decodeFromByteArray(Int.serializer(), it) - } + { false }, // always skip reconnection + deserializer = Int.serializer() + ) var currentlyCheckingData: Int? = null incomingWebsocketFlow.onEach { diff --git a/settings.gradle b/settings.gradle index f0356ccd..dbb6eb43 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,6 +6,7 @@ String[] includes = [ ':utils:repos:common', ':utils:repos:ktor:common', ':utils:repos:ktor:client', + ':utils:repos:ktor:server', ':utils:repos:exposed', ':exposed:commons', diff --git a/utils/repos/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/StandardCRUDRepo.kt b/utils/repos/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/StandardCRUDRepo.kt index 26b0f55a..8e78cb93 100644 --- a/utils/repos/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/StandardCRUDRepo.kt +++ b/utils/repos/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/StandardCRUDRepo.kt @@ -21,11 +21,21 @@ interface WriteStandardCRUDRepo : Repo { val updatedObjectsFlow: Flow val deletedObjectsIdsFlow: Flow - suspend fun create(vararg values: InputValueType): List + suspend fun create(values: List): List suspend fun update(id: IdType, value: InputValueType): ObjectType? - suspend fun update(vararg values: UpdatedValuePair): List - suspend fun deleteById(vararg ids: IdType) + suspend fun update(values: List>): List + suspend fun deleteById(ids: List) } +suspend fun WriteStandardCRUDRepo.create( + vararg values: InputValueType +): List = create(values.toList()) +suspend fun WriteStandardCRUDRepo.update( + vararg values: UpdatedValuePair +): List = update(values.toList()) +suspend fun WriteStandardCRUDRepo.deleteById( + vararg ids: IdType +) = deleteById(ids.toList()) + interface StandardCRUDRepo : ReadStandardCRUDRepo, WriteStandardCRUDRepo diff --git a/utils/repos/exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedWriteCRUDRepo.kt b/utils/repos/exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedWriteCRUDRepo.kt index a718dfb2..abfbac76 100644 --- a/utils/repos/exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedWriteCRUDRepo.kt +++ b/utils/repos/exposed/src/main/kotlin/com/insanusmokrassar/postssystem/utils/repos/exposed/AbstractExposedWriteCRUDRepo.kt @@ -27,20 +27,20 @@ abstract class AbstractExposedWriteCRUDRepo( override val deletedObjectsIdsFlow: Flow = deleteObjectsIdsChannel.asFlow() abstract val InsertStatement.asObject: ObjectType - abstract val selectByIds: SqlExpressionBuilder.(Array) -> Op + abstract val selectByIds: SqlExpressionBuilder.(List) -> Op protected abstract fun insert(value: InputValueType, it: InsertStatement) protected abstract fun update(id: IdType, value: InputValueType, it: UpdateStatement) - protected open suspend fun onBeforeCreate(vararg value: InputValueType) {} + protected open suspend fun onBeforeCreate(value: List) {} private fun createWithoutNotification(value: InputValueType): ObjectType { return transaction(database) { insert { insert(value, it) }.asObject } } - override suspend fun create(vararg values: InputValueType): List { - onBeforeCreate(*values) + override suspend fun create(values: List): List { + onBeforeCreate(values) return transaction(db = database) { values.map { value -> createWithoutNotification(value) } }.also { @@ -50,7 +50,7 @@ abstract class AbstractExposedWriteCRUDRepo( } } - protected open suspend fun onBeforeUpdate(vararg value: UpdatedValuePair) {} + protected open suspend fun onBeforeUpdate(value: List>) {} private fun updateWithoutNotification(id: IdType, value: InputValueType): ObjectType? { return transaction(db = database) { update( @@ -72,15 +72,15 @@ abstract class AbstractExposedWriteCRUDRepo( } override suspend fun update(id: IdType, value: InputValueType): ObjectType? { - onBeforeUpdate(id to value) + onBeforeUpdate(listOf(id to value)) return updateWithoutNotification(id, value).also { if (it != null) { updateObjectsChannel.send(it) } } } - override suspend fun update(vararg values: UpdatedValuePair): List { - onBeforeUpdate(*values) + override suspend fun update(values: List>): List { + onBeforeUpdate(values) return ( transaction(db = database) { values.map { (id, value) -> updateWithoutNotification(id, value) } @@ -93,9 +93,9 @@ abstract class AbstractExposedWriteCRUDRepo( } } } - protected open suspend fun onBeforeDelete(vararg ids: IdType) {} - override suspend fun deleteById(vararg ids: IdType) { - onBeforeDelete(*ids) + protected open suspend fun onBeforeDelete(ids: List) {} + override suspend fun deleteById(ids: List) { + onBeforeDelete(ids) transaction(db = database) { deleteWhere(null, null) { selectByIds(ids) diff --git a/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/KtorWriteStandardCrudRepo.kt b/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/KtorWriteStandardCrudRepo.kt index 5ce98d23..fdb845e3 100644 --- a/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/KtorWriteStandardCrudRepo.kt +++ b/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/KtorWriteStandardCrudRepo.kt @@ -2,15 +2,12 @@ package com.insanusmokrassar.postssystem.utils.repos.ktor.client import com.insanusmokrassar.postssystem.ktor.* import com.insanusmokrassar.postssystem.ktor.client.* -import com.insanusmokrassar.postssystem.utils.common.pagination.Pagination -import com.insanusmokrassar.postssystem.utils.common.pagination.PaginationResult import com.insanusmokrassar.postssystem.utils.repos.* import com.insanusmokrassar.postssystem.utils.repos.ktor.common.* import io.ktor.client.HttpClient import kotlinx.coroutines.flow.Flow import kotlinx.serialization.KSerializer import kotlinx.serialization.builtins.* -import kotlinx.serialization.encodeToHexString class KtorWriteStandardCrudRepo ( private val baseUrl: String, @@ -23,45 +20,47 @@ class KtorWriteStandardCrudRepo ( private val listObjectsSerializer = ListSerializer(objectsSerializer) private val listInputSerializer = ListSerializer(inputsSerializer) private val listIdsSerializer = ListSerializer(idsSerializer) - private val inputUpdateSerializer = TemporalInputObjectForUpdate.serializer( + private val inputUpdateSerializer = PairSerializer( idsSerializer, inputsSerializer ) private val listInputUpdateSerializer = ListSerializer(inputUpdateSerializer) override val newObjectsFlow: Flow = client.createStandardWebsocketFlow( - buildStandardUrl(baseUrl, newObjectsFlowRouting) - ) { standardKtorSerialFormat.decodeFromByteArray(objectsSerializer, it) } + buildStandardUrl(baseUrl, newObjectsFlowRouting), + deserializer = objectsSerializer + ) override val updatedObjectsFlow: Flow = client.createStandardWebsocketFlow( - buildStandardUrl(baseUrl, updatedObjectsFlowRouting) - ) { standardKtorSerialFormat.decodeFromByteArray(objectsSerializer, it) } + buildStandardUrl(baseUrl, updatedObjectsFlowRouting), + deserializer = objectsSerializer + ) override val deletedObjectsIdsFlow: Flow = client.createStandardWebsocketFlow( - buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting) - ) { standardKtorSerialFormat.decodeFromByteArray(idsSerializer, it) } + buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting), + deserializer = idsSerializer + ) - - override suspend fun create(vararg values: InputValue): List = client.unipost( + override suspend fun create(values: List): List = client.unipost( buildStandardUrl(baseUrl, createRouting), - BodyPair(listInputSerializer, values.toList()), + BodyPair(listInputSerializer, values), listObjectsSerializer ) override suspend fun update(id: IdType, value: InputValue): ObjectType? = client.unipost( buildStandardUrl(baseUrl, updateRouting), - BodyPair(inputUpdateSerializer, TemporalInputObjectForUpdate(id, value)), + BodyPair(inputUpdateSerializer, id to value), objectsNullableSerializer ) - override suspend fun update(vararg values: UpdatedValuePair): List = client.unipost( + override suspend fun update(values: List>): List = client.unipost( buildStandardUrl(baseUrl, updateManyRouting), - BodyPair(listInputUpdateSerializer, values.map { TemporalInputObjectForUpdate(it.first, it.second) }), + BodyPair(listInputUpdateSerializer, values), listObjectsSerializer ) - override suspend fun deleteById(vararg ids: IdType) = client.unipost( + override suspend fun deleteById(ids: List) = client.unipost( buildStandardUrl(baseUrl, deleteByIdRouting), - BodyPair(listIdsSerializer, ids.toList()), + BodyPair(listIdsSerializer, ids), Unit.serializer() ) } diff --git a/utils/repos/ktor/server/build.gradle b/utils/repos/ktor/server/build.gradle new file mode 100644 index 00000000..cab1a09e --- /dev/null +++ b/utils/repos/ktor/server/build.gradle @@ -0,0 +1,64 @@ +buildscript { + repositories { + mavenLocal() + jcenter() + mavenCentral() + } + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" + classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version" + } +} + +plugins { + id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version" + id "org.jetbrains.kotlin.plugin.serialization" version "$kotlin_version" +} + +project.version = "$core_version" +project.group = "com.insanusmokrassar" + +repositories { + mavenLocal() + jcenter() + mavenCentral() + maven { url "https://kotlin.bintray.com/kotlinx" } +} + +kotlin { + jvm() + + sourceSets { + commonMain { + dependencies { + implementation kotlin('stdlib') + api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" + + api projectByName("postssystem.utils.repos.ktor.common") + api projectByName("postssystem.ktor.server") + } + } + commonTest { + dependencies { + implementation kotlin('test-common') + implementation kotlin('test-annotations-common') + } + } + + jvmMain { + dependencies { + api "io.ktor:ktor-server:$ktor_version" + api "io.ktor:ktor-server-host-common:$ktor_version" + api "io.ktor:ktor-server-netty:$ktor_version" + api "io.ktor:ktor-websockets:$ktor_version" + } + } + jvmTest { + dependencies { + implementation kotlin('test-junit') + } + } + } +} diff --git a/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/KtorReadStandardCrudRepo.kt b/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/KtorReadStandardCrudRepo.kt new file mode 100644 index 00000000..ffd1a7fd --- /dev/null +++ b/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/KtorReadStandardCrudRepo.kt @@ -0,0 +1,55 @@ +package com.insanusmokrassar.postssystem.utils.repos.ktor.server + +import com.insanusmokrassar.postssystem.ktor.server.* +import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat +import com.insanusmokrassar.postssystem.utils.common.pagination.PaginationResult +import com.insanusmokrassar.postssystem.utils.repos.ReadStandardCRUDRepo +import com.insanusmokrassar.postssystem.utils.repos.ktor.common.* +import io.ktor.application.call +import io.ktor.routing.Route +import io.ktor.routing.get +import kotlinx.serialization.KSerializer +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.decodeFromHexString + +fun Route.configureReadStandardCrudRepoRoutes( + originalRepo: ReadStandardCRUDRepo, + objectsSerializer: KSerializer, + objectsNullableSerializer: KSerializer, + idsSerializer: KSerializer +) { + val paginationResultSerializer = PaginationResult.serializer(objectsSerializer) + + get(getByPaginationRouting) { + val pagination = call.request.queryParameters.extractPagination + + call.unianswer( + paginationResultSerializer, + originalRepo.getByPagination(pagination) + ) + } + + get(getByIdRouting) { + val id = standardKtorSerialFormat.decodeFromHexString( + idsSerializer, + call.getQueryParameterOrSendError("id") ?: return@get + ) + + call.unianswer( + objectsNullableSerializer, + originalRepo.getById(id) + ) + } + + get(containsRouting) { + val id = standardKtorSerialFormat.decodeFromHexString( + idsSerializer, + call.getQueryParameterOrSendError("id") ?: return@get + ) + + call.unianswer( + Boolean.serializer(), + originalRepo.contains(id) + ) + } +} diff --git a/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/KtorStandardCrudRepo.kt b/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/KtorStandardCrudRepo.kt new file mode 100644 index 00000000..741006d4 --- /dev/null +++ b/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/KtorStandardCrudRepo.kt @@ -0,0 +1,27 @@ +package com.insanusmokrassar.postssystem.utils.repos.ktor.server + +import com.insanusmokrassar.postssystem.ktor.server.* +import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat +import com.insanusmokrassar.postssystem.utils.common.pagination.PaginationResult +import com.insanusmokrassar.postssystem.utils.repos.* +import com.insanusmokrassar.postssystem.utils.repos.ktor.common.* +import io.ktor.application.call +import io.ktor.routing.* +import io.ktor.routing.get +import kotlinx.serialization.KSerializer +import kotlinx.serialization.builtins.* +import kotlinx.serialization.decodeFromHexString + +fun Route.configureStandardCrudRepoRoutes( + baseSubpart: String, + originalRepo: StandardCRUDRepo, + objectsSerializer: KSerializer, + objectsNullableSerializer: KSerializer, + inputsSerializer: KSerializer, + idsSerializer: KSerializer +) { + route(baseSubpart) { + configureReadStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer) + configureWriteStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer) + } +} diff --git a/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/KtorWriteStandardCrudRepo.kt b/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/KtorWriteStandardCrudRepo.kt new file mode 100644 index 00000000..1f7b5973 --- /dev/null +++ b/utils/repos/ktor/server/src/jvmMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/server/KtorWriteStandardCrudRepo.kt @@ -0,0 +1,86 @@ +package com.insanusmokrassar.postssystem.utils.repos.ktor.server + +import com.insanusmokrassar.postssystem.ktor.server.* +import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat +import com.insanusmokrassar.postssystem.utils.common.pagination.PaginationResult +import com.insanusmokrassar.postssystem.utils.repos.ReadStandardCRUDRepo +import com.insanusmokrassar.postssystem.utils.repos.WriteStandardCRUDRepo +import com.insanusmokrassar.postssystem.utils.repos.ktor.common.* +import io.ktor.application.call +import io.ktor.routing.* +import io.ktor.routing.get +import kotlinx.serialization.KSerializer +import kotlinx.serialization.builtins.* +import kotlinx.serialization.decodeFromHexString + +fun Route.configureWriteStandardCrudRepoRoutes( + originalRepo: WriteStandardCRUDRepo, + objectsSerializer: KSerializer, + objectsNullableSerializer: KSerializer, + inputsSerializer: KSerializer, + idsSerializer: KSerializer +) { + val listObjectsSerializer = ListSerializer(objectsSerializer) + val listInputSerializer = ListSerializer(inputsSerializer) + val listIdsSerializer = ListSerializer(idsSerializer) + val inputUpdateSerializer = PairSerializer( + idsSerializer, + inputsSerializer + ) + val listInputUpdateSerializer = ListSerializer(inputUpdateSerializer) + + includeWebsocketHandling( + newObjectsFlowRouting, + originalRepo.newObjectsFlow, + objectsSerializer + ) + includeWebsocketHandling( + updatedObjectsFlowRouting, + originalRepo.updatedObjectsFlow, + objectsSerializer + ) + includeWebsocketHandling( + deletedObjectsIdsFlowRouting, + originalRepo.deletedObjectsIdsFlow, + idsSerializer + ) + + post(createRouting) { + call.unianswer( + listObjectsSerializer, + originalRepo.create( + call.uniload(listInputSerializer) + ) + ) + } + + post(updateRouting) { + val (id, input) = call.uniload(inputUpdateSerializer) + call.unianswer( + objectsNullableSerializer, + originalRepo.update( + id, input + ) + ) + } + + post(updateManyRouting) { + val updates = call.uniload(listInputUpdateSerializer) + call.unianswer( + listObjectsSerializer, + originalRepo.update( + updates + ) + ) + } + + post(deleteByIdRouting) { + val ids = call.uniload(listIdsSerializer) + call.unianswer( + Unit.serializer(), + originalRepo.deleteById( + ids + ) + ) + } +}