add selector

This commit is contained in:
2022-09-06 23:56:58 +06:00
parent cf5a4c0f61
commit f3f7761bf9
16 changed files with 361 additions and 17 deletions

View File

@@ -0,0 +1,22 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
id "com.android.library"
}
apply from: "$mppProjectWithSerializationPresetPath"
kotlin {
sourceSets {
commonMain {
dependencies {
api project(":plaguposter.common")
api project(":plaguposter.ratings")
}
}
jvmMain {
dependencies {
}
}
}
}

View File

@@ -0,0 +1,21 @@
package dev.inmo.plaguposter.ratings.selector
import dev.inmo.plaguposter.posts.models.PostId
import dev.inmo.plaguposter.ratings.repo.RatingsRepo
import dev.inmo.plaguposter.ratings.selector.models.SelectorConfig
class DefaultSelector (
private val config: SelectorConfig,
private val repo: RatingsRepo
) : Selector {
override suspend fun take(n: Int): List<PostId> {
val result = mutableListOf<PostId>()
do {
val selected = config.active ?.ratings ?.select(repo, result) ?: break
result.add(selected)
} while (result.size < n)
return result.toList()
}
}

View File

@@ -0,0 +1 @@
package dev.inmo.plaguposter.ratings.selector

View File

@@ -0,0 +1,7 @@
package dev.inmo.plaguposter.ratings.selector
import dev.inmo.plaguposter.posts.models.PostId
interface Selector {
suspend fun take(n: Int = 1): List<PostId>
}

View File

@@ -0,0 +1,104 @@
package dev.inmo.plaguposter.ratings.selector.models
import dev.inmo.micro_utils.pagination.FirstPagePagination
import dev.inmo.micro_utils.pagination.Pagination
import dev.inmo.plaguposter.posts.models.PostId
import dev.inmo.plaguposter.ratings.models.Rating
import dev.inmo.plaguposter.ratings.repo.RatingsRepo
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlin.random.Random
@Serializable
data class RatingConfig(
val min: Rating?,
val max: Rating?,
val prefer: Prefer
) {
suspend fun select(repo: RatingsRepo, exclude: List<PostId>): PostId? {
var reversed: Boolean = false
var count: Int? = null
when (prefer) {
Prefer.Max -> {
reversed = true
count = 1
}
Prefer.Min -> {
reversed = false
count = 1
}
Prefer.Random -> {
reversed = false
count = null
}
}
val posts = when(min) {
null -> {
when (max) {
null -> {
repo.keys(
count ?.let { Pagination(0, it) } ?: FirstPagePagination(repo.count().toInt()),
reversed
).results.filterNot {
it in exclude
}
}
else -> {
repo.getPostsWithRatingLessEq(max, exclude = exclude).keys
}
}
}
else -> {
when (max) {
null -> {
repo.getPostsWithRatingGreaterEq(min, exclude = exclude).keys
}
else -> {
repo.getPosts(min .. max, reversed, count, exclude = exclude).keys
}
}
}
}
return when (prefer) {
Prefer.Max,
Prefer.Min -> posts.firstOrNull()
Prefer.Random -> posts.randomOrNull()
}
}
@Serializable(Prefer.Serializer::class)
sealed interface Prefer {
val type: String
@Serializable(Serializer::class)
object Max : Prefer { override val type: String = "max" }
@Serializable(Serializer::class)
object Min : Prefer { override val type: String = "min" }
@Serializable(Serializer::class)
object Random : Prefer { override val type: String = "random" }
object Serializer : KSerializer<Prefer> {
override val descriptor: SerialDescriptor = String.serializer().descriptor
override fun deserialize(decoder: Decoder): Prefer {
val identifier = decoder.decodeString().lowercase()
return values.first { it.type.lowercase() == identifier }
}
override fun serialize(encoder: Encoder, value: Prefer) {
encoder.encodeString(value.type.lowercase())
}
}
companion object {
val values = arrayOf(Max, Min, Random)
}
}
}

View File

@@ -0,0 +1,11 @@
package dev.inmo.plaguposter.ratings.selector.models
import kotlinx.serialization.Serializable
@Serializable
data class SelectorConfig(
val items: List<SelectorConfigItem>
) {
val active: SelectorConfigItem?
get() = items.firstOrNull { it.time.isActive }
}

View File

@@ -0,0 +1,9 @@
package dev.inmo.plaguposter.ratings.selector.models
import kotlinx.serialization.Serializable
@Serializable
data class SelectorConfigItem(
val time: TimeConfig,
val ratings: RatingConfig
)

View File

@@ -0,0 +1,36 @@
package dev.inmo.plaguposter.ratings.selector.models
import com.soywiz.klock.*
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Serializable
class TimeConfig(
@Serializable(TimeSerializer::class)
val from: Time,
@Serializable(TimeSerializer::class)
val to: Time
) {
@Transient
val range = from .. to
val isActive: Boolean
get() = DateTime.now().time in range
object TimeSerializer : KSerializer<Time> {
val format = TimeFormat("HH:mm")
override val descriptor: SerialDescriptor = String.serializer().descriptor
override fun deserialize(decoder: Decoder): Time {
return format.parseTime(decoder.decodeString())
}
override fun serialize(encoder: Encoder, value: Time) {
encoder.encodeString(format.format(value))
}
}
}

View File

@@ -0,0 +1,14 @@
package dev.inmo.plaguposter.ratings.selector
import dev.inmo.plagubot.Plugin
import dev.inmo.plaguposter.ratings.selector.models.SelectorConfig
import kotlinx.serialization.json.*
import org.jetbrains.exposed.sql.Database
import org.koin.core.module.Module
object Plugin : Plugin {
override fun Module.setupDI(database: Database, params: JsonObject) {
single { get<Json>().decodeFromJsonElement(SelectorConfig.serializer(), params["selector"] ?: return@single null) }
single<Selector> { DefaultSelector(get(), get()) }
}
}

View File

@@ -0,0 +1 @@
<manifest package="dev.inmo.plaguposter.ratings.selector"/>