Introduce OfflineCiphersDao/Entity

This commit is contained in:
Hinton 2024-10-21 15:40:08 -07:00
parent c7d7ed6cb9
commit 9cb8f414ba
No known key found for this signature in database
GPG key ID: 5F7295599C5D965C
8 changed files with 153 additions and 6 deletions

View file

@ -2,8 +2,56 @@
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "64bb48a6bc6a544d168b0b4f4862cbcd",
"identityHash": "67b7550b79460fd815162804f4a00c2e",
"entities": [
{
"tableName": "offline_ciphers",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `user_id` TEXT NOT NULL, `cipher_type` TEXT NOT NULL, `cipher_json` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "userId",
"columnName": "user_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "cipherType",
"columnName": "cipher_type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "cipherJson",
"columnName": "cipher_json",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_offline_ciphers_user_id",
"unique": false,
"columnNames": [
"user_id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_offline_ciphers_user_id` ON `${TABLE_NAME}` (`user_id`)"
}
],
"foreignKeys": []
},
{
"tableName": "ciphers",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `user_id` TEXT NOT NULL, `cipher_type` TEXT NOT NULL, `cipher_json` TEXT NOT NULL, PRIMARY KEY(`id`))",
@ -244,7 +292,7 @@
"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, '64bb48a6bc6a544d168b0b4f4862cbcd')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '67b7550b79460fd815162804f4a00c2e')"
]
}
}

View file

