Database traits

This commit is contained in:
Kgothatso Ngako
2026-03-24 22:49:03 +02:00
parent 23033b0b47
commit 907aaac788
17 changed files with 362 additions and 95 deletions

View File

@@ -3,7 +3,10 @@ package ac.aux.compose.database.dao
import ac.aux.compose.database.AuxDatabase
import ac.aux.compose.database.model.NostrEvent
import ac.aux.compose.database.model.Post
import ac.aux.compose.database.model.Profile
import androidx.room.Dao
import androidx.room.Embedded
import androidx.room.Relation
import androidx.room.Transaction
@Dao
@@ -11,8 +14,18 @@ abstract class NostrDao(
private val database: AuxDatabase
) {
@Transaction
open suspend fun insertPostAndNostrEvent(post: Post, nostrEvent: NostrEvent) {
database.nostrEventDao().insert(nostrEvent)
database.postDao().insert(post) // TODO: Make use of the nostrEventId...
open suspend fun insertPostAndNostrEvent(nostrEvent: NostrEvent) {
// TODO: Get post from nostrEvent
// database.nostrEventDao().insert(nostrEvent)
// database.postDao().insert(nostrEvent.post) // TODO: Make use of the nostrEventId...
}
data class NostrEventAndPost(
@Embedded val nostrEvent: NostrEvent,
@Relation(
parentColumn = "id",
entityColumn = "nostrEventId"
)
val post: Post
)
}

View File

@@ -0,0 +1,28 @@
package ac.aux.compose.database.model
import ac.aux.compose.database.model.traits.NostrEventEntity
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey
import com.vitorpamplona.quartz.nip01Core.core.HexKey
@Entity(
foreignKeys = [
ForeignKey(
entity = NostrEvent::class,
parentColumns = ["id"],
childColumns = ["nostrEventId"],
onDelete = ForeignKey.CASCADE,
),
],
indices = [
Index("nostrEventId"),
],
)
data class BroadcastRequest(
@PrimaryKey(autoGenerate = true)
val id: Long,
override val nostrEventId: HexKey,
val status: String = "pending",
): NostrEventEntity

View File

@@ -1,5 +1,10 @@
package ac.aux.compose.database.model
import ac.aux.compose.database.model.traits.BroadcastableEntity
import ac.aux.compose.database.model.traits.LocalStoreEntity
import ac.aux.compose.database.model.traits.SoftDeletableEntity
import ac.aux.compose.database.model.traits.TimestampedEntity
import ac.aux.compose.database.model.traits.UserViewableEntity
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Fts4
@@ -8,6 +13,7 @@ import androidx.room.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.Clock
import kotlin.time.Instant
@Entity
@@ -15,14 +21,17 @@ data class NostrEvent(
@PrimaryKey
val id: String,
val pubKey: HexKey,
val createdAt: Instant,
val savedAt: Instant,
val broadcastedAt: Instant,
val kind: Kind,
val tags: TagArray,
val content: String,
val sig: HexKey,
) {
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 {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false

View File

@@ -1,5 +1,11 @@
package ac.aux.compose.database.model
import ac.aux.compose.database.model.traits.BroadcastableEntity
import ac.aux.compose.database.model.traits.LocalStoreEntity
import ac.aux.compose.database.model.traits.NostrEventEntity
import ac.aux.compose.database.model.traits.SoftDeletableEntity
import ac.aux.compose.database.model.traits.TimestampedEntity
import ac.aux.compose.database.model.traits.UserViewableEntity
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
@@ -50,27 +56,17 @@ import kotlin.time.Instant
data class Post(
@PrimaryKey
val id: HexKey,
val nostrEventId: HexKey, // Might be a replaceable nostr event?
override val nostrEventId: HexKey, // Might be a replaceable nostr event?
val replyToId: HexKey? = null,
val repostId: HexKey? = null,
val quote: HexKey? = null,
val profilePublicKey: HexKey,
val createdAt: Instant,
val savedAt: Instant,
val broadcastedAt: Instant,
val content: String,
) {
companion object {
val DUMMY_POSTS = arrayOf(
Post(
id = "genesisnoteid",
nostrEventId = "genesisnoteid", // Need to check how to handle addressableEvents...
profilePublicKey = "satoshi",
createdAt = Clock.System.now(),
savedAt = Clock.System.now(),
broadcastedAt = Clock.System.now(),
content = "Chancellor the rapper...",
)
)
}
}
override val createdAt: Instant = Clock.System.now(),
override val updatedAt: Instant = Clock.System.now(),
override val savedAt: Instant = Clock.System.now(),
override val viewedAt: Instant? = null,
override val deletedAt: Instant? = null,
override val broadcastedAt: Instant? = null,
): NostrEventEntity, TimestampedEntity, LocalStoreEntity, UserViewableEntity, BroadcastableEntity, SoftDeletableEntity

View File

@@ -1,9 +1,17 @@
package ac.aux.compose.database.model
import ac.aux.compose.database.model.traits.BroadcastableEntity
import ac.aux.compose.database.model.traits.LocalStoreEntity
import ac.aux.compose.database.model.traits.NostrEventEntity
import ac.aux.compose.database.model.traits.SoftDeletableEntity
import ac.aux.compose.database.model.traits.TimestampedEntity
import ac.aux.compose.database.model.traits.UserViewableEntity
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey
import kotlin.time.Clock
import kotlin.time.Instant
@Entity(
foreignKeys = [
@@ -21,7 +29,7 @@ import androidx.room.PrimaryKey
data class Profile(
@PrimaryKey
val publicKey: String,
val nostrEventId: String,
override val nostrEventId: String,
val userName: String? = null, // name in the nostr event...
val displayName: String? = null,
val picture: String? = null,
@@ -34,9 +42,12 @@ data class Profile(
val domain: String? = null,
val lud06: String? = null,
val lud16: String? = null,
val twitter: String? = null
) {
companion object {
val DUMMAY_PROFILES = arrayOf<Profile>()
}
}
val twitter: String? = null,
override val createdAt: Instant = Clock.System.now(),
override val updatedAt: Instant = Clock.System.now(),
override val savedAt: Instant = Clock.System.now(),
override val viewedAt: Instant? = null,
override val deletedAt: Instant? = null,
override val broadcastedAt: Instant? = null,
): NostrEventEntity, TimestampedEntity, LocalStoreEntity, UserViewableEntity, BroadcastableEntity, SoftDeletableEntity

View File

@@ -1,5 +1,11 @@
package ac.aux.compose.database.model
import ac.aux.compose.database.model.traits.BroadcastableEntity
import ac.aux.compose.database.model.traits.LocalStoreEntity
import ac.aux.compose.database.model.traits.NostrEventEntity
import ac.aux.compose.database.model.traits.SoftDeletableEntity
import ac.aux.compose.database.model.traits.TimestampedEntity
import ac.aux.compose.database.model.traits.UserViewableEntity
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
@@ -42,9 +48,14 @@ import kotlin.time.Instant
data class Reaction(
@PrimaryKey
val id: HexKey,
val nostrEventId: HexKey, // Might be a replaceable nostr event?
override val nostrEventId: HexKey, // Might be a replaceable nostr event?
val replyToId: HexKey,
val profilePublicKey: HexKey,
val createdAt: Instant,
val content: String,
)
override val createdAt: Instant = Clock.System.now(),
override val updatedAt: Instant = Clock.System.now(),
override val savedAt: Instant = Clock.System.now(),
override val viewedAt: Instant? = null,
override val deletedAt: Instant? = null,
override val broadcastedAt: Instant? = null,
): NostrEventEntity, TimestampedEntity, LocalStoreEntity, UserViewableEntity, BroadcastableEntity, SoftDeletableEntity

View File

@@ -1,5 +1,11 @@
package ac.aux.compose.database.model
import ac.aux.compose.database.model.traits.BroadcastableEntity
import ac.aux.compose.database.model.traits.LocalStoreEntity
import ac.aux.compose.database.model.traits.NostrEventEntity
import ac.aux.compose.database.model.traits.SoftDeletableEntity
import ac.aux.compose.database.model.traits.TimestampedEntity
import ac.aux.compose.database.model.traits.UserViewableEntity
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
@@ -42,9 +48,14 @@ import kotlin.time.Instant
data class Repost(
@PrimaryKey
val id: HexKey,
val nostrEventId: HexKey, // Might be a replaceable nostr event?
override val nostrEventId: HexKey, // Might be a replaceable nostr event?
val postId: HexKey? = null,
val profilePublicKey: HexKey,
val createdAt: Instant,
val content: String,
)
override val createdAt: Instant = Clock.System.now(),
override val updatedAt: Instant = Clock.System.now(),
override val savedAt: Instant = Clock.System.now(),
override val viewedAt: Instant? = null,
override val deletedAt: Instant? = null,
override val broadcastedAt: Instant? = null,
): NostrEventEntity, TimestampedEntity, LocalStoreEntity, UserViewableEntity, BroadcastableEntity, SoftDeletableEntity

View File

@@ -1,10 +1,17 @@
package ac.aux.compose.database.model
import ac.aux.compose.database.model.traits.BroadcastableEntity
import ac.aux.compose.database.model.traits.LocalStoreEntity
import ac.aux.compose.database.model.traits.NostrEventEntity
import ac.aux.compose.database.model.traits.SoftDeletableEntity
import ac.aux.compose.database.model.traits.TimestampedEntity
import ac.aux.compose.database.model.traits.UserViewableEntity
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import kotlin.time.Clock
import kotlin.time.Instant
@Entity(
@@ -45,11 +52,16 @@ import kotlin.time.Instant
data class Zap(
@PrimaryKey
val id: HexKey,
val nostrEventId: HexKey, // Might be a replaceable nostr event?
override val nostrEventId: HexKey, // Might be a replaceable nostr event?
val postId: HexKey,
val senderPublicKey: HexKey,
val receiverPublicKey: HexKey,
val createdAt: Instant,
val message: String?,
val invoice: String?,
)
override val createdAt: Instant = Clock.System.now(),
override val updatedAt: Instant = Clock.System.now(),
override val savedAt: Instant = Clock.System.now(),
override val viewedAt: Instant? = null,
override val deletedAt: Instant? = null,
override val broadcastedAt: Instant? = null,
) : NostrEventEntity, TimestampedEntity, LocalStoreEntity, UserViewableEntity, BroadcastableEntity, SoftDeletableEntity

View File

@@ -0,0 +1,7 @@
package ac.aux.compose.database.model.traits
import kotlin.time.Instant
interface BroadcastableEntity {
val broadcastedAt: Instant?
}

View File

@@ -0,0 +1,7 @@
package ac.aux.compose.database.model.traits
import kotlin.time.Instant
interface LocalStoreEntity {
val savedAt: Instant
}

View File

@@ -0,0 +1,7 @@
package ac.aux.compose.database.model.traits
import com.vitorpamplona.quartz.nip01Core.core.HexKey
interface NostrEventEntity {
val nostrEventId: HexKey
}

View File

@@ -0,0 +1,7 @@
package ac.aux.compose.database.model.traits
import kotlin.time.Instant
interface SoftDeletableEntity {
val deletedAt: Instant?
}

View File

@@ -0,0 +1,8 @@
package ac.aux.compose.database.model.traits
import kotlin.time.Instant
interface TimestampedEntity {
val createdAt: Instant
val updatedAt: Instant
}

View File

@@ -0,0 +1,7 @@
package ac.aux.compose.database.model.traits
import kotlin.time.Instant
interface UserViewableEntity {
val viewedAt: Instant?
}

View File

@@ -2,23 +2,18 @@ package ac.aux.compose.database.repository
import ac.aux.compose.database.AuxDatabase
import ac.aux.compose.database.model.NostrEvent
import ac.aux.compose.database.model.Post
import ac.aux.compose.repository.PostRepository
class DatabasePostRepository(
private val database: AuxDatabase
): PostRepository {
override suspend fun publishPost(
post: Post,
nostrEvent: NostrEvent
) {
val nostrDao = database.nostrDao()
nostrDao.insertPostAndNostrEvent(
post,
nostrEvent
)
}
}

View File

@@ -1,8 +1,7 @@
package ac.aux.compose.repository
import ac.aux.compose.database.model.NostrEvent
import ac.aux.compose.database.model.Post
interface PostRepository {
suspend fun publishPost(post: Post, nostrEvent: NostrEvent)
suspend fun publishPost(nostrEvent: NostrEvent)
}