From 8cc0b78f74610a5b93f4273e85d3d5acb8385122 Mon Sep 17 00:00:00 2001 From: KaiRaiChu Date: Thu, 29 Jan 2026 18:59:49 +0000 Subject: [PATCH 1/2] #171:Created Supabase Message repository --- src/main/kotlin/chatserver/MessageResult.kt | 7 ++- .../messages/SupabaseMessageRepository.kt | 55 +++++++++++++++++++ .../profiles/SupabaseProfilesRepository.kt | 2 +- 3 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 src/main/kotlin/chatserver/messages/SupabaseMessageRepository.kt diff --git a/src/main/kotlin/chatserver/MessageResult.kt b/src/main/kotlin/chatserver/MessageResult.kt index 56f4c5e..d75564e 100644 --- a/src/main/kotlin/chatserver/MessageResult.kt +++ b/src/main/kotlin/chatserver/MessageResult.kt @@ -1,15 +1,16 @@ package chatserver import chatserver.ReadChatRepository.ReadResult +import chatserver.messages.SupabaseMessageRepository.* data class MessageResult( override val isOk: Boolean, - override val item: List, + override val item: List, override val error: Exception?, ) : - ReadResult> { + ReadResult> { companion object { - fun ok(item: List): MessageResult = MessageResult(true, item, null) + fun ok(item: List): MessageResult = MessageResult(true, item, null) fun fail(e: Exception? = null): MessageResult = MessageResult(false, emptyList(), e) } diff --git a/src/main/kotlin/chatserver/messages/SupabaseMessageRepository.kt b/src/main/kotlin/chatserver/messages/SupabaseMessageRepository.kt new file mode 100644 index 0000000..f415bb1 --- /dev/null +++ b/src/main/kotlin/chatserver/messages/SupabaseMessageRepository.kt @@ -0,0 +1,55 @@ +package chatserver.messages + +import chatserver.MessageResult +import chatserver.ReadChatRepository +import chatserver.SubscribeChatRepository +import chatserver.WriteChatRepository +import io.github.jan.supabase.SupabaseClient +import io.github.jan.supabase.annotations.SupabaseExperimental +import io.github.jan.supabase.postgrest.from +import io.github.jan.supabase.realtime.selectAsFlow +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +class SupabaseMessageRepository( + private val client: SupabaseClient, + private val scope: CoroutineScope, +) : ReadChatRepository, WriteChatRepository, SubscribeChatRepository { + private val messages: MutableStateFlow = MutableStateFlow(MessageResult.ok(emptyList())) + + override fun latest(): MessageResult = messages.value + + + override fun observe(): Flow = messages.asStateFlow() + + @OptIn(SupabaseExperimental::class) + override fun subscribe() { + client.from("messages") + .selectAsFlow(Message::id) + .map { MessageResult.ok(it) } + .onEach { messages.value = it } + .catch { println(it) } + .launchIn(scope) + } + + + override fun write(item: String) { + TODO("Not yet implemented") + } + + + override fun unsubscribe() { + scope.cancel() + } + + @Serializable + data class Message( + @SerialName("id") val id: String, + @SerialName("profile_id") val profileId: String, + @SerialName("content") val content: String, + @SerialName("created_at") val createdAt: String, + ) +} diff --git a/src/main/kotlin/chatserver/profiles/SupabaseProfilesRepository.kt b/src/main/kotlin/chatserver/profiles/SupabaseProfilesRepository.kt index fc20dc2..d111cad 100644 --- a/src/main/kotlin/chatserver/profiles/SupabaseProfilesRepository.kt +++ b/src/main/kotlin/chatserver/profiles/SupabaseProfilesRepository.kt @@ -69,6 +69,6 @@ class SupabaseProfilesRepository( @Serializable data class Profile( @SerialName("id") val id: String, - @SerialName("username") val username: String, + @SerialName("username") val username: String ) } From 09859d5605783675c10cdfc42fa7bc746d890a1c Mon Sep 17 00:00:00 2001 From: Terry Rampling Date: Thu, 5 Feb 2026 18:39:04 +0000 Subject: [PATCH 2/2] #171: added write functionality to supabase chat messages --- .../messages/SupabaseMessageRepository.kt | 19 +++++++++++++++---- .../profiles/SupabaseProfilesRepository.kt | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/chatserver/messages/SupabaseMessageRepository.kt b/src/main/kotlin/chatserver/messages/SupabaseMessageRepository.kt index f415bb1..d29affd 100644 --- a/src/main/kotlin/chatserver/messages/SupabaseMessageRepository.kt +++ b/src/main/kotlin/chatserver/messages/SupabaseMessageRepository.kt @@ -6,13 +6,17 @@ import chatserver.SubscribeChatRepository import chatserver.WriteChatRepository import io.github.jan.supabase.SupabaseClient import io.github.jan.supabase.annotations.SupabaseExperimental +import io.github.jan.supabase.auth.auth import io.github.jan.supabase.postgrest.from import io.github.jan.supabase.realtime.selectAsFlow import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import kotlinx.datetime.Clock import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import java.util.UUID class SupabaseMessageRepository( private val client: SupabaseClient, @@ -22,7 +26,6 @@ class SupabaseMessageRepository( override fun latest(): MessageResult = messages.value - override fun observe(): Flow = messages.asStateFlow() @OptIn(SupabaseExperimental::class) @@ -35,11 +38,19 @@ class SupabaseMessageRepository( .launchIn(scope) } - - override fun write(item: String) { - TODO("Not yet implemented") + override fun write(item: String) { + scope.launch { + client.from("messages").insert(item.toChatMessage()) + } } + private fun String.toChatMessage() = + Message( + id = UUID.randomUUID().toString(), + profileId = client.auth.currentUserOrNull()?.id.orEmpty(), + content = this, + createdAt = Clock.System.now().toString(), + ) override fun unsubscribe() { scope.cancel() diff --git a/src/main/kotlin/chatserver/profiles/SupabaseProfilesRepository.kt b/src/main/kotlin/chatserver/profiles/SupabaseProfilesRepository.kt index d111cad..fc20dc2 100644 --- a/src/main/kotlin/chatserver/profiles/SupabaseProfilesRepository.kt +++ b/src/main/kotlin/chatserver/profiles/SupabaseProfilesRepository.kt @@ -69,6 +69,6 @@ class SupabaseProfilesRepository( @Serializable data class Profile( @SerialName("id") val id: String, - @SerialName("username") val username: String + @SerialName("username") val username: String, ) }