package coredevices.database import androidx.room.Dao import androidx.room.Delete import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.Index import androidx.room.Insert import androidx.room.PrimaryKey import androidx.room.Query import androidx.room.Transaction import androidx.room.Upsert import kotlinx.coroutines.flow.Flow @Entity( primaryKeys = ["sourceId", "appId"], foreignKeys = [ ForeignKey( entity = AppstoreSource::class, parentColumns = ["id"], childColumns = ["sourceId"], onDelete = ForeignKey.CASCADE, ) ], ) data class HeartEntity( val sourceId: Int, val appId: String, ) @Dao interface HeartsDao { @Upsert suspend fun addHeart(heart: HeartEntity) @Upsert suspend fun addHearts(hearts: List) @Delete suspend fun removeHeart(heart: HeartEntity) @Delete suspend fun removeHearts(hearts: List) @Query("SELECT EXISTS(SELECT 1 FROM HeartEntity WHERE appId = :appId AND sourceId = :sourceId)") fun isHeartedFlow(sourceId: Int, appId: String): Flow @Query("SELECT * FROM HeartEntity") fun getAllHeartsFlow(): Flow> // ORDER BY rowid DESC gives best-effort "most recently hearted first" without a // dedicated timestamp column — SQLite assigns rowid in insertion order, and // updateHeartsForSource only inserts new hearts (existing rows keep their rowid). @Query("SELECT appId FROM HeartEntity WHERE sourceId = :sourceId ORDER BY rowid DESC") suspend fun getAllHeartsForSource(sourceId: Int): List @Transaction suspend fun updateHeartsForSource(sourceId: Int, newHearts: List) { val oldHearts = getAllHeartsForSource(sourceId) val toInsert = newHearts.filter { it !in oldHearts } val toRemove = oldHearts.filter { it !in newHearts } addHearts(toInsert.map { HeartEntity(sourceId, it) }) removeHearts(toRemove.map { HeartEntity(sourceId, it) }) } }