fully rewrite content
This commit is contained in:
parent
20e3fd6934
commit
5c1f5c0bba
@ -7,25 +7,25 @@ import dev.inmo.postssystem.core.post.*
|
||||
import dev.inmo.postssystem.core.post.repo.PostsRepo
|
||||
import dev.inmo.postssystem.core.publishing.*
|
||||
|
||||
class BusinessPostCreatingCase(
|
||||
private val postsRepo: PostsRepo,
|
||||
private val contentRepo: ContentRepo,
|
||||
private val publishingRegistrar: PublishingRegistrar,
|
||||
private val postKeyGenerator: PostKeyGenerator = { _, _ -> uuid4().toString() },
|
||||
private val publishingKeyReceiverGetter: PublishingKeyReceiverGetter
|
||||
) : PostCreatingCase {
|
||||
override suspend fun createPost(postContent: List<Content>, triggerId: TriggerId?): RegisteredPost? {
|
||||
val content = postContent.mapNotNull { contentRepo.registerContent(it) }
|
||||
val post = postsRepo.createPost(SimplePost(content.map { it.id })) ?: return null
|
||||
|
||||
triggerId ?.let {
|
||||
val key = postKeyGenerator(post.id, triggerId)
|
||||
|
||||
if (publishingRegistrar.registerTriggerForPost(key, post.id)) {
|
||||
publishingKeyReceiverGetter(it) ?.acceptKey(post.id, key)
|
||||
}
|
||||
}
|
||||
|
||||
return post
|
||||
}
|
||||
}
|
||||
//class BusinessPostCreatingCase(
|
||||
// private val postsRepo: PostsRepo,
|
||||
// private val contentRepo: ContentRepo,
|
||||
// private val publishingRegistrar: PublishingRegistrar,
|
||||
// private val postKeyGenerator: PostKeyGenerator = { _, _ -> uuid4().toString() },
|
||||
// private val publishingKeyReceiverGetter: PublishingKeyReceiverGetter
|
||||
//) : PostCreatingCase {
|
||||
// override suspend fun createPost(postContent: List<Content>, triggerId: TriggerId?): RegisteredPost? {
|
||||
// val content = postContent.mapNotNull { contentRepo.registerContent(it) }
|
||||
// val post = postsRepo.createPost(SimplePost(content.map { it.id })) ?: return null
|
||||
//
|
||||
// triggerId ?.let {
|
||||
// val key = postKeyGenerator(post.id, triggerId)
|
||||
//
|
||||
// if (publishingRegistrar.registerTriggerForPost(key, post.id)) {
|
||||
// publishingKeyReceiverGetter(it) ?.acceptKey(post.id, key)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return post
|
||||
// }
|
||||
//}
|
||||
|
@ -14,6 +14,7 @@ kotlin {
|
||||
|
||||
api "com.soywiz.korlibs.klock:klock:$klockVersion"
|
||||
api "dev.inmo:micro_utils.common:$microutils_version"
|
||||
api "dev.inmo:micro_utils.coroutines:$microutils_version"
|
||||
api "dev.inmo:micro_utils.repos.common:$microutils_version"
|
||||
api "dev.inmo:micro_utils.mime_types:$microutils_version"
|
||||
}
|
||||
|
@ -22,21 +22,7 @@ data class SpecialContent(
|
||||
val internalId: ContentId
|
||||
) : Content
|
||||
|
||||
@Serializable
|
||||
data class TextContent(
|
||||
val text: String
|
||||
) : Content
|
||||
|
||||
@Serializable
|
||||
data class BinaryContent(
|
||||
val mimeType: MimeType,
|
||||
val originalFileName: String,
|
||||
@Serializable(ByteArrayAllocatorSerializer::class)
|
||||
val dataAllocator: ByteArrayAllocator
|
||||
) : Content
|
||||
|
||||
val BinaryContent.isImage: Boolean
|
||||
get() = mimeType is KnownMimeTypes.Image
|
||||
|
||||
/**
|
||||
* Content which is already registered in database. Using its [id] you can retrieve all known
|
||||
|
@ -1,26 +1,12 @@
|
||||
package dev.inmo.postssystem.core.content.api
|
||||
package dev.inmo.postssystem.core.content.api.business
|
||||
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
import dev.inmo.micro_utils.repos.Repo
|
||||
import dev.inmo.micro_utils.repos.UpdatedValuePair
|
||||
import dev.inmo.postssystem.core.content.*
|
||||
import dev.inmo.postssystem.core.content.api.*
|
||||
import dev.inmo.postssystem.core.generateContentId
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
interface BusinessContentRepoReadHelpInterface : Repo {
|
||||
suspend fun getKeysByPagination(pagination: Pagination): PaginationResult<ContentId>
|
||||
suspend fun contains(contentId: ContentId): Boolean
|
||||
suspend fun getType(contentId: ContentId): AdapterType?
|
||||
suspend fun count(): Long
|
||||
}
|
||||
interface BusinessContentRepoWriteHelpInterface : Repo {
|
||||
suspend fun deleteContentId(contentId: ContentId)
|
||||
suspend fun saveType(contentId: ContentId, type: AdapterType): Boolean
|
||||
}
|
||||
interface BusinessContentRepoHelpInterface : BusinessContentRepoReadHelpInterface, BusinessContentRepoWriteHelpInterface
|
||||
|
||||
typealias AdapterType = String
|
||||
|
||||
interface BusinessContentRepoContentAdapter {
|
||||
val type: AdapterType
|
||||
suspend fun storeContent(contentId: ContentId, content: Content): Boolean
|
||||
@ -30,7 +16,7 @@ interface BusinessContentRepoContentAdapter {
|
||||
|
||||
class BusinessReadContentRepo(
|
||||
adapters: List<BusinessContentRepoContentAdapter>,
|
||||
private val helperRepo: BusinessContentRepoReadHelpInterface,
|
||||
private val helperRepo: BusinessContentRepoReadHelper,
|
||||
) : ReadContentRepo {
|
||||
private val adaptersMap: Map<String, BusinessContentRepoContentAdapter> = adapters.map {
|
||||
it.type to it
|
||||
@ -61,7 +47,7 @@ class BusinessReadContentRepo(
|
||||
|
||||
class BusinessWriteContentRepo(
|
||||
private val adapters: List<BusinessContentRepoContentAdapter>,
|
||||
private val helperRepo: BusinessContentRepoHelpInterface
|
||||
private val helperRepo: BusinessContentRepoHelper
|
||||
) : WriteContentRepo {
|
||||
private val adaptersMap = adapters.map { it.type to it }.toMap()
|
||||
private val _deletedObjectsIdsFlow = MutableSharedFlow<ContentId>()
|
||||
@ -110,7 +96,7 @@ class BusinessWriteContentRepo(
|
||||
|
||||
class BusinessContentRepo(
|
||||
adapters: List<BusinessContentRepoContentAdapter>,
|
||||
helperRepo: BusinessContentRepoHelpInterface
|
||||
helperRepo: BusinessContentRepoHelper
|
||||
) : ContentRepo, ReadContentRepo by BusinessReadContentRepo(
|
||||
adapters,
|
||||
helperRepo
|
@ -0,0 +1,59 @@
|
||||
package dev.inmo.postssystem.core.content.api.business
|
||||
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.postssystem.core.content.ContentId
|
||||
|
||||
typealias AdapterType = String
|
||||
|
||||
interface BusinessContentRepoReadHelper : Repo {
|
||||
suspend fun getKeysByPagination(pagination: Pagination): PaginationResult<ContentId>
|
||||
suspend fun contains(contentId: ContentId): Boolean
|
||||
suspend fun getType(contentId: ContentId): AdapterType?
|
||||
suspend fun count(): Long
|
||||
}
|
||||
interface BusinessContentRepoWriteHelper : Repo {
|
||||
suspend fun deleteContentId(contentId: ContentId)
|
||||
suspend fun saveType(contentId: ContentId, type: AdapterType): Boolean
|
||||
}
|
||||
interface BusinessContentRepoHelper : BusinessContentRepoReadHelper, BusinessContentRepoWriteHelper
|
||||
|
||||
class KeyValueBusinessContentRepoReadHelper(
|
||||
private val keyValueRepo: ReadStandardKeyValueRepo<ContentId, AdapterType>
|
||||
) : BusinessContentRepoReadHelper {
|
||||
override suspend fun getKeysByPagination(pagination: Pagination): PaginationResult<ContentId> = keyValueRepo.keys(pagination)
|
||||
override suspend fun contains(contentId: ContentId): Boolean = keyValueRepo.contains(contentId)
|
||||
override suspend fun getType(contentId: ContentId): AdapterType? = keyValueRepo.get(contentId)
|
||||
override suspend fun count(): Long = keyValueRepo.count()
|
||||
}
|
||||
|
||||
class KeyValueBusinessContentRepoWriteHelper(
|
||||
private val keyValueRepo: WriteStandardKeyValueRepo<ContentId, AdapterType>
|
||||
) : BusinessContentRepoWriteHelper {
|
||||
override suspend fun deleteContentId(contentId: ContentId) { keyValueRepo.unset(contentId) }
|
||||
|
||||
override suspend fun saveType(contentId: ContentId, type: AdapterType): Boolean {
|
||||
keyValueRepo.set(contentId, type)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class KeyValueBusinessContentRepoHelper(
|
||||
private val keyValueRepo: StandardKeyValueRepo<ContentId, AdapterType>
|
||||
) : BusinessContentRepoHelper, BusinessContentRepoReadHelper by KeyValueBusinessContentRepoReadHelper(
|
||||
keyValueRepo
|
||||
), BusinessContentRepoWriteHelper by KeyValueBusinessContentRepoWriteHelper(
|
||||
keyValueRepo
|
||||
)
|
||||
|
||||
fun StandardKeyValueRepo<ContentId, AdapterType>.asBusinessContentRepo(
|
||||
adapters: List<BusinessContentRepoContentAdapter>
|
||||
) = BusinessContentRepo(
|
||||
adapters,
|
||||
KeyValueBusinessContentRepoHelper(this)
|
||||
)
|
||||
|
||||
fun StandardKeyValueRepo<ContentId, AdapterType>.asBusinessContentRepo(
|
||||
vararg adapters: BusinessContentRepoContentAdapter
|
||||
) = asBusinessContentRepo(adapters.toList())
|
@ -0,0 +1,29 @@
|
||||
package dev.inmo.postssystem.core.content.api.business.content_adapters
|
||||
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.postssystem.core.content.Content
|
||||
import dev.inmo.postssystem.core.content.ContentId
|
||||
import dev.inmo.postssystem.core.content.api.business.AdapterType
|
||||
import dev.inmo.postssystem.core.content.api.business.BusinessContentRepoContentAdapter
|
||||
|
||||
class KeyValueBusinessContentRepoAdapter<T>(
|
||||
override val type: AdapterType,
|
||||
private val keyValueRepo: StandardKeyValueRepo<ContentId, T>,
|
||||
private val contentToData: suspend (Content) -> T?,
|
||||
private val dataToContent: suspend (T) -> Content
|
||||
) : BusinessContentRepoContentAdapter {
|
||||
override suspend fun storeContent(contentId: ContentId, content: Content): Boolean {
|
||||
keyValueRepo.set(contentId, contentToData(content) ?: return false)
|
||||
return true
|
||||
}
|
||||
|
||||
override suspend fun getContent(contentId: ContentId): Content? {
|
||||
return dataToContent(
|
||||
keyValueRepo.get(contentId) ?: return null
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun removeContent(contentId: ContentId) {
|
||||
keyValueRepo.unset(contentId)
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package dev.inmo.postssystem.core.content.api.business.content_adapters.binary
|
||||
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.postssystem.core.content.Content
|
||||
import dev.inmo.postssystem.core.content.ContentId
|
||||
import dev.inmo.postssystem.core.content.api.business.AdapterType
|
||||
import dev.inmo.postssystem.core.content.api.business.BusinessContentRepoContentAdapter
|
||||
import dev.inmo.postssystem.core.content.api.business.content_adapters.KeyValueBusinessContentRepoAdapter
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
private val format = Json { ignoreUnknownKeys = true }
|
||||
|
||||
class BinaryBusinessContentRepoContentAdapter(
|
||||
private val dataStore: KeyValueRepo<String, String>,
|
||||
private val filesStore: KeyValueRepo<String, ByteArray>,
|
||||
private val removeOnAbsentInOneOfStores: Boolean = false
|
||||
) : BusinessContentRepoContentAdapter {
|
||||
override val type: AdapterType
|
||||
get() = "binary"
|
||||
|
||||
override suspend fun storeContent(contentId: ContentId, content: Content): Boolean {
|
||||
(content as? BinaryContent) ?.also {
|
||||
filesStore.set(it.originalFileName, it.dataAllocator())
|
||||
dataStore.set(
|
||||
contentId,
|
||||
format.encodeToString(BinaryContent.serializer(), it.copy { ByteArray(0) })
|
||||
)
|
||||
} ?: return false
|
||||
return true
|
||||
}
|
||||
|
||||
override suspend fun getContent(contentId: ContentId): Content? {
|
||||
return filesStore.get(contentId) ?.let {
|
||||
val serializedData = dataStore.get(contentId)
|
||||
if (serializedData != null) {
|
||||
format.decodeFromString(BinaryContent.serializer(), serializedData).copy {
|
||||
it
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} ?: null.also {
|
||||
if (removeOnAbsentInOneOfStores) {
|
||||
filesStore.unset(contentId)
|
||||
dataStore.unset(contentId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun removeContent(contentId: ContentId) {
|
||||
filesStore.unset(contentId)
|
||||
dataStore.unset(contentId)
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package dev.inmo.postssystem.core.content.api.business.content_adapters.binary
|
||||
|
||||
import dev.inmo.micro_utils.common.ByteArrayAllocator
|
||||
import dev.inmo.micro_utils.common.ByteArrayAllocatorSerializer
|
||||
import dev.inmo.micro_utils.mime_types.KnownMimeTypes
|
||||
import dev.inmo.micro_utils.mime_types.MimeType
|
||||
import dev.inmo.postssystem.core.content.Content
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class BinaryContent(
|
||||
val mimeType: MimeType,
|
||||
val originalFileName: String,
|
||||
@Serializable(ByteArrayAllocatorSerializer::class)
|
||||
val dataAllocator: ByteArrayAllocator
|
||||
) : Content
|
||||
|
||||
val BinaryContent.isImage: Boolean
|
||||
get() = mimeType is KnownMimeTypes.Image
|
@ -0,0 +1,15 @@
|
||||
package dev.inmo.postssystem.core.content.api.business.content_adapters.text
|
||||
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.postssystem.core.content.ContentId
|
||||
import dev.inmo.postssystem.core.content.api.business.BusinessContentRepoContentAdapter
|
||||
import dev.inmo.postssystem.core.content.api.business.content_adapters.KeyValueBusinessContentRepoAdapter
|
||||
|
||||
class TextBusinessContentRepoContentAdapter(
|
||||
private val keyValueRepo: StandardKeyValueRepo<ContentId, String>
|
||||
) : BusinessContentRepoContentAdapter by KeyValueBusinessContentRepoAdapter(
|
||||
"regularText",
|
||||
keyValueRepo,
|
||||
{ (it as? TextContent) ?.text },
|
||||
{ TextContent(it) }
|
||||
)
|
@ -0,0 +1,9 @@
|
||||
package dev.inmo.postssystem.core.content.api.business.content_adapters.text
|
||||
|
||||
import dev.inmo.postssystem.core.content.Content
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class TextContent(
|
||||
val text: String
|
||||
) : Content
|
@ -1,11 +1,26 @@
|
||||
package dev.inmo.postssystem.core.api
|
||||
|
||||
import dev.inmo.micro_utils.common.ByteArrayAllocator
|
||||
import dev.inmo.micro_utils.mime_types.KnownMimeTypes
|
||||
import dev.inmo.postssystem.core.content.*
|
||||
import dev.inmo.postssystem.core.content.api.business.content_adapters.binary.BinaryContent
|
||||
import dev.inmo.postssystem.core.content.api.business.content_adapters.text.TextContent
|
||||
import dev.inmo.postssystem.core.generateContentId
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.modules.SerializersModule
|
||||
import kotlinx.serialization.modules.polymorphic
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
private val jsonFormat = Json {
|
||||
serializersModule = SerializersModule {
|
||||
polymorphic(Content::class) {
|
||||
subclass(TextContent::class, TextContent.serializer())
|
||||
subclass(BinaryContent::class, BinaryContent.serializer())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ContentSerialization {
|
||||
private val simpleTextTestEntries = 10
|
||||
private val simpleSpecialTestEntries = 10
|
||||
@ -15,7 +30,9 @@ class ContentSerialization {
|
||||
val contents = (0 until simpleTextTestEntries).map {
|
||||
TextContent("Example$it")
|
||||
} + (0 until simpleSpecialTestEntries).map {
|
||||
SpecialContent("$it")
|
||||
BinaryContent(KnownMimeTypes.Any, "$it.example") {
|
||||
byteArrayOf(it.toByte())
|
||||
}
|
||||
}
|
||||
|
||||
val registeredContentFakes = contents.map { content ->
|
||||
@ -26,13 +43,33 @@ class ContentSerialization {
|
||||
}
|
||||
|
||||
val stringified = registeredContentFakes.map {
|
||||
Json.encodeToString(RegisteredContent.serializer(), it)
|
||||
jsonFormat.encodeToString(RegisteredContent.serializer(), it)
|
||||
}
|
||||
|
||||
val parsed = stringified.map {
|
||||
Json.decodeFromString(RegisteredContent.serializer(), it)
|
||||
jsonFormat.decodeFromString(RegisteredContent.serializer(), it)
|
||||
}
|
||||
|
||||
parsed.forEachIndexed { i, registeredContent -> assertEquals(registeredContentFakes[i], registeredContent) }
|
||||
parsed.forEachIndexed { i, registeredContent ->
|
||||
val content = registeredContent.content
|
||||
assertEquals(registeredContentFakes[i].id, registeredContent.id)
|
||||
when (content) {
|
||||
is TextContent -> assertEquals(registeredContentFakes[i].content, content)
|
||||
is BinaryContent -> {
|
||||
val expectedContent = registeredContentFakes[i].content as BinaryContent
|
||||
val fakeByteArrayAllocator: ByteArrayAllocator = { byteArrayOf() }
|
||||
assertEquals(
|
||||
expectedContent.copy(dataAllocator = fakeByteArrayAllocator),
|
||||
content.copy(dataAllocator = fakeByteArrayAllocator)
|
||||
)
|
||||
val expectedData = expectedContent.dataAllocator()
|
||||
val parsedData = content.dataAllocator()
|
||||
assertEquals(expectedData.size, parsedData.size)
|
||||
expectedData.withIndex().forEach { (i, byte) ->
|
||||
assertEquals(byte, parsedData[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,79 @@
|
||||
package dev.inmo.postssystem.core.content.api.business.content_adapters.binary
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.doOutsideOfCoroutine
|
||||
import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
import dev.inmo.micro_utils.repos.KeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.set
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.io.File
|
||||
|
||||
class FilesStoreRepoAdapter(
|
||||
private val filesRepo: KeyValueRepo<String, File>,
|
||||
private val temporalFilesFolder: File
|
||||
) : KeyValueRepo<String, ByteArray> {
|
||||
private val File.asByteArray
|
||||
get() = readBytes()
|
||||
override val onNewValue: Flow<Pair<String, ByteArray>> = filesRepo.onNewValue.map { (filename, file) ->
|
||||
filename to file.asByteArray
|
||||
}
|
||||
override val onValueRemoved: Flow<String> = filesRepo.onValueRemoved
|
||||
|
||||
init {
|
||||
temporalFilesFolder.mkdirs()
|
||||
}
|
||||
|
||||
override suspend fun contains(key: String): Boolean = filesRepo.contains(key)
|
||||
|
||||
override suspend fun count(): Long = filesRepo.count()
|
||||
|
||||
override suspend fun get(k: String): ByteArray? = filesRepo.get(k) ?.asByteArray
|
||||
|
||||
override suspend fun keys(
|
||||
v: ByteArray,
|
||||
pagination: Pagination,
|
||||
reversed: Boolean
|
||||
): PaginationResult<String> = emptyPaginationResult()
|
||||
|
||||
override suspend fun keys(
|
||||
pagination: Pagination,
|
||||
reversed: Boolean
|
||||
): PaginationResult<String> = filesRepo.keys(pagination, reversed)
|
||||
|
||||
override suspend fun set(toSet: Map<String, ByteArray>) {
|
||||
supervisorScope {
|
||||
toSet.map { (filename, bytes) ->
|
||||
launch {
|
||||
safelyWithoutExceptions {
|
||||
val file = File(temporalFilesFolder, filename).also {
|
||||
it.delete()
|
||||
doOutsideOfCoroutine {
|
||||
it.createNewFile()
|
||||
it.writeBytes(bytes)
|
||||
}
|
||||
}
|
||||
filesRepo.set(filename, file)
|
||||
doOutsideOfCoroutine { file.delete() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}.joinAll()
|
||||
}
|
||||
|
||||
override suspend fun unset(toUnset: List<String>) = filesRepo.unset(toUnset)
|
||||
|
||||
override suspend fun values(
|
||||
pagination: Pagination,
|
||||
reversed: Boolean
|
||||
): PaginationResult<ByteArray> = filesRepo.values(pagination, reversed).let {
|
||||
PaginationResult(
|
||||
it.page,
|
||||
it.pagesNumber,
|
||||
it.results.map { it.readBytes() },
|
||||
it.size
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
package dev.inmo.postssystem.core.exposed
|
||||
|
||||
import dev.inmo.postssystem.core.content.*
|
||||
import dev.inmo.postssystem.core.content.api.ContentRepo
|
||||
import dev.inmo.postssystem.core.exposed.content.*
|
||||
import dev.inmo.postssystem.core.generateContentId
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
import kotlinx.coroutines.channels.BroadcastChannel
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
private val Content.type
|
||||
get() = when (this) {
|
||||
is TextContent -> "text"
|
||||
is BinaryContent -> "binary"
|
||||
is SpecialContent -> "special"
|
||||
}
|
||||
|
||||
private class ContentRepoDatabaseTable(
|
||||
private val database: Database,
|
||||
tableName: String = "",
|
||||
private val textHolder: ContentHolderRepo<TextContent>,
|
||||
private val binaryHolder: ContentHolderRepo<BinaryContent>,
|
||||
private val specialHolder: ContentHolderRepo<SpecialContent>
|
||||
) : Table(tableName), ContentRepo, ContentHolderRepo<Content> {
|
||||
internal val idColumn = text("_id")
|
||||
internal val typeColumn = text("type")
|
||||
|
||||
init {
|
||||
transaction(
|
||||
db = database
|
||||
) {
|
||||
SchemaUtils.createMissingTablesAndColumns(this@ContentRepoDatabaseTable)
|
||||
}
|
||||
}
|
||||
|
||||
private val contentCreatedBroadcastChannel = BroadcastChannel<RegisteredContent>(Channel.BUFFERED)
|
||||
private val contentDeletedBroadcastChannel = BroadcastChannel<RegisteredContent>(Channel.BUFFERED)
|
||||
override val contentCreatedFlow: Flow<RegisteredContent> = contentCreatedBroadcastChannel.asFlow()
|
||||
override val contentDeletedFlow: Flow<RegisteredContent> = contentDeletedBroadcastChannel.asFlow()
|
||||
|
||||
private val String.holder
|
||||
get() = when (this) {
|
||||
"text" -> textHolder
|
||||
"binary" -> binaryHolder
|
||||
"special" -> specialHolder
|
||||
else -> null
|
||||
}
|
||||
|
||||
override suspend fun putContent(id: ContentId, content: Content) {
|
||||
when (content) {
|
||||
is TextContent -> textHolder.putContent(id, content)
|
||||
is BinaryContent -> binaryHolder.putContent(id, content)
|
||||
is SpecialContent -> specialHolder.putContent(id, content)
|
||||
}
|
||||
}
|
||||
override suspend fun getContent(id: ContentId): Content? = transaction(
|
||||
db = database
|
||||
) {
|
||||
select { idColumn.eq(id) }.limit(1).firstOrNull() ?.get(typeColumn)
|
||||
} ?.holder ?.getContent(id)
|
||||
|
||||
override suspend fun removeContent(id: ContentId) {
|
||||
transaction(
|
||||
db = database
|
||||
) {
|
||||
select { idColumn.eq(id) }.limit(1).firstOrNull() ?.get(typeColumn)
|
||||
} ?.holder ?.removeContent(id)
|
||||
}
|
||||
|
||||
override suspend fun registerContent(content: Content): RegisteredContent? {
|
||||
val id = generateContentId()
|
||||
val type = content.type
|
||||
return transaction(
|
||||
db = database
|
||||
) {
|
||||
insert {
|
||||
it[idColumn] = id
|
||||
it[typeColumn] = type
|
||||
}.getOrNull(idColumn)
|
||||
} ?.let { id ->
|
||||
putContent(id, content)
|
||||
RegisteredContent(
|
||||
id,
|
||||
content
|
||||
)
|
||||
} ?.also {
|
||||
contentCreatedBroadcastChannel.send(it)
|
||||
} ?: null.also {
|
||||
removeContent(id)
|
||||
}
|
||||
}
|
||||
override suspend fun deleteContent(id: ContentId): Boolean {
|
||||
val content = getContentById(id) ?: return false
|
||||
return transaction(
|
||||
db = database
|
||||
) {
|
||||
deleteWhere {
|
||||
idColumn.eq(id)
|
||||
} > 0
|
||||
}.also {
|
||||
if (it) {
|
||||
removeContent(id)
|
||||
contentDeletedBroadcastChannel.send(content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ResultRow.asRegisteredContent(content: Content): RegisteredContent? = get(idColumn).let {
|
||||
RegisteredContent(
|
||||
it,
|
||||
content
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getContentsIds(): Set<ContentId> {
|
||||
return transaction(
|
||||
db = database
|
||||
) {
|
||||
selectAll().map { it[idColumn] }
|
||||
}.toSet()
|
||||
}
|
||||
override suspend fun getContentById(id: ContentId): RegisteredContent? {
|
||||
val content = getContent(id) ?: return null
|
||||
return transaction(
|
||||
db = database
|
||||
) {
|
||||
select { idColumn.eq(id) }.limit(1).firstOrNull() ?.asRegisteredContent(content)
|
||||
}
|
||||
}
|
||||
override suspend fun getContentByPagination(pagination: Pagination): PaginationResult<RegisteredContent> {
|
||||
return transaction(
|
||||
db = database
|
||||
) {
|
||||
selectAll().count() to selectAll().paginate(pagination).map { it[idColumn] }
|
||||
}.let { (count, results) ->
|
||||
results.mapNotNull { RegisteredContent(it, getContent(it) ?: return@mapNotNull null) }.createPaginationResult(
|
||||
pagination,
|
||||
count
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ExposedContentRepo (
|
||||
database: Database,
|
||||
tableName: String = "",
|
||||
textHolder: ContentHolderRepo<TextContent> = TextContentHolderRepo(database),
|
||||
binaryHolder: ContentHolderRepo<BinaryContent> = BinaryContentHolderRepo(database),
|
||||
specialHolder: ContentHolderRepo<SpecialContent> = SpecialContentHolderRepo(database)
|
||||
) : ContentRepo by ContentRepoDatabaseTable(database, tableName, textHolder, binaryHolder, specialHolder)
|
@ -1,67 +0,0 @@
|
||||
package dev.inmo.postssystem.core.exposed.content
|
||||
|
||||
import dev.inmo.postssystem.core.content.BinaryContent
|
||||
import dev.inmo.postssystem.core.content.ContentId
|
||||
import dev.inmo.micro_utils.mime_types.mimeType
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.statements.api.ExposedBlob
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
private class BinaryContentHolderRepoTable(
|
||||
private val database: Database
|
||||
) : ContentHolderRepo<BinaryContent>, Table() {
|
||||
private val idColumn = text("id")
|
||||
private val dataColumn = blob("data")
|
||||
private val mimeColumn = text("mimeType")
|
||||
private val originalFileNameColumn = text("filename")
|
||||
override val primaryKey: PrimaryKey = PrimaryKey(idColumn)
|
||||
|
||||
init {
|
||||
transaction (
|
||||
db = database
|
||||
) {
|
||||
SchemaUtils.createMissingTablesAndColumns(this@BinaryContentHolderRepoTable)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getContent(id: ContentId): BinaryContent? = transaction (
|
||||
db = database
|
||||
) {
|
||||
select {
|
||||
idColumn.eq(id)
|
||||
}.limit(1).firstOrNull() ?.let {
|
||||
val bytes = it[dataColumn].bytes
|
||||
BinaryContent(
|
||||
mimeType(it[mimeColumn]),
|
||||
it[originalFileNameColumn]
|
||||
) {
|
||||
bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun removeContent(id: ContentId) {
|
||||
transaction(
|
||||
db = database
|
||||
) {
|
||||
deleteWhere { idColumn.eq(id) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun putContent(id: ContentId, content: BinaryContent) {
|
||||
transaction(
|
||||
db = database
|
||||
) {
|
||||
insert {
|
||||
it[idColumn] = id
|
||||
it[originalFileNameColumn] = content.originalFileName
|
||||
it[mimeColumn] = content.mimeType.raw
|
||||
it[dataColumn] = ExposedBlob(content.dataAllocator())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BinaryContentHolderRepo(
|
||||
database: Database
|
||||
) : ContentHolderRepo<BinaryContent> by BinaryContentHolderRepoTable(database)
|
@ -1,10 +0,0 @@
|
||||
package dev.inmo.postssystem.core.exposed.content
|
||||
|
||||
import dev.inmo.postssystem.core.content.Content
|
||||
import dev.inmo.postssystem.core.content.ContentId
|
||||
|
||||
interface ContentHolderRepo<T : Content> {
|
||||
suspend fun getContent(id: ContentId) : T?
|
||||
suspend fun removeContent(id: ContentId)
|
||||
suspend fun putContent(id: ContentId, content: T)
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
package dev.inmo.postssystem.core.exposed.content
|
||||
|
||||
import dev.inmo.postssystem.core.content.ContentId
|
||||
import dev.inmo.postssystem.core.content.SpecialContent
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
private class SpecialContentHolderRepoTable(
|
||||
private val database: Database
|
||||
) : ContentHolderRepo<SpecialContent>, Table() {
|
||||
private val idColumn = text("id")
|
||||
private val internalIdColumn = text("internalId")
|
||||
override val primaryKey: PrimaryKey = PrimaryKey(idColumn)
|
||||
|
||||
init {
|
||||
transaction(
|
||||
db = database
|
||||
) {
|
||||
SchemaUtils.createMissingTablesAndColumns(this@SpecialContentHolderRepoTable)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getContent(id: ContentId): SpecialContent? = transaction(
|
||||
db = database
|
||||
) {
|
||||
select {
|
||||
idColumn.eq(id)
|
||||
}.limit(1).firstOrNull() ?.get(internalIdColumn) ?.let {
|
||||
SpecialContent(it)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun removeContent(id: ContentId) {
|
||||
transaction(
|
||||
db = database
|
||||
) {
|
||||
deleteWhere { idColumn.eq(id) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun putContent(id: ContentId, content: SpecialContent) {
|
||||
transaction(
|
||||
db = database
|
||||
) {
|
||||
insert {
|
||||
it[idColumn] = id
|
||||
it[internalIdColumn] = content.internalId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SpecialContentHolderRepo(
|
||||
database: Database
|
||||
) : ContentHolderRepo<SpecialContent> by SpecialContentHolderRepoTable(database)
|
@ -1,55 +0,0 @@
|
||||
package dev.inmo.postssystem.core.exposed.content
|
||||
|
||||
import dev.inmo.postssystem.core.content.ContentId
|
||||
import dev.inmo.postssystem.core.content.TextContent
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
private class TextContentHolderRepoTable(
|
||||
private val database: Database
|
||||
) : ContentHolderRepo<TextContent>, Table() {
|
||||
private val idColumn = text("id")
|
||||
private val textColumn = text("text")
|
||||
override val primaryKey: PrimaryKey = PrimaryKey(idColumn)
|
||||
|
||||
init {
|
||||
transaction(
|
||||
db = database
|
||||
) {
|
||||
SchemaUtils.createMissingTablesAndColumns(this@TextContentHolderRepoTable)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getContent(id: ContentId): TextContent? = transaction(
|
||||
db = database
|
||||
) {
|
||||
select {
|
||||
idColumn.eq(id)
|
||||
}.limit(1).firstOrNull() ?.get(textColumn) ?.let {
|
||||
TextContent(it)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun removeContent(id: ContentId) {
|
||||
transaction(
|
||||
db = database
|
||||
) {
|
||||
deleteWhere { idColumn.eq(id) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun putContent(id: ContentId, content: TextContent) {
|
||||
transaction(
|
||||
db = database
|
||||
) {
|
||||
insert {
|
||||
it[idColumn] = id
|
||||
it[textColumn] = content.text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TextContentHolderRepo(
|
||||
database: Database
|
||||
) : ContentHolderRepo<TextContent> by TextContentHolderRepoTable(database)
|
@ -1,7 +1,15 @@
|
||||
package dev.inmo.postssystem.core.exposed
|
||||
|
||||
import dev.inmo.postssystem.core.content.TextContent
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import dev.inmo.micro_utils.repos.create
|
||||
import dev.inmo.micro_utils.repos.deleteById
|
||||
import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedKeyValueRepo
|
||||
import dev.inmo.postssystem.core.content.ContentId
|
||||
import dev.inmo.postssystem.core.content.api.business.AdapterType
|
||||
import dev.inmo.postssystem.core.content.api.business.asBusinessContentRepo
|
||||
import dev.inmo.postssystem.core.content.api.business.content_adapters.text.TextBusinessContentRepoContentAdapter
|
||||
import dev.inmo.postssystem.core.content.api.business.content_adapters.text.TextContent
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.first
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.jetbrains.exposed.sql.transactions.transactionManager
|
||||
import java.io.File
|
||||
@ -25,33 +33,49 @@ class ExposedContentRepoCommonTests {
|
||||
it.delete()
|
||||
it.deleteOnExit()
|
||||
}
|
||||
ExposedContentRepo(
|
||||
Database.Companion.connect("jdbc:sqlite:$it", driver = "org.sqlite.JDBC").also {
|
||||
val database = Database.Companion.connect("jdbc:sqlite:$it", driver = "org.sqlite.JDBC").also {
|
||||
it.transactionManager.defaultIsolationLevel = Connection.TRANSACTION_SERIALIZABLE
|
||||
}
|
||||
ExposedKeyValueRepo<ContentId, AdapterType>(
|
||||
database,
|
||||
{ text("contentId") },
|
||||
{ text("adapterType") },
|
||||
"ContentRepo"
|
||||
).asBusinessContentRepo(
|
||||
TextBusinessContentRepoContentAdapter(
|
||||
ExposedKeyValueRepo<ContentId, String>(
|
||||
database,
|
||||
{ text("contentId") },
|
||||
{ text("text") },
|
||||
"TextContentRepo"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val results = apis.mapIndexed { i, api ->
|
||||
val content = runBlocking { api.registerContent(TextContent(i.toString())) }
|
||||
assert(content != null)
|
||||
val ids = runBlocking { api.getContentsIds() }
|
||||
assertEquals(ids.size, 1)
|
||||
content!!
|
||||
val expectedContent = TextContent(i.toString())
|
||||
val contents = runBlocking { api.create(TextContent(i.toString())) }
|
||||
val idsCount = runBlocking { api.count() }
|
||||
assertEquals(idsCount, 1)
|
||||
assert(contents.isNotEmpty())
|
||||
assertEquals(
|
||||
expectedContent,
|
||||
contents.first().content
|
||||
)
|
||||
contents.first()
|
||||
}
|
||||
|
||||
results.forEachIndexed { i, content ->
|
||||
apis.forEachIndexed { j, api ->
|
||||
assert(
|
||||
runBlocking {
|
||||
api.getContentById(content.id) == (if (i != j) null else content)
|
||||
api.getById(content.id) == (if (i != j) null else content)
|
||||
}
|
||||
)
|
||||
assert(
|
||||
runBlocking {
|
||||
api.deleteContent(content.id) == (i == j)
|
||||
api.deleteById(content.id)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,23 +5,23 @@ import dev.inmo.postssystem.core.ktor.contentRootRoute
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.features.websocket.WebSockets
|
||||
|
||||
class ContentRepoKtorClient private constructor(
|
||||
readContentRepo: ReadContentRepo,
|
||||
writeContentRepo: WriteContentRepo
|
||||
) : ContentRepo, ReadContentRepo by readContentRepo, WriteContentRepo by writeContentRepo {
|
||||
constructor(
|
||||
baseUrl: String,
|
||||
client: HttpClient = HttpClient {
|
||||
install(WebSockets)
|
||||
}
|
||||
) : this(
|
||||
ReadContentRepoKtorClient(
|
||||
"$baseUrl/$contentRootRoute",
|
||||
client
|
||||
),
|
||||
WriteContentRepoKtorClient(
|
||||
"$baseUrl/$contentRootRoute",
|
||||
client
|
||||
)
|
||||
)
|
||||
}
|
||||
//class ContentRepoKtorClient private constructor(
|
||||
// readContentRepo: ReadContentRepo,
|
||||
// writeContentRepo: WriteContentRepo
|
||||
//) : ContentRepo, ReadContentRepo by readContentRepo, WriteContentRepo by writeContentRepo {
|
||||
// constructor(
|
||||
// baseUrl: String,
|
||||
// client: HttpClient = HttpClient {
|
||||
// install(WebSockets)
|
||||
// }
|
||||
// ) : this(
|
||||
// ReadContentRepoKtorClient(
|
||||
// "$baseUrl/$contentRootRoute",
|
||||
// client
|
||||
// ),
|
||||
// WriteContentRepoKtorClient(
|
||||
// "$baseUrl/$contentRootRoute",
|
||||
// client
|
||||
// )
|
||||
// )
|
||||
//}
|
||||
|
@ -12,23 +12,23 @@ import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.get
|
||||
import kotlinx.serialization.builtins.nullable
|
||||
|
||||
class ReadContentRepoKtorClient(
|
||||
private val baseUrl: String,
|
||||
private val client: HttpClient = HttpClient()
|
||||
) : ReadContentRepo {
|
||||
override suspend fun getContentsIds(): Set<ContentId> = client.get<ByteArray>(
|
||||
"$baseUrl/$getContentsIdsRoute"
|
||||
).let {
|
||||
standardKtorSerialFormat.decodeFromByteArray(contentIdsSerializer, it)
|
||||
}
|
||||
|
||||
override suspend fun getContentById(id: ContentId): RegisteredContent? = client.uniget(
|
||||
"$baseUrl/$getContentByIdRoute/$id",
|
||||
RegisteredContent.serializer().nullable
|
||||
)
|
||||
|
||||
override suspend fun getContentByPagination(pagination: Pagination): PaginationResult<RegisteredContent> = client.uniget(
|
||||
"$baseUrl/$getContentByPaginationRoute".includeQueryParams(pagination.asUrlQueryParts),
|
||||
registeredContentPaginationResultSerializer
|
||||
)
|
||||
}
|
||||
//class ReadContentRepoKtorClient(
|
||||
// private val baseUrl: String,
|
||||
// private val client: HttpClient = HttpClient()
|
||||
//) : ReadContentRepo {
|
||||
// override suspend fun getContentsIds(): Set<ContentId> = client.get<ByteArray>(
|
||||
// "$baseUrl/$getContentsIdsRoute"
|
||||
// ).let {
|
||||
// standardKtorSerialFormat.decodeFromByteArray(contentIdsSerializer, it)
|
||||
// }
|
||||
//
|
||||
// override suspend fun getContentById(id: ContentId): RegisteredContent? = client.uniget(
|
||||
// "$baseUrl/$getContentByIdRoute/$id",
|
||||
// RegisteredContent.serializer().nullable
|
||||
// )
|
||||
//
|
||||
// override suspend fun getContentByPagination(pagination: Pagination): PaginationResult<RegisteredContent> = client.uniget(
|
||||
// "$baseUrl/$getContentByPaginationRoute".includeQueryParams(pagination.asUrlQueryParts),
|
||||
// registeredContentPaginationResultSerializer
|
||||
// )
|
||||
//}
|
@ -9,29 +9,29 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.serialization.builtins.nullable
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
|
||||
class WriteContentRepoKtorClient(
|
||||
private val baseUrl: String,
|
||||
private val client: HttpClient = HttpClient()
|
||||
) : WriteContentRepo {
|
||||
override val contentCreatedFlow: Flow<RegisteredContent> = client.createStandardWebsocketFlow(
|
||||
"$baseUrl/$contentCreatedFlowRoute",
|
||||
deserializer = RegisteredContent.serializer()
|
||||
)
|
||||
|
||||
override val contentDeletedFlow: Flow<RegisteredContent> = client.createStandardWebsocketFlow(
|
||||
"$baseUrl/$contentDeletedFlowRoute",
|
||||
deserializer = RegisteredContent.serializer()
|
||||
)
|
||||
|
||||
override suspend fun registerContent(content: Content): RegisteredContent? = client.unipost(
|
||||
"$baseUrl/$registerContentRoute",
|
||||
BodyPair(Content.serializer(), content),
|
||||
RegisteredContent.serializer().nullable
|
||||
)
|
||||
|
||||
override suspend fun deleteContent(id: ContentId): Boolean = client.unipost(
|
||||
"$baseUrl/$deleteContentRoute",
|
||||
BodyPair(ContentId.serializer(), id),
|
||||
Boolean.serializer()
|
||||
)
|
||||
}
|
||||
//class WriteContentRepoKtorClient(
|
||||
// private val baseUrl: String,
|
||||
// private val client: HttpClient = HttpClient()
|
||||
//) : WriteContentRepo {
|
||||
// override val contentCreatedFlow: Flow<RegisteredContent> = client.createStandardWebsocketFlow(
|
||||
// "$baseUrl/$contentCreatedFlowRoute",
|
||||
// deserializer = RegisteredContent.serializer()
|
||||
// )
|
||||
//
|
||||
// override val contentDeletedFlow: Flow<RegisteredContent> = client.createStandardWebsocketFlow(
|
||||
// "$baseUrl/$contentDeletedFlowRoute",
|
||||
// deserializer = RegisteredContent.serializer()
|
||||
// )
|
||||
//
|
||||
// override suspend fun registerContent(content: Content): RegisteredContent? = client.unipost(
|
||||
// "$baseUrl/$registerContentRoute",
|
||||
// BodyPair(Content.serializer(), content),
|
||||
// RegisteredContent.serializer().nullable
|
||||
// )
|
||||
//
|
||||
// override suspend fun deleteContent(id: ContentId): Boolean = client.unipost(
|
||||
// "$baseUrl/$deleteContentRoute",
|
||||
// BodyPair(ContentId.serializer(), id),
|
||||
// Boolean.serializer()
|
||||
// )
|
||||
//}
|
@ -1,26 +0,0 @@
|
||||
package dev.inmo.postssystem.core.ktor.server.content
|
||||
|
||||
import dev.inmo.postssystem.core.content.api.ContentRepo
|
||||
import dev.inmo.postssystem.core.ktor.contentRootRoute
|
||||
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
|
||||
import io.ktor.routing.Route
|
||||
import io.ktor.routing.route
|
||||
|
||||
fun Route.configureContentRepoRoutes(
|
||||
proxyTo: ContentRepo
|
||||
) {
|
||||
route(
|
||||
contentRootRoute
|
||||
) {
|
||||
configureReadContentRepoRoutes(proxyTo)
|
||||
configureWriteContentRepoRoutes(proxyTo)
|
||||
}
|
||||
}
|
||||
|
||||
class ContentRepoRoutingConfigurator(
|
||||
private val proxyTo: ContentRepo
|
||||
) : ApplicationRoutingConfigurator.Element {
|
||||
override fun Route.invoke() {
|
||||
configureContentRepoRoutes(proxyTo)
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package dev.inmo.postssystem.core.ktor.server.content
|
||||
|
||||
import dev.inmo.postssystem.core.content.ContentId
|
||||
import dev.inmo.postssystem.core.content.RegisteredContent
|
||||
import dev.inmo.postssystem.core.content.api.ReadContentRepo
|
||||
import dev.inmo.postssystem.core.ktor.*
|
||||
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
|
||||
import dev.inmo.micro_utils.ktor.server.getParameterOrSendError
|
||||
import dev.inmo.micro_utils.ktor.server.unianswer
|
||||
import dev.inmo.micro_utils.pagination.extractPagination
|
||||
import io.ktor.application.call
|
||||
import io.ktor.routing.Route
|
||||
import io.ktor.routing.get
|
||||
import kotlinx.serialization.builtins.nullable
|
||||
|
||||
fun Route.configureReadContentRepoRoutes(
|
||||
proxyTo: ReadContentRepo
|
||||
) {
|
||||
get(getContentsIdsRoute) {
|
||||
call.unianswer(
|
||||
contentIdsSerializer,
|
||||
proxyTo.getContentsIds()
|
||||
)
|
||||
}
|
||||
get("$getContentByIdRoute/{id}") {
|
||||
val id: ContentId = call.getParameterOrSendError("id") ?: return@get
|
||||
|
||||
call.unianswer(
|
||||
RegisteredContent.serializer().nullable,
|
||||
proxyTo.getContentById(id)
|
||||
)
|
||||
}
|
||||
get(getContentByPaginationRoute) {
|
||||
val pagination = call.request.queryParameters.extractPagination
|
||||
|
||||
call.unianswer(
|
||||
registeredContentPaginationResultSerializer,
|
||||
proxyTo.getContentByPagination(pagination)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ReadContentRepoRoutingConfigurator(
|
||||
private val proxyTo: ReadContentRepo
|
||||
) : ApplicationRoutingConfigurator.Element {
|
||||
override fun Route.invoke() {
|
||||
configureReadContentRepoRoutes(proxyTo)
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
package dev.inmo.postssystem.core.ktor.server.content
|
||||
|
||||
import dev.inmo.postssystem.core.content.*
|
||||
import dev.inmo.postssystem.core.content.api.WriteContentRepo
|
||||
import dev.inmo.postssystem.core.ktor.*
|
||||
import dev.inmo.micro_utils.ktor.server.*
|
||||
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
|
||||
import io.ktor.application.call
|
||||
import io.ktor.routing.Route
|
||||
import io.ktor.routing.post
|
||||
import kotlinx.serialization.builtins.nullable
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
|
||||
fun Route.configureWriteContentRepoRoutes(
|
||||
proxyTo: WriteContentRepo
|
||||
) {
|
||||
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)
|
||||
call.unianswer(
|
||||
RegisteredContent.serializer().nullable,
|
||||
registered
|
||||
)
|
||||
}
|
||||
post(deleteContentRoute) {
|
||||
val contentId = call.uniload(ContentId.serializer())
|
||||
val isDeleted = proxyTo.deleteContent(contentId)
|
||||
call.unianswer(
|
||||
Boolean.serializer(),
|
||||
isDeleted
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class WriteContentRepoRoutingConfigurator(
|
||||
private val proxyTo: WriteContentRepo
|
||||
) : ApplicationRoutingConfigurator.Element {
|
||||
override fun Route.invoke() {
|
||||
configureWriteContentRepoRoutes(proxyTo)
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ uuidVersion=0.2.3
|
||||
exposed_version=0.28.1
|
||||
test_sqlite_version=3.32.3.2
|
||||
|
||||
microutils_version=0.4.5
|
||||
microutils_version=0.4.6
|
||||
|
||||
javax_activation_version=1.1.1
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user