diff --git a/gradle/libraries.toml b/gradle/libraries.toml index f20a332e5ef..1f227392c89 100644 --- a/gradle/libraries.toml +++ b/gradle/libraries.toml @@ -53,6 +53,7 @@ androidx-activity = "androidx.activity:activity-ktx:1.7.2" androidx-annotation = { group = "androidx.annotation", name = "annotation", version = "1.7.1" } androidx-core = "androidx.core:core-ktx:1.12.0" androidx-espresso-idlingresource = { group = "androidx.test.espresso", name = "espresso-idling-resource", version = "3.5.1" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version = "3.5.1" } androidx-lint-rules = "androidx.lint:lint-gradle:1.0.0-alpha01" androidx-lint-gradle-plugin = { module = "com.android.lint:com.android.lint.gradle.plugin", version.ref = "android-plugin" } androidx-profileinstaller = "androidx.profileinstaller:profileinstaller:1.3.1" diff --git a/libraries/apollo-annotations/src/commonMain/kotlin/com/apollographql/apollo/annotations/ApolloDeprecatedSince.kt b/libraries/apollo-annotations/src/commonMain/kotlin/com/apollographql/apollo/annotations/ApolloDeprecatedSince.kt index 2d9ad2c8499..147a62788ea 100644 --- a/libraries/apollo-annotations/src/commonMain/kotlin/com/apollographql/apollo/annotations/ApolloDeprecatedSince.kt +++ b/libraries/apollo-annotations/src/commonMain/kotlin/com/apollographql/apollo/annotations/ApolloDeprecatedSince.kt @@ -33,5 +33,6 @@ annotation class ApolloDeprecatedSince(val version: Version) { v4_0_0, v4_0_1, v4_0_2, + v4_1_1, } } diff --git a/libraries/apollo-normalized-cache-api/api/apollo-normalized-cache-api.api b/libraries/apollo-normalized-cache-api/api/apollo-normalized-cache-api.api index 97215bff15b..03a1056c78c 100644 --- a/libraries/apollo-normalized-cache-api/api/apollo-normalized-cache-api.api +++ b/libraries/apollo-normalized-cache-api/api/apollo-normalized-cache-api.api @@ -104,11 +104,12 @@ public final class com/apollographql/apollo/cache/normalized/api/MemoryCacheFact public synthetic fun create ()Lcom/apollographql/apollo/cache/normalized/api/NormalizedCache; } -public abstract class com/apollographql/apollo/cache/normalized/api/NormalizedCache : com/apollographql/apollo/cache/normalized/api/ReadOnlyNormalizedCache { +public abstract class com/apollographql/apollo/cache/normalized/api/NormalizedCache : com/apollographql/apollo/cache/normalized/api/ReadOnlyNormalizedCache, java/io/Closeable { public static final field Companion Lcom/apollographql/apollo/cache/normalized/api/NormalizedCache$Companion; public fun ()V public final fun chain (Lcom/apollographql/apollo/cache/normalized/api/NormalizedCache;)Lcom/apollographql/apollo/cache/normalized/api/NormalizedCache; public abstract fun clearAll ()V + public fun close ()V public final fun getNextCache ()Lcom/apollographql/apollo/cache/normalized/api/NormalizedCache; public abstract fun merge (Lcom/apollographql/apollo/cache/normalized/api/Record;Lcom/apollographql/apollo/cache/normalized/api/CacheHeaders;)Ljava/util/Set; public abstract fun merge (Ljava/util/Collection;Lcom/apollographql/apollo/cache/normalized/api/CacheHeaders;)Ljava/util/Set; diff --git a/libraries/apollo-normalized-cache-api/api/apollo-normalized-cache-api.klib.api b/libraries/apollo-normalized-cache-api/api/apollo-normalized-cache-api.klib.api index aeebe15221e..d3a524b8319 100644 --- a/libraries/apollo-normalized-cache-api/api/apollo-normalized-cache-api.klib.api +++ b/libraries/apollo-normalized-cache-api/api/apollo-normalized-cache-api.klib.api @@ -28,7 +28,7 @@ abstract class com.apollographql.apollo.cache.normalized.api/CacheKeyResolver : open fun listOfCacheKeysForField(com.apollographql.apollo.api/CompiledField, com.apollographql.apollo.api/Executable.Variables): kotlin.collections/List? // com.apollographql.apollo.cache.normalized.api/CacheKeyResolver.listOfCacheKeysForField|listOfCacheKeysForField(com.apollographql.apollo.api.CompiledField;com.apollographql.apollo.api.Executable.Variables){}[0] } -abstract class com.apollographql.apollo.cache.normalized.api/NormalizedCache : com.apollographql.apollo.cache.normalized.api/ReadOnlyNormalizedCache { // com.apollographql.apollo.cache.normalized.api/NormalizedCache|null[0] +abstract class com.apollographql.apollo.cache.normalized.api/NormalizedCache : com.apollographql.apollo.cache.normalized.api/ReadOnlyNormalizedCache, okio/Closeable { // com.apollographql.apollo.cache.normalized.api/NormalizedCache|null[0] constructor () // com.apollographql.apollo.cache.normalized.api/NormalizedCache.|(){}[0] final var nextCache // com.apollographql.apollo.cache.normalized.api/NormalizedCache.nextCache|{}nextCache[0] @@ -40,6 +40,7 @@ abstract class com.apollographql.apollo.cache.normalized.api/NormalizedCache : c abstract fun remove(com.apollographql.apollo.cache.normalized.api/CacheKey, kotlin/Boolean): kotlin/Boolean // com.apollographql.apollo.cache.normalized.api/NormalizedCache.remove|remove(com.apollographql.apollo.cache.normalized.api.CacheKey;kotlin.Boolean){}[0] abstract fun remove(kotlin/String): kotlin/Int // com.apollographql.apollo.cache.normalized.api/NormalizedCache.remove|remove(kotlin.String){}[0] final fun chain(com.apollographql.apollo.cache.normalized.api/NormalizedCache): com.apollographql.apollo.cache.normalized.api/NormalizedCache // com.apollographql.apollo.cache.normalized.api/NormalizedCache.chain|chain(com.apollographql.apollo.cache.normalized.api.NormalizedCache){}[0] + open fun close() // com.apollographql.apollo.cache.normalized.api/NormalizedCache.close|close(){}[0] final object Companion { // com.apollographql.apollo.cache.normalized.api/NormalizedCache.Companion|null[0] final fun patternToRegex(kotlin/String): kotlin.text/Regex // com.apollographql.apollo.cache.normalized.api/NormalizedCache.Companion.patternToRegex|patternToRegex(kotlin.String){}[0] diff --git a/libraries/apollo-normalized-cache-api/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/api/NormalizedCache.kt b/libraries/apollo-normalized-cache-api/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/api/NormalizedCache.kt index 204194db377..6b250c69b63 100644 --- a/libraries/apollo-normalized-cache-api/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/api/NormalizedCache.kt +++ b/libraries/apollo-normalized-cache-api/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/api/NormalizedCache.kt @@ -1,5 +1,6 @@ package com.apollographql.apollo.cache.normalized.api +import okio.Closeable import kotlin.jvm.JvmStatic import kotlin.jvm.JvmSuppressWildcards import kotlin.reflect.KClass @@ -17,7 +18,7 @@ import kotlin.reflect.KClass * * A [NormalizedCache] can choose to store records in any manner. */ -abstract class NormalizedCache : ReadOnlyNormalizedCache { +abstract class NormalizedCache : ReadOnlyNormalizedCache, Closeable { var nextCache: NormalizedCache? = null private set @@ -146,5 +147,12 @@ abstract class NormalizedCache : ReadOnlyNormalizedCache { private val specialChars = "()^$.*?+{}" } + + /** + * Closes resources associated with the cache if any. + * This function must not call `nextCache.close()`, this is done by the caller. + */ + override fun close() { + } } diff --git a/libraries/apollo-normalized-cache-sqlite/api/android/apollo-normalized-cache-sqlite.api b/libraries/apollo-normalized-cache-sqlite/api/android/apollo-normalized-cache-sqlite.api index 7bb6dd1fc8e..0f2d1026ee5 100644 --- a/libraries/apollo-normalized-cache-sqlite/api/android/apollo-normalized-cache-sqlite.api +++ b/libraries/apollo-normalized-cache-sqlite/api/android/apollo-normalized-cache-sqlite.api @@ -10,7 +10,9 @@ public final class com/apollographql/apollo/cache/normalized/sql/ApolloInitializ } public final class com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCache : com/apollographql/apollo/cache/normalized/api/NormalizedCache { + public fun (Lapp/cash/sqldelight/db/SqlDriver;)V public fun clearAll ()V + public fun close ()V public fun dump ()Ljava/util/Map; public fun loadRecord (Ljava/lang/String;Lcom/apollographql/apollo/cache/normalized/api/CacheHeaders;)Lcom/apollographql/apollo/cache/normalized/api/Record; public fun loadRecords (Ljava/util/Collection;Lcom/apollographql/apollo/cache/normalized/api/CacheHeaders;)Ljava/util/Collection; diff --git a/libraries/apollo-normalized-cache-sqlite/api/apollo-normalized-cache-sqlite.klib.api b/libraries/apollo-normalized-cache-sqlite/api/apollo-normalized-cache-sqlite.klib.api index e1500e4cee7..e1149833889 100644 --- a/libraries/apollo-normalized-cache-sqlite/api/apollo-normalized-cache-sqlite.klib.api +++ b/libraries/apollo-normalized-cache-sqlite/api/apollo-normalized-cache-sqlite.klib.api @@ -7,7 +7,10 @@ // Library unique name: final class com.apollographql.apollo.cache.normalized.sql/SqlNormalizedCache : com.apollographql.apollo.cache.normalized.api/NormalizedCache { // com.apollographql.apollo.cache.normalized.sql/SqlNormalizedCache|null[0] + constructor (app.cash.sqldelight.db/SqlDriver) // com.apollographql.apollo.cache.normalized.sql/SqlNormalizedCache.|(app.cash.sqldelight.db.SqlDriver){}[0] + final fun clearAll() // com.apollographql.apollo.cache.normalized.sql/SqlNormalizedCache.clearAll|clearAll(){}[0] + final fun close() // com.apollographql.apollo.cache.normalized.sql/SqlNormalizedCache.close|close(){}[0] final fun dump(): kotlin.collections/Map, kotlin.collections/Map> // com.apollographql.apollo.cache.normalized.sql/SqlNormalizedCache.dump|dump(){}[0] final fun loadRecord(kotlin/String, com.apollographql.apollo.cache.normalized.api/CacheHeaders): com.apollographql.apollo.cache.normalized.api/Record? // com.apollographql.apollo.cache.normalized.sql/SqlNormalizedCache.loadRecord|loadRecord(kotlin.String;com.apollographql.apollo.cache.normalized.api.CacheHeaders){}[0] final fun loadRecords(kotlin.collections/Collection, com.apollographql.apollo.cache.normalized.api/CacheHeaders): kotlin.collections/Collection // com.apollographql.apollo.cache.normalized.sql/SqlNormalizedCache.loadRecords|loadRecords(kotlin.collections.Collection;com.apollographql.apollo.cache.normalized.api.CacheHeaders){}[0] diff --git a/libraries/apollo-normalized-cache-sqlite/api/jvm/apollo-normalized-cache-sqlite.api b/libraries/apollo-normalized-cache-sqlite/api/jvm/apollo-normalized-cache-sqlite.api index 5f5af5a7074..353c47ebec9 100644 --- a/libraries/apollo-normalized-cache-sqlite/api/jvm/apollo-normalized-cache-sqlite.api +++ b/libraries/apollo-normalized-cache-sqlite/api/jvm/apollo-normalized-cache-sqlite.api @@ -1,5 +1,7 @@ public final class com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCache : com/apollographql/apollo/cache/normalized/api/NormalizedCache { + public fun (Lapp/cash/sqldelight/db/SqlDriver;)V public fun clearAll ()V + public fun close ()V public fun dump ()Ljava/util/Map; public fun loadRecord (Ljava/lang/String;Lcom/apollographql/apollo/cache/normalized/api/CacheHeaders;)Lcom/apollographql/apollo/cache/normalized/api/Record; public fun loadRecords (Ljava/util/Collection;Lcom/apollographql/apollo/cache/normalized/api/CacheHeaders;)Ljava/util/Collection; diff --git a/libraries/apollo-normalized-cache-sqlite/src/androidMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheFactory.kt b/libraries/apollo-normalized-cache-sqlite/src/androidMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheFactory.kt index aabe4ff6535..50c09eb0d50 100644 --- a/libraries/apollo-normalized-cache-sqlite/src/androidMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheFactory.kt +++ b/libraries/apollo-normalized-cache-sqlite/src/androidMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheFactory.kt @@ -6,7 +6,6 @@ import androidx.sqlite.db.SupportSQLiteOpenHelper import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory import com.apollographql.apollo.cache.normalized.api.NormalizedCacheFactory import com.apollographql.apollo.cache.normalized.sql.internal.createDriver -import com.apollographql.apollo.cache.normalized.sql.internal.createRecordDatabase import com.apollographql.apollo.cache.normalized.sql.internal.getSchema import app.cash.sqldelight.driver.android.AndroidSqliteDriver import app.cash.sqldelight.db.SqlDriver @@ -52,7 +51,7 @@ actual class SqlNormalizedCacheFactory actual constructor( actual constructor(name: String?): this(createDriver(name, null, getSchema())) actual override fun create(): NormalizedCache { - return SqlNormalizedCache(createRecordDatabase(driver)) + return SqlNormalizedCache(driver) } } diff --git a/libraries/apollo-normalized-cache-sqlite/src/appleMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheFactory.kt b/libraries/apollo-normalized-cache-sqlite/src/appleMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheFactory.kt index 24dd3d1a900..df90ddc4dfb 100644 --- a/libraries/apollo-normalized-cache-sqlite/src/appleMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheFactory.kt +++ b/libraries/apollo-normalized-cache-sqlite/src/appleMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheFactory.kt @@ -4,7 +4,6 @@ import app.cash.sqldelight.db.SqlDriver import com.apollographql.apollo.cache.normalized.api.NormalizedCache import com.apollographql.apollo.cache.normalized.api.NormalizedCacheFactory import com.apollographql.apollo.cache.normalized.sql.internal.createDriver -import com.apollographql.apollo.cache.normalized.sql.internal.createRecordDatabase import com.apollographql.apollo.cache.normalized.sql.internal.getSchema actual class SqlNormalizedCacheFactory actual constructor( @@ -22,8 +21,6 @@ actual class SqlNormalizedCacheFactory actual constructor( constructor() : this("apollo.db") actual override fun create(): NormalizedCache { - return SqlNormalizedCache( - recordDatabase = createRecordDatabase(driver) - ) + return SqlNormalizedCache(driver) } } diff --git a/libraries/apollo-normalized-cache-sqlite/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCache.kt b/libraries/apollo-normalized-cache-sqlite/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCache.kt index 605f83eb54a..dabd882e81d 100644 --- a/libraries/apollo-normalized-cache-sqlite/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCache.kt +++ b/libraries/apollo-normalized-cache-sqlite/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCache.kt @@ -1,19 +1,35 @@ package com.apollographql.apollo.cache.normalized.sql +import app.cash.sqldelight.db.SqlDriver import com.apollographql.apollo.cache.normalized.api.ApolloCacheHeaders import com.apollographql.apollo.cache.normalized.api.ApolloCacheHeaders.EVICT_AFTER_READ import com.apollographql.apollo.cache.normalized.api.CacheHeaders import com.apollographql.apollo.cache.normalized.api.CacheKey import com.apollographql.apollo.cache.normalized.api.NormalizedCache import com.apollographql.apollo.cache.normalized.api.Record +import com.apollographql.apollo.cache.normalized.sql.internal.JsonRecordDatabase import com.apollographql.apollo.cache.normalized.sql.internal.RecordDatabase +import com.apollographql.apollo.cache.normalized.sql.internal.checkDatabase +import com.apollographql.apollo.cache.normalized.sql.internal.json.JsonDatabase import com.apollographql.apollo.exception.apolloExceptionHandler import kotlin.reflect.KClass class SqlNormalizedCache internal constructor( - private val recordDatabase: RecordDatabase, + private val driver: SqlDriver, + doChecks: Boolean ) : NormalizedCache() { + constructor(driver: SqlDriver): this(driver, true) + + private val recordDatabase: RecordDatabase + + init { + if (doChecks) { + checkDatabase(driver) + } + recordDatabase = JsonRecordDatabase(JsonDatabase(driver).jsonQueries) + } + override fun loadRecord(key: String, cacheHeaders: CacheHeaders): Record? { if (cacheHeaders.hasHeader(ApolloCacheHeaders.MEMORY_CACHE_ONLY)) { return null @@ -212,4 +228,8 @@ class SqlNormalizedCache internal constructor( recordDatabase.select(chunkedKeys) } } + + override fun close() { + driver.close() + } } diff --git a/libraries/apollo-normalized-cache-sqlite/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/sql/internal/factoryHelpers.kt b/libraries/apollo-normalized-cache-sqlite/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/sql/internal/factoryHelpers.kt index 73a88879012..cf1ee3b6afb 100644 --- a/libraries/apollo-normalized-cache-sqlite/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/sql/internal/factoryHelpers.kt +++ b/libraries/apollo-normalized-cache-sqlite/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/sql/internal/factoryHelpers.kt @@ -8,7 +8,7 @@ import app.cash.sqldelight.db.SqlDriver import app.cash.sqldelight.db.SqlSchema import app.cash.sqldelight.db.use -internal fun createRecordDatabase(driver: SqlDriver): RecordDatabase { +internal fun checkDatabase(driver: SqlDriver) { maybeCreateOrMigrateSchema(driver, getSchema()) val tableNames = mutableListOf() @@ -39,8 +39,6 @@ internal fun createRecordDatabase(driver: SqlDriver): RecordDatabase { check(tableNames.isEmpty() || tableNames.contains(expectedTableName)) { "Apollo: Cannot find the '$expectedTableName' table? (found '$tableNames' instead)" } - - return JsonRecordDatabase(JsonDatabase(driver).jsonQueries) } internal fun getSchema(): SqlSchema> = JsonDatabase.Schema diff --git a/libraries/apollo-normalized-cache-sqlite/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/sql/internal/factoryImplementations.kt b/libraries/apollo-normalized-cache-sqlite/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/sql/internal/factoryImplementations.kt index f8cd87629ac..d93634e0e6c 100644 --- a/libraries/apollo-normalized-cache-sqlite/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/sql/internal/factoryImplementations.kt +++ b/libraries/apollo-normalized-cache-sqlite/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/sql/internal/factoryImplementations.kt @@ -10,5 +10,7 @@ internal expect fun createDriver(name: String?, baseDir: String?, schema: SqlSch * will take care of migrations * * Others like JVM don't do this automatically. This is when [maybeCreateOrMigrateSchema] is needed + * + * See https://github.com/sqldelight/sqldelight/issues/1901 */ internal expect fun maybeCreateOrMigrateSchema(driver: SqlDriver, schema: SqlSchema>) \ No newline at end of file diff --git a/libraries/apollo-normalized-cache-sqlite/src/commonTest/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheTest.kt b/libraries/apollo-normalized-cache-sqlite/src/commonTest/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheTest.kt index 422aadae176..6690a34e705 100644 --- a/libraries/apollo-normalized-cache-sqlite/src/commonTest/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheTest.kt +++ b/libraries/apollo-normalized-cache-sqlite/src/commonTest/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheTest.kt @@ -20,6 +20,7 @@ import app.cash.sqldelight.db.QueryResult import app.cash.sqldelight.db.SqlCursor import app.cash.sqldelight.db.SqlDriver import app.cash.sqldelight.db.SqlPreparedStatement +import com.apollographql.apollo.cache.normalized.sql.internal.json.JsonDatabase import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals @@ -331,7 +332,7 @@ class SqlNormalizedCacheTest { @Test fun exceptionCallsExceptionHandler() { - val badCache = SqlNormalizedCache(JsonRecordDatabase(JsonQueries(BadDriver))) + val badCache = SqlNormalizedCache(BadDriver, doChecks = false) var throwable: Throwable? = null apolloExceptionHandler = { throwable = it diff --git a/libraries/apollo-normalized-cache-sqlite/src/jvmMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheFactoryJvm.kt b/libraries/apollo-normalized-cache-sqlite/src/jvmMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheFactoryJvm.kt index 632587c3fc9..d52b280ed5d 100644 --- a/libraries/apollo-normalized-cache-sqlite/src/jvmMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheFactoryJvm.kt +++ b/libraries/apollo-normalized-cache-sqlite/src/jvmMain/kotlin/com/apollographql/apollo/cache/normalized/sql/SqlNormalizedCacheFactoryJvm.kt @@ -1,12 +1,11 @@ package com.apollographql.apollo.cache.normalized.sql -import com.apollographql.apollo.cache.normalized.api.NormalizedCacheFactory -import com.apollographql.apollo.cache.normalized.sql.internal.createDriver -import com.apollographql.apollo.cache.normalized.sql.internal.createRecordDatabase -import com.apollographql.apollo.cache.normalized.sql.internal.getSchema import app.cash.sqldelight.db.SqlDriver import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver import com.apollographql.apollo.cache.normalized.api.NormalizedCache +import com.apollographql.apollo.cache.normalized.api.NormalizedCacheFactory +import com.apollographql.apollo.cache.normalized.sql.internal.createDriver +import com.apollographql.apollo.cache.normalized.sql.internal.getSchema import java.util.Properties actual class SqlNormalizedCacheFactory actual constructor( @@ -32,7 +31,7 @@ actual class SqlNormalizedCacheFactory actual constructor( actual constructor(name: String?, ) : this(name, null) actual override fun create(): NormalizedCache { - return SqlNormalizedCache(createRecordDatabase(driver)) + return SqlNormalizedCache(driver) } } diff --git a/libraries/apollo-normalized-cache/api/apollo-normalized-cache.api b/libraries/apollo-normalized-cache/api/apollo-normalized-cache.api index 60a3f302216..4f729b9e400 100644 --- a/libraries/apollo-normalized-cache/api/apollo-normalized-cache.api +++ b/libraries/apollo-normalized-cache/api/apollo-normalized-cache.api @@ -1,7 +1,8 @@ -public abstract interface class com/apollographql/apollo/cache/normalized/ApolloStore { +public abstract interface class com/apollographql/apollo/cache/normalized/ApolloStore : java/io/Closeable { public abstract fun accessCache (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public abstract fun clearAll ()Z - public abstract fun dispose ()V + public fun close ()V + public fun dispose ()V public abstract fun dump ()Ljava/util/Map; public abstract fun getChangedKeys ()Lkotlinx/coroutines/flow/SharedFlow; public abstract fun normalize (Lcom/apollographql/apollo/api/Operation;Lcom/apollographql/apollo/api/Operation$Data;Lcom/apollographql/apollo/api/CustomScalarAdapters;)Ljava/util/Map; diff --git a/libraries/apollo-normalized-cache/api/apollo-normalized-cache.klib.api b/libraries/apollo-normalized-cache/api/apollo-normalized-cache.klib.api index a62823e975d..aa1caf9abfc 100644 --- a/libraries/apollo-normalized-cache/api/apollo-normalized-cache.klib.api +++ b/libraries/apollo-normalized-cache/api/apollo-normalized-cache.klib.api @@ -20,7 +20,7 @@ final enum class com.apollographql.apollo.cache.normalized/FetchPolicy : kotlin/ final fun values(): kotlin/Array // com.apollographql.apollo.cache.normalized/FetchPolicy.values|values#static(){}[0] } -abstract interface com.apollographql.apollo.cache.normalized/ApolloStore { // com.apollographql.apollo.cache.normalized/ApolloStore|null[0] +abstract interface com.apollographql.apollo.cache.normalized/ApolloStore : okio/Closeable { // com.apollographql.apollo.cache.normalized/ApolloStore|null[0] abstract val changedKeys // com.apollographql.apollo.cache.normalized/ApolloStore.changedKeys|{}changedKeys[0] abstract fun (): kotlinx.coroutines.flow/SharedFlow> // com.apollographql.apollo.cache.normalized/ApolloStore.changedKeys.|(){}[0] @@ -32,7 +32,6 @@ abstract interface com.apollographql.apollo.cache.normalized/ApolloStore { // co abstract fun <#A1: com.apollographql.apollo.api/Operation.Data> writeOptimisticUpdatesSync(com.apollographql.apollo.api/Operation<#A1>, #A1, com.benasher44.uuid/Uuid, com.apollographql.apollo.api/CustomScalarAdapters = ...): kotlin.collections/Set // com.apollographql.apollo.cache.normalized/ApolloStore.writeOptimisticUpdatesSync|writeOptimisticUpdatesSync(com.apollographql.apollo.api.Operation<0:0>;0:0;com.benasher44.uuid.Uuid;com.apollographql.apollo.api.CustomScalarAdapters){0§}[0] abstract fun <#A1: kotlin/Any?> accessCache(kotlin/Function1): #A1 // com.apollographql.apollo.cache.normalized/ApolloStore.accessCache|accessCache(kotlin.Function1){0§}[0] abstract fun clearAll(): kotlin/Boolean // com.apollographql.apollo.cache.normalized/ApolloStore.clearAll|clearAll(){}[0] - abstract fun dispose() // com.apollographql.apollo.cache.normalized/ApolloStore.dispose|dispose(){}[0] abstract fun dump(): kotlin.collections/Map, kotlin.collections/Map> // com.apollographql.apollo.cache.normalized/ApolloStore.dump|dump(){}[0] abstract fun remove(com.apollographql.apollo.cache.normalized.api/CacheKey, kotlin/Boolean = ...): kotlin/Boolean // com.apollographql.apollo.cache.normalized/ApolloStore.remove|remove(com.apollographql.apollo.cache.normalized.api.CacheKey;kotlin.Boolean){}[0] abstract fun remove(kotlin.collections/List, kotlin/Boolean = ...): kotlin/Int // com.apollographql.apollo.cache.normalized/ApolloStore.remove|remove(kotlin.collections.List;kotlin.Boolean){}[0] @@ -42,6 +41,8 @@ abstract interface com.apollographql.apollo.cache.normalized/ApolloStore { // co abstract suspend fun <#A1: com.apollographql.apollo.api/Operation.Data> writeOptimisticUpdates(com.apollographql.apollo.api/Operation<#A1>, #A1, com.benasher44.uuid/Uuid, com.apollographql.apollo.api/CustomScalarAdapters = ..., kotlin/Boolean = ...): kotlin.collections/Set // com.apollographql.apollo.cache.normalized/ApolloStore.writeOptimisticUpdates|writeOptimisticUpdates(com.apollographql.apollo.api.Operation<0:0>;0:0;com.benasher44.uuid.Uuid;com.apollographql.apollo.api.CustomScalarAdapters;kotlin.Boolean){0§}[0] abstract suspend fun publish(kotlin.collections/Set) // com.apollographql.apollo.cache.normalized/ApolloStore.publish|publish(kotlin.collections.Set){}[0] abstract suspend fun rollbackOptimisticUpdates(com.benasher44.uuid/Uuid, kotlin/Boolean = ...): kotlin.collections/Set // com.apollographql.apollo.cache.normalized/ApolloStore.rollbackOptimisticUpdates|rollbackOptimisticUpdates(com.benasher44.uuid.Uuid;kotlin.Boolean){}[0] + open fun close() // com.apollographql.apollo.cache.normalized/ApolloStore.close|close(){}[0] + open fun dispose() // com.apollographql.apollo.cache.normalized/ApolloStore.dispose|dispose(){}[0] } final class com.apollographql.apollo.cache.normalized/CacheInfo : com.apollographql.apollo.api/ExecutionContext.Element { // com.apollographql.apollo.cache.normalized/CacheInfo|null[0] diff --git a/libraries/apollo-normalized-cache/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/ApolloStore.kt b/libraries/apollo-normalized-cache/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/ApolloStore.kt index 53c72c606c8..4e81b709929 100644 --- a/libraries/apollo-normalized-cache/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/ApolloStore.kt +++ b/libraries/apollo-normalized-cache/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/ApolloStore.kt @@ -1,5 +1,6 @@ package com.apollographql.apollo.cache.normalized +import com.apollographql.apollo.annotations.ApolloDeprecatedSince import com.apollographql.apollo.api.CustomScalarAdapters import com.apollographql.apollo.api.Fragment import com.apollographql.apollo.api.Operation @@ -17,6 +18,7 @@ import com.apollographql.apollo.cache.normalized.internal.DefaultApolloStore import com.apollographql.apollo.interceptor.ApolloInterceptor import com.benasher44.uuid.Uuid import kotlinx.coroutines.flow.SharedFlow +import okio.Closeable import kotlin.reflect.KClass /** @@ -25,7 +27,7 @@ import kotlin.reflect.KClass * Note that most operations are synchronous and might block if the underlying cache is doing IO - calling them from the main thread * should be avoided. */ -interface ApolloStore { +interface ApolloStore: Closeable { /** * Exposes the keys of records that have changed. */ @@ -259,7 +261,19 @@ interface ApolloStore { /** * Release resources associated with this store. */ - fun dispose() + @Deprecated("Use close() instead", ReplaceWith("close()")) + @ApolloDeprecatedSince(ApolloDeprecatedSince.Version.v4_1_1) + fun dispose() { + + } + + /** + * Release resources associated with this store. + */ + override fun close() { + @Suppress("DEPRECATION") + dispose() + } } fun ApolloStore( diff --git a/libraries/apollo-normalized-cache/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/internal/DefaultApolloStore.kt b/libraries/apollo-normalized-cache/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/internal/DefaultApolloStore.kt index 982ca0f5760..f934ee90d4f 100644 --- a/libraries/apollo-normalized-cache/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/internal/DefaultApolloStore.kt +++ b/libraries/apollo-normalized-cache/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/internal/DefaultApolloStore.kt @@ -1,5 +1,6 @@ package com.apollographql.apollo.cache.normalized.internal +import com.apollographql.apollo.annotations.ApolloDeprecatedSince import com.apollographql.apollo.api.CustomScalarAdapters import com.apollographql.apollo.api.Fragment import com.apollographql.apollo.api.Operation @@ -295,6 +296,20 @@ internal class DefaultApolloStore( } } - override fun dispose() {} + @Deprecated("Use close instead", ReplaceWith("close()")) + @ApolloDeprecatedSince(ApolloDeprecatedSince.Version.v4_1_1) + override fun dispose() { + close() + } + + override fun close() { + lock.write { + var cache: NormalizedCache? = this.cache + while (cache != null) { + cache.close() + cache = cache.nextCache + } + } + } } diff --git a/tests/sqlite/build.gradle.kts b/tests/sqlite/build.gradle.kts new file mode 100644 index 00000000000..1089018fa67 --- /dev/null +++ b/tests/sqlite/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") +} + +apolloTest() + +dependencies { + implementation(libs.apollo.normalizedcache.sqlite) + androidTestImplementation(libs.kotlin.test) + androidTestImplementation(libs.androidx.espresso.core) +} + + +android { + namespace = "com.example" + compileSdk = libs.versions.android.sdkversion.compile.get().toInt() + + defaultConfig { + applicationId = "com.example.myapplication" + minSdk = libs.versions.android.sdkversion.min.get().toInt() + targetSdk = libs.versions.android.sdkversion.compile.get().toInt() + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + +} \ No newline at end of file diff --git a/tests/sqlite/src/androidTest/kotlin/test/CloseDatabaseTest.kt b/tests/sqlite/src/androidTest/kotlin/test/CloseDatabaseTest.kt new file mode 100644 index 00000000000..ef476a5c09d --- /dev/null +++ b/tests/sqlite/src/androidTest/kotlin/test/CloseDatabaseTest.kt @@ -0,0 +1,29 @@ +package test + +import com.apollographql.apollo.cache.normalized.api.CacheHeaders +import com.apollographql.apollo.cache.normalized.api.Record +import com.apollographql.apollo.cache.normalized.sql.SqlNormalizedCacheFactory +import kotlin.test.Ignore +import kotlin.test.Test + + +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + println("starting...") + + // Starting a thread is important because the thread holds a ThreadLocal + // reference to the session that won't be garbage collected if using the main thread. + Thread { + SqlNormalizedCacheFactory("foo.db") + .create() + .merge(Record("9", mapOf("key" to "value")), CacheHeaders.NONE) + }.start() + + System.gc() + println("wait for the connection to leak, you should see it in logcat.") + // The leak should look like + // A SQLiteConnection object for database '/data/user/0/com.example.myapplication/databases/foo.db' was leaked! + Thread.sleep(60_000) + } +} \ No newline at end of file diff --git a/tests/sqlite/src/main/AndroidManifest.xml b/tests/sqlite/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..a2618f17624 --- /dev/null +++ b/tests/sqlite/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file