Add a CacheStore module.

This commit is contained in:
Benoit Marty 2026-04-29 16:39:07 +02:00 committed by Benoit Marty
parent ea1ccbf806
commit c86532778c
15 changed files with 374 additions and 0 deletions

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.cachestore.impl
import io.element.android.libraries.cachestore.api.CacheData
import java.util.Date
import io.element.android.libraries.cachestore.CacheData as DbCacheData
internal fun CacheData.toDbModel(key: String): DbCacheData {
return DbCacheData(
key = key,
value_ = value,
updatedAt = updatedAt.time,
)
}
internal fun DbCacheData.toApiModel(): CacheData {
return CacheData(
value = value_,
updatedAt = Date(updatedAt),
)
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.cachestore.impl
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.cachestore.api.CacheData
import io.element.android.libraries.cachestore.api.CacheStore
@SingleIn(AppScope::class)
@ContributesBinding(AppScope::class)
class DatabaseCacheStore(
private val database: CacheDatabase,
) : CacheStore {
override suspend fun getData(key: String): CacheData? {
return database.cacheDataQueries.selectData(key)
.executeAsOneOrNull()
?.toApiModel()
}
override suspend fun storeData(key: String, data: CacheData) {
database.cacheDataQueries.insertData(
data.toDbModel(key)
)
}
override suspend fun deleteData(key: String) {
database.cacheDataQueries.deleteData(key)
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.cachestore.impl.di
import android.content.Context
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Provides
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.cachestore.impl.CacheDatabase
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.encrypteddb.SqlCipherDriverFactory
import io.element.encrypteddb.passphrase.RandomSecretPassphraseProvider
@BindingContainer
@ContributesTo(AppScope::class)
object CacheStoreModule {
@Provides
@SingleIn(AppScope::class)
fun provideCacheDatabase(
@ApplicationContext context: Context,
): CacheDatabase {
val name = "cache_database"
val secretFile = context.getDatabasePath("$name.key")
// Make sure the parent directory of the key file exists, otherwise it will crash in older Android versions
val parentDir = secretFile.parentFile
if (parentDir != null && !parentDir.exists()) {
parentDir.mkdirs()
}
val passphraseProvider = RandomSecretPassphraseProvider(context, secretFile)
val driver = SqlCipherDriverFactory(passphraseProvider)
.create(CacheDatabase.Schema, "$name.db", context)
return CacheDatabase(driver)
}
}

View file

@ -0,0 +1,26 @@
--------------------------------------------------------------------
-- Current version of the DB is the highest value of filename
-- in the folder `sqldelight/databases`.
--
-- When upgrading the schema, you have to create a file .sqm in the
-- `sqldelight/databases` folder and run the following task to
-- generate a .db file using the latest schema
-- > ./gradlew generateDebugCacheDatabaseSchema
--------------------------------------------------------------------
CREATE TABLE CacheData (
key TEXT NOT NULL PRIMARY KEY,
value TEXT NOT NULL,
updatedAt INTEGER NOT NULL
);
selectData:
SELECT * FROM CacheData WHERE key = ?;
-- insert or update data by key
insertData:
INSERT INTO CacheData VALUES ? ON CONFLICT(key) DO UPDATE SET value = excluded.value, updatedAt = excluded.updatedAt;
deleteData:
DELETE FROM CacheData WHERE key = ?;