From 32e60dc6f8813a7fb6b543c724892af5529bb889 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Fri, 22 Dec 2023 02:29:37 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=E3=82=AB=E3=82=B9=E3=82=BF=E3=83=A0?= =?UTF-8?q?=E7=B5=B5=E6=96=87=E5=AD=97=E3=81=AE=E3=83=AA=E3=82=A2=E3=82=AF?= =?UTF-8?q?=E3=82=B7=E3=83=A7=E3=83=B3=E3=81=AE=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/model/emoji/CustomEmoji.kt | 4 +- .../core/domain/model/reaction/Reaction.kt | 4 +- .../CustomEmojiRepositoryImpl.kt | 78 +++++++++++++++++++ .../ReactionRepositoryImpl.kt | 65 ++++++++++++---- .../resources/db/migration/V1__Init_DB.sql | 12 ++- 5 files changed, 143 insertions(+), 20 deletions(-) create mode 100644 src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/CustomEmojiRepositoryImpl.kt diff --git a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/emoji/CustomEmoji.kt b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/emoji/CustomEmoji.kt index 9d6598e2..6323d42e 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/emoji/CustomEmoji.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/emoji/CustomEmoji.kt @@ -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 { diff --git a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/reaction/Reaction.kt b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/reaction/Reaction.kt index 02997373..ad2fefec 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/reaction/Reaction.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/reaction/Reaction.kt @@ -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) diff --git a/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/CustomEmojiRepositoryImpl.kt b/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/CustomEmojiRepositoryImpl.kt new file mode 100644 index 00000000..3296f5d5 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/CustomEmojiRepositoryImpl.kt @@ -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) + } +} diff --git a/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ReactionRepositoryImpl.kt b/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ReactionRepositoryImpl.kt index 1a3a14ff..2c4274b7 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ReactionRepositoryImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ReactionRepositoryImpl.kt @@ -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 = 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 = 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("emoji_id") + val customEmojiId = long("custom_emoji_id").references(CustomEmojis.id).nullable() + val unicodeEmoji = varchar("unicode_emoji", 255).nullable() val postId: Column = long("post_id").references(Posts.id, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE) val actorId: Column = long("actor_id").references(Actors.id, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE) init { - uniqueIndex(emojiId, postId, actorId) + uniqueIndex(customEmojiId, postId, actorId) } } diff --git a/src/main/resources/db/migration/V1__Init_DB.sql b/src/main/resources/db/migration/V1__Init_DB.sql index 5f989b5b..2b79292d 100644 --- a/src/main/resources/db/migration/V1__Init_DB.sql +++ b/src/main/resources/db/migration/V1__Init_DB.sql @@ -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,