diff --git a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/reaction/ReactionRepository.kt b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/reaction/ReactionRepository.kt index 8005bbd2..4d3964eb 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/reaction/ReactionRepository.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/reaction/ReactionRepository.kt @@ -11,10 +11,13 @@ interface ReactionRepository { suspend fun delete(reaction: Reaction): Reaction suspend fun deleteByPostId(postId: Long): Int suspend fun deleteByActorId(actorId: Long): Int + suspend fun deleteByPostIdAndActorId(postId: Long, actorId: Long) + suspend fun deleteByPostIdAndActorIdAndEmoji(postId: Long, actorId: Long, emoji: Emoji) suspend fun findByPostId(postId: Long): List suspend fun findByPostIdAndActorIdAndEmojiId(postId: Long, actorId: Long, emojiId: Long): Reaction? suspend fun existByPostIdAndActorIdAndEmojiId(postId: Long, actorId: Long, emojiId: Long): Boolean suspend fun existByPostIdAndActorIdAndUnicodeEmoji(postId: Long, actorId: Long, unicodeEmoji: String): Boolean suspend fun existByPostIdAndActorIdAndEmoji(postId: Long, actorId: Long, emoji: Emoji): Boolean + suspend fun existByPostIdAndActor(postId: Long, actorId: Long): Boolean suspend fun findByPostIdAndActorId(postId: Long, actorId: Long): List } 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 6847ab14..b932a54f 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 @@ -79,6 +79,29 @@ class ReactionRepositoryImpl( } } + override suspend fun deleteByPostIdAndActorId(postId: Long, actorId: Long): Unit = query { + Reactions.deleteWhere { + Reactions.postId eq postId and (Reactions.actorId eq actorId) + } + } + + override suspend fun deleteByPostIdAndActorIdAndEmoji(postId: Long, actorId: Long, emoji: Emoji): Unit = query { + if (emoji is CustomEmoji) { + Reactions.deleteWhere { + Reactions.postId.eq(postId) + .and(Reactions.actorId.eq(actorId)) + .and(Reactions.customEmojiId.eq(emoji.id)) + } + } else { + Reactions.deleteWhere { + Reactions.postId.eq(postId) + .and(Reactions.actorId.eq(actorId)) + .and(Reactions.unicodeEmoji.eq(emoji.name)) + } + } + + } + override suspend fun findByPostId(postId: Long): List = query { return@query Reactions.leftJoin(CustomEmojis).select { Reactions.postId eq postId }.map { it.toReaction() } } @@ -135,6 +158,12 @@ class ReactionRepositoryImpl( return@query query.empty().not() } + override suspend fun existByPostIdAndActor(postId: Long, actorId: Long): Boolean = query { + Reactions.select { + Reactions.postId.eq(postId).and(Reactions.actorId.eq(actorId)) + }.empty().not() + } + override suspend fun findByPostIdAndActorId(postId: Long, actorId: Long): List = query { return@query Reactions.leftJoin(CustomEmojis) .select { Reactions.postId eq postId and (Reactions.actorId eq actorId) } diff --git a/src/main/kotlin/dev/usbharu/hideout/core/service/reaction/ReactionServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/core/service/reaction/ReactionServiceImpl.kt index 0d623846..927dd9fb 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/service/reaction/ReactionServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/service/reaction/ReactionServiceImpl.kt @@ -1,10 +1,10 @@ package dev.usbharu.hideout.core.service.reaction import dev.usbharu.hideout.activitypub.service.activity.like.APReactionService +import dev.usbharu.hideout.core.domain.exception.resource.DuplicateException import dev.usbharu.hideout.core.domain.model.emoji.Emoji import dev.usbharu.hideout.core.domain.model.reaction.Reaction import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository -import org.jetbrains.exposed.exceptions.ExposedSQLException import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.stereotype.Service @@ -19,13 +19,12 @@ class ReactionServiceImpl( actorId: Long, postId: Long ) { - if (reactionRepository.existByPostIdAndActorIdAndEmoji(postId, actorId, emoji).not()) { - try { - reactionRepository.save( - Reaction(reactionRepository.generateId(), emoji, postId, actorId) - ) - } catch (_: ExposedSQLException) { - } + if (reactionRepository.existByPostIdAndActor(postId, actorId)) { + reactionRepository.deleteByPostIdAndActorId(postId, actorId) + } + try { + reactionRepository.save(Reaction(reactionRepository.generateId(), emoji, postId, actorId)) + } catch (_: DuplicateException) { } } diff --git a/src/main/resources/db/migration/V1__Init_DB.sql b/src/main/resources/db/migration/V1__Init_DB.sql index e331c9f8..2e9e638b 100644 --- a/src/main/resources/db/migration/V1__Init_DB.sql +++ b/src/main/resources/db/migration/V1__Init_DB.sql @@ -131,11 +131,12 @@ alter table posts_emojis create table if not exists reactions ( - id bigserial primary key, + id bigint 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 + actor_id bigint not null, + unique (post_id, actor_id) ); alter table reactions add constraint fk_reactions_post_id__id foreign key (post_id) references posts (id) on delete restrict on update restrict;