From 11426e1c4c1ec9ebd7a956679ad00965efad1019 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Wed, 19 Jul 2023 17:38:12 +0800 Subject: [PATCH] Upgrade db, add galleries table --- .../com.hippo.ehviewer.dao.EhDatabase/13.json | 534 ++++++++++++++++++ app/src/main/java/com/hippo/ehviewer/EhDB.kt | 4 + .../hippo/ehviewer/dao/CommonGalleryInfo.kt | 43 ++ .../java/com/hippo/ehviewer/dao/Database.kt | 40 +- .../com/hippo/ehviewer/dao/GalleriesDao.kt | 22 + 5 files changed, 638 insertions(+), 5 deletions(-) create mode 100644 app/schemas/com.hippo.ehviewer.dao.EhDatabase/13.json create mode 100644 app/src/main/java/com/hippo/ehviewer/dao/CommonGalleryInfo.kt create mode 100644 app/src/main/java/com/hippo/ehviewer/dao/GalleriesDao.kt diff --git a/app/schemas/com.hippo.ehviewer.dao.EhDatabase/13.json b/app/schemas/com.hippo.ehviewer.dao.EhDatabase/13.json new file mode 100644 index 000000000..d0575ebe2 --- /dev/null +++ b/app/schemas/com.hippo.ehviewer.dao.EhDatabase/13.json @@ -0,0 +1,534 @@ +{ + "formatVersion": 1, + "database": { + "version": 13, + "identityHash": "df15d8f70f45047a738c8911212ea73c", + "entities": [ + { + "tableName": "GALLERIES", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, `FAVORITE_SLOT` INTEGER NOT NULL, PRIMARY KEY(`GID`))", + "fields": [ + { + "fieldPath": "gid", + "columnName": "GID", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "token", + "columnName": "TOKEN", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "TITLE", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "titleJpn", + "columnName": "TITLE_JPN", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "thumbKey", + "columnName": "THUMB", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "category", + "columnName": "CATEGORY", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "posted", + "columnName": "POSTED", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploader", + "columnName": "UPLOADER", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rating", + "columnName": "RATING", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "simpleLanguage", + "columnName": "SIMPLE_LANGUAGE", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "favoriteSlot", + "columnName": "FAVORITE_SLOT", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "GID" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "DOWNLOADS", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `POSITION` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))", + "fields": [ + { + "fieldPath": "state", + "columnName": "STATE", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "legacy", + "columnName": "LEGACY", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "time", + "columnName": "TIME", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "LABEL", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "position", + "columnName": "POSITION", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "gid", + "columnName": "GID", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "token", + "columnName": "TOKEN", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "TITLE", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "titleJpn", + "columnName": "TITLE_JPN", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "thumbKey", + "columnName": "THUMB", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "category", + "columnName": "CATEGORY", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "posted", + "columnName": "POSTED", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploader", + "columnName": "UPLOADER", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rating", + "columnName": "RATING", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "simpleLanguage", + "columnName": "SIMPLE_LANGUAGE", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "GID" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "DOWNLOAD_LABELS", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `POSITION` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))", + "fields": [ + { + "fieldPath": "label", + "columnName": "LABEL", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "POSITION", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "DOWNLOAD_DIRNAME", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))", + "fields": [ + { + "fieldPath": "gid", + "columnName": "GID", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dirname", + "columnName": "DIRNAME", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "GID" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "FILTER", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))", + "fields": [ + { + "fieldPath": "mode", + "columnName": "MODE", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "TEXT", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "enable", + "columnName": "ENABLE", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "HISTORY", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `FAVORITE_SLOT` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))", + "fields": [ + { + "fieldPath": "time", + "columnName": "TIME", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "favoriteSlot", + "columnName": "FAVORITE_SLOT", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "gid", + "columnName": "GID", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "token", + "columnName": "TOKEN", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "TITLE", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "titleJpn", + "columnName": "TITLE_JPN", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "thumbKey", + "columnName": "THUMB", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "category", + "columnName": "CATEGORY", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "posted", + "columnName": "POSTED", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploader", + "columnName": "UPLOADER", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rating", + "columnName": "RATING", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "simpleLanguage", + "columnName": "SIMPLE_LANGUAGE", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "GID" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "LOCAL_FAVORITES", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))", + "fields": [ + { + "fieldPath": "time", + "columnName": "TIME", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "gid", + "columnName": "GID", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "token", + "columnName": "TOKEN", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "TITLE", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "titleJpn", + "columnName": "TITLE_JPN", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "thumbKey", + "columnName": "THUMB", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "category", + "columnName": "CATEGORY", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "posted", + "columnName": "POSTED", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploader", + "columnName": "UPLOADER", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rating", + "columnName": "RATING", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "simpleLanguage", + "columnName": "SIMPLE_LANGUAGE", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "GID" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "QUICK_SEARCH", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`_id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "NAME", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mode", + "columnName": "MODE", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "CATEGORY", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "keyword", + "columnName": "KEYWORD", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "advanceSearch", + "columnName": "ADVANCE_SEARCH", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "minRating", + "columnName": "MIN_RATING", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pageFrom", + "columnName": "PAGE_FROM", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pageTo", + "columnName": "PAGE_TO", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "POSITION", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "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, 'df15d8f70f45047a738c8911212ea73c')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/hippo/ehviewer/EhDB.kt b/app/src/main/java/com/hippo/ehviewer/EhDB.kt index 04a070e2d..2c3603142 100644 --- a/app/src/main/java/com/hippo/ehviewer/EhDB.kt +++ b/app/src/main/java/com/hippo/ehviewer/EhDB.kt @@ -262,6 +262,7 @@ object EhDB { it.close() context.deleteDatabase(ehExportName) } use { newDb -> + db.galleryDao().list().let { newDb.galleryDao().insert(it) } db.downloadsDao().list().forEach { newDb.downloadsDao().insert(it) } db.downloadLabelDao().list().forEach { newDb.downloadLabelDao().insert(it) } db.downloadDirnameDao().list().forEach { newDb.downloadDirnameDao().insert(it) } @@ -288,6 +289,9 @@ object EhDB { it.close() context.deleteDatabase(tempDBName) } use { oldDB -> + runCatching { + db.galleryDao().insert(oldDB.galleryDao().list()) + } runCatching { val downloadLabelList = oldDB.downloadLabelDao().list() DownloadManager.addDownloadLabel(downloadLabelList) diff --git a/app/src/main/java/com/hippo/ehviewer/dao/CommonGalleryInfo.kt b/app/src/main/java/com/hippo/ehviewer/dao/CommonGalleryInfo.kt new file mode 100644 index 000000000..6ae0b0f30 --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/dao/CommonGalleryInfo.kt @@ -0,0 +1,43 @@ +package com.hippo.ehviewer.dao + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.hippo.ehviewer.client.data.BaseGalleryInfo + +@Entity(tableName = "GALLERIES") +data class CommonGalleryInfo( + @PrimaryKey + @ColumnInfo(name = "GID") + override var gid: Long, + + @ColumnInfo(name = "TOKEN") + override var token: String?, + + @ColumnInfo(name = "TITLE") + override var title: String?, + + @ColumnInfo(name = "TITLE_JPN") + override var titleJpn: String?, + + @ColumnInfo(name = "THUMB") + override var thumbKey: String?, + + @ColumnInfo(name = "CATEGORY") + override var category: Int = 0, + + @ColumnInfo(name = "POSTED") + override var posted: String?, + + @ColumnInfo(name = "UPLOADER") + override var uploader: String?, + + @ColumnInfo(name = "RATING") + override var rating: Float, + + @ColumnInfo(name = "SIMPLE_LANGUAGE") + override var simpleLanguage: String?, + + @ColumnInfo(name = "FAVORITE_SLOT") + override var favoriteSlot: Int, +) : BaseGalleryInfo() diff --git a/app/src/main/java/com/hippo/ehviewer/dao/Database.kt b/app/src/main/java/com/hippo/ehviewer/dao/Database.kt index a70e627a4..47f087ad9 100644 --- a/app/src/main/java/com/hippo/ehviewer/dao/Database.kt +++ b/app/src/main/java/com/hippo/ehviewer/dao/Database.kt @@ -9,6 +9,7 @@ import androidx.room.RoomDatabase import androidx.room.TypeConverters import androidx.room.migration.AutoMigrationSpec import androidx.sqlite.db.SupportSQLiteDatabase +import com.hippo.ehviewer.client.data.GalleryInfo.Companion.NOT_FAVORITED @DeleteTable(tableName = "BOOKMARKS") class DropBookMarkDao : AutoMigrationSpec @@ -22,9 +23,15 @@ class HistoryMigration : AutoMigrationSpec { class AddPositionColumn : AutoMigrationSpec { override fun onPostMigrate(db: SupportSQLiteDatabase) { - db.execSQL("UPDATE QUICK_SEARCH SET POSITION = (SELECT COUNT(*) FROM QUICK_SEARCH T WHERE T.TIME < QUICK_SEARCH.TIME)") - db.execSQL("UPDATE DOWNLOAD_LABELS SET POSITION = (SELECT COUNT(*) FROM DOWNLOAD_LABELS T WHERE T.TIME < DOWNLOAD_LABELS.TIME)") - db.execSQL("UPDATE DOWNLOADS SET POSITION = (SELECT COUNT(*) FROM DOWNLOADS T WHERE T.TIME < DOWNLOADS.TIME)") + val needMigrationTables = arrayOf( + "QUICK_SEARCH", + "DOWNLOAD_LABELS", + "DOWNLOADS", + ) + needMigrationTables.forEach { table -> + // TODO: Rewrite this with row_number() when min sdk is 30 (SQLite 3.28.0) + db.execSQL("UPDATE $table SET POSITION = (SELECT COUNT(*) FROM $table T WHERE T.TIME < $table.TIME)") + } } } @@ -32,6 +39,23 @@ class AddPositionColumn : AutoMigrationSpec { @DeleteColumn(tableName = "DOWNLOAD_LABELS", columnName = "TIME") class DropTimeColumn : AutoMigrationSpec +class AddGalleryTable : AutoMigrationSpec { + override fun onPostMigrate(db: SupportSQLiteDatabase) { + val needMigrationTables = arrayOf( + "HISTORY", + "DOWNLOADS", + "LOCAL_FAVORITES", + ) + needMigrationTables.forEachIndexed { index, table -> + db.execSQL( + "INSERT OR IGNORE INTO GALLERIES " + + "SELECT GID, TOKEN, TITLE, TITLE_JPN, THUMB, CATEGORY, POSTED, UPLOADER, RATING, SIMPLE_LANGUAGE, " + + "${if (index == 0) "FAVORITE_SLOT" else NOT_FAVORITED} FROM $table", + ) + } + } +} + class ThumbKeyMigration : AutoMigrationSpec { override fun onPostMigrate(db: SupportSQLiteDatabase) { val needMigrationTables = arrayOf( @@ -53,8 +77,8 @@ class ThumbKeyMigration : AutoMigrationSpec { } @Database( - entities = [DownloadInfo::class, DownloadLabel::class, DownloadDirname::class, Filter::class, HistoryInfo::class, LocalFavoriteInfo::class, QuickSearch::class], - version = 12, + entities = [CommonGalleryInfo::class, DownloadInfo::class, DownloadLabel::class, DownloadDirname::class, Filter::class, HistoryInfo::class, LocalFavoriteInfo::class, QuickSearch::class], + version = 13, exportSchema = true, autoMigrations = [ AutoMigration( @@ -94,10 +118,16 @@ class ThumbKeyMigration : AutoMigrationSpec { to = 12, spec = DropTimeColumn::class, ), + AutoMigration( + from = 12, + to = 13, + spec = AddGalleryTable::class, + ), ], ) @TypeConverters(FilterModeConverter::class) abstract class EhDatabase : RoomDatabase() { + abstract fun galleryDao(): GalleryDao abstract fun downloadDirnameDao(): DownloadDirnameDao abstract fun downloadLabelDao(): DownloadLabelDao abstract fun downloadsDao(): DownloadsDao diff --git a/app/src/main/java/com/hippo/ehviewer/dao/GalleriesDao.kt b/app/src/main/java/com/hippo/ehviewer/dao/GalleriesDao.kt new file mode 100644 index 000000000..179a1e9ea --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/dao/GalleriesDao.kt @@ -0,0 +1,22 @@ +package com.hippo.ehviewer.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Update + +@Dao +interface GalleryDao { + @Query("SELECT * FROM GALLERIES WHERE GID = :gid") + suspend fun load(gid: Long): CommonGalleryInfo? + + @Query("SELECT * FROM GALLERIES") + suspend fun list(): List + + @Insert(onConflict = OnConflictStrategy.IGNORE) + suspend fun insert(galleryInfoList: List) + + @Update + suspend fun update(galleryInfo: CommonGalleryInfo) +}