Add chat database models
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,12 @@ package ac.cord.auxiliary.compose.database
|
||||
import ac.cord.auxiliary.compose.database.converters.AuxConverters
|
||||
import ac.cord.auxiliary.compose.database.dao.BroadcastNostrEventReceiptDao
|
||||
import ac.cord.auxiliary.compose.database.dao.BroadcastNostrEventRequestDao
|
||||
import ac.cord.auxiliary.compose.database.dao.ChatMessageDao
|
||||
import ac.cord.auxiliary.compose.database.dao.ChatRoomDao
|
||||
import ac.cord.auxiliary.compose.database.dao.ConnectionDao
|
||||
import ac.cord.auxiliary.compose.database.dao.GiftWrapMessageDao
|
||||
import ac.cord.auxiliary.compose.database.dao.GiftWrapSealDao
|
||||
import ac.cord.auxiliary.compose.database.dao.GiftWrapUnsignedDao
|
||||
import ac.cord.auxiliary.compose.database.dao.InReplyToRelationDao
|
||||
import ac.cord.auxiliary.compose.database.dao.MentionDao
|
||||
import ac.cord.auxiliary.compose.database.dao.NegentropySynchronizeRequestDao
|
||||
@@ -24,7 +29,12 @@ import ac.cord.auxiliary.compose.database.dao.UnsignedNostrEventDao
|
||||
import ac.cord.auxiliary.compose.database.dao.ZapDao
|
||||
import ac.cord.auxiliary.compose.database.model.BroadcastNostrEventReceipt
|
||||
import ac.cord.auxiliary.compose.database.model.BroadcastNostrEventRequest
|
||||
import ac.cord.auxiliary.compose.database.model.ChatMessage
|
||||
import ac.cord.auxiliary.compose.database.model.ChatRoom
|
||||
import ac.cord.auxiliary.compose.database.model.Connection
|
||||
import ac.cord.auxiliary.compose.database.model.GiftWrapMessage
|
||||
import ac.cord.auxiliary.compose.database.model.GiftWrapSeal
|
||||
import ac.cord.auxiliary.compose.database.model.GiftWrapUnsigned
|
||||
import ac.cord.auxiliary.compose.database.model.InReplyToRelation
|
||||
import ac.cord.auxiliary.compose.database.model.Mention
|
||||
import ac.cord.auxiliary.compose.database.model.NegentropySynchronizeRequest
|
||||
@@ -42,6 +52,7 @@ import ac.cord.auxiliary.compose.database.model.SynchronizeNostrEventRequest
|
||||
import ac.cord.auxiliary.compose.database.model.SynchronizeNostrEventResult
|
||||
import ac.cord.auxiliary.compose.database.model.UnsignedNostrEvent
|
||||
import ac.cord.auxiliary.compose.database.model.Zap
|
||||
import androidx.room3.AutoMigration
|
||||
import androidx.room3.Database
|
||||
import androidx.room3.RoomDatabase
|
||||
import androidx.room3.TypeConverters
|
||||
@@ -56,7 +67,12 @@ val GENESIS_AT = Instant.fromEpochMilliseconds(1231006505000L)
|
||||
BroadcastNostrEventReceipt::class,
|
||||
BroadcastNostrEventRequest::class,
|
||||
Connection::class,
|
||||
ChatMessage::class,
|
||||
ChatRoom::class,
|
||||
InReplyToRelation::class,
|
||||
GiftWrapMessage::class,
|
||||
GiftWrapSeal::class,
|
||||
GiftWrapUnsigned::class,
|
||||
Mention::class,
|
||||
NegentropySynchronizeRequest::class,
|
||||
NegentropySynchronizeResult::class,
|
||||
@@ -74,14 +90,31 @@ val GENESIS_AT = Instant.fromEpochMilliseconds(1231006505000L)
|
||||
UnsignedNostrEvent::class,
|
||||
Zap::class
|
||||
],
|
||||
version = 1
|
||||
version = 2,
|
||||
autoMigrations = [
|
||||
AutoMigration(
|
||||
from = 1,
|
||||
to = 2
|
||||
)
|
||||
]
|
||||
)
|
||||
@TypeConverters(AuxConverters::class)
|
||||
abstract class AuxDatabase: RoomDatabase() {
|
||||
abstract fun broadcastNostrEventReceiptDao(): BroadcastNostrEventReceiptDao
|
||||
abstract fun broadcastNostrEventRequestDao(): BroadcastNostrEventRequestDao
|
||||
|
||||
abstract fun chatMessageDao(): ChatMessageDao
|
||||
|
||||
abstract fun chatRoomDao(): ChatRoomDao
|
||||
|
||||
abstract fun connectionDao(): ConnectionDao
|
||||
|
||||
abstract fun giftWrapMessageDao(): GiftWrapMessageDao
|
||||
|
||||
abstract fun giftWrapSealDao(): GiftWrapSealDao
|
||||
|
||||
abstract fun giftWrapUnsignedDao(): GiftWrapUnsignedDao
|
||||
|
||||
abstract fun inReplyToRelationDao(): InReplyToRelationDao
|
||||
|
||||
abstract fun mentionDao(): MentionDao
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package ac.cord.auxiliary.compose.database.dao
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.ChatMessage
|
||||
import ac.cord.auxiliary.compose.database.model.Relay
|
||||
import androidx.room3.Dao
|
||||
import androidx.room3.Query
|
||||
import androidx.room3.Upsert
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface ChatMessageDao {
|
||||
@Query("SELECT * FROM ChatMessage WHERE chatRoomId = :chatRoomId")
|
||||
fun observeChatMessagesByChatRoomId(chatRoomId: String): Flow<List<ChatMessage>>
|
||||
|
||||
@Upsert
|
||||
suspend fun upsert(chatMessage: ChatMessage)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package ac.cord.auxiliary.compose.database.dao
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.ChatRoom
|
||||
import ac.cord.auxiliary.compose.database.model.Relay
|
||||
import androidx.room3.Dao
|
||||
import androidx.room3.Query
|
||||
import androidx.room3.Upsert
|
||||
import fr.acinq.bitcoin.PublicKey
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface ChatRoomDao {
|
||||
|
||||
@Query("SELECT * FROM ChatRoom WHERE userPublicKey = :userPublicKey")
|
||||
fun observeChatRoomByUserPublicKey(userPublicKey: String): Flow<List<ChatRoom>>
|
||||
|
||||
@Upsert
|
||||
suspend fun upsert(chatRoom: ChatRoom)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package ac.cord.auxiliary.compose.database.dao
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.GiftWrapMessage
|
||||
import ac.cord.auxiliary.compose.database.model.Relay
|
||||
import androidx.room3.Dao
|
||||
import androidx.room3.Query
|
||||
import androidx.room3.Upsert
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface GiftWrapMessageDao {
|
||||
@Query("SELECT * FROM GiftWrapMessage")
|
||||
fun getAllGiftWrapMessages(): List<GiftWrapMessage>
|
||||
|
||||
@Upsert
|
||||
suspend fun upsert(giftWrapMessage: GiftWrapMessage)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package ac.cord.auxiliary.compose.database.dao
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.GiftWrapSeal
|
||||
import ac.cord.auxiliary.compose.database.model.Relay
|
||||
import androidx.room3.Dao
|
||||
import androidx.room3.Query
|
||||
import androidx.room3.Upsert
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface GiftWrapSealDao {
|
||||
@Query("SELECT * FROM GiftWrapSeal")
|
||||
fun getAllGiftWrapSeals(): List<GiftWrapSeal>
|
||||
|
||||
@Upsert
|
||||
suspend fun upsert(giftWrapSeal: GiftWrapSeal)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package ac.cord.auxiliary.compose.database.dao
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.GiftWrapUnsigned
|
||||
import ac.cord.auxiliary.compose.database.model.Relay
|
||||
import androidx.room3.Dao
|
||||
import androidx.room3.Query
|
||||
import androidx.room3.Upsert
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface GiftWrapUnsignedDao {
|
||||
@Query("SELECT * FROM GiftWrapUnsigned")
|
||||
fun getAllGiftWrapUnsigned(): List<GiftWrapUnsigned>
|
||||
|
||||
|
||||
@Upsert
|
||||
suspend fun upsert(giftWrapUnsigned: GiftWrapUnsigned)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package ac.cord.auxiliary.compose.database.model
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.traits.LocalStoreEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.SoftDeletableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.UserViewableEntity
|
||||
import androidx.room3.Entity
|
||||
import androidx.room3.ForeignKey
|
||||
import androidx.room3.PrimaryKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import kotlin.time.Instant
|
||||
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = ChatRoom::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["chatRoomId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
ForeignKey(
|
||||
entity = GiftWrapUnsigned::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["giftWrapUnsignedId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
],
|
||||
)
|
||||
data class ChatMessage(
|
||||
@PrimaryKey
|
||||
val id: HexKey,
|
||||
|
||||
val senderPublicKey: String,
|
||||
val isUserMessage: Boolean,
|
||||
|
||||
val chatRoomId: String,
|
||||
|
||||
val giftWrapUnsignedId: String,
|
||||
|
||||
val replyToEventId: String?,
|
||||
val quotedEventId: String?,
|
||||
|
||||
val content: String,
|
||||
|
||||
override val createdAt: Instant,
|
||||
override val updatedAt: Instant,
|
||||
override val savedAt: Instant,
|
||||
override val viewedAt: Instant?,
|
||||
override val deletedAt: Instant?, // Who this message should be seen by (used to derive conversationId)
|
||||
): TimestampedEntity, LocalStoreEntity, UserViewableEntity, SoftDeletableEntity {
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package ac.cord.auxiliary.compose.database.model
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.traits.LocalStoreEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.SoftDeletableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.UserViewableEntity
|
||||
import androidx.room3.Entity
|
||||
import androidx.room3.ForeignKey
|
||||
import androidx.room3.PrimaryKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import kotlin.time.Instant
|
||||
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Profile::class,
|
||||
parentColumns = ["publicKey"],
|
||||
childColumns = ["userPublicKey"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
ForeignKey(
|
||||
entity = GiftWrapUnsigned::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["initialGiftWrapUnsignedId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
],
|
||||
)
|
||||
data class ChatRoom(
|
||||
/**
|
||||
* Derived from the participants...
|
||||
*
|
||||
* can aggregate them into one id like musig(participants...)
|
||||
*/
|
||||
@PrimaryKey
|
||||
val id: String,
|
||||
|
||||
/**
|
||||
* Logged in user PublicKey... should help us have multiple user support...
|
||||
*/
|
||||
val userPublicKey: HexKey,
|
||||
|
||||
/**
|
||||
* Optional retrieved from tags...
|
||||
*
|
||||
* Any member can change the topic by simply submitting a new subject to an existing pubkey + p tags room.
|
||||
*
|
||||
* There is no need to send subject in every message. The newest subject in the chat room is the subject of the conversation.
|
||||
*/
|
||||
val subject: String?,
|
||||
|
||||
/**
|
||||
* Should probably be the human-readable name of whichever participant is not the user...
|
||||
*/
|
||||
val name: String?,
|
||||
|
||||
/**
|
||||
* Derived from kind14/15 tags
|
||||
* [
|
||||
* ["p", "<receiver-1-pubkey>", "<relay-url>"],
|
||||
* ["p", "<receiver-2-pubkey>", "<relay-url>"],
|
||||
* // rest of tags...
|
||||
* ]
|
||||
*
|
||||
* TODO: Might want to add a relation for this...
|
||||
*/
|
||||
// TODO: Add a LastChatMessageRelation
|
||||
// val lastChatMessageId: String? = null,
|
||||
// Might want to focus on the other last messages...
|
||||
val initialGiftWrapUnsignedId: String,
|
||||
|
||||
override val createdAt: Instant,
|
||||
override val updatedAt: Instant,
|
||||
override val savedAt: Instant,
|
||||
override val viewedAt: Instant?,
|
||||
override val deletedAt: Instant?,
|
||||
|
||||
): TimestampedEntity, LocalStoreEntity, UserViewableEntity, SoftDeletableEntity {
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package ac.cord.auxiliary.compose.database.model
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.traits.LocalStoreEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.NostrEventEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.SoftDeletableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.UserViewableEntity
|
||||
import androidx.room3.Entity
|
||||
import androidx.room3.ForeignKey
|
||||
import androidx.room3.PrimaryKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Kind
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArray
|
||||
import kotlin.time.Instant
|
||||
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = NostrEvent::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["nostrEventId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
],
|
||||
)
|
||||
data class GiftWrapMessage(
|
||||
@PrimaryKey
|
||||
val id: HexKey,
|
||||
|
||||
/**
|
||||
* Random PublicKey (should it be derived from randomPrivateKey?)
|
||||
*/
|
||||
val publicKey: String,
|
||||
|
||||
val kind: Kind = 1059,
|
||||
/**
|
||||
* [
|
||||
* ["p", receiverPublicKey, "<relay-url>"] // receiver
|
||||
* ]
|
||||
*/
|
||||
val tags: Array<Array<String>>,
|
||||
/**
|
||||
*
|
||||
* encrypt(GiftWrapSeal, randomPrivateKey, receiverPublicKey)
|
||||
*/
|
||||
val content: String,
|
||||
/**
|
||||
* Signed using the randomPrivateKey used to encrypt the GiftWrapSeal
|
||||
*/
|
||||
val signature: String,
|
||||
|
||||
/**
|
||||
* What gets broadcasts?
|
||||
*/
|
||||
override val nostrEventId: String,
|
||||
|
||||
/**
|
||||
* randomTimeUpTo2DaysInThePast
|
||||
*/
|
||||
override val createdAt: Instant,
|
||||
override val updatedAt: Instant,
|
||||
override val savedAt: Instant,
|
||||
override val viewedAt: Instant?,
|
||||
override val deletedAt: Instant?, // Who this message should be seen by (used to derive conversationId)
|
||||
): NostrEventEntity, TimestampedEntity, LocalStoreEntity, UserViewableEntity, SoftDeletableEntity {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || this::class != other::class) return false
|
||||
|
||||
other as GiftWrapMessage
|
||||
|
||||
if (kind != other.kind) return false
|
||||
if (id != other.id) return false
|
||||
if (publicKey != other.publicKey) return false
|
||||
if (!tags.contentDeepEquals(other.tags)) return false
|
||||
if (content != other.content) return false
|
||||
if (signature != other.signature) return false
|
||||
if (nostrEventId != other.nostrEventId) return false
|
||||
if (createdAt != other.createdAt) return false
|
||||
if (updatedAt != other.updatedAt) return false
|
||||
if (savedAt != other.savedAt) return false
|
||||
if (viewedAt != other.viewedAt) return false
|
||||
if (deletedAt != other.deletedAt) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = kind
|
||||
result = 31 * result + id.hashCode()
|
||||
result = 31 * result + publicKey.hashCode()
|
||||
result = 31 * result + tags.contentDeepHashCode()
|
||||
result = 31 * result + content.hashCode()
|
||||
result = 31 * result + signature.hashCode()
|
||||
result = 31 * result + nostrEventId.hashCode()
|
||||
result = 31 * result + createdAt.hashCode()
|
||||
result = 31 * result + updatedAt.hashCode()
|
||||
result = 31 * result + savedAt.hashCode()
|
||||
result = 31 * result + (viewedAt?.hashCode() ?: 0)
|
||||
result = 31 * result + (deletedAt?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package ac.cord.auxiliary.compose.database.model
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.traits.LocalStoreEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.SoftDeletableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.UserViewableEntity
|
||||
import androidx.room3.Entity
|
||||
import androidx.room3.ForeignKey
|
||||
import androidx.room3.PrimaryKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Kind
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArray
|
||||
import kotlin.time.Instant
|
||||
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = GiftWrapMessage::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["giftWrapMessageId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
|
||||
],
|
||||
)
|
||||
data class GiftWrapSeal(
|
||||
@PrimaryKey
|
||||
val id: HexKey,
|
||||
/**
|
||||
* senderPublicKey
|
||||
*/
|
||||
val publicKey: String,
|
||||
|
||||
val kind: Kind = 13,
|
||||
/**
|
||||
* No tags
|
||||
*/
|
||||
val tags: Array<Array<String>> = emptyArray(),
|
||||
|
||||
/**
|
||||
*
|
||||
* nip44Encrypt(unsignedKind14, senderPrivateKey, receiverPublicKey)
|
||||
*/
|
||||
val content: String,
|
||||
|
||||
/**
|
||||
* signed by senderPrivateKey
|
||||
*/
|
||||
val signature: String,
|
||||
|
||||
/**
|
||||
* Associated GiftWrapMessage
|
||||
*/
|
||||
val giftWrapMessageId: String? = null,
|
||||
|
||||
/**
|
||||
* randomTimeUpTo2DaysInThePast()
|
||||
*/
|
||||
override val createdAt: Instant,
|
||||
override val updatedAt: Instant,
|
||||
override val savedAt: Instant,
|
||||
override val viewedAt: Instant?,
|
||||
override val deletedAt: Instant?, // Who this message should be seen by (used to derive conversationId)
|
||||
): TimestampedEntity, LocalStoreEntity, UserViewableEntity, SoftDeletableEntity {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || this::class != other::class) return false
|
||||
|
||||
other as GiftWrapSeal
|
||||
|
||||
if (kind != other.kind) return false
|
||||
if (id != other.id) return false
|
||||
if (publicKey != other.publicKey) return false
|
||||
if (!tags.contentDeepEquals(other.tags)) return false
|
||||
if (content != other.content) return false
|
||||
if (signature != other.signature) return false
|
||||
if (giftWrapMessageId != other.giftWrapMessageId) return false
|
||||
if (createdAt != other.createdAt) return false
|
||||
if (updatedAt != other.updatedAt) return false
|
||||
if (savedAt != other.savedAt) return false
|
||||
if (viewedAt != other.viewedAt) return false
|
||||
if (deletedAt != other.deletedAt) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = kind
|
||||
result = 31 * result + id.hashCode()
|
||||
result = 31 * result + publicKey.hashCode()
|
||||
result = 31 * result + tags.contentDeepHashCode()
|
||||
result = 31 * result + content.hashCode()
|
||||
result = 31 * result + signature.hashCode()
|
||||
result = 31 * result + (giftWrapMessageId?.hashCode() ?: 0)
|
||||
result = 31 * result + createdAt.hashCode()
|
||||
result = 31 * result + updatedAt.hashCode()
|
||||
result = 31 * result + savedAt.hashCode()
|
||||
result = 31 * result + (viewedAt?.hashCode() ?: 0)
|
||||
result = 31 * result + (deletedAt?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package ac.cord.auxiliary.compose.database.model
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.traits.LocalStoreEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.SoftDeletableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.UserViewableEntity
|
||||
import androidx.room3.Entity
|
||||
import androidx.room3.ForeignKey
|
||||
import androidx.room3.PrimaryKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Kind
|
||||
import kotlin.time.Instant
|
||||
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = GiftWrapSeal::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["giftWrapSealId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
],
|
||||
)
|
||||
data class GiftWrapUnsigned(
|
||||
@PrimaryKey
|
||||
val id: HexKey,
|
||||
|
||||
/**
|
||||
* Sender Public Key
|
||||
*/
|
||||
val publicKey: String,
|
||||
|
||||
/**
|
||||
* Chat Message Kind
|
||||
*/
|
||||
val kind: Kind = 14,
|
||||
|
||||
/**
|
||||
* Tags for the unsigned giftwrap
|
||||
*
|
||||
* [
|
||||
* ["p", "<receiver-1-pubkey>", "<relay-url>"],
|
||||
* ["p", "<receiver-2-pubkey>", "<relay-url>"],
|
||||
* ["e", "<kind-14-id>", "<relay-url>"] // if this is a reply
|
||||
* ["subject", "<conversation-title>"],
|
||||
* // rest of tags...
|
||||
* ]
|
||||
*
|
||||
* q tags MAY be used when citing events in the .content with NIP-21.
|
||||
*/
|
||||
val tags: Array<Array<String>>,
|
||||
|
||||
/**
|
||||
* content MUST be plain text. Fields id and created_at are required.
|
||||
*/
|
||||
val content: String,
|
||||
val quotedEventId: String?,
|
||||
|
||||
/**
|
||||
* Associated GiftWrapSeal
|
||||
*/
|
||||
val giftWrapSealId: String? = null,
|
||||
|
||||
/**
|
||||
* Current time
|
||||
*/
|
||||
override val createdAt: Instant,
|
||||
override val updatedAt: Instant,
|
||||
override val savedAt: Instant,
|
||||
override val viewedAt: Instant?,
|
||||
override val deletedAt: Instant?, // Who this message should be seen by (used to derive conversationId)
|
||||
): TimestampedEntity, LocalStoreEntity, UserViewableEntity, SoftDeletableEntity {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || this::class != other::class) return false
|
||||
|
||||
other as GiftWrapUnsigned
|
||||
|
||||
if (kind != other.kind) return false
|
||||
if (id != other.id) return false
|
||||
if (publicKey != other.publicKey) return false
|
||||
if (!tags.contentDeepEquals(other.tags)) return false
|
||||
if (content != other.content) return false
|
||||
if (quotedEventId != other.quotedEventId) return false
|
||||
if (giftWrapSealId != other.giftWrapSealId) return false
|
||||
if (createdAt != other.createdAt) return false
|
||||
if (updatedAt != other.updatedAt) return false
|
||||
if (savedAt != other.savedAt) return false
|
||||
if (viewedAt != other.viewedAt) return false
|
||||
if (deletedAt != other.deletedAt) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = kind
|
||||
result = 31 * result + id.hashCode()
|
||||
result = 31 * result + publicKey.hashCode()
|
||||
result = 31 * result + tags.contentDeepHashCode()
|
||||
result = 31 * result + content.hashCode()
|
||||
result = 31 * result + (quotedEventId?.hashCode() ?: 0)
|
||||
result = 31 * result + (giftWrapSealId?.hashCode() ?: 0)
|
||||
result = 31 * result + createdAt.hashCode()
|
||||
result = 31 * result + updatedAt.hashCode()
|
||||
result = 31 * result + savedAt.hashCode()
|
||||
result = 31 * result + (viewedAt?.hashCode() ?: 0)
|
||||
result = 31 * result + (deletedAt?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package ac.cord.auxiliary.compose.database.model
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.traits.BroadcastableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.LocalStoreEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.SoftDeletableEntity
|
||||
import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity
|
||||
import androidx.room3.Entity
|
||||
import androidx.room3.ForeignKey
|
||||
import androidx.room3.PrimaryKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
|
||||
/**
|
||||
* Derived from kind14/15 tags
|
||||
* [
|
||||
* ["p", "<receiver-1-pubkey>", "<relay-url>"],
|
||||
* ["p", "<receiver-2-pubkey>", "<relay-url>"],
|
||||
* // rest of tags...
|
||||
* ]
|
||||
*
|
||||
* TODO: Might want to add a relation for this...
|
||||
*/
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Profile::class,
|
||||
parentColumns = ["publicKey"],
|
||||
childColumns = ["participantPublicKey"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
ForeignKey(
|
||||
entity = ChatRoom::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["chatRoomId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
]
|
||||
)
|
||||
data class Participant(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val id: Long = 0,
|
||||
|
||||
val participantPublicKey: HexKey,
|
||||
val chatRoomId: String,
|
||||
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val updatedAt: Instant = Clock.System.now(),
|
||||
override val savedAt: Instant = Clock.System.now(),
|
||||
override val deletedAt: Instant? = null,
|
||||
override val broadcastedAt: Instant? = null,
|
||||
): TimestampedEntity, LocalStoreEntity, BroadcastableEntity, SoftDeletableEntity
|
||||
@@ -0,0 +1,16 @@
|
||||
package ac.cord.auxiliary.compose.database.model.intermdiate
|
||||
|
||||
import ac.cord.auxiliary.compose.database.model.Participant
|
||||
import ac.cord.auxiliary.compose.database.model.Profile
|
||||
import androidx.room3.Embedded
|
||||
import androidx.room3.Relation
|
||||
|
||||
data class LocalParticipant(
|
||||
@Embedded val participant: Participant,
|
||||
|
||||
@Relation(
|
||||
parentColumn = "participantPublicKey",
|
||||
entityColumn = "publicKey"
|
||||
)
|
||||
val profile: Profile?,
|
||||
)
|
||||
Reference in New Issue
Block a user