Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

PUT_CHANGELOG_HERE

- Database files are now stored in the `cache` directory by default on Android (#164)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably worth and explicit warning that it's going to lose all the data.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


# v1.0.0-alpha.7
_2025-10-14_

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@ import android.content.Context
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.sqlite.db.SupportSQLiteOpenHelper
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
import com.apollographql.cache.normalized.api.NormalizedCacheFactory
import com.apollographql.cache.normalized.sql.internal.record.SqlRecordDatabase
import app.cash.sqldelight.async.coroutines.synchronous
import app.cash.sqldelight.driver.android.AndroidSqliteDriver
import app.cash.sqldelight.db.SqlDriver
import com.apollographql.cache.normalized.api.NormalizedCache
import app.cash.sqldelight.driver.android.AndroidSqliteDriver
import com.apollographql.cache.normalized.api.NormalizedCacheFactory
import com.apollographql.cache.normalized.sql.internal.record.SqlRecordDatabase

actual fun SqlNormalizedCacheFactory(name: String?): NormalizedCacheFactory =
SqlNormalizedCacheFactory(createDriver(name, null))
SqlNormalizedCacheFactory(createDriver(name))

/**
* @param [name] Name of the database file, or null for an in-memory database (as per Android framework implementation).
* @param [factory] Factory class to create instances of [SupportSQLiteOpenHelper]
* @param [configure] Optional callback, called when the database connection is being configured, to enable features such as
* write-ahead logging or foreign key support. It should not modify the database except to configure it.
* @param [useNoBackupDirectory] Sets whether to use a no backup directory or not.
* @param [windowSizeBytes] Size of cursor window in bytes, per [android.database.CursorWindow] (Android 28+ only), or null to use the default.
* @param name Name of the database file in the cache directory, or an absolute path to a file, or null for an in-memory database
* (as per Android framework implementation).
* @param factory Factory class to create instances of [SupportSQLiteOpenHelper]
* @param configure Optional callback, called when the database connection is being configured, to enable features such as
* write-ahead logging or foreign key support. It should not modify the database except to configure it.
* @param useNoBackupDirectory Sets whether to use a no backup directory or not.
* @param windowSizeBytes Size of cursor window in bytes, per [android.database.CursorWindow] (Android 28+ only), or null to use the default.
*/
@JvmOverloads
fun SqlNormalizedCacheFactory(
Expand All @@ -32,13 +32,29 @@ fun SqlNormalizedCacheFactory(
windowSizeBytes: Long? = null,
): NormalizedCacheFactory {
val synchronousSchema = SqlRecordDatabase.Schema.synchronous()
val filePath = when {
name == null -> {
null
}

name.startsWith("/") -> {
// Absolute path: keep as-is
name
}

else -> {
// Old versions of the library used to store the database in the database directory.
// If such file exists, use it, otherwise, use the cache directory.
Copy link
Contributor

@rohandhruva rohandhruva Oct 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For users who would prefer to switch to using the cache directory, do you think it's possible to provide a migration path? (understanding that you'll lose all the existing data)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think switching to the cache directory should become the default (with a big warning in the release notes). Users that want to keep the old one could use a dedicated overload that takes a path maybe?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can pass an absolute path for name, so I think that's enough to do that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for me!

(context.getDatabasePath(name).takeIf { it.exists() } ?: context.cacheDir.resolve(name)).absolutePath
}
}
return SqlNormalizedCacheFactory(
AndroidSqliteDriver(
synchronousSchema,
context.applicationContext,
name,
factory,
object : AndroidSqliteDriver.Callback(synchronousSchema) {
schema = synchronousSchema,
context = context.applicationContext,
name = filePath,
factory = factory,
callback = object : AndroidSqliteDriver.Callback(synchronousSchema) {
override fun onConfigure(db: SupportSQLiteDatabase) {
super.onConfigure(db)
configure?.invoke(db)
Expand All @@ -50,15 +66,12 @@ fun SqlNormalizedCacheFactory(
)
}

private fun createDriver(name: String?, baseDir: String?): SqlDriver {
check(baseDir == null) {
"Apollo: Android SqlNormalizedCacheFactory doesn't support 'baseDir'"
}
private fun createDriver(name: String?): SqlDriver {
return AndroidSqliteDriver(
SqlRecordDatabase.Schema.synchronous(),
ApolloInitializer.context,
name,
FrameworkSQLiteOpenHelperFactory(),
schema = SqlRecordDatabase.Schema.synchronous(),
context = ApolloInitializer.context,
name = name,
factory = FrameworkSQLiteOpenHelperFactory(),
)
}

Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import com.apollographql.cache.normalized.sql.internal.RecordDatabase
/**
* Creates a new [NormalizedCacheFactory] that uses a persistent cache based on Sqlite
*
* @param name: the name of the database or null for an in-memory database
* @param name The name of the database or null for an in-memory database
* When not in memory, the database will be stored in a platform specific folder
* - on Android it will use [Context.getDatabaseName](https://developer.android.com/reference/android/content/Context#getDatabasePath(java.lang.String))
* - on Android it will use [Context.getCacheDir](https://developer.android.com/reference/android/content/Context#getCacheDir()). It can
* also be an absolute path to a file.
* - on MacOS, it will use "Application Support/databases/name"
* - on the JVM, it will use "System.getProperty("user.home")/.apollo"
* - on JS/Wasm, this argument is unused
Expand Down