Оптимизация
This commit is contained in:
@@ -12,13 +12,14 @@ import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
[
|
||||
EncryptedAccountEntity::class,
|
||||
MessageEntity::class,
|
||||
MessageSearchIndexEntity::class,
|
||||
DialogEntity::class,
|
||||
BlacklistEntity::class,
|
||||
AvatarCacheEntity::class,
|
||||
AccountSyncTimeEntity::class,
|
||||
GroupEntity::class,
|
||||
PinnedMessageEntity::class],
|
||||
version = 15,
|
||||
version = 17,
|
||||
exportSchema = false
|
||||
)
|
||||
abstract class RosettaDatabase : RoomDatabase() {
|
||||
@@ -30,6 +31,7 @@ abstract class RosettaDatabase : RoomDatabase() {
|
||||
abstract fun syncTimeDao(): SyncTimeDao
|
||||
abstract fun groupDao(): GroupDao
|
||||
abstract fun pinnedMessageDao(): PinnedMessageDao
|
||||
abstract fun messageSearchIndexDao(): MessageSearchIndexDao
|
||||
|
||||
companion object {
|
||||
@Volatile private var INSTANCE: RosettaDatabase? = null
|
||||
@@ -232,6 +234,124 @@ abstract class RosettaDatabase : RoomDatabase() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🧱 МИГРАЦИЯ 15->16: Денормализованный has_content для быстрых выборок dialogs/requests
|
||||
*/
|
||||
private val MIGRATION_15_16 =
|
||||
object : Migration(15, 16) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"ALTER TABLE dialogs ADD COLUMN has_content INTEGER NOT NULL DEFAULT 0"
|
||||
)
|
||||
database.execSQL(
|
||||
"CREATE INDEX IF NOT EXISTS index_dialogs_account_i_have_sent_has_content_last_message_timestamp ON dialogs (account, i_have_sent, has_content, last_message_timestamp)"
|
||||
)
|
||||
database.execSQL(
|
||||
"""
|
||||
UPDATE dialogs
|
||||
SET has_content = CASE
|
||||
WHEN TRIM(last_message) != '' THEN 1
|
||||
WHEN last_message_attachments IS NOT NULL
|
||||
AND TRIM(last_message_attachments) != ''
|
||||
AND TRIM(last_message_attachments) != '[]' THEN 1
|
||||
ELSE 0
|
||||
END
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🧱 МИГРАЦИЯ 16->17:
|
||||
* - dialogs: last_message_attachment_type + last_sender_key
|
||||
* - messages: индекс (account, timestamp)
|
||||
* - локальный message_search_index для поиска без повторной дешифровки
|
||||
*/
|
||||
private val MIGRATION_16_17 =
|
||||
object : Migration(16, 17) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"ALTER TABLE dialogs ADD COLUMN last_message_attachment_type INTEGER NOT NULL DEFAULT -1"
|
||||
)
|
||||
database.execSQL(
|
||||
"ALTER TABLE dialogs ADD COLUMN last_sender_key TEXT NOT NULL DEFAULT ''"
|
||||
)
|
||||
database.execSQL(
|
||||
"CREATE INDEX IF NOT EXISTS index_messages_account_timestamp ON messages (account, timestamp)"
|
||||
)
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS message_search_index (
|
||||
account TEXT NOT NULL,
|
||||
message_id TEXT NOT NULL,
|
||||
dialog_key TEXT NOT NULL,
|
||||
opponent_key TEXT NOT NULL,
|
||||
timestamp INTEGER NOT NULL,
|
||||
from_me INTEGER NOT NULL DEFAULT 0,
|
||||
plain_text TEXT NOT NULL,
|
||||
plain_text_normalized TEXT NOT NULL,
|
||||
PRIMARY KEY(account, message_id)
|
||||
)
|
||||
"""
|
||||
)
|
||||
database.execSQL(
|
||||
"CREATE INDEX IF NOT EXISTS index_message_search_index_account_timestamp ON message_search_index (account, timestamp)"
|
||||
)
|
||||
database.execSQL(
|
||||
"CREATE INDEX IF NOT EXISTS index_message_search_index_account_opponent_key_timestamp ON message_search_index (account, opponent_key, timestamp)"
|
||||
)
|
||||
database.execSQL(
|
||||
"""
|
||||
UPDATE dialogs
|
||||
SET last_message_attachment_type = CASE
|
||||
WHEN last_message_attachments IS NULL
|
||||
OR TRIM(last_message_attachments) = ''
|
||||
OR TRIM(last_message_attachments) = '[]' THEN -1
|
||||
WHEN last_message_attachments LIKE '%"type":0%' OR last_message_attachments LIKE '%"type": 0%' THEN 0
|
||||
WHEN last_message_attachments LIKE '%"type":1%' OR last_message_attachments LIKE '%"type": 1%' THEN 1
|
||||
WHEN last_message_attachments LIKE '%"type":2%' OR last_message_attachments LIKE '%"type": 2%' THEN 2
|
||||
WHEN last_message_attachments LIKE '%"type":3%' OR last_message_attachments LIKE '%"type": 3%' THEN 3
|
||||
WHEN last_message_attachments LIKE '%"type":4%' OR last_message_attachments LIKE '%"type": 4%' THEN 4
|
||||
ELSE -1
|
||||
END
|
||||
"""
|
||||
)
|
||||
database.execSQL(
|
||||
"""
|
||||
UPDATE dialogs
|
||||
SET last_sender_key = COALESCE(
|
||||
(
|
||||
SELECT m.from_public_key
|
||||
FROM messages m
|
||||
WHERE m.account = dialogs.account
|
||||
AND m.dialog_key = CASE
|
||||
WHEN dialogs.opponent_key = dialogs.account THEN dialogs.account
|
||||
WHEN LOWER(dialogs.opponent_key) LIKE '#group:%' OR LOWER(dialogs.opponent_key) LIKE 'group:%'
|
||||
THEN dialogs.opponent_key
|
||||
WHEN dialogs.account < dialogs.opponent_key
|
||||
THEN dialogs.account || ':' || dialogs.opponent_key
|
||||
ELSE dialogs.opponent_key || ':' || dialogs.account
|
||||
END
|
||||
ORDER BY m.timestamp DESC, m.message_id DESC
|
||||
LIMIT 1
|
||||
),
|
||||
''
|
||||
)
|
||||
"""
|
||||
)
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TRIGGER IF NOT EXISTS trg_message_search_index_delete
|
||||
AFTER DELETE ON messages
|
||||
BEGIN
|
||||
DELETE FROM message_search_index
|
||||
WHERE account = OLD.account AND message_id = OLD.message_id;
|
||||
END
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun getDatabase(context: Context): RosettaDatabase {
|
||||
return INSTANCE
|
||||
?: synchronized(this) {
|
||||
@@ -255,7 +375,9 @@ abstract class RosettaDatabase : RoomDatabase() {
|
||||
MIGRATION_11_12,
|
||||
MIGRATION_12_13,
|
||||
MIGRATION_13_14,
|
||||
MIGRATION_14_15
|
||||
MIGRATION_14_15,
|
||||
MIGRATION_15_16,
|
||||
MIGRATION_16_17
|
||||
)
|
||||
.fallbackToDestructiveMigration() // Для разработки - только
|
||||
// если миграция не
|
||||
|
||||
Reference in New Issue
Block a user