Merge branch 'PSC-2' of PostsSystem/PostsSystemCore into master

This commit is contained in:
Aleksei Ovsiannikov 2019-11-04 14:47:45 +00:00 committed by Gogs
commit 93c3ebd870
10 changed files with 119 additions and 69 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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