ntfy-android/app/src/main/java/io/heckel/ntfy/data/Database.kt

146 lines
5.6 KiB
Kotlin
Raw Normal View History

2021-10-30 14:13:58 +13:00
package io.heckel.ntfy.data
import android.content.Context
import androidx.annotation.NonNull
2021-11-01 08:19:25 +13:00
import androidx.lifecycle.LiveData
2021-10-30 14:13:58 +13:00
import androidx.room.*
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
2021-10-30 14:13:58 +13:00
import kotlinx.coroutines.flow.Flow
2021-10-31 01:57:20 +13:00
@Entity(indices = [Index(value = ["baseUrl", "topic"], unique = true)])
2021-10-30 14:13:58 +13:00
data class Subscription(
@PrimaryKey val id: Long, // Internal ID, only used in Repository and activities
@ColumnInfo(name = "baseUrl") val baseUrl: String,
@ColumnInfo(name = "topic") val topic: String,
2021-11-14 13:26:37 +13:00
@ColumnInfo(name = "instant") val instant: Boolean,
@Ignore val notifications: Int,
@Ignore val lastActive: Long = 0 // Unix timestamp
) {
2021-11-14 13:26:37 +13:00
constructor(id: Long, baseUrl: String, topic: String, instant: Boolean) : this(id, baseUrl, topic, instant, 0, 0)
}
data class SubscriptionWithMetadata(
val id: Long,
val baseUrl: String,
val topic: String,
2021-11-14 13:26:37 +13:00
val instant: Boolean,
val notifications: Int,
val lastActive: Long
2021-10-30 14:13:58 +13:00
)
2021-11-01 08:19:25 +13:00
@Entity
data class Notification(
2021-11-02 03:49:52 +13:00
@PrimaryKey val id: String,
2021-11-01 08:19:25 +13:00
@ColumnInfo(name = "subscriptionId") val subscriptionId: Long,
@ColumnInfo(name = "timestamp") val timestamp: Long, // Unix timestamp
@ColumnInfo(name = "message") val message: String,
@ColumnInfo(name = "deleted") val deleted: Boolean
2021-11-01 08:19:25 +13:00
)
@androidx.room.Database(entities = [Subscription::class, Notification::class], version = 2)
2021-10-30 14:13:58 +13:00
abstract class Database : RoomDatabase() {
abstract fun subscriptionDao(): SubscriptionDao
2021-11-01 08:19:25 +13:00
abstract fun notificationDao(): NotificationDao
2021-10-30 14:13:58 +13:00
companion object {
@Volatile
private var instance: Database? = null
fun getInstance(context: Context): Database {
return instance ?: synchronized(this) {
val instance = Room
.databaseBuilder(context.applicationContext, Database::class.java,"AppDatabase")
.addMigrations(MIGRATION_1_2)
2021-10-30 14:13:58 +13:00
.fallbackToDestructiveMigration()
.build()
this.instance = instance
instance
}
}
private val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
// Drop "notifications" & "lastActive" columns (SQLite does not support dropping columns, ...)
2021-11-14 13:26:37 +13:00
db.execSQL("CREATE TABLE Subscription_New (id INTEGER NOT NULL, baseUrl TEXT NOT NULL, topic TEXT NOT NULL, instant INTEGER NOT NULL DEFAULT('0'), PRIMARY KEY(id))")
db.execSQL("INSERT INTO Subscription_New SELECT id, baseUrl, topic FROM Subscription")
db.execSQL("DROP TABLE Subscription")
db.execSQL("ALTER TABLE Subscription_New RENAME TO Subscription")
db.execSQL("CREATE UNIQUE INDEX index_Subscription_baseUrl_topic ON Subscription (baseUrl, topic)")
// Add "deleted" column
db.execSQL("ALTER TABLE Notification ADD COLUMN deleted INTEGER NOT NULL DEFAULT('0')")
}
}
2021-10-30 14:13:58 +13:00
}
}
@Dao
interface SubscriptionDao {
@Query(
2021-11-14 13:26:37 +13:00
"SELECT s.id, s.baseUrl, s.topic, s.instant, COUNT(n.id) notifications, IFNULL(MAX(n.timestamp),0) AS lastActive " +
"FROM subscription AS s " +
"LEFT JOIN notification AS n ON s.id=n.subscriptionId AND n.deleted != 1 " +
"GROUP BY s.id " +
"ORDER BY MAX(n.timestamp) DESC"
)
fun listFlow(): Flow<List<SubscriptionWithMetadata>>
@Query(
2021-11-14 13:26:37 +13:00
"SELECT s.id, s.baseUrl, s.topic, s.instant, COUNT(n.id) notifications, IFNULL(MAX(n.timestamp),0) AS lastActive " +
"FROM subscription AS s " +
"LEFT JOIN notification AS n ON s.id=n.subscriptionId AND n.deleted != 1 " +
"GROUP BY s.id " +
"ORDER BY MAX(n.timestamp) DESC"
)
fun list(): List<SubscriptionWithMetadata>
@Query(
2021-11-14 13:26:37 +13:00
"SELECT s.id, s.baseUrl, s.topic, s.instant, COUNT(n.id) notifications, IFNULL(MAX(n.timestamp),0) AS lastActive " +
"FROM subscription AS s " +
"LEFT JOIN notification AS n ON s.id=n.subscriptionId AND n.deleted != 1 " +
"WHERE s.baseUrl = :baseUrl AND s.topic = :topic " +
"GROUP BY s.id "
)
fun get(baseUrl: String, topic: String): SubscriptionWithMetadata?
@Query(
2021-11-14 13:26:37 +13:00
"SELECT s.id, s.baseUrl, s.topic, s.instant, COUNT(n.id) notifications, IFNULL(MAX(n.timestamp),0) AS lastActive " +
"FROM subscription AS s " +
"LEFT JOIN notification AS n ON s.id=n.subscriptionId AND n.deleted != 1 " +
"WHERE s.id = :subscriptionId " +
"GROUP BY s.id "
)
fun get(subscriptionId: Long): SubscriptionWithMetadata?
2021-10-30 14:13:58 +13:00
@Insert
fun add(subscription: Subscription)
@Update
fun update(subscription: Subscription)
2021-11-01 08:19:25 +13:00
@Query("DELETE FROM subscription WHERE id = :subscriptionId")
fun remove(subscriptionId: Long)
}
@Dao
interface NotificationDao {
@Query("SELECT * FROM notification WHERE subscriptionId = :subscriptionId AND deleted != 1 ORDER BY timestamp DESC")
2021-11-01 08:19:25 +13:00
fun list(subscriptionId: Long): Flow<List<Notification>>
@Query("SELECT id FROM notification WHERE subscriptionId = :subscriptionId") // Includes deleted
2021-11-08 07:13:32 +13:00
fun listIds(subscriptionId: Long): List<String>
2021-11-11 15:16:00 +13:00
@Insert(onConflict = OnConflictStrategy.IGNORE)
2021-11-01 08:19:25 +13:00
fun add(notification: Notification)
@Query("SELECT * FROM notification WHERE id = :notificationId")
fun get(notificationId: String): Notification?
@Query("UPDATE notification SET deleted = 1 WHERE id = :notificationId")
2021-11-04 06:56:08 +13:00
fun remove(notificationId: String)
2021-11-01 08:19:25 +13:00
@Query("DELETE FROM notification WHERE subscriptionId = :subscriptionId")
fun removeAll(subscriptionId: Long)
2021-10-30 14:13:58 +13:00
}