package com.rosetta.messenger.database import androidx.room.* import kotlinx.coroutines.flow.Flow /** * Entity для кэша аватаров - хранит пути к зашифрованным файлам * Совместимо с desktop версией (AvatarProvider) * * Desktop логика: * - Аватары передаются как attachment в сообщениях (AttachmentType.AVATAR) * - Локальное хранение: SQLite + зашифрованные файлы */ @Entity( tableName = "avatar_cache", indices = [ Index(value = ["public_key", "timestamp"]) ] ) data class AvatarCacheEntity( @PrimaryKey(autoGenerate = true) val id: Long = 0, @ColumnInfo(name = "public_key") val publicKey: String, @ColumnInfo(name = "avatar") val avatar: String, // Путь к файлу (формат: "a/md5hash") @ColumnInfo(name = "timestamp") val timestamp: Long // Unix timestamp ) /** * DAO для работы с аватарами */ @Dao interface AvatarDao { /** * Получить все аватары пользователя (отсортированные по времени) */ @Query("SELECT * FROM avatar_cache WHERE public_key = :publicKey ORDER BY timestamp DESC") fun getAvatars(publicKey: String): Flow> /** * Получить последний аватар пользователя */ @Query("SELECT * FROM avatar_cache WHERE public_key = :publicKey ORDER BY timestamp DESC LIMIT 1") suspend fun getLatestAvatar(publicKey: String): AvatarCacheEntity? /** * Получить последний аватар пользователя как Flow */ @Query("SELECT * FROM avatar_cache WHERE public_key = :publicKey ORDER BY timestamp DESC LIMIT 1") fun getLatestAvatarFlow(publicKey: String): Flow /** * Сохранить новый аватар */ @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertAvatar(avatar: AvatarCacheEntity) /** * Удалить все аватары пользователя */ @Query("DELETE FROM avatar_cache WHERE public_key = :publicKey") suspend fun deleteAvatars(publicKey: String) /** * Удалить старые аватары (оставить только N последних) */ @Query(""" DELETE FROM avatar_cache WHERE public_key = :publicKey AND id NOT IN ( SELECT id FROM avatar_cache WHERE public_key = :publicKey ORDER BY timestamp DESC LIMIT :keepCount ) """) suspend fun deleteOldAvatars(publicKey: String, keepCount: Int = 5) }