@ -1,5 +1,6 @@
package com.x8bit.bitwarden.data.vault.datasource.disk
import com.bitwarden.vault.Cipher
import com.bitwarden.vault.CipherView
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
import kotlinx.coroutines.flow.Flow
@ -13,7 +14,7 @@ interface VaultDiskSource {
/**
* Saves a cipher to the offline data source for the given [userId].
*/
suspend fun saveOfflineCipher(userId: String, cipher: CipherView)
suspend fun saveOfflineCipher(userId: String, cipher: Cipher)
/**
* Saves a cipher to the data source for the given [userId].

View file

@ -1,5 +1,6 @@
package com.x8bit.bitwarden.data.vault.datasource.disk
import com.bitwarden.vault.Cipher
import com.bitwarden.vault.CipherView
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
@ -7,6 +8,7 @@ import com.x8bit.bitwarden.data.vault.datasource.disk.dao.CiphersDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.CollectionsDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.DomainsDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.FoldersDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.OfflineCiphersDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.SendsDao
import com.x8bit.bitwarden.data.vault.datasource.disk.entity.CipherEntity
import com.x8bit.bitwarden.data.vault.datasource.disk.entity.CollectionEntity
@ -31,7 +33,7 @@ import kotlinx.serialization.json.Json
*/
@Suppress("TooManyFunctions", "LongParameterList")
class VaultDiskSourceImpl(
private val offlineCiphersDao: CiphersDao,
private val offlineCiphersDao: OfflineCiphersDao,
private val ciphersDao: CiphersDao,
private val collectionsDao: CollectionsDao,
private val domainsDao: DomainsDao,
@ -47,7 +49,7 @@ class VaultDiskSourceImpl(
private val forceFolderFlow = bufferedMutableSharedFlow<List<SyncResponseJson.Folder>>()
private val forceSendFlow = bufferedMutableSharedFlow<List<SyncResponseJson.Send>>()
override suspend fun saveOfflineCipher(userId: String, cipher: CipherView) {
override suspend fun saveOfflineCipher(userId: String, cipher: Cipher) {
TODO("Not yet implemented")
}

View file

@ -0,0 +1,57 @@
package com.x8bit.bitwarden.data.vault.datasource.disk.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import com.x8bit.bitwarden.data.vault.datasource.disk.entity.OfflineCipherEntity
import kotlinx.coroutines.flow.Flow
/**
* Provides methods for inserting, retrieving, and deleting ciphers from the database using the
* [OfflineCipherEntity].
*/
@Dao
interface OfflineCiphersDao {
/**
* Inserts multiple ciphers into the database.
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertCiphers(ciphers: List<OfflineCipherEntity>)
/**
* Retrieves all ciphers from the database for a given [userId].
*/
@Query("SELECT * FROM offline_ciphers WHERE user_id = :userId")
fun getAllCiphers(
userId: String,
): Flow<List<OfflineCipherEntity>>
/**
* Deletes all the stored ciphers associated with the given [userId]. This will return the
* number of rows deleted by this query.
*/
@Query("DELETE FROM offline_ciphers WHERE user_id = :userId")
suspend fun deleteAllCiphers(userId: String): Int
/**
* Deletes the specified cipher associated with the given [userId] and [cipherId]. This will
* return the number of rows deleted by this query.
*/
@Query("DELETE FROM offline_ciphers WHERE user_id = :userId AND id = :cipherId")
suspend fun deleteCipher(userId: String, cipherId: String): Int
/**
* Deletes all the stored ciphers associated with the given [userId] and then add all new
* [ciphers] to the database. This will return `true` if any changes were made to the database
* and `false` otherwise.
*/
@Transaction
suspend fun replaceAllCiphers(userId: String, ciphers: List<OfflineCipherEntity>): Boolean {
val deletedCiphersCount = deleteAllCiphers(userId)
insertCiphers(ciphers)
return deletedCiphersCount > 0 || ciphers.isNotEmpty()
}
}

View file

@ -8,11 +8,13 @@ import com.x8bit.bitwarden.data.vault.datasource.disk.dao.CiphersDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.CollectionsDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.DomainsDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.FoldersDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.OfflineCiphersDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.SendsDao
import com.x8bit.bitwarden.data.vault.datasource.disk.entity.CipherEntity
import com.x8bit.bitwarden.data.vault.datasource.disk.entity.CollectionEntity
import com.x8bit.bitwarden.data.vault.datasource.disk.entity.DomainsEntity
import com.x8bit.bitwarden.data.vault.datasource.disk.entity.FolderEntity
import com.x8bit.bitwarden.data.vault.datasource.disk.entity.OfflineCipherEntity
import com.x8bit.bitwarden.data.vault.datasource.disk.entity.SendEntity
/**
@ -20,6 +22,7 @@ import com.x8bit.bitwarden.data.vault.datasource.disk.entity.SendEntity
*/
@Database(
entities = [
OfflineCipherEntity::class,
CipherEntity::class,
CollectionEntity::class,
DomainsEntity::class,
@ -32,6 +35,11 @@ import com.x8bit.bitwarden.data.vault.datasource.disk.entity.SendEntity
@TypeConverters(ZonedDateTimeTypeConverter::class)
abstract class VaultDatabase : RoomDatabase() {
/**
* Provides the DAO for accessing cipher data.
*/
abstract fun offlineCipherDao(): OfflineCiphersDao
/**
* Provides the DAO for accessing cipher data.
*/

View file

@ -10,6 +10,7 @@ import com.x8bit.bitwarden.data.vault.datasource.disk.dao.CiphersDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.CollectionsDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.DomainsDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.FoldersDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.OfflineCiphersDao
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.SendsDao
import com.x8bit.bitwarden.data.vault.datasource.disk.database.VaultDatabase
import dagger.Module
@ -39,6 +40,10 @@ class VaultDiskModule {
.addTypeConverter(ZonedDateTimeTypeConverter())
.build()
@Provides
@Singleton
fun provideOfflineCipherDao(database: VaultDatabase): OfflineCiphersDao = database.offlineCipherDao()
@Provides
@Singleton
fun provideCipherDao(database: VaultDatabase): CiphersDao = database.cipherDao()
@ -62,6 +67,7 @@ class VaultDiskModule {
@Provides
@Singleton
fun provideVaultDiskSource(
offlineCiphersDao: OfflineCiphersDao,
ciphersDao: CiphersDao,
collectionsDao: CollectionsDao,
domainsDao: DomainsDao,
@ -70,6 +76,7 @@ class VaultDiskModule {
json: Json,
dispatcherManager: DispatcherManager,
): VaultDiskSource = VaultDiskSourceImpl(
offlineCiphersDao = offlineCiphersDao,
ciphersDao = ciphersDao,
collectionsDao = collectionsDao,
domainsDao = domainsDao,

View file

@ -0,0 +1,24 @@
package com.x8bit.bitwarden.data.vault.datasource.disk.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
/**
* Entity representing a cipher in the database.
*/
@Entity(tableName = "offline_ciphers")
data class OfflineCipherEntity(
@PrimaryKey(autoGenerate = false)
@ColumnInfo(name = "id")
val id: String,
@ColumnInfo(name = "user_id", index = true)
val userId: String,
@ColumnInfo(name = "cipher_type")
val cipherType: String,
@ColumnInfo(name = "cipher_json")
val cipherJson: String,
)

View file

@ -53,7 +53,7 @@ class CipherManagerImpl(
userId = userId,
cipherView = cipherView
)
.flatMap { vaultDiskSource.saveOfflineCipher(userId = userId, cipher = it) }
.map { vaultDiskSource.saveOfflineCipher(userId = userId, cipher = it) }
.fold(
onFailure = { CreateCipherResult.Error },
onSuccess = { CreateCipherResult.Success }