From 907aaac78820cd57332809e73610cdad039a1e79 Mon Sep 17 00:00:00 2001 From: Kgothatso Ngako Date: Tue, 24 Mar 2026 22:49:03 +0200 Subject: [PATCH] Database traits --- .../1.json | 231 ++++++++++++++---- .../ac/aux/compose/database/dao/NostrDao.kt | 19 +- .../model/BroadcastNostrEventRequest.kt | 28 +++ .../aux/compose/database/model/NostrEvent.kt | 17 +- .../ac/aux/compose/database/model/Post.kt | 34 ++- .../ac/aux/compose/database/model/Profile.kt | 25 +- .../ac/aux/compose/database/model/Reaction.kt | 17 +- .../ac/aux/compose/database/model/Repost.kt | 17 +- .../ac/aux/compose/database/model/Zap.kt | 18 +- .../model/traits/BroadcastableEntity.kt | 7 + .../database/model/traits/LocalStoreEntity.kt | 7 + .../database/model/traits/NostrEventEntity.kt | 7 + .../model/traits/SoftDeletableEntity.kt | 7 + .../model/traits/TimestampedEntity.kt | 8 + .../model/traits/UserViewableEntity.kt | 7 + .../repository/DatabasePostRepository.kt | 5 - .../aux/compose/repository/PostRepository.kt | 3 +- 17 files changed, 362 insertions(+), 95 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/BroadcastNostrEventRequest.kt create mode 100644 composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/BroadcastableEntity.kt create mode 100644 composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/LocalStoreEntity.kt create mode 100644 composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/NostrEventEntity.kt create mode 100644 composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/SoftDeletableEntity.kt create mode 100644 composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/TimestampedEntity.kt create mode 100644 composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/UserViewableEntity.kt diff --git a/composeApp/schemas/ac.aux.compose.database.AuxDatabase/1.json b/composeApp/schemas/ac.aux.compose.database.AuxDatabase/1.json index acefeedb..e28c4492 100644 --- a/composeApp/schemas/ac.aux.compose.database.AuxDatabase/1.json +++ b/composeApp/schemas/ac.aux.compose.database.AuxDatabase/1.json @@ -2,11 +2,11 @@ "formatVersion": 1, "database": { "version": 1, - "identityHash": "9a4e13a505370c8fd3433ef4241cbcc8", + "identityHash": "7219ad348874b83380e4072dec332bee", "entities": [ { "tableName": "NostrEvent", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `pubKey` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `broadcastedAt` INTEGER NOT NULL, `kind` INTEGER NOT NULL, `tags` TEXT NOT NULL, `content` TEXT NOT NULL, `sig` TEXT NOT NULL, PRIMARY KEY(`id`))", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `pubKey` TEXT NOT NULL, `kind` INTEGER NOT NULL, `tags` TEXT NOT NULL, `content` TEXT NOT NULL, `sig` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`id`))", "fields": [ { "fieldPath": "id", @@ -20,24 +20,6 @@ "affinity": "TEXT", "notNull": true }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "savedAt", - "columnName": "savedAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "broadcastedAt", - "columnName": "broadcastedAt", - "affinity": "INTEGER", - "notNull": true - }, { "fieldPath": "kind", "columnName": "kind", @@ -61,6 +43,34 @@ "columnName": "sig", "affinity": "TEXT", "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "savedAt", + "columnName": "savedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "INTEGER" + }, + { + "fieldPath": "broadcastedAt", + "columnName": "broadcastedAt", + "affinity": "INTEGER" } ], "primaryKey": { @@ -72,7 +82,7 @@ }, { "tableName": "Post", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `nostrEventId` TEXT NOT NULL, `replyToId` TEXT, `repostId` TEXT, `quote` TEXT, `profilePublicKey` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `broadcastedAt` INTEGER NOT NULL, `content` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`profilePublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`replyToId`) REFERENCES `Post`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`repostId`) REFERENCES `Post`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `nostrEventId` TEXT NOT NULL, `replyToId` TEXT, `repostId` TEXT, `quote` TEXT, `profilePublicKey` TEXT NOT NULL, `content` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `viewedAt` INTEGER, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`profilePublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`replyToId`) REFERENCES `Post`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`repostId`) REFERENCES `Post`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { "fieldPath": "id", @@ -107,12 +117,24 @@ "affinity": "TEXT", "notNull": true }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, { "fieldPath": "createdAt", "columnName": "createdAt", "affinity": "INTEGER", "notNull": true }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", + "notNull": true + }, { "fieldPath": "savedAt", "columnName": "savedAt", @@ -120,16 +142,19 @@ "notNull": true }, { - "fieldPath": "broadcastedAt", - "columnName": "broadcastedAt", - "affinity": "INTEGER", - "notNull": true + "fieldPath": "viewedAt", + "columnName": "viewedAt", + "affinity": "INTEGER" }, { - "fieldPath": "content", - "columnName": "content", - "affinity": "TEXT", - "notNull": true + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "INTEGER" + }, + { + "fieldPath": "broadcastedAt", + "columnName": "broadcastedAt", + "affinity": "INTEGER" } ], "primaryKey": { @@ -225,7 +250,7 @@ }, { "tableName": "Profile", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`publicKey` TEXT NOT NULL, `nostrEventId` TEXT NOT NULL, `userName` TEXT, `displayName` TEXT, `picture` TEXT, `banner` TEXT, `website` TEXT, `about` TEXT, `bot` INTEGER, `pronouns` TEXT, `nip05` TEXT, `domain` TEXT, `lud06` TEXT, `lud16` TEXT, `twitter` TEXT, PRIMARY KEY(`publicKey`), FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`publicKey` TEXT NOT NULL, `nostrEventId` TEXT NOT NULL, `userName` TEXT, `displayName` TEXT, `picture` TEXT, `banner` TEXT, `website` TEXT, `about` TEXT, `bot` INTEGER, `pronouns` TEXT, `nip05` TEXT, `domain` TEXT, `lud06` TEXT, `lud16` TEXT, `twitter` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `viewedAt` INTEGER, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`publicKey`), FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { "fieldPath": "publicKey", @@ -303,6 +328,39 @@ "fieldPath": "twitter", "columnName": "twitter", "affinity": "TEXT" + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "savedAt", + "columnName": "savedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "viewedAt", + "columnName": "viewedAt", + "affinity": "INTEGER" + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "INTEGER" + }, + { + "fieldPath": "broadcastedAt", + "columnName": "broadcastedAt", + "affinity": "INTEGER" } ], "primaryKey": { @@ -338,7 +396,7 @@ }, { "tableName": "Reaction", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `nostrEventId` TEXT NOT NULL, `replyToId` TEXT NOT NULL, `profilePublicKey` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `content` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`profilePublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`replyToId`) REFERENCES `Post`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `nostrEventId` TEXT NOT NULL, `replyToId` TEXT NOT NULL, `profilePublicKey` TEXT NOT NULL, `content` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `viewedAt` INTEGER, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`profilePublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`replyToId`) REFERENCES `Post`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { "fieldPath": "id", @@ -364,6 +422,12 @@ "affinity": "TEXT", "notNull": true }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, { "fieldPath": "createdAt", "columnName": "createdAt", @@ -371,10 +435,31 @@ "notNull": true }, { - "fieldPath": "content", - "columnName": "content", - "affinity": "TEXT", + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", "notNull": true + }, + { + "fieldPath": "savedAt", + "columnName": "savedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "viewedAt", + "columnName": "viewedAt", + "affinity": "INTEGER" + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "INTEGER" + }, + { + "fieldPath": "broadcastedAt", + "columnName": "broadcastedAt", + "affinity": "INTEGER" } ], "primaryKey": { @@ -450,7 +535,7 @@ }, { "tableName": "Repost", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `nostrEventId` TEXT NOT NULL, `postId` TEXT, `profilePublicKey` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `content` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`profilePublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`postId`) REFERENCES `Post`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `nostrEventId` TEXT NOT NULL, `postId` TEXT, `profilePublicKey` TEXT NOT NULL, `content` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `viewedAt` INTEGER, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`profilePublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`postId`) REFERENCES `Post`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { "fieldPath": "id", @@ -475,6 +560,12 @@ "affinity": "TEXT", "notNull": true }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, { "fieldPath": "createdAt", "columnName": "createdAt", @@ -482,10 +573,31 @@ "notNull": true }, { - "fieldPath": "content", - "columnName": "content", - "affinity": "TEXT", + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", "notNull": true + }, + { + "fieldPath": "savedAt", + "columnName": "savedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "viewedAt", + "columnName": "viewedAt", + "affinity": "INTEGER" + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "INTEGER" + }, + { + "fieldPath": "broadcastedAt", + "columnName": "broadcastedAt", + "affinity": "INTEGER" } ], "primaryKey": { @@ -561,7 +673,7 @@ }, { "tableName": "Zap", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `nostrEventId` TEXT NOT NULL, `postId` TEXT NOT NULL, `senderPublicKey` TEXT NOT NULL, `receiverPublicKey` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `message` TEXT, `invoice` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`senderPublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`receiverPublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`postId`) REFERENCES `Post`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `nostrEventId` TEXT NOT NULL, `postId` TEXT NOT NULL, `senderPublicKey` TEXT NOT NULL, `receiverPublicKey` TEXT NOT NULL, `message` TEXT, `invoice` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `viewedAt` INTEGER, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`senderPublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`receiverPublicKey`) REFERENCES `Profile`(`publicKey`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`postId`) REFERENCES `Post`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { "fieldPath": "id", @@ -593,12 +705,6 @@ "affinity": "TEXT", "notNull": true }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - }, { "fieldPath": "message", "columnName": "message", @@ -608,6 +714,39 @@ "fieldPath": "invoice", "columnName": "invoice", "affinity": "TEXT" + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "savedAt", + "columnName": "savedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "viewedAt", + "columnName": "viewedAt", + "affinity": "INTEGER" + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "INTEGER" + }, + { + "fieldPath": "broadcastedAt", + "columnName": "broadcastedAt", + "affinity": "INTEGER" } ], "primaryKey": { @@ -695,7 +834,7 @@ ], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '9a4e13a505370c8fd3433ef4241cbcc8')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7219ad348874b83380e4072dec332bee')" ] } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/dao/NostrDao.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/dao/NostrDao.kt index f8fa94cc..3c85132a 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/dao/NostrDao.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/dao/NostrDao.kt @@ -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 + ) } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/BroadcastNostrEventRequest.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/BroadcastNostrEventRequest.kt new file mode 100644 index 00000000..19262c91 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/BroadcastNostrEventRequest.kt @@ -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 \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/NostrEvent.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/NostrEvent.kt index c800e8d3..edbbd448 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/NostrEvent.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/NostrEvent.kt @@ -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 diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Post.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Post.kt index e341e1c0..e51c0fc9 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Post.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Post.kt @@ -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 \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Profile.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Profile.kt index b498bd6c..d351e9c6 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Profile.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Profile.kt @@ -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() - } -} \ No newline at end of file + 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 \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Reaction.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Reaction.kt index b0d22778..afbd305f 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Reaction.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Reaction.kt @@ -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 diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Repost.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Repost.kt index ebbc7f8d..832fe981 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Repost.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Repost.kt @@ -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, -) \ No newline at end of file + 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 \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Zap.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Zap.kt index 806430a4..b2cb1560 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Zap.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/Zap.kt @@ -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 diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/BroadcastableEntity.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/BroadcastableEntity.kt new file mode 100644 index 00000000..1ea78705 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/BroadcastableEntity.kt @@ -0,0 +1,7 @@ +package ac.aux.compose.database.model.traits + +import kotlin.time.Instant + +interface BroadcastableEntity { + val broadcastedAt: Instant? +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/LocalStoreEntity.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/LocalStoreEntity.kt new file mode 100644 index 00000000..e13630f5 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/LocalStoreEntity.kt @@ -0,0 +1,7 @@ +package ac.aux.compose.database.model.traits + +import kotlin.time.Instant + +interface LocalStoreEntity { + val savedAt: Instant +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/NostrEventEntity.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/NostrEventEntity.kt new file mode 100644 index 00000000..9b1605d6 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/NostrEventEntity.kt @@ -0,0 +1,7 @@ +package ac.aux.compose.database.model.traits + +import com.vitorpamplona.quartz.nip01Core.core.HexKey + +interface NostrEventEntity { + val nostrEventId: HexKey +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/SoftDeletableEntity.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/SoftDeletableEntity.kt new file mode 100644 index 00000000..b49865f7 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/SoftDeletableEntity.kt @@ -0,0 +1,7 @@ +package ac.aux.compose.database.model.traits + +import kotlin.time.Instant + +interface SoftDeletableEntity { + val deletedAt: Instant? +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/TimestampedEntity.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/TimestampedEntity.kt new file mode 100644 index 00000000..d0e0123b --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/TimestampedEntity.kt @@ -0,0 +1,8 @@ +package ac.aux.compose.database.model.traits + +import kotlin.time.Instant + +interface TimestampedEntity { + val createdAt: Instant + val updatedAt: Instant +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/UserViewableEntity.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/UserViewableEntity.kt new file mode 100644 index 00000000..5d2003bd --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/traits/UserViewableEntity.kt @@ -0,0 +1,7 @@ +package ac.aux.compose.database.model.traits + +import kotlin.time.Instant + +interface UserViewableEntity { + val viewedAt: Instant? +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/repository/DatabasePostRepository.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/repository/DatabasePostRepository.kt index b254a78f..679c131e 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/repository/DatabasePostRepository.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/repository/DatabasePostRepository.kt @@ -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 ) - - } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/repository/PostRepository.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/repository/PostRepository.kt index 8715dab8..11f3998d 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/repository/PostRepository.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/repository/PostRepository.kt @@ -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) } \ No newline at end of file