
com.github.insanusmokrassar.AutoPostTelegramBot.plugins.rating.database.PostsLikesTable.kt Maven / Gradle / Ivy
package com.github.insanusmokrassar.AutoPostTelegramBot.plugins.rating.database
import com.github.insanusmokrassar.AutoPostTelegramBot.base.database.tables.PostsTable
import com.github.insanusmokrassar.AutoPostTelegramBot.base.plugins.commonLogger
import com.github.insanusmokrassar.AutoPostTelegramBot.utils.extensions.subscribe
import kotlinx.coroutines.experimental.channels.BroadcastChannel
import kotlinx.coroutines.experimental.launch
import org.h2.jdbc.JdbcSQLException
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.transactions.transaction
typealias PostIdRatingPair = Pair
typealias PostIdUserId = Pair
private const val countOfSubscriptions = 256
private const val resultColumnName = "result"
class PostsLikesTable : Table() {
val likesChannel = BroadcastChannel(countOfSubscriptions)
val dislikesChannel = BroadcastChannel(countOfSubscriptions)
val ratingsChannel = BroadcastChannel(countOfSubscriptions)
private val userId = long("userId").primaryKey()
private val postId = integer("postId").primaryKey()
private val like = bool("like").default(false)
internal lateinit var postsLikesMessagesTable: PostsLikesMessagesTable
init {
PostsTable.postRemovedChannel.subscribe(
{
commonLogger.throwing(
"PostsLikesTable",
"Clear likes",
it
)
true
}
) {
clearPostMarks(it)
}
}
fun userLikePost(userId: Long, postId: Int) {
userLike(userId, postId, true)
launch {
likesChannel.send(postId to userId)
}
}
fun userDislikePost(userId: Long, postId: Int) {
userLike(userId, postId, false)
launch {
dislikesChannel.send(postId to userId)
}
}
fun postLikes(postId: Int): Int = postLikeCount(postId, true)
fun postDislikes(postId: Int): Int = postLikeCount(postId, false)
fun getPostRating(postId: Int): Int {
return transaction {
try {
exec("SELECT (likes-dislikes) as $resultColumnName FROM " +
"(SELECT count(*) as likes FROM ${nameInDatabaseCase()} WHERE ${[email protected]}=$postId AND \"${like.name}\"=${like.columnType.valueToString(true)}), " +
"(SELECT count(*) as dislikes FROM ${nameInDatabaseCase()} WHERE ${[email protected]}=$postId AND \"${like.name}\"=${like.columnType.valueToString(false)});") {
if (it.first()) {
it.getInt(it.findColumn(resultColumnName))
} else {
0
}
} ?: 0
} catch (e: JdbcSQLException) {
select {
createChooser(postId, like = true)
}.count() - select {
createChooser(postId, like = false)
}.count()
}
}
}
fun getMostRated(): List {
return transaction {
postsLikesMessagesTable.getEnabledPostsIdAndRatings().let {
var maxRating = Int.MIN_VALUE
ArrayList().apply {
it.forEach {
val currentRating = it.second
if (currentRating > maxRating) {
maxRating = currentRating
clear()
}
if (currentRating == maxRating) {
add(it.first)
}
}
}
}
}
}
/**
* @param min Included. If null - always true
* @param max Included. If null - always true
*
* @return Pairs with postId to Rate
*/
fun getRateRange(min: Int?, max: Int?): List {
return postsLikesMessagesTable.getEnabledPostsIdAndRatings().sortedByDescending {
it.second
}.filter {
pair ->
min ?.let { it <= pair.second } != false && max ?.let { pair.second <= it } != false
}
}
private fun postLikeCount(postId: Int, like: Boolean): Int = transaction {
select {
[email protected](postId).and([email protected](like))
}.count()
}
private fun createChooser(postId: Int, userId: Long? = null, like: Boolean? = null): Op {
return [email protected](postId).let {
userId ?.let {
userId ->
it.and([email protected](userId))
} ?: it
}.let {
like ?. let {
like ->
it.and([email protected](like))
} ?: it
}
}
private fun userLike(userId: Long, postId: Int, like: Boolean) {
val chooser = createChooser(postId, userId)
transaction {
val record = select {
chooser
}.firstOrNull()
record ?.let {
if (it[[email protected]] == like) {
deleteWhere { chooser }
} else {
update(
{
chooser
}
) {
it[[email protected]] = like
}
}
} ?:let {
addUser(userId, postId, like)
}
launch {
ratingsChannel.send(
PostIdRatingPair(postId, getPostRating(postId))
)
}
}
}
private fun addUser(userId: Long, postId: Int, like: Boolean) {
transaction {
insert {
it[[email protected]] = postId
it[[email protected]] = userId
it[[email protected]] = like
}
}
}
internal fun clearPostMarks(postId: Int) {
transaction {
deleteWhere { [email protected](postId) }
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy