add crud repo server and change a lot of different things

This commit is contained in:
2020-08-25 15:55:47 +06:00
parent 14d6915282
commit b94417b77d
16 changed files with 339 additions and 77 deletions
core/ktor
client
src
commonMain
kotlin
com
insanusmokrassar
server
src
main
kotlin
com
insanusmokrassar
ktor
client
src
commonMain
kotlin
com
insanusmokrassar
postssystem
server
src
jvmMain
kotlin
com
insanusmokrassar
tests
src
test
kotlin
com
insanusmokrassar
postssystem
settings.gradle
utils/repos
common
src
commonMain
kotlin
com
insanusmokrassar
postssystem
exposed
src
main
kotlin
com
insanusmokrassar
postssystem
ktor
client
src
commonMain
kotlin
com
insanusmokrassar
postssystem
utils
server
build.gradle
src
jvmMain
kotlin

@ -4,7 +4,6 @@ import com.insanusmokrassar.postssystem.core.content.*
import com.insanusmokrassar.postssystem.core.content.api.WriteContentRepo import com.insanusmokrassar.postssystem.core.content.api.WriteContentRepo
import com.insanusmokrassar.postssystem.core.ktor.* import com.insanusmokrassar.postssystem.core.ktor.*
import com.insanusmokrassar.postssystem.ktor.client.* import com.insanusmokrassar.postssystem.ktor.client.*
import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.serialization.builtins.nullable import kotlinx.serialization.builtins.nullable
@ -15,16 +14,14 @@ class WriteContentRepoKtorClient(
private val client: HttpClient = HttpClient() private val client: HttpClient = HttpClient()
) : WriteContentRepo { ) : WriteContentRepo {
override val contentCreatedFlow: Flow<RegisteredContent> = client.createStandardWebsocketFlow( override val contentCreatedFlow: Flow<RegisteredContent> = client.createStandardWebsocketFlow(
"$baseUrl/$contentCreatedFlowRoute" "$baseUrl/$contentCreatedFlowRoute",
) { deserializer = RegisteredContent.serializer()
standardKtorSerialFormat.decodeFromByteArray(RegisteredContent.serializer(), it) )
}
override val contentDeletedFlow: Flow<RegisteredContent> = client.createStandardWebsocketFlow( override val contentDeletedFlow: Flow<RegisteredContent> = client.createStandardWebsocketFlow(
"$baseUrl/$contentDeletedFlowRoute" "$baseUrl/$contentDeletedFlowRoute",
) { deserializer = RegisteredContent.serializer()
standardKtorSerialFormat.decodeFromByteArray(RegisteredContent.serializer(), it) )
}
override suspend fun registerContent(content: Content): RegisteredContent? = client.unipost( override suspend fun registerContent(content: Content): RegisteredContent? = client.unipost(
"$baseUrl/$registerContentRoute", "$baseUrl/$registerContentRoute",

@ -4,7 +4,6 @@ import com.insanusmokrassar.postssystem.core.ktor.*
import com.insanusmokrassar.postssystem.core.post.* import com.insanusmokrassar.postssystem.core.post.*
import com.insanusmokrassar.postssystem.core.post.repo.WritePostsRepo import com.insanusmokrassar.postssystem.core.post.repo.WritePostsRepo
import com.insanusmokrassar.postssystem.ktor.client.* import com.insanusmokrassar.postssystem.ktor.client.*
import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.features.websocket.WebSockets import io.ktor.client.features.websocket.WebSockets
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -18,20 +17,17 @@ class WritePostsRepoKtorClient (
} }
) : WritePostsRepo { ) : WritePostsRepo {
override val postCreatedFlow: Flow<RegisteredPost> = client.createStandardWebsocketFlow( override val postCreatedFlow: Flow<RegisteredPost> = client.createStandardWebsocketFlow(
"$baseUrl/$postCreatedFlowRoute" "$baseUrl/$postCreatedFlowRoute",
) { deserializer = RegisteredPost.serializer()
standardKtorSerialFormat.decodeFromByteArray(RegisteredPost.serializer(), it) )
}
override val postDeletedFlow: Flow<RegisteredPost> = client.createStandardWebsocketFlow( override val postDeletedFlow: Flow<RegisteredPost> = client.createStandardWebsocketFlow(
"$baseUrl/$postDeletedFlowRoute" "$baseUrl/$postDeletedFlowRoute",
) { deserializer = RegisteredPost.serializer()
standardKtorSerialFormat.decodeFromByteArray(RegisteredPost.serializer(), it) )
}
override val postUpdatedFlow: Flow<RegisteredPost> = client.createStandardWebsocketFlow( override val postUpdatedFlow: Flow<RegisteredPost> = client.createStandardWebsocketFlow(
"$baseUrl/$postUpdatedFlowRoute" "$baseUrl/$postUpdatedFlowRoute",
) { deserializer = RegisteredPost.serializer()
standardKtorSerialFormat.decodeFromByteArray(RegisteredPost.serializer(), it) )
}
override suspend fun createPost(post: Post): RegisteredPost? = client.unipost( override suspend fun createPost(post: Post): RegisteredPost? = client.unipost(
"$baseUrl/$createPostRoute", "$baseUrl/$createPostRoute",

@ -15,12 +15,8 @@ import kotlinx.serialization.builtins.serializer
fun Route.configureWriteContentRepoRoutes( fun Route.configureWriteContentRepoRoutes(
proxyTo: WriteContentRepo proxyTo: WriteContentRepo
) { ) {
includeWebsocketHandling(contentCreatedFlowRoute, proxyTo.contentCreatedFlow) { includeWebsocketHandling(contentCreatedFlowRoute, proxyTo.contentCreatedFlow, RegisteredContent.serializer())
standardKtorSerialFormat.encodeToByteArray(RegisteredContent.serializer(), it) includeWebsocketHandling(contentDeletedFlowRoute, proxyTo.contentDeletedFlow, RegisteredContent.serializer())
}
includeWebsocketHandling(contentDeletedFlowRoute, proxyTo.contentDeletedFlow) {
standardKtorSerialFormat.encodeToByteArray(RegisteredContent.serializer(), it)
}
post(registerContentRoute) { post(registerContentRoute) {
val content = call.uniload(Content.serializer()) val content = call.uniload(Content.serializer())
val registered = proxyTo.registerContent(content) val registered = proxyTo.registerContent(content)

@ -15,15 +15,9 @@ import kotlinx.serialization.builtins.serializer
fun Route.configureWritePostsRepoRoutes( fun Route.configureWritePostsRepoRoutes(
proxyTo: WritePostsRepo proxyTo: WritePostsRepo
) { ) {
includeWebsocketHandling(postCreatedFlowRoute, proxyTo.postCreatedFlow) { includeWebsocketHandling(postCreatedFlowRoute, proxyTo.postCreatedFlow, RegisteredPost.serializer())
standardKtorSerialFormat.encodeToByteArray(RegisteredPost.serializer(), it) includeWebsocketHandling(postDeletedFlowRoute, proxyTo.postDeletedFlow, RegisteredPost.serializer())
} includeWebsocketHandling(postUpdatedFlowRoute, proxyTo.postUpdatedFlow, RegisteredPost.serializer())
includeWebsocketHandling(postDeletedFlowRoute, proxyTo.postDeletedFlow) {
standardKtorSerialFormat.encodeToByteArray(RegisteredPost.serializer(), it)
}
includeWebsocketHandling(postUpdatedFlowRoute, proxyTo.postUpdatedFlow) {
standardKtorSerialFormat.encodeToByteArray(RegisteredPost.serializer(), it)
}
post(createPostRoute) { post(createPostRoute) {
call.unianswer( call.unianswer(

@ -1,6 +1,7 @@
package com.insanusmokrassar.postssystem.ktor.client package com.insanusmokrassar.postssystem.ktor.client
import com.insanusmokrassar.postssystem.ktor.asCorrectWebSocketUrl import com.insanusmokrassar.postssystem.ktor.asCorrectWebSocketUrl
import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat
import com.insanusmokrassar.postssystem.utils.common.safely import com.insanusmokrassar.postssystem.utils.common.safely
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.features.websocket.ws 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 io.ktor.http.cio.websocket.readBytes
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow 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 * @param checkReconnection This lambda will be called when it is required to reconnect to websocket to establish
@ -63,3 +65,19 @@ inline fun <T> 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 <T> HttpClient.createStandardWebsocketFlow(
url: String,
crossinline checkReconnection: (Throwable?) -> Boolean = { true },
deserializer: DeserializationStrategy<T>
) = createStandardWebsocketFlow(
url,
checkReconnection
) {
standardKtorSerialFormat.decodeFromByteArray(deserializer, it)
}

@ -1,12 +1,15 @@
package com.insanusmokrassar.postssystem.ktor.server package com.insanusmokrassar.postssystem.ktor.server
import com.insanusmokrassar.postssystem.ktor.CorrectCloseException import com.insanusmokrassar.postssystem.ktor.CorrectCloseException
import com.insanusmokrassar.postssystem.ktor.standardKtorSerialFormat
import com.insanusmokrassar.postssystem.utils.common.safely import com.insanusmokrassar.postssystem.utils.common.safely
import io.ktor.http.cio.websocket.* import io.ktor.http.cio.websocket.*
import io.ktor.routing.Route import io.ktor.routing.Route
import io.ktor.websocket.webSocket import io.ktor.websocket.webSocket
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerializationStrategy
private suspend fun DefaultWebSocketSession.checkReceivedAndCloseIfExists() { private suspend fun DefaultWebSocketSession.checkReceivedAndCloseIfExists() {
if (incoming.poll() != null) { if (incoming.poll() != null) {
@ -29,3 +32,14 @@ fun <T> Route.includeWebsocketHandling(
} }
} }
} }
fun <T> Route.includeWebsocketHandling(
suburl: String,
flow: Flow<T>,
serializer: SerializationStrategy<T>
) = includeWebsocketHandling(
suburl,
flow
) {
standardKtorSerialFormat.encodeToByteArray(serializer, it)
}

@ -30,6 +30,14 @@ suspend fun ApplicationCall.getParameterOrSendError(
field: String field: String
) = parameters[field].also { ) = parameters[field].also {
if (it == null) { 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")
} }
} }

@ -27,9 +27,7 @@ class WebsocketsTest {
val server = createKtorServer(host = "127.0.0.1", port = port) { val server = createKtorServer(host = "127.0.0.1", port = port) {
install(WebSockets) install(WebSockets)
routing { routing {
includeWebsocketHandling(suburl, dataFlow) { includeWebsocketHandling(suburl, dataFlow, Int.serializer())
standardKtorSerialFormat.encodeToByteArray(Int.serializer(), it)
}
} }
}.also { }.also {
it.start(false) it.start(false)
@ -42,10 +40,9 @@ class WebsocketsTest {
} }
val incomingWebsocketFlow = client.createStandardWebsocketFlow( val incomingWebsocketFlow = client.createStandardWebsocketFlow(
"$serverUrl/$suburl", "$serverUrl/$suburl",
{ false } // always skip reconnection { false }, // always skip reconnection
) { deserializer = Int.serializer()
standardKtorSerialFormat.decodeFromByteArray(Int.serializer(), it) )
}
var currentlyCheckingData: Int? = null var currentlyCheckingData: Int? = null
incomingWebsocketFlow.onEach { incomingWebsocketFlow.onEach {

@ -6,6 +6,7 @@ String[] includes = [
':utils:repos:common', ':utils:repos:common',
':utils:repos:ktor:common', ':utils:repos:ktor:common',
':utils:repos:ktor:client', ':utils:repos:ktor:client',
':utils:repos:ktor:server',
':utils:repos:exposed', ':utils:repos:exposed',
':exposed:commons', ':exposed:commons',

@ -21,11 +21,21 @@ interface WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> : Repo {
val updatedObjectsFlow: Flow<ObjectType> val updatedObjectsFlow: Flow<ObjectType>
val deletedObjectsIdsFlow: Flow<IdType> val deletedObjectsIdsFlow: Flow<IdType>
suspend fun create(vararg values: InputValueType): List<ObjectType> suspend fun create(values: List<InputValueType>): List<ObjectType>
suspend fun update(id: IdType, value: InputValueType): ObjectType? suspend fun update(id: IdType, value: InputValueType): ObjectType?
suspend fun update(vararg values: UpdatedValuePair<IdType, InputValueType>): List<ObjectType> suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType>
suspend fun deleteById(vararg ids: IdType) suspend fun deleteById(ids: List<IdType>)
} }
suspend fun <ObjectType, IdType, InputValueType> WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>.create(
vararg values: InputValueType
): List<ObjectType> = create(values.toList())
suspend fun <ObjectType, IdType, InputValueType> WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>.update(
vararg values: UpdatedValuePair<IdType, InputValueType>
): List<ObjectType> = update(values.toList())
suspend fun <ObjectType, IdType, InputValueType> WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>.deleteById(
vararg ids: IdType
) = deleteById(ids.toList())
interface StandardCRUDRepo<ObjectType, IdType, InputValueType> : ReadStandardCRUDRepo<ObjectType, IdType>, interface StandardCRUDRepo<ObjectType, IdType, InputValueType> : ReadStandardCRUDRepo<ObjectType, IdType>,
WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>

@ -27,20 +27,20 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
override val deletedObjectsIdsFlow: Flow<IdType> = deleteObjectsIdsChannel.asFlow() override val deletedObjectsIdsFlow: Flow<IdType> = deleteObjectsIdsChannel.asFlow()
abstract val InsertStatement<Number>.asObject: ObjectType abstract val InsertStatement<Number>.asObject: ObjectType
abstract val selectByIds: SqlExpressionBuilder.(Array<out IdType>) -> Op<Boolean> abstract val selectByIds: SqlExpressionBuilder.(List<out IdType>) -> Op<Boolean>
protected abstract fun insert(value: InputValueType, it: InsertStatement<Number>) protected abstract fun insert(value: InputValueType, it: InsertStatement<Number>)
protected abstract fun update(id: IdType, value: InputValueType, it: UpdateStatement) 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<InputValueType>) {}
private fun createWithoutNotification(value: InputValueType): ObjectType { private fun createWithoutNotification(value: InputValueType): ObjectType {
return transaction(database) { return transaction(database) {
insert { insert(value, it) }.asObject insert { insert(value, it) }.asObject
} }
} }
override suspend fun create(vararg values: InputValueType): List<ObjectType> { override suspend fun create(values: List<InputValueType>): List<ObjectType> {
onBeforeCreate(*values) onBeforeCreate(values)
return transaction(db = database) { return transaction(db = database) {
values.map { value -> createWithoutNotification(value) } values.map { value -> createWithoutNotification(value) }
}.also { }.also {
@ -50,7 +50,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
} }
} }
protected open suspend fun onBeforeUpdate(vararg value: UpdatedValuePair<IdType, InputValueType>) {} protected open suspend fun onBeforeUpdate(value: List<UpdatedValuePair<IdType, InputValueType>>) {}
private fun updateWithoutNotification(id: IdType, value: InputValueType): ObjectType? { private fun updateWithoutNotification(id: IdType, value: InputValueType): ObjectType? {
return transaction(db = database) { return transaction(db = database) {
update( update(
@ -72,15 +72,15 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
} }
override suspend fun update(id: IdType, value: InputValueType): ObjectType? { override suspend fun update(id: IdType, value: InputValueType): ObjectType? {
onBeforeUpdate(id to value) onBeforeUpdate(listOf(id to value))
return updateWithoutNotification(id, value).also { return updateWithoutNotification(id, value).also {
if (it != null) { if (it != null) {
updateObjectsChannel.send(it) updateObjectsChannel.send(it)
} }
} }
} }
override suspend fun update(vararg values: UpdatedValuePair<IdType, InputValueType>): List<ObjectType> { override suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType> {
onBeforeUpdate(*values) onBeforeUpdate(values)
return ( return (
transaction(db = database) { transaction(db = database) {
values.map { (id, value) -> updateWithoutNotification(id, value) } values.map { (id, value) -> updateWithoutNotification(id, value) }
@ -93,9 +93,9 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
} }
} }
} }
protected open suspend fun onBeforeDelete(vararg ids: IdType) {} protected open suspend fun onBeforeDelete(ids: List<IdType>) {}
override suspend fun deleteById(vararg ids: IdType) { override suspend fun deleteById(ids: List<IdType>) {
onBeforeDelete(*ids) onBeforeDelete(ids)
transaction(db = database) { transaction(db = database) {
deleteWhere(null, null) { deleteWhere(null, null) {
selectByIds(ids) selectByIds(ids)

@ -2,15 +2,12 @@ package com.insanusmokrassar.postssystem.utils.repos.ktor.client
import com.insanusmokrassar.postssystem.ktor.* import com.insanusmokrassar.postssystem.ktor.*
import com.insanusmokrassar.postssystem.ktor.client.* 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.*
import com.insanusmokrassar.postssystem.utils.repos.ktor.common.* import com.insanusmokrassar.postssystem.utils.repos.ktor.common.*
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.* import kotlinx.serialization.builtins.*
import kotlinx.serialization.encodeToHexString
class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> ( class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> (
private val baseUrl: String, private val baseUrl: String,
@ -23,45 +20,47 @@ class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> (
private val listObjectsSerializer = ListSerializer(objectsSerializer) private val listObjectsSerializer = ListSerializer(objectsSerializer)
private val listInputSerializer = ListSerializer(inputsSerializer) private val listInputSerializer = ListSerializer(inputsSerializer)
private val listIdsSerializer = ListSerializer(idsSerializer) private val listIdsSerializer = ListSerializer(idsSerializer)
private val inputUpdateSerializer = TemporalInputObjectForUpdate.serializer( private val inputUpdateSerializer = PairSerializer(
idsSerializer, idsSerializer,
inputsSerializer inputsSerializer
) )
private val listInputUpdateSerializer = ListSerializer(inputUpdateSerializer) private val listInputUpdateSerializer = ListSerializer(inputUpdateSerializer)
override val newObjectsFlow: Flow<ObjectType> = client.createStandardWebsocketFlow( override val newObjectsFlow: Flow<ObjectType> = client.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, newObjectsFlowRouting) buildStandardUrl(baseUrl, newObjectsFlowRouting),
) { standardKtorSerialFormat.decodeFromByteArray(objectsSerializer, it) } deserializer = objectsSerializer
)
override val updatedObjectsFlow: Flow<ObjectType> = client.createStandardWebsocketFlow( override val updatedObjectsFlow: Flow<ObjectType> = client.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, updatedObjectsFlowRouting) buildStandardUrl(baseUrl, updatedObjectsFlowRouting),
) { standardKtorSerialFormat.decodeFromByteArray(objectsSerializer, it) } deserializer = objectsSerializer
)
override val deletedObjectsIdsFlow: Flow<IdType> = client.createStandardWebsocketFlow( override val deletedObjectsIdsFlow: Flow<IdType> = client.createStandardWebsocketFlow(
buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting) buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting),
) { standardKtorSerialFormat.decodeFromByteArray(idsSerializer, it) } deserializer = idsSerializer
)
override suspend fun create(values: List<InputValue>): List<ObjectType> = client.unipost(
override suspend fun create(vararg values: InputValue): List<ObjectType> = client.unipost(
buildStandardUrl(baseUrl, createRouting), buildStandardUrl(baseUrl, createRouting),
BodyPair(listInputSerializer, values.toList()), BodyPair(listInputSerializer, values),
listObjectsSerializer listObjectsSerializer
) )
override suspend fun update(id: IdType, value: InputValue): ObjectType? = client.unipost( override suspend fun update(id: IdType, value: InputValue): ObjectType? = client.unipost(
buildStandardUrl(baseUrl, updateRouting), buildStandardUrl(baseUrl, updateRouting),
BodyPair(inputUpdateSerializer, TemporalInputObjectForUpdate(id, value)), BodyPair(inputUpdateSerializer, id to value),
objectsNullableSerializer objectsNullableSerializer
) )
override suspend fun update(vararg values: UpdatedValuePair<IdType, InputValue>): List<ObjectType> = client.unipost( override suspend fun update(values: List<UpdatedValuePair<IdType, InputValue>>): List<ObjectType> = client.unipost(
buildStandardUrl(baseUrl, updateManyRouting), buildStandardUrl(baseUrl, updateManyRouting),
BodyPair(listInputUpdateSerializer, values.map { TemporalInputObjectForUpdate(it.first, it.second) }), BodyPair(listInputUpdateSerializer, values),
listObjectsSerializer listObjectsSerializer
) )
override suspend fun deleteById(vararg ids: IdType) = client.unipost( override suspend fun deleteById(ids: List<IdType>) = client.unipost(
buildStandardUrl(baseUrl, deleteByIdRouting), buildStandardUrl(baseUrl, deleteByIdRouting),
BodyPair(listIdsSerializer, ids.toList()), BodyPair(listIdsSerializer, ids),
Unit.serializer() Unit.serializer()
) )
} }

@ -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')
}
}
}
}

@ -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 <ObjectType, IdType> Route.configureReadStandardCrudRepoRoutes(
originalRepo: ReadStandardCRUDRepo<ObjectType, IdType>,
objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>,
idsSerializer: KSerializer<IdType>
) {
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)
)
}
}

@ -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 <ObjectType, IdType, InputValue> Route.configureStandardCrudRepoRoutes(
baseSubpart: String,
originalRepo: StandardCRUDRepo<ObjectType, IdType, InputValue>,
objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>,
inputsSerializer: KSerializer<InputValue>,
idsSerializer: KSerializer<IdType>
) {
route(baseSubpart) {
configureReadStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer)
configureWriteStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer)
}
}

@ -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 <ObjectType, IdType, InputValue> Route.configureWriteStandardCrudRepoRoutes(
originalRepo: WriteStandardCRUDRepo<ObjectType, IdType, InputValue>,
objectsSerializer: KSerializer<ObjectType>,
objectsNullableSerializer: KSerializer<ObjectType?>,
inputsSerializer: KSerializer<InputValue>,
idsSerializer: KSerializer<IdType>
) {
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
)
)
}
}