feat(sync): перевёл группы синхронизации на Room и добавил контроль совместимости
This commit is contained in:
@@ -4,24 +4,28 @@ import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.dao.StorageKeyMapDao
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.dao.StorageMetaInfoDao
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.dao.StorageSyncGroupDao
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.dao.YandexAccountDao
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbStorageKeyMap
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbStorageMetaInfo
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbStorageSyncGroup
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbYandexAccount
|
||||
|
||||
interface IAppDb {
|
||||
val storageKeyMapDao: StorageKeyMapDao
|
||||
val storageMetaInfoDao: StorageMetaInfoDao
|
||||
val storageSyncGroupDao: StorageSyncGroupDao
|
||||
val yandexAccountDao: YandexAccountDao
|
||||
}
|
||||
|
||||
@Database(
|
||||
entities = [DbStorageKeyMap::class, DbStorageMetaInfo::class, DbYandexAccount::class],
|
||||
version = 4,
|
||||
entities = [DbStorageKeyMap::class, DbStorageMetaInfo::class, DbYandexAccount::class, DbStorageSyncGroup::class],
|
||||
version = 5,
|
||||
exportSchema = false
|
||||
)
|
||||
abstract class AppDb : IAppDb, RoomDatabase() {
|
||||
abstract override val storageKeyMapDao: StorageKeyMapDao
|
||||
abstract override val storageMetaInfoDao: StorageMetaInfoDao
|
||||
abstract override val storageSyncGroupDao: StorageSyncGroupDao
|
||||
abstract override val yandexAccountDao: YandexAccountDao
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.db.app.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbStorageSyncGroup
|
||||
|
||||
@Dao
|
||||
interface StorageSyncGroupDao {
|
||||
@Query("SELECT * FROM storage_sync_groups")
|
||||
suspend fun getAll(): List<DbStorageSyncGroup>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun upsert(group: DbStorageSyncGroup)
|
||||
|
||||
@Query("DELETE FROM storage_sync_groups WHERE group_id = :groupId")
|
||||
suspend fun deleteById(groupId: String)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.db.app.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "storage_sync_groups")
|
||||
data class DbStorageSyncGroup(
|
||||
@PrimaryKey @ColumnInfo(name = "group_id") val id: String,
|
||||
@ColumnInfo(name = "storage_uuids_csv") val storageUuidsCsv: String,
|
||||
@ColumnInfo(name = "encryption_kind") val encryptionKind: String,
|
||||
@ColumnInfo(name = "encryption_secret") val encryptionSecret: String?,
|
||||
)
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.db.app.repository
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorageSyncGroupStore
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.StorageSyncGroup
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.StorageSyncGroupEncryptionKind
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.dao.StorageSyncGroupDao
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbStorageSyncGroup
|
||||
import com.github.nullptroma.wallenc.infrastructure.utils.IProvider
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.UUID
|
||||
|
||||
class StorageSyncGroupRepository(
|
||||
private val dao: StorageSyncGroupDao,
|
||||
private val ioDispatcher: CoroutineDispatcher,
|
||||
) : IStorageSyncGroupStore {
|
||||
private val allGroupsProvider: IProvider<List<StorageSyncGroup>> = object : IProvider<List<StorageSyncGroup>> {
|
||||
override suspend fun get(): List<StorageSyncGroup> = dao.getAll().mapNotNull(::toDomain)
|
||||
|
||||
override suspend fun set(value: List<StorageSyncGroup>) {
|
||||
val desiredIds = value.map { it.id }.toSet()
|
||||
val current = dao.getAll()
|
||||
current
|
||||
.asSequence()
|
||||
.filter { it.id !in desiredIds }
|
||||
.forEach { dao.deleteById(it.id) }
|
||||
value.forEach { group ->
|
||||
dao.upsert(toDb(group))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun clear() {
|
||||
dao.getAll().forEach { dao.deleteById(it.id) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getGroups(): List<StorageSyncGroup> = withContext(ioDispatcher) {
|
||||
allGroupsProvider.get().orEmpty()
|
||||
}
|
||||
|
||||
override suspend fun putGroup(group: StorageSyncGroup) = withContext(ioDispatcher) {
|
||||
val all = allGroupsProvider.get().orEmpty().toMutableList()
|
||||
val idx = all.indexOfFirst { it.id == group.id }
|
||||
if (idx >= 0) {
|
||||
all[idx] = group
|
||||
} else {
|
||||
all.add(group)
|
||||
}
|
||||
allGroupsProvider.set(all)
|
||||
}
|
||||
|
||||
override suspend fun removeGroup(groupId: String) = withContext(ioDispatcher) {
|
||||
val all = allGroupsProvider.get().orEmpty().filterNot { it.id == groupId }
|
||||
allGroupsProvider.set(all)
|
||||
}
|
||||
|
||||
private fun toDb(group: StorageSyncGroup): DbStorageSyncGroup = DbStorageSyncGroup(
|
||||
id = group.id,
|
||||
storageUuidsCsv = group.storageUuids.joinToString(",") { it.toString() },
|
||||
encryptionKind = group.encryptionKind.name,
|
||||
encryptionSecret = group.encryptionSecret,
|
||||
)
|
||||
|
||||
private fun toDomain(db: DbStorageSyncGroup): StorageSyncGroup? {
|
||||
val kind = runCatching {
|
||||
StorageSyncGroupEncryptionKind.valueOf(db.encryptionKind)
|
||||
}.getOrElse {
|
||||
StorageSyncGroupEncryptionKind.UNSET
|
||||
}
|
||||
if (db.id.isBlank()) {
|
||||
return null
|
||||
}
|
||||
val uuids = db.storageUuidsCsv
|
||||
.split(",")
|
||||
.mapNotNull { token ->
|
||||
val value = token.trim()
|
||||
if (value.isBlank()) {
|
||||
null
|
||||
} else {
|
||||
runCatching { UUID.fromString(value) }.getOrNull()
|
||||
}
|
||||
}
|
||||
.toSet()
|
||||
return StorageSyncGroup(
|
||||
id = db.id,
|
||||
storageUuids = uuids,
|
||||
encryptionKind = kind,
|
||||
encryptionSecret = db.encryptionSecret?.takeIf { it.isNotBlank() },
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user