package it.vfsfitvnm.vimusic import android.content.Context import android.database.Cursor import androidx.room.* import androidx.room.migration.AutoMigrationSpec import it.vfsfitvnm.vimusic.models.* import kotlinx.coroutines.flow.Flow @Dao interface Database { companion object : Database by DatabaseInitializer.Instance.database @Query("SELECT * FROM SearchQuery WHERE query LIKE :query ORDER BY id DESC") fun getRecentQueries(query: String): Flow> @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(searchQuery: SearchQuery) @Insert(onConflict = OnConflictStrategy.ABORT) fun insert(info: Info): Long @Insert(onConflict = OnConflictStrategy.ABORT) fun insert(playlist: Playlist): Long @Insert(onConflict = OnConflictStrategy.IGNORE) fun insert(info: SongInPlaylist): Long @Insert(onConflict = OnConflictStrategy.ABORT) fun insert(info: List): List @Query("SELECT * FROM Song WHERE id = :id") fun songFlow(id: String): Flow @Query("SELECT * FROM Song WHERE id = :id") fun song(id: String): Song? @Query("SELECT * FROM Playlist WHERE id = :id") fun playlist(id: Long): Playlist? @Query("SELECT * FROM Song") fun songs(): Flow> @Transaction @Query("SELECT * FROM Song WHERE id = :id") fun songWithInfo(id: String): SongWithInfo? @Transaction @Query("SELECT * FROM Song WHERE totalPlayTimeMs >= 15000 ORDER BY ROWID DESC") fun history(): Flow> @Transaction @Query("SELECT * FROM Song WHERE likedAt IS NOT NULL ORDER BY likedAt DESC") fun favorites(): Flow> @Transaction @Query("SELECT * FROM Song WHERE totalPlayTimeMs >= 60000 ORDER BY totalPlayTimeMs DESC LIMIT 20") fun mostPlayed(): Flow> @Query("UPDATE Song SET totalPlayTimeMs = totalPlayTimeMs + :addition WHERE id = :id") fun incrementTotalPlayTimeMs(id: String, addition: Long) @Transaction @Query("SELECT * FROM Playlist WHERE id = :id") fun playlistWithSongs(id: Long): Flow @Query("SELECT COUNT(*) FROM SongInPlaylist WHERE playlistId = :id") fun playlistSongCount(id: Long): Int @Query("UPDATE SongInPlaylist SET position = position - 1 WHERE playlistId = :playlistId AND position >= :fromPosition") fun decrementSongPositions(playlistId: Long, fromPosition: Int) @Query("UPDATE SongInPlaylist SET position = position - 1 WHERE playlistId = :playlistId AND position >= :fromPosition AND position <= :toPosition") fun decrementSongPositions(playlistId: Long, fromPosition: Int, toPosition: Int) @Query("UPDATE SongInPlaylist SET position = position + 1 WHERE playlistId = :playlistId AND position >= :fromPosition AND position <= :toPosition") fun incrementSongPositions(playlistId: Long, fromPosition: Int, toPosition: Int) @Insert(onConflict = OnConflictStrategy.ABORT) fun insert(songWithAuthors: SongWithAuthors): Long @Insert(onConflict = OnConflictStrategy.ABORT) fun insert(song: Song): Long @Update fun update(song: Song) @Update fun update(songInPlaylist: SongInPlaylist) @Update fun update(playlist: Playlist) @Delete fun delete(searchQuery: SearchQuery) @Delete fun delete(playlist: Playlist) @Delete fun delete(song: Song) @Delete fun delete(songInPlaylist: SongInPlaylist) @Transaction @Query("SELECT id, name, (SELECT COUNT(*) FROM SongInPlaylist WHERE playlistId = id) as songCount FROM Playlist") fun playlistPreviews(): Flow> @Query("SELECT thumbnailUrl FROM Song JOIN SongInPlaylist ON id = songId WHERE playlistId = :id ORDER BY position LIMIT 4") fun playlistThumbnailUrls(id: Long): Flow> } @androidx.room.Database( entities = [ Song::class, SongInPlaylist::class, Playlist::class, Info::class, SongWithAuthors::class, SearchQuery::class, ], views = [ SortedSongInPlaylist::class ], version = 4, exportSchema = true, autoMigrations = [ AutoMigration(from = 1, to = 2), AutoMigration(from = 2, to = 3), AutoMigration(from = 3, to = 4, spec = DatabaseInitializer.From3To4Migration::class), ], ) abstract class DatabaseInitializer protected constructor() : RoomDatabase() { abstract val database: Database companion object { lateinit var Instance: DatabaseInitializer context(Context) operator fun invoke() { if (!::Instance.isInitialized) { Instance = Room .databaseBuilder(this@Context, DatabaseInitializer::class.java, "data.db") .build() } } } @DeleteTable.Entries(DeleteTable(tableName = "QueuedMediaItem")) class From3To4Migration : AutoMigrationSpec } val Database.internal: RoomDatabase get() = DatabaseInitializer.Instance fun Database.checkpoint() { internal.openHelper.writableDatabase.run { query("PRAGMA journal_mode").use { cursor -> if (cursor.moveToFirst()) { when (cursor.getString(0).lowercase()) { "wal" -> { query("PRAGMA wal_checkpoint").use(Cursor::moveToFirst) query("PRAGMA wal_checkpoint(TRUNCATE)").use(Cursor::moveToFirst) query("PRAGMA wal_checkpoint").use(Cursor::moveToFirst) } } } } } }