diff --git a/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/content/Content.kt b/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/content/Content.kt index c21ffb42..55f08b41 100644 --- a/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/content/Content.kt +++ b/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/content/Content.kt @@ -1,17 +1,30 @@ package com.insanusmokrassar.postssystem.core.content +import kotlinx.serialization.Serializable + typealias ContentId = String /** * Content which is planned to be registered in database */ -interface Content +sealed class Content + +@Serializable +data class SimpleSpecialContent( + val internalId: ContentId +) : Content() + +@Serializable +data class SimpleTextContent( + val text: String +) : Content() /** * Content which is already registered in database. Using its [id] you can retrieve all known * [com.insanusmokrassar.postssystem.core.post.RegisteredPost]s by using * [com.insanusmokrassar.postssystem.core.post.api.ReadPostsAPI.getPostsByContent] */ -interface RegisteredContent : Content { - val id: ContentId -} +data class RegisteredContent( + val id: ContentId, + val content: Content +) diff --git a/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/content/SpecialContent.kt b/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/content/SpecialContent.kt deleted file mode 100644 index f4100390..00000000 --- a/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/content/SpecialContent.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.insanusmokrassar.postssystem.core.content - -import kotlinx.serialization.Serializable - -/** - * Special content, which usually better known in some plugin or system, but is not representable in others. For - * example, it could be issue in some git system, which is unknown for all other systems. - * - * @property internalId Represent Id of this content in system which knows exact type and can correctly handle this - * content - */ -interface SpecialContent : Content { - val internalId: ContentId -} - -/** - * As [SpecialContent], but already registered in posts system - */ -interface SpecialRegisteredContent : RegisteredContent, SpecialContent - -@Serializable -data class SimpleSpecialContent( - override val internalId: ContentId -) : SpecialContent - -@Serializable -data class SimpleSpecialRegisteredContent( - override val id: ContentId, - override val internalId: ContentId -) : SpecialRegisteredContent - diff --git a/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/content/TextContent.kt b/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/content/TextContent.kt deleted file mode 100644 index af2608e6..00000000 --- a/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/content/TextContent.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.insanusmokrassar.postssystem.core.content - -import kotlinx.serialization.Serializable - -interface TextContent : Content { - val text: String -} - -interface TextRegisteredContent : RegisteredContent, TextContent - -@Serializable -data class SimpleTextContent( - override val text: String -) : TextContent - -@Serializable -data class SimpleTextRegisteredContent( - override val id: ContentId, - override val text: String -) : TextRegisteredContent diff --git a/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/content/api/WriteContentAPI.kt b/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/content/api/WriteContentAPI.kt index 3fbad021..213f1a51 100644 --- a/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/content/api/WriteContentAPI.kt +++ b/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/content/api/WriteContentAPI.kt @@ -7,6 +7,6 @@ interface WriteContentAPI { val contentCreatedFlow: Flow val contentDeletedFlow: Flow - suspend fun createContent(post: Content): RegisteredContent? + suspend fun createContent(content: Content): RegisteredContent? suspend fun deleteContent(id: ContentId): Boolean } diff --git a/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/utils/DateTimeUtils.kt b/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/utils/DateTimeUtils.kt new file mode 100644 index 00000000..3beef0cd --- /dev/null +++ b/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/utils/DateTimeUtils.kt @@ -0,0 +1,9 @@ +package com.insanusmokrassar.postssystem.core.utils + +import org.joda.time.DateTime + +fun DateTime?.orMin(): DateTime = this ?: MIN_DATE +fun DateTime?.orMax(): DateTime = this ?: MAX_DATE + +private val MIN_DATE = DateTime(Long.MIN_VALUE) +private val MAX_DATE = DateTime(Long.MAX_VALUE) diff --git a/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/utils/IdUtils.kt b/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/utils/IdUtils.kt new file mode 100644 index 00000000..68c970ba --- /dev/null +++ b/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/utils/IdUtils.kt @@ -0,0 +1,10 @@ +package com.insanusmokrassar.postssystem.core.utils + +import com.insanusmokrassar.postssystem.core.content.ContentId +import com.insanusmokrassar.postssystem.core.post.PostId +import java.util.* + +private fun generateId() = UUID.randomUUID().toString() + +internal fun generatePostId(): PostId = generateId() +internal fun generateContentId(): ContentId = generateId() diff --git a/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/utils/pagination/Pagination.kt b/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/utils/pagination/Pagination.kt index a8496b9d..c904b3ce 100644 --- a/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/utils/pagination/Pagination.kt +++ b/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/utils/pagination/Pagination.kt @@ -1,5 +1,7 @@ package com.insanusmokrassar.postssystem.core.utils.pagination +import kotlin.math.ceil + /** * Base interface of pagination * @@ -33,3 +35,15 @@ val Pagination.firstIndex: Int */ val Pagination.lastIndex: Int get() = firstIndex + size - 1 + +/** + * Calculates pages count for given [datasetSize] + */ +fun calculatePagesNumber(datasetSize: Int, pageSize: Int): Int { + return ceil(datasetSize.toDouble() / pageSize).toInt() +} + +/** + * Calculates pages count for given [datasetSize] + */ +inline fun Pagination.calculatePagesNumber(datasetSize: Int): Int = calculatePagesNumber(datasetSize, size) diff --git a/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/utils/pagination/PaginationResult.kt b/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/utils/pagination/PaginationResult.kt index 67f3e855..bcff16d9 100644 --- a/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/utils/pagination/PaginationResult.kt +++ b/core/src/main/kotlin/com/insanusmokrassar/postssystem/core/utils/pagination/PaginationResult.kt @@ -1,14 +1,18 @@ package com.insanusmokrassar.postssystem.core.utils.pagination -import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient - -@Serializable data class PaginationResult( override val page: Int, val pagesNumber: Int, - val results: List -) : Pagination { - @Transient + val results: List, override val size: Int = results.size -} +) : Pagination + +fun Pagination.createResult( + commonObjectsNumber: Int, + results: List +) = PaginationResult( + page, + calculatePagesNumber(commonObjectsNumber), + results, + size +) diff --git a/core/src/test/kotlin/com/insanusmokrassar/postssystem/core/api/InMemoryContentAPI.kt b/core/src/test/kotlin/com/insanusmokrassar/postssystem/core/api/InMemoryContentAPI.kt new file mode 100644 index 00000000..87e7fb82 --- /dev/null +++ b/core/src/test/kotlin/com/insanusmokrassar/postssystem/core/api/InMemoryContentAPI.kt @@ -0,0 +1,54 @@ +package com.insanusmokrassar.postssystem.core.api + +import com.insanusmokrassar.postssystem.core.content.* +import com.insanusmokrassar.postssystem.core.content.api.ContentAPI +import com.insanusmokrassar.postssystem.core.utils.generateContentId +import com.insanusmokrassar.postssystem.core.utils.pagination.* +import kotlinx.coroutines.channels.BroadcastChannel +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.asFlow +import kotlinx.serialization.ImplicitReflectionSerializer + +@ImplicitReflectionSerializer +class InMemoryContentAPI( + initialContent: List = emptyList() +): ContentAPI { + private val contentCreatedBroadcastChannel = BroadcastChannel(Channel.BUFFERED) + private val contentDeletedBroadcastChannel = BroadcastChannel(Channel.BUFFERED) + + override val contentCreatedFlow: Flow + get() = contentCreatedBroadcastChannel.asFlow() + + override val contentDeletedFlow: Flow + get() = contentDeletedBroadcastChannel.asFlow() + + private val contents: MutableMap = initialContent + .associateBy(RegisteredContent::id) + .toMutableMap() + + override suspend fun createContent(content: Content): RegisteredContent? { + return RegisteredContent( + generateContentId(), + content + ).also { registeredContent -> + contents[registeredContent.id] = registeredContent + contentCreatedBroadcastChannel.send(registeredContent) + } + } + + override suspend fun getContentById(id: ContentId): RegisteredContent? = contents[id] + + override suspend fun getContentByPagination(pagination: Pagination): PaginationResult { + return pagination.createResult( + commonObjectsNumber = contents.size, + results = contents.values.asSequence().drop(pagination.firstIndex).take(pagination.size).toList() + ) + } + + override suspend fun deleteContent(id: ContentId): Boolean { + return contents.remove(id)?.also { content -> + contentDeletedBroadcastChannel.send(content) + } != null + } +} \ No newline at end of file diff --git a/core/src/test/kotlin/com/insanusmokrassar/postssystem/core/api/InMemoryPostsAPI.kt b/core/src/test/kotlin/com/insanusmokrassar/postssystem/core/api/InMemoryPostsAPI.kt index c932a4f4..c9d5a317 100644 --- a/core/src/test/kotlin/com/insanusmokrassar/postssystem/core/api/InMemoryPostsAPI.kt +++ b/core/src/test/kotlin/com/insanusmokrassar/postssystem/core/api/InMemoryPostsAPI.kt @@ -3,6 +3,7 @@ package com.insanusmokrassar.postssystem.core.api import com.insanusmokrassar.postssystem.core.content.ContentId import com.insanusmokrassar.postssystem.core.post.* import com.insanusmokrassar.postssystem.core.post.api.PostsAPI +import com.insanusmokrassar.postssystem.core.utils.generatePostId import com.insanusmokrassar.postssystem.core.utils.pagination.* import kotlinx.coroutines.channels.BroadcastChannel import kotlinx.coroutines.channels.Channel.Factory.BUFFERED @@ -10,10 +11,6 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.asFlow import kotlinx.serialization.ImplicitReflectionSerializer import org.joda.time.DateTime -import java.util.* - -@ImplicitReflectionSerializer -private fun generateId(): PostId = UUID.randomUUID().toString() /** * Thread-unsafe sample realization of [PostsAPI] @@ -39,7 +36,7 @@ class InMemoryPostsAPI( override suspend fun createPost(post: Post): RegisteredPost? { return SimpleRegisteredPost( - generateId(), + generatePostId(), post.content ).also { newPost -> posts[newPost.id] = newPost