From 14d69152826daed7f8bdb8894c114da7f5b0cbb9 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 25 Aug 2020 14:46:44 +0600 Subject: [PATCH] add ktor standard realisation of crud repo --- .../client/post/ReadPostsRepoKtorClient.kt | 21 +++--- .../ktor/client/FlowsWebsockets.kt | 2 +- .../postssystem/ktor/BuildStandardUrl.kt | 9 +++ settings.gradle | 2 + utils/repos/ktor/client/build.gradle | 74 +++++++++++++++++++ .../ktor/client/KtorReadStandardCrudRepo.kt | 49 ++++++++++++ .../repos/ktor/client/KtorStandardCrudRepo.kt | 30 ++++++++ .../ktor/client/KtorWriteStandardCrudRepo.kt | 67 +++++++++++++++++ utils/repos/ktor/common/build.gradle | 74 +++++++++++++++++++ .../utils/repos/ktor/common/CrudReadRoutes.kt | 6 ++ .../repos/ktor/common/CrudWriteRoutes.kt | 10 +++ .../common/TemporalInputObjectForUpdate.kt | 9 +++ 12 files changed, 343 insertions(+), 10 deletions(-) create mode 100644 ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/ktor/BuildStandardUrl.kt create mode 100644 utils/repos/ktor/client/build.gradle create mode 100644 utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/KtorReadStandardCrudRepo.kt create mode 100644 utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/KtorStandardCrudRepo.kt create mode 100644 utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/KtorWriteStandardCrudRepo.kt create mode 100644 utils/repos/ktor/common/build.gradle create mode 100644 utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/CrudReadRoutes.kt create mode 100644 utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/CrudWriteRoutes.kt create mode 100644 utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/TemporalInputObjectForUpdate.kt diff --git a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/ReadPostsRepoKtorClient.kt b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/ReadPostsRepoKtorClient.kt index ba88f0a6..c7c5a6e2 100644 --- a/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/ReadPostsRepoKtorClient.kt +++ b/core/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/core/ktor/client/post/ReadPostsRepoKtorClient.kt @@ -18,19 +18,18 @@ class ReadPostsRepoKtorClient( private val baseUrl: String, private val client: HttpClient = HttpClient() ) : ReadPostsRepo { - override suspend fun getPostsIds(): Set = client.get( - "$baseUrl/$getPostsIdsRoute" - ).let { - standardKtorSerialFormat.decodeFromByteArray(postIdsSerializer, it) - } + override suspend fun getPostsIds(): Set = client.uniget( + buildStandardUrl(baseUrl, getPostsIdsRoute), + postIdsSerializer + ) override suspend fun getPostById(id: PostId): RegisteredPost? = client.uniget( - "$baseUrl/$getPostByIdRoute/$id", + buildStandardUrl(baseUrl, "$getPostByIdRoute/$id"), RegisteredPost.serializer().nullable ) override suspend fun getPostsByContent(id: ContentId): List = client.uniget( - "$baseUrl/$getPostsByContentRoute/$id", + buildStandardUrl(baseUrl, "$getPostsByContentRoute/$id"), registeredPostsListSerializer ) @@ -39,14 +38,18 @@ class ReadPostsRepoKtorClient( to: DateTime, pagination: Pagination ): PaginationResult = client.uniget( - "$baseUrl/$getPostsByCreatingDatesRoute".includeQueryParams( + buildStandardUrl( + baseUrl, + getPostsByCreatingDatesRoute, (from to to).asFromToUrlPart + pagination.asUrlQueryParts ), registeredPostsPaginationResultSerializer ) override suspend fun getPostsByPagination(pagination: Pagination): PaginationResult = client.uniget( - "$baseUrl/$getPostsByPaginationRoute".includeQueryParams( + buildStandardUrl( + baseUrl, + getPostsByCreatingDatesRoute, pagination.asUrlQueryParts ), registeredPostsPaginationResultSerializer 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 190780d1..656a4abd 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 @@ -13,7 +13,7 @@ import kotlinx.coroutines.flow.channelFlow * @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( +inline fun HttpClient.createStandardWebsocketFlow( url: String, crossinline checkReconnection: (Throwable?) -> Boolean = { true }, crossinline conversation: suspend (ByteArray) -> T diff --git a/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/ktor/BuildStandardUrl.kt b/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/ktor/BuildStandardUrl.kt new file mode 100644 index 00000000..1204ec93 --- /dev/null +++ b/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/ktor/BuildStandardUrl.kt @@ -0,0 +1,9 @@ +package com.insanusmokrassar.postssystem.ktor + +fun buildStandardUrl( + basePart: String, + subpart: String, + parameters: QueryParams = emptyMap() +) = "$basePart/$subpart".includeQueryParams( + parameters +) diff --git a/settings.gradle b/settings.gradle index babfd742..f0356ccd 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,6 +4,8 @@ String[] includes = [ ':utils:common', ':utils:repos', ':utils:repos:common', + ':utils:repos:ktor:common', + ':utils:repos:ktor:client', ':utils:repos:exposed', ':exposed:commons', diff --git a/utils/repos/ktor/client/build.gradle b/utils/repos/ktor/client/build.gradle new file mode 100644 index 00000000..ef1f20ad --- /dev/null +++ b/utils/repos/ktor/client/build.gradle @@ -0,0 +1,74 @@ +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() + js (BOTH) { + browser() + nodejs() + } + + sourceSets { + commonMain { + dependencies { + implementation kotlin('stdlib') + + api projectByName("postssystem.utils.repos.ktor.common") + api projectByName("postssystem.ktor.client") + } + } + commonTest { + dependencies { + implementation kotlin('test-common') + implementation kotlin('test-annotations-common') + } + } + jvmMain { + dependencies { + implementation kotlin('stdlib-jdk8') + } + } + jvmTest { + dependencies { + implementation kotlin('test-junit') + } + } + jsMain { + dependencies { + implementation kotlin('stdlib-js') + } + } + jsTest { + dependencies { + implementation kotlin('test-js') + implementation kotlin('test-junit') + } + } + } +} diff --git a/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/KtorReadStandardCrudRepo.kt b/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/KtorReadStandardCrudRepo.kt new file mode 100644 index 00000000..bf85dbf9 --- /dev/null +++ b/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/KtorReadStandardCrudRepo.kt @@ -0,0 +1,49 @@ +package com.insanusmokrassar.postssystem.utils.repos.ktor.client + +import com.insanusmokrassar.postssystem.ktor.* +import com.insanusmokrassar.postssystem.ktor.client.uniget +import com.insanusmokrassar.postssystem.utils.common.pagination.Pagination +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.client.HttpClient +import kotlinx.serialization.KSerializer +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.encodeToHexString + +class KtorReadStandardCrudRepo ( + private val baseUrl: String, + private val client: HttpClient = HttpClient(), + private val objectsSerializer: KSerializer, + private val objectsSerializerNullable: KSerializer, + private val idsSerializer: KSerializer +) : ReadStandardCRUDRepo { + private val paginationResultSerializer = PaginationResult.serializer(objectsSerializer) + + override suspend fun getByPagination(pagination: Pagination): PaginationResult = client.uniget( + buildStandardUrl(baseUrl, getByPaginationRouting, pagination.asUrlQueryParts), + paginationResultSerializer + ) + + override suspend fun getById(id: IdType): ObjectType? = client.uniget( + buildStandardUrl( + baseUrl, + getByIdRouting, + mapOf( + "id" to standardKtorSerialFormat.encodeToHexString(idsSerializer, id) + ) + ), + objectsSerializerNullable + ) + + override suspend fun contains(id: IdType): Boolean = client.uniget( + buildStandardUrl( + baseUrl, + containsRouting, + mapOf( + "id" to standardKtorSerialFormat.encodeToHexString(idsSerializer, id) + ) + ), + Boolean.serializer() + ) +} diff --git a/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/KtorStandardCrudRepo.kt b/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/KtorStandardCrudRepo.kt new file mode 100644 index 00000000..127d2ea6 --- /dev/null +++ b/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/KtorStandardCrudRepo.kt @@ -0,0 +1,30 @@ +package com.insanusmokrassar.postssystem.utils.repos.ktor.client + +import com.insanusmokrassar.postssystem.utils.repos.* +import io.ktor.client.HttpClient +import kotlinx.serialization.KSerializer + +class KtorStandardCrudRepo ( + baseUrl: String, + baseSubpart: String, + client: HttpClient, + objectsSerializer: KSerializer, + objectsNullableSerializer: KSerializer, + inputsSerializer: KSerializer, + idsSerializer: KSerializer +) : StandardCRUDRepo, + ReadStandardCRUDRepo by KtorReadStandardCrudRepo( + "$baseUrl/$baseSubpart", + client, + objectsSerializer, + objectsNullableSerializer, + idsSerializer + ), + WriteStandardCRUDRepo by KtorWriteStandardCrudRepo( + "$baseUrl/$baseSubpart", + client, + objectsSerializer, + objectsNullableSerializer, + inputsSerializer, + idsSerializer + ) 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 new file mode 100644 index 00000000..5ce98d23 --- /dev/null +++ b/utils/repos/ktor/client/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/client/KtorWriteStandardCrudRepo.kt @@ -0,0 +1,67 @@ +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, + private val client: HttpClient = HttpClient(), + private val objectsSerializer: KSerializer, + private val objectsNullableSerializer: KSerializer, + private val inputsSerializer: KSerializer, + private val idsSerializer: KSerializer +) : WriteStandardCRUDRepo { + private val listObjectsSerializer = ListSerializer(objectsSerializer) + private val listInputSerializer = ListSerializer(inputsSerializer) + private val listIdsSerializer = ListSerializer(idsSerializer) + private val inputUpdateSerializer = TemporalInputObjectForUpdate.serializer( + idsSerializer, + inputsSerializer + ) + private val listInputUpdateSerializer = ListSerializer(inputUpdateSerializer) + + override val newObjectsFlow: Flow = client.createStandardWebsocketFlow( + buildStandardUrl(baseUrl, newObjectsFlowRouting) + ) { standardKtorSerialFormat.decodeFromByteArray(objectsSerializer, it) } + override val updatedObjectsFlow: Flow = client.createStandardWebsocketFlow( + buildStandardUrl(baseUrl, updatedObjectsFlowRouting) + ) { standardKtorSerialFormat.decodeFromByteArray(objectsSerializer, it) } + override val deletedObjectsIdsFlow: Flow = client.createStandardWebsocketFlow( + buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting) + ) { standardKtorSerialFormat.decodeFromByteArray(idsSerializer, it) } + + + + override suspend fun create(vararg values: InputValue): List = client.unipost( + buildStandardUrl(baseUrl, createRouting), + BodyPair(listInputSerializer, values.toList()), + listObjectsSerializer + ) + + override suspend fun update(id: IdType, value: InputValue): ObjectType? = client.unipost( + buildStandardUrl(baseUrl, updateRouting), + BodyPair(inputUpdateSerializer, TemporalInputObjectForUpdate(id, value)), + objectsNullableSerializer + ) + + override suspend fun update(vararg values: UpdatedValuePair): List = client.unipost( + buildStandardUrl(baseUrl, updateManyRouting), + BodyPair(listInputUpdateSerializer, values.map { TemporalInputObjectForUpdate(it.first, it.second) }), + listObjectsSerializer + ) + + override suspend fun deleteById(vararg ids: IdType) = client.unipost( + buildStandardUrl(baseUrl, deleteByIdRouting), + BodyPair(listIdsSerializer, ids.toList()), + Unit.serializer() + ) +} diff --git a/utils/repos/ktor/common/build.gradle b/utils/repos/ktor/common/build.gradle new file mode 100644 index 00000000..a9537f79 --- /dev/null +++ b/utils/repos/ktor/common/build.gradle @@ -0,0 +1,74 @@ +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() + js (BOTH) { + browser() + nodejs() + } + + sourceSets { + commonMain { + dependencies { + implementation kotlin('stdlib') + + api projectByName("postssystem.utils.repos.common") + api projectByName("postssystem.ktor.common") + } + } + commonTest { + dependencies { + implementation kotlin('test-common') + implementation kotlin('test-annotations-common') + } + } + jvmMain { + dependencies { + implementation kotlin('stdlib-jdk8') + } + } + jvmTest { + dependencies { + implementation kotlin('test-junit') + } + } + jsMain { + dependencies { + implementation kotlin('stdlib-js') + } + } + jsTest { + dependencies { + implementation kotlin('test-js') + implementation kotlin('test-junit') + } + } + } +} diff --git a/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/CrudReadRoutes.kt b/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/CrudReadRoutes.kt new file mode 100644 index 00000000..b1bb2cfb --- /dev/null +++ b/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/CrudReadRoutes.kt @@ -0,0 +1,6 @@ +package com.insanusmokrassar.postssystem.utils.repos.ktor.common + +const val getByPaginationRouting = "getByPagination" +const val getByIdRouting = "getById" +const val containsRouting = "contains" +const val getAllRouting = "getAll" diff --git a/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/CrudWriteRoutes.kt b/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/CrudWriteRoutes.kt new file mode 100644 index 00000000..9a8b265e --- /dev/null +++ b/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/CrudWriteRoutes.kt @@ -0,0 +1,10 @@ +package com.insanusmokrassar.postssystem.utils.repos.ktor.common + +const val newObjectsFlowRouting = "newObjectsFlow" +const val updatedObjectsFlowRouting = "updatedObjectsFlow" +const val deletedObjectsIdsFlowRouting = "deletedObjectsIdsFlow" + +const val createRouting = "create" +const val updateRouting = "update" +const val updateManyRouting = "updateMany" +const val deleteByIdRouting = "deleteById" diff --git a/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/TemporalInputObjectForUpdate.kt b/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/TemporalInputObjectForUpdate.kt new file mode 100644 index 00000000..7aa97c29 --- /dev/null +++ b/utils/repos/ktor/common/src/commonMain/kotlin/com/insanusmokrassar/postssystem/utils/repos/ktor/common/TemporalInputObjectForUpdate.kt @@ -0,0 +1,9 @@ +package com.insanusmokrassar.postssystem.utils.repos.ktor.common + +import kotlinx.serialization.Serializable + +@Serializable +data class TemporalInputObjectForUpdate( + val id: IdType, + val input: InputValue +)