From 6f366f04ae4e82289111b074cea2631c65f4da55 Mon Sep 17 00:00:00 2001 From: lisonge Date: Fri, 16 Aug 2024 11:01:34 +0800 Subject: [PATCH] perf: activity_log autoGenerate id (#704) --- app/schemas/li.songe.gkd.db.AppDb/8.json | 347 ++++++++++++++++++ .../kotlin/li/songe/gkd/data/ActivityLog.kt | 35 +- app/src/main/kotlin/li/songe/gkd/db/AppDb.kt | 3 +- 3 files changed, 372 insertions(+), 13 deletions(-) create mode 100644 app/schemas/li.songe.gkd.db.AppDb/8.json diff --git a/app/schemas/li.songe.gkd.db.AppDb/8.json b/app/schemas/li.songe.gkd.db.AppDb/8.json new file mode 100644 index 0000000..f802a48 --- /dev/null +++ b/app/schemas/li.songe.gkd.db.AppDb/8.json @@ -0,0 +1,347 @@ +{ + "formatVersion": 1, + "database": { + "version": 8, + "identityHash": "409bb51310bcdb55ea721a8e88b6cef6", + "entities": [ + { + "tableName": "subs_item", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `ctime` INTEGER NOT NULL, `mtime` INTEGER NOT NULL, `enable` INTEGER NOT NULL, `enable_update` INTEGER NOT NULL, `order` INTEGER NOT NULL, `update_url` TEXT, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ctime", + "columnName": "ctime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "mtime", + "columnName": "mtime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enable", + "columnName": "enable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enableUpdate", + "columnName": "enable_update", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "order", + "columnName": "order", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "updateUrl", + "columnName": "update_url", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "snapshot", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `app_id` TEXT, `activity_id` TEXT, `app_name` TEXT, `app_version_code` INTEGER, `app_version_name` TEXT, `screen_height` INTEGER NOT NULL, `screen_width` INTEGER NOT NULL, `is_landscape` INTEGER NOT NULL, `github_asset_id` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "appId", + "columnName": "app_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "activityId", + "columnName": "activity_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "appName", + "columnName": "app_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "appVersionCode", + "columnName": "app_version_code", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "appVersionName", + "columnName": "app_version_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "screenHeight", + "columnName": "screen_height", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "screenWidth", + "columnName": "screen_width", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isLandscape", + "columnName": "is_landscape", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "githubAssetId", + "columnName": "github_asset_id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "subs_config", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `type` INTEGER NOT NULL, `enable` INTEGER, `subs_item_id` INTEGER NOT NULL, `app_id` TEXT NOT NULL, `group_key` INTEGER NOT NULL, `exclude` TEXT NOT NULL DEFAULT '', PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enable", + "columnName": "enable", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "subsItemId", + "columnName": "subs_item_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "appId", + "columnName": "app_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "groupKey", + "columnName": "group_key", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exclude", + "columnName": "exclude", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "click_log", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `app_id` TEXT, `activity_id` TEXT, `subs_id` INTEGER NOT NULL, `subs_version` INTEGER NOT NULL DEFAULT 0, `group_key` INTEGER NOT NULL, `group_type` INTEGER NOT NULL DEFAULT 2, `rule_index` INTEGER NOT NULL, `rule_key` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "appId", + "columnName": "app_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "activityId", + "columnName": "activity_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "subsId", + "columnName": "subs_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subsVersion", + "columnName": "subs_version", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "groupKey", + "columnName": "group_key", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "groupType", + "columnName": "group_type", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "2" + }, + { + "fieldPath": "ruleIndex", + "columnName": "rule_index", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ruleKey", + "columnName": "rule_key", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "category_config", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `enable` INTEGER, `subs_item_id` INTEGER NOT NULL, `category_key` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enable", + "columnName": "enable", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "subsItemId", + "columnName": "subs_item_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "categoryKey", + "columnName": "category_key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "activity_log_v2", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `ctime` INTEGER NOT NULL, `app_id` TEXT NOT NULL, `activity_id` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ctime", + "columnName": "ctime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "appId", + "columnName": "app_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "activityId", + "columnName": "activity_id", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "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, '409bb51310bcdb55ea721a8e88b6cef6')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/li/songe/gkd/data/ActivityLog.kt b/app/src/main/kotlin/li/songe/gkd/data/ActivityLog.kt index 3d60ae3..0928bb8 100644 --- a/app/src/main/kotlin/li/songe/gkd/data/ActivityLog.kt +++ b/app/src/main/kotlin/li/songe/gkd/data/ActivityLog.kt @@ -3,18 +3,23 @@ package li.songe.gkd.data import androidx.paging.PagingSource import androidx.room.ColumnInfo import androidx.room.Dao +import androidx.room.DeleteTable import androidx.room.Entity import androidx.room.Insert import androidx.room.PrimaryKey import androidx.room.Query +import androidx.room.migration.AutoMigrationSpec import kotlinx.coroutines.flow.Flow import li.songe.gkd.util.format @Entity( - tableName = "activity_log", + tableName = "activity_log_v2", ) data class ActivityLog( - @PrimaryKey @ColumnInfo(name = "id") val id: Long = System.currentTimeMillis(), + // 不使用时间戳作为主键的原因 + // https://github.com/gkd-kit/gkd/issues/704 + @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") val id: Int = 0, + @ColumnInfo(name = "ctime") val ctime: Long = System.currentTimeMillis(), @ColumnInfo(name = "app_id") val appId: String, @ColumnInfo(name = "activity_id") val activityId: String? = null, ) { @@ -32,37 +37,43 @@ data class ActivityLog( null } } - val date by lazy { id.format("MM-dd HH:mm:ss SSS") } + val date by lazy { ctime.format("MM-dd HH:mm:ss SSS") } @Dao interface ActivityLogDao { @Insert suspend fun insert(vararg objects: ActivityLog): List - @Query("DELETE FROM activity_log") + @Query("DELETE FROM activity_log_v2") suspend fun deleteAll() - @Query("SELECT * FROM activity_log ORDER BY id DESC ") + @Query("SELECT * FROM activity_log_v2 ORDER BY ctime DESC ") fun pagingSource(): PagingSource - @Query("SELECT COUNT(*) FROM activity_log") + @Query("SELECT COUNT(*) FROM activity_log_v2") fun count(): Flow @Query( """ - DELETE FROM activity_log + DELETE FROM activity_log_v2 WHERE ( SELECT COUNT(*) - FROM activity_log + FROM activity_log_v2 ) > 1000 - AND id <= ( - SELECT id - FROM activity_log - ORDER BY id DESC + AND ctime <= ( + SELECT ctime + FROM activity_log_v2 + ORDER BY ctime DESC LIMIT 1 OFFSET 1000 ) """ ) suspend fun deleteKeepLatest(): Int } + + + @DeleteTable.Entries( + DeleteTable(tableName = "activity_log") + ) + class ActivityLogV2Spec : AutoMigrationSpec } diff --git a/app/src/main/kotlin/li/songe/gkd/db/AppDb.kt b/app/src/main/kotlin/li/songe/gkd/db/AppDb.kt index dc7f813..e4febf4 100644 --- a/app/src/main/kotlin/li/songe/gkd/db/AppDb.kt +++ b/app/src/main/kotlin/li/songe/gkd/db/AppDb.kt @@ -11,7 +11,7 @@ import li.songe.gkd.data.SubsConfig import li.songe.gkd.data.SubsItem @Database( - version = 7, + version = 8, entities = [ SubsItem::class, Snapshot::class, @@ -27,6 +27,7 @@ import li.songe.gkd.data.SubsItem AutoMigration(from = 4, to = 5), AutoMigration(from = 5, to = 6), AutoMigration(from = 6, to = 7), + AutoMigration(from = 7, to = 8, spec = ActivityLog.ActivityLogV2Spec::class), ] ) abstract class AppDb : RoomDatabase() {