mirror of https://github.com/usbharu/Hideout.git
feat: カスタム絵文字のリアクションの対応
This commit is contained in:
parent
0607fe2bc5
commit
32e60dc6f8
|
@ -12,9 +12,9 @@ data class CustomEmoji(
|
|||
val id: Long,
|
||||
override val name: String,
|
||||
override val domain: String,
|
||||
val instanceId: Long,
|
||||
val instanceId: Long?,
|
||||
val url: String,
|
||||
val category: String,
|
||||
val category: String?,
|
||||
val createdAt: Instant
|
||||
) : Emoji() {
|
||||
override fun id(): String {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
package dev.usbharu.hideout.core.domain.model.reaction
|
||||
|
||||
data class Reaction(val id: Long, val emojiId: Long, val postId: Long, val actorId: Long)
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.Emoji
|
||||
|
||||
data class Reaction(val id: Long, val emoji: Emoji, val postId: Long, val actorId: Long)
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmoji
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiRepository
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
import org.jetbrains.exposed.sql.javatime.CurrentTimestamp
|
||||
import org.jetbrains.exposed.sql.javatime.timestamp
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
class CustomEmojiRepositoryImpl : CustomEmojiRepository, AbstractRepository() {
|
||||
override suspend fun save(customEmoji: CustomEmoji): CustomEmoji = query {
|
||||
val singleOrNull = CustomEmojis.select { CustomEmojis.id eq customEmoji.id }.forUpdate().singleOrNull()
|
||||
if (singleOrNull == null) {
|
||||
CustomEmojis.insert {
|
||||
it[CustomEmojis.id] = customEmoji.id
|
||||
it[CustomEmojis.name] = customEmoji.name
|
||||
it[CustomEmojis.domain] = customEmoji.domain
|
||||
it[CustomEmojis.instanceId] = customEmoji.instanceId
|
||||
it[CustomEmojis.url] = customEmoji.url
|
||||
it[CustomEmojis.category] = customEmoji.category
|
||||
it[CustomEmojis.createdAt] = customEmoji.createdAt
|
||||
}
|
||||
} else {
|
||||
CustomEmojis.update({ CustomEmojis.id eq customEmoji.id }) {
|
||||
it[CustomEmojis.name] = customEmoji.name
|
||||
it[CustomEmojis.domain] = customEmoji.domain
|
||||
it[CustomEmojis.instanceId] = customEmoji.instanceId
|
||||
it[CustomEmojis.url] = customEmoji.url
|
||||
it[CustomEmojis.category] = customEmoji.category
|
||||
it[CustomEmojis.createdAt] = customEmoji.createdAt
|
||||
}
|
||||
}
|
||||
return@query customEmoji
|
||||
}
|
||||
|
||||
override suspend fun findById(id: Long): CustomEmoji? = query {
|
||||
return@query CustomEmojis.select { CustomEmojis.id eq id }.singleOrNull()?.toCustomEmoji()
|
||||
}
|
||||
|
||||
override suspend fun delete(customEmoji: CustomEmoji): Unit = query {
|
||||
CustomEmojis.deleteWhere { CustomEmojis.id eq customEmoji.id }
|
||||
}
|
||||
|
||||
override val logger: Logger
|
||||
get() = Companion.logger
|
||||
|
||||
companion object {
|
||||
private val logger = LoggerFactory.getLogger(CustomEmojiRepositoryImpl::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
fun ResultRow.toCustomEmoji(): CustomEmoji = CustomEmoji(
|
||||
this[CustomEmojis.id],
|
||||
this[CustomEmojis.name],
|
||||
this[CustomEmojis.domain],
|
||||
this[CustomEmojis.instanceId],
|
||||
this[CustomEmojis.url],
|
||||
this[CustomEmojis.category],
|
||||
this[CustomEmojis.createdAt]
|
||||
)
|
||||
|
||||
object CustomEmojis : Table("emojis") {
|
||||
val id = long("id")
|
||||
val name = varchar("name", 1000)
|
||||
val domain = varchar("domain", 1000)
|
||||
val instanceId = long("instance_id").references(Instance.id).nullable()
|
||||
val url = varchar("url", 255).uniqueIndex()
|
||||
val category = varchar("category", 255).nullable()
|
||||
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp())
|
||||
|
||||
override val primaryKey: PrimaryKey = PrimaryKey(id)
|
||||
|
||||
init {
|
||||
uniqueIndex(name, instanceId)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
||||
|
||||
import dev.usbharu.hideout.application.service.id.IdGenerateService
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmoji
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.UnicodeEmoji
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
|
||||
import org.jetbrains.exposed.dao.id.LongIdTable
|
||||
|
@ -23,13 +25,25 @@ class ReactionRepositoryImpl(
|
|||
if (Reactions.select { Reactions.id eq reaction.id }.forUpdate().empty()) {
|
||||
Reactions.insert {
|
||||
it[id] = reaction.id
|
||||
it[emojiId] = reaction.emojiId
|
||||
if (reaction.emoji is CustomEmoji) {
|
||||
it[customEmojiId] = reaction.emoji.id
|
||||
it[unicodeEmoji] = null
|
||||
} else {
|
||||
it[customEmojiId] = null
|
||||
it[unicodeEmoji] = reaction.emoji.name
|
||||
}
|
||||
it[postId] = reaction.postId
|
||||
it[actorId] = reaction.actorId
|
||||
}
|
||||
} else {
|
||||
Reactions.update({ Reactions.id eq reaction.id }) {
|
||||
it[emojiId] = reaction.emojiId
|
||||
if (reaction.emoji is CustomEmoji) {
|
||||
it[customEmojiId] = reaction.emoji.id
|
||||
it[unicodeEmoji] = null
|
||||
} else {
|
||||
it[customEmojiId] = null
|
||||
it[unicodeEmoji] = reaction.emoji.name
|
||||
}
|
||||
it[postId] = reaction.postId
|
||||
it[actorId] = reaction.actorId
|
||||
}
|
||||
|
@ -38,9 +52,16 @@ class ReactionRepositoryImpl(
|
|||
}
|
||||
|
||||
override suspend fun delete(reaction: Reaction): Reaction = query {
|
||||
Reactions.deleteWhere {
|
||||
id.eq(reaction.id).and(postId.eq(reaction.postId)).and(actorId.eq(reaction.actorId))
|
||||
.and(emojiId.eq(reaction.emojiId))
|
||||
if (reaction.emoji is CustomEmoji) {
|
||||
Reactions.deleteWhere {
|
||||
id.eq(reaction.id).and(postId.eq(reaction.postId)).and(actorId.eq(reaction.actorId))
|
||||
.and(customEmojiId.eq(reaction.emoji.id))
|
||||
}
|
||||
} else {
|
||||
Reactions.deleteWhere {
|
||||
id.eq(reaction.id).and(postId.eq(reaction.postId)).and(actorId.eq(reaction.actorId))
|
||||
.and(unicodeEmoji.eq(reaction.emoji.name))
|
||||
}
|
||||
}
|
||||
return@query reaction
|
||||
}
|
||||
|
@ -58,14 +79,14 @@ class ReactionRepositoryImpl(
|
|||
}
|
||||
|
||||
override suspend fun findByPostId(postId: Long): List<Reaction> = query {
|
||||
return@query Reactions.select { Reactions.postId eq postId }.map { it.toReaction() }
|
||||
return@query Reactions.leftJoin(CustomEmojis).select { Reactions.postId eq postId }.map { it.toReaction() }
|
||||
}
|
||||
|
||||
override suspend fun findByPostIdAndActorIdAndEmojiId(postId: Long, actorId: Long, emojiId: Long): Reaction? =
|
||||
query {
|
||||
return@query Reactions.select {
|
||||
return@query Reactions.leftJoin(CustomEmojis).select {
|
||||
Reactions.postId eq postId and (Reactions.actorId eq actorId).and(
|
||||
Reactions.emojiId.eq(
|
||||
Reactions.customEmojiId.eq(
|
||||
emojiId
|
||||
)
|
||||
)
|
||||
|
@ -78,12 +99,13 @@ class ReactionRepositoryImpl(
|
|||
Reactions.postId
|
||||
.eq(postId)
|
||||
.and(Reactions.actorId.eq(actorId))
|
||||
.and(Reactions.emojiId.eq(emojiId))
|
||||
.and(Reactions.customEmojiId.eq(emojiId))
|
||||
}.empty().not()
|
||||
}
|
||||
|
||||
override suspend fun findByPostIdAndActorId(postId: Long, actorId: Long): List<Reaction> = query {
|
||||
return@query Reactions.select { Reactions.postId eq postId and (Reactions.actorId eq actorId) }
|
||||
return@query Reactions.leftJoin(CustomEmojis)
|
||||
.select { Reactions.postId eq postId and (Reactions.actorId eq actorId) }
|
||||
.map { it.toReaction() }
|
||||
}
|
||||
|
||||
|
@ -93,22 +115,39 @@ class ReactionRepositoryImpl(
|
|||
}
|
||||
|
||||
fun ResultRow.toReaction(): Reaction {
|
||||
val emoji = if (this[Reactions.customEmojiId] != null) {
|
||||
CustomEmoji(
|
||||
this[Reactions.customEmojiId]!!,
|
||||
this[CustomEmojis.name],
|
||||
this[CustomEmojis.domain],
|
||||
this[CustomEmojis.instanceId],
|
||||
this[CustomEmojis.url],
|
||||
this[CustomEmojis.category],
|
||||
this[CustomEmojis.createdAt]
|
||||
)
|
||||
} else if (this[Reactions.unicodeEmoji] != null) {
|
||||
UnicodeEmoji(this[Reactions.unicodeEmoji]!!)
|
||||
} else {
|
||||
throw IllegalStateException("customEmojiId and unicodeEmoji is null.")
|
||||
}
|
||||
|
||||
return Reaction(
|
||||
this[Reactions.id].value,
|
||||
this[Reactions.emojiId],
|
||||
emoji,
|
||||
this[Reactions.postId],
|
||||
this[Reactions.actorId]
|
||||
)
|
||||
}
|
||||
|
||||
object Reactions : LongIdTable("reactions") {
|
||||
val emojiId: Column<Long> = long("emoji_id")
|
||||
val customEmojiId = long("custom_emoji_id").references(CustomEmojis.id).nullable()
|
||||
val unicodeEmoji = varchar("unicode_emoji", 255).nullable()
|
||||
val postId: Column<Long> =
|
||||
long("post_id").references(Posts.id, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE)
|
||||
val actorId: Column<Long> =
|
||||
long("actor_id").references(Actors.id, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE)
|
||||
|
||||
init {
|
||||
uniqueIndex(emojiId, postId, actorId)
|
||||
uniqueIndex(customEmojiId, postId, actorId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,15 +132,19 @@ alter table posts_emojis
|
|||
|
||||
create table if not exists reactions
|
||||
(
|
||||
id bigserial primary key,
|
||||
emoji_id bigint not null,
|
||||
post_id bigint not null,
|
||||
actor_id bigint not null
|
||||
id bigserial primary key,
|
||||
unicode_emoji varchar(255) null default null,
|
||||
custom_emoji_id bigint null default null,
|
||||
post_id bigint not null,
|
||||
actor_id bigint not null
|
||||
);
|
||||
alter table reactions
|
||||
add constraint fk_reactions_post_id__id foreign key (post_id) references posts (id) on delete restrict on update restrict;
|
||||
alter table reactions
|
||||
add constraint fk_reactions_actor_id__id foreign key (actor_id) references actors (id) on delete restrict on update restrict;
|
||||
alter table reactions
|
||||
add constraint fk_reactions_emoji_id__id foreign key (emoji_id) references emojis (id) on delete cascade on update cascade;
|
||||
|
||||
create table if not exists timelines
|
||||
(
|
||||
id bigint primary key,
|
||||
|
|
Loading…
Reference in New Issue