add crud repo server and change a lot of different things

This commit is contained in:
InsanusMokrassar 2020-08-25 15:55:47 +06:00
parent 14d6915282
commit b94417b77d
16 changed files with 339 additions and 77 deletions

View File

@ -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",

View File

@ -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",

View File

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

View File

@ -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(

View File

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

View File

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

View File

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

View File

@ -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 {

View File

@ -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',

View File

@ -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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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