2021-10-30 14:13:58 +13:00
package io.heckel.ntfy.data
import android.content.Context
2021-11-12 16:14:28 +13:00
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.*
2021-11-12 16:14:28 +13:00
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 ,
2021-11-12 16:14:28 +13:00
@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 )
2021-11-12 16:14:28 +13:00
}
data class SubscriptionWithMetadata (
val id : Long ,
val baseUrl : String ,
val topic : String ,
2021-11-14 13:26:37 +13:00
val instant : Boolean ,
2021-11-12 16:14:28 +13:00
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
2021-11-12 16:14:28 +13:00
@ColumnInfo ( name = " message " ) val message : String ,
@ColumnInfo ( name = " deleted " ) val deleted : Boolean
2021-11-01 08:19:25 +13:00
)
2021-11-12 16:14:28 +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 " )
2021-11-12 16:14:28 +13:00
. addMigrations ( MIGRATION _1 _2 )
2021-10-30 14:13:58 +13:00
. fallbackToDestructiveMigration ( )
. build ( )
this . instance = instance
instance
}
}
2021-11-12 16:14:28 +13:00
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)) " )
2021-11-12 16:14:28 +13:00
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 {
2021-11-12 16:14:28 +13:00
@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 " +
2021-11-12 16:14:28 +13:00
" 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 " +
2021-11-12 16:14:28 +13:00
" 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 " +
2021-11-12 16:14:28 +13:00
" 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 " +
2021-11-12 16:14:28 +13:00
" 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-11-12 13:41:29 +13:00
2021-10-30 14:13:58 +13:00
@Insert
fun add ( subscription : Subscription )
2021-11-15 07:54:48 +13:00
@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 {
2021-11-12 16:14:28 +13:00
@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 > >
2021-11-12 16:14:28 +13:00
@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 )
2021-11-12 13:41:29 +13:00
@Query ( " SELECT * FROM notification WHERE id = :notificationId " )
fun get ( notificationId : String ) : Notification ?
2021-11-12 16:14:28 +13:00
@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
}