diff --git a/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/Content.kt b/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/Content.kt index 68a0bdde..631f0c3b 100644 --- a/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/Content.kt +++ b/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/Content.kt @@ -11,8 +11,7 @@ typealias ContentId = String /** * Content which is planned to be registered in database */ -@Serializable -sealed class Content +interface Content /** * It is content, which was added by some external source to use inside of some plugins. For example, you can use @@ -21,12 +20,12 @@ sealed class Content @Serializable data class SpecialContent( val internalId: ContentId -) : Content() +) : Content @Serializable data class TextContent( val text: String -) : Content() +) : Content @Serializable data class BinaryContent( @@ -34,7 +33,7 @@ data class BinaryContent( val originalFileName: String, @Serializable(ByteArrayAllocatorSerializer::class) val dataAllocator: ByteArrayAllocator -) : Content() +) : Content val BinaryContent.isImage: Boolean get() = mimeType is KnownMimeTypes.Image diff --git a/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/api/BusinessContentRepo.kt b/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/api/BusinessContentRepo.kt new file mode 100644 index 00000000..564d8968 --- /dev/null +++ b/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/api/BusinessContentRepo.kt @@ -0,0 +1,120 @@ +package dev.inmo.postssystem.core.content.api + +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.generateContentId +import kotlinx.coroutines.flow.* + +interface BusinessContentRepoReadHelpInterface : Repo { + suspend fun getKeysByPagination(pagination: Pagination): PaginationResult + 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 + suspend fun getContent(contentId: ContentId): Content? + suspend fun removeContent(contentId: ContentId) +} + +class BusinessReadContentRepo( + adapters: List, + private val helperRepo: BusinessContentRepoReadHelpInterface, +) : ReadContentRepo { + private val adaptersMap: Map = adapters.map { + it.type to it + }.toMap() + override suspend fun contains(id: ContentId): Boolean = helperRepo.contains(id) + + override suspend fun count(): Long = helperRepo.count() + + override suspend fun getById(id: ContentId): RegisteredContent? = helperRepo.getType(id) ?.let { + adaptersMap[it] ?.getContent(id) ?.let { content -> + RegisteredContent(id, content) + } + } + + override suspend fun getByPagination( + pagination: Pagination + ): PaginationResult = helperRepo.getKeysByPagination( + pagination + ).let { + it.results.mapNotNull { + getById(it) + }.createPaginationResult( + it, + count() + ) + } +} + +class BusinessWriteContentRepo( + private val adapters: List, + private val helperRepo: BusinessContentRepoHelpInterface +) : WriteContentRepo { + private val adaptersMap = adapters.map { it.type to it }.toMap() + private val _deletedObjectsIdsFlow = MutableSharedFlow() + override val deletedObjectsIdsFlow: Flow = _deletedObjectsIdsFlow.asSharedFlow() + private val _newObjectsFlow = MutableSharedFlow() + override val newObjectsFlow: Flow = _newObjectsFlow.asSharedFlow() + private val _updatedObjectsFlow = MutableSharedFlow() + override val updatedObjectsFlow: Flow = _updatedObjectsFlow.asSharedFlow() + + override suspend fun create(values: List): List { + return values.mapNotNull { content -> + val contentId = generateContentId() + val adapter = adapters.firstOrNull { it.storeContent(contentId, content) } ?: return@mapNotNull null + if (!helperRepo.saveType(contentId, adapter.type)) { + adapter.removeContent(contentId) + } + RegisteredContent(contentId, content).also { _newObjectsFlow.emit(it) } + } + } + + override suspend fun deleteById(ids: List) { + ids.forEach { contentId -> + adaptersMap[helperRepo.getType(contentId)] ?.removeContent(contentId) ?: adapters.forEach { + it.removeContent(contentId) + } + helperRepo.deleteContentId(contentId) + _deletedObjectsIdsFlow.emit(contentId) + } + } + + override suspend fun update(id: ContentId, value: Content): RegisteredContent? { + adaptersMap[helperRepo.getType(id)] ?.removeContent(id) ?: adapters.forEach { + it.removeContent(id) + } + adapters.firstOrNull { it.storeContent(id, value) } ?: return null + return RegisteredContent(id, value).also { _updatedObjectsFlow.emit(it) } + } + + override suspend fun update(values: List>): List { + return values.mapNotNull { + update(it.first, it.second) + } + } + +} + +class BusinessContentRepo( + adapters: List, + helperRepo: BusinessContentRepoHelpInterface +) : ContentRepo, ReadContentRepo by BusinessReadContentRepo( + adapters, + helperRepo +), WriteContentRepo by BusinessWriteContentRepo( + adapters, + helperRepo +) diff --git a/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/api/ReadContentRepo.kt b/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/api/ReadContentRepo.kt index 1fc6e7e6..f65fae5d 100644 --- a/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/api/ReadContentRepo.kt +++ b/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/api/ReadContentRepo.kt @@ -4,22 +4,10 @@ import dev.inmo.postssystem.core.content.ContentId import dev.inmo.postssystem.core.content.RegisteredContent import dev.inmo.micro_utils.pagination.Pagination import dev.inmo.micro_utils.pagination.PaginationResult +import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo +import dev.inmo.micro_utils.repos.pagination.getAll /** * Simple read API by different properties of [dev.inmo.postssystem.core.content.Content]. */ -interface ReadContentRepo { - /** - * @return [Set] of [ContentId] wich currently known in this instance of API - */ - suspend fun getContentsIds(): Set - /** - * @return [RegisteredContent] if it is available by [id] - */ - suspend fun getContentById(id: ContentId): RegisteredContent? - - /** - * @return all [RegisteredContent] by pages basing on their creation date - */ - suspend fun getContentByPagination(pagination: Pagination): PaginationResult -} \ No newline at end of file +interface ReadContentRepo : ReadStandardCRUDRepo diff --git a/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/api/WriteContentRepo.kt b/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/api/WriteContentRepo.kt index 5fb9d19a..368dcbfa 100644 --- a/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/api/WriteContentRepo.kt +++ b/core/api/src/commonMain/kotlin/dev/inmo/postssystem/core/content/api/WriteContentRepo.kt @@ -1,12 +1,7 @@ package dev.inmo.postssystem.core.content.api +import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo import dev.inmo.postssystem.core.content.* import kotlinx.coroutines.flow.Flow -interface WriteContentRepo { - val contentCreatedFlow: Flow - val contentDeletedFlow: Flow - - suspend fun registerContent(content: Content): RegisteredContent? - suspend fun deleteContent(id: ContentId): Boolean -} +interface WriteContentRepo : WriteStandardCRUDRepo