Merge branch 'PSC-2' of PostsSystem/PostsSystemCore into master
This commit is contained in:
commit
93c3ebd870
@ -1,17 +1,30 @@
|
|||||||
package com.insanusmokrassar.postssystem.core.content
|
package com.insanusmokrassar.postssystem.core.content
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
typealias ContentId = String
|
typealias ContentId = String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Content which is planned to be registered in database
|
* 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
|
* 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.RegisteredPost]s by using
|
||||||
* [com.insanusmokrassar.postssystem.core.post.api.ReadPostsAPI.getPostsByContent]
|
* [com.insanusmokrassar.postssystem.core.post.api.ReadPostsAPI.getPostsByContent]
|
||||||
*/
|
*/
|
||||||
interface RegisteredContent : Content {
|
data class RegisteredContent(
|
||||||
val id: ContentId
|
val id: ContentId,
|
||||||
}
|
val content: Content
|
||||||
|
)
|
||||||
|
@ -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
|
|
||||||
|
|
@ -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
|
|
@ -7,6 +7,6 @@ interface WriteContentAPI {
|
|||||||
val contentCreatedFlow: Flow<RegisteredContent>
|
val contentCreatedFlow: Flow<RegisteredContent>
|
||||||
val contentDeletedFlow: Flow<RegisteredContent>
|
val contentDeletedFlow: Flow<RegisteredContent>
|
||||||
|
|
||||||
suspend fun createContent(post: Content): RegisteredContent?
|
suspend fun createContent(content: Content): RegisteredContent?
|
||||||
suspend fun deleteContent(id: ContentId): Boolean
|
suspend fun deleteContent(id: ContentId): Boolean
|
||||||
}
|
}
|
||||||
|
@ -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)
|
@ -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()
|
@ -1,5 +1,7 @@
|
|||||||
package com.insanusmokrassar.postssystem.core.utils.pagination
|
package com.insanusmokrassar.postssystem.core.utils.pagination
|
||||||
|
|
||||||
|
import kotlin.math.ceil
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base interface of pagination
|
* Base interface of pagination
|
||||||
*
|
*
|
||||||
@ -33,3 +35,15 @@ val Pagination.firstIndex: Int
|
|||||||
*/
|
*/
|
||||||
val Pagination.lastIndex: Int
|
val Pagination.lastIndex: Int
|
||||||
get() = firstIndex + size - 1
|
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)
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
package com.insanusmokrassar.postssystem.core.utils.pagination
|
package com.insanusmokrassar.postssystem.core.utils.pagination
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.Transient
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class PaginationResult<T>(
|
data class PaginationResult<T>(
|
||||||
override val page: Int,
|
override val page: Int,
|
||||||
val pagesNumber: Int,
|
val pagesNumber: Int,
|
||||||
val results: List<T>
|
val results: List<T>,
|
||||||
) : Pagination {
|
|
||||||
@Transient
|
|
||||||
override val size: Int = results.size
|
override val size: Int = results.size
|
||||||
}
|
) : Pagination
|
||||||
|
|
||||||
|
fun <T> Pagination.createResult(
|
||||||
|
commonObjectsNumber: Int,
|
||||||
|
results: List<T>
|
||||||
|
) = PaginationResult(
|
||||||
|
page,
|
||||||
|
calculatePagesNumber(commonObjectsNumber),
|
||||||
|
results,
|
||||||
|
size
|
||||||
|
)
|
||||||
|
@ -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<RegisteredContent> = emptyList()
|
||||||
|
): ContentAPI {
|
||||||
|
private val contentCreatedBroadcastChannel = BroadcastChannel<RegisteredContent>(Channel.BUFFERED)
|
||||||
|
private val contentDeletedBroadcastChannel = BroadcastChannel<RegisteredContent>(Channel.BUFFERED)
|
||||||
|
|
||||||
|
override val contentCreatedFlow: Flow<RegisteredContent>
|
||||||
|
get() = contentCreatedBroadcastChannel.asFlow()
|
||||||
|
|
||||||
|
override val contentDeletedFlow: Flow<RegisteredContent>
|
||||||
|
get() = contentDeletedBroadcastChannel.asFlow()
|
||||||
|
|
||||||
|
private val contents: MutableMap<ContentId, RegisteredContent> = 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<out RegisteredContent> {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ package com.insanusmokrassar.postssystem.core.api
|
|||||||
import com.insanusmokrassar.postssystem.core.content.ContentId
|
import com.insanusmokrassar.postssystem.core.content.ContentId
|
||||||
import com.insanusmokrassar.postssystem.core.post.*
|
import com.insanusmokrassar.postssystem.core.post.*
|
||||||
import com.insanusmokrassar.postssystem.core.post.api.PostsAPI
|
import com.insanusmokrassar.postssystem.core.post.api.PostsAPI
|
||||||
|
import com.insanusmokrassar.postssystem.core.utils.generatePostId
|
||||||
import com.insanusmokrassar.postssystem.core.utils.pagination.*
|
import com.insanusmokrassar.postssystem.core.utils.pagination.*
|
||||||
import kotlinx.coroutines.channels.BroadcastChannel
|
import kotlinx.coroutines.channels.BroadcastChannel
|
||||||
import kotlinx.coroutines.channels.Channel.Factory.BUFFERED
|
import kotlinx.coroutines.channels.Channel.Factory.BUFFERED
|
||||||
@ -10,10 +11,6 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.asFlow
|
import kotlinx.coroutines.flow.asFlow
|
||||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
@ImplicitReflectionSerializer
|
|
||||||
private fun generateId(): PostId = UUID.randomUUID().toString()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread-unsafe sample realization of [PostsAPI]
|
* Thread-unsafe sample realization of [PostsAPI]
|
||||||
@ -39,7 +36,7 @@ class InMemoryPostsAPI(
|
|||||||
|
|
||||||
override suspend fun createPost(post: Post): RegisteredPost? {
|
override suspend fun createPost(post: Post): RegisteredPost? {
|
||||||
return SimpleRegisteredPost(
|
return SimpleRegisteredPost(
|
||||||
generateId(),
|
generatePostId(),
|
||||||
post.content
|
post.content
|
||||||
).also { newPost ->
|
).also { newPost ->
|
||||||
posts[newPost.id] = newPost
|
posts[newPost.id] = newPost
|
||||||
|
Loading…
Reference in New Issue
Block a user