Skip to content

Commit d6f859a

Browse files
authored
dataconnect: add back public apis for offline caching (#7833)
1 parent d802076 commit d6f859a

File tree

13 files changed

+406
-143
lines changed

13 files changed

+406
-143
lines changed

firebase-dataconnect/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
[#7714](https://github.com/firebase/firebase-android-sdk/pull/7714)),
66
[#7720](https://github.com/firebase/firebase-android-sdk/pull/7720)),
77
[#7759](https://github.com/firebase/firebase-android-sdk/pull/7759)),
8-
[#NNNN](https://github.com/firebase/firebase-android-sdk/pull/NNNN))
8+
[#7821](https://github.com/firebase/firebase-android-sdk/pull/7821))
9+
- [changed] Added public APIs for offline caching.
10+
[#7833](https://github.com/firebase/firebase-android-sdk/pull/7833))
911

1012
# 17.1.3
1113

firebase-dataconnect/api.txt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,21 @@ package com.google.firebase.dataconnect {
2424
method public static com.google.firebase.dataconnect.AnyValue? fromNullableAny(com.google.firebase.dataconnect.AnyValue.Companion, Object? value);
2525
}
2626

27+
public final class CacheSettings {
28+
ctor public CacheSettings(com.google.firebase.dataconnect.CacheSettings.Storage storage = com.google.firebase.dataconnect.CacheSettings.Storage.PERSISTENT);
29+
method public com.google.firebase.dataconnect.CacheSettings.Storage getStorage();
30+
property public final com.google.firebase.dataconnect.CacheSettings.Storage storage;
31+
}
32+
33+
public enum CacheSettings.Storage {
34+
enum_constant public static final com.google.firebase.dataconnect.CacheSettings.Storage MEMORY;
35+
enum_constant public static final com.google.firebase.dataconnect.CacheSettings.Storage PERSISTENT;
36+
}
37+
38+
public final class CacheSettingsKt {
39+
method public static com.google.firebase.dataconnect.CacheSettings copy(com.google.firebase.dataconnect.CacheSettings, com.google.firebase.dataconnect.CacheSettings.Storage storage = storage);
40+
}
41+
2742
public final class ConnectorConfig {
2843
ctor public ConnectorConfig(String connector, String location, String serviceId);
2944
method public String getConnector();
@@ -85,14 +100,23 @@ package com.google.firebase.dataconnect {
85100

86101
public final class DataConnectSettings {
87102
ctor public DataConnectSettings(String host = "firebasedataconnect.googleapis.com", boolean sslEnabled = true);
103+
ctor public DataConnectSettings(String host = "firebasedataconnect.googleapis.com", boolean sslEnabled = true, com.google.firebase.dataconnect.CacheSettings? cacheSettings);
104+
method public com.google.firebase.dataconnect.CacheSettings? getCacheSettings();
88105
method public String getHost();
89106
method public boolean getSslEnabled();
107+
property public final com.google.firebase.dataconnect.CacheSettings? cacheSettings;
90108
property public final String host;
91109
property public final boolean sslEnabled;
92110
}
93111

94112
public final class DataConnectSettingsKt {
95113
method public static com.google.firebase.dataconnect.DataConnectSettings copy(com.google.firebase.dataconnect.DataConnectSettings, String host = host, boolean sslEnabled = sslEnabled);
114+
method public static com.google.firebase.dataconnect.DataConnectSettings copy(com.google.firebase.dataconnect.DataConnectSettings, String host = host, boolean sslEnabled = sslEnabled, com.google.firebase.dataconnect.CacheSettings? cacheSettings);
115+
}
116+
117+
public enum DataSource {
118+
enum_constant public static final com.google.firebase.dataconnect.DataSource CACHE;
119+
enum_constant public static final com.google.firebase.dataconnect.DataSource SERVER;
96120
}
97121

98122
public sealed interface EnumValue<T extends java.lang.Enum<? extends T>> {
@@ -280,14 +304,23 @@ package com.google.firebase.dataconnect {
280304

281305
public interface QueryRef<Data, Variables> extends com.google.firebase.dataconnect.OperationRef<Data,Variables> {
282306
method @com.google.firebase.dataconnect.ExperimentalFirebaseDataConnect public com.google.firebase.dataconnect.QueryRef<Data,Variables> copy(String operationName, Variables variables, kotlinx.serialization.DeserializationStrategy<? extends Data> dataDeserializer, kotlinx.serialization.SerializationStrategy<? super Variables> variablesSerializer, com.google.firebase.dataconnect.FirebaseDataConnect.CallerSdkType callerSdkType, kotlinx.serialization.modules.SerializersModule? dataSerializersModule, kotlinx.serialization.modules.SerializersModule? variablesSerializersModule);
307+
method public suspend Object? execute(com.google.firebase.dataconnect.QueryRef.FetchPolicy fetchPolicy, kotlin.coroutines.Continuation<? super com.google.firebase.dataconnect.QueryResult<Data,Variables>>);
283308
method public suspend Object? execute(kotlin.coroutines.Continuation<? super com.google.firebase.dataconnect.QueryResult<Data,Variables>>);
284309
method public com.google.firebase.dataconnect.QuerySubscription<Data,Variables> subscribe();
285310
method @com.google.firebase.dataconnect.ExperimentalFirebaseDataConnect public <NewData> com.google.firebase.dataconnect.QueryRef<NewData,Variables> withDataDeserializer(kotlinx.serialization.DeserializationStrategy<? extends NewData> dataDeserializer, kotlinx.serialization.modules.SerializersModule? dataSerializersModule);
286311
method @com.google.firebase.dataconnect.ExperimentalFirebaseDataConnect public <NewVariables> com.google.firebase.dataconnect.QueryRef<Data,NewVariables> withVariablesSerializer(NewVariables variables, kotlinx.serialization.SerializationStrategy<? super NewVariables> variablesSerializer, kotlinx.serialization.modules.SerializersModule? variablesSerializersModule);
287312
}
288313

314+
public enum QueryRef.FetchPolicy {
315+
enum_constant public static final com.google.firebase.dataconnect.QueryRef.FetchPolicy CACHE_ONLY;
316+
enum_constant public static final com.google.firebase.dataconnect.QueryRef.FetchPolicy PREFER_CACHE;
317+
enum_constant public static final com.google.firebase.dataconnect.QueryRef.FetchPolicy SERVER_ONLY;
318+
}
319+
289320
public interface QueryResult<Data, Variables> extends com.google.firebase.dataconnect.OperationResult<Data,Variables> {
321+
method public com.google.firebase.dataconnect.DataSource getDataSource();
290322
method public com.google.firebase.dataconnect.QueryRef<Data,Variables> getRef();
323+
property public abstract com.google.firebase.dataconnect.DataSource dataSource;
291324
property public abstract com.google.firebase.dataconnect.QueryRef<Data,Variables> ref;
292325
}
293326

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
version=17.1.4
1+
version=17.2.0
22
latestReleasedVersion=17.1.3

firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/CacheSettings.kt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,14 @@ import java.util.Objects
2424
*
2525
* @property storage The type of storage to use to store the cache data.
2626
*/
27-
// TODO: make public when offline caching goes public
28-
internal class CacheSettings(
29-
val storage: Storage = Storage.PERSISTENT,
27+
public class CacheSettings(
28+
public val storage: Storage = Storage.PERSISTENT,
3029
) {
3130

3231
/**
3332
* The types of cache storage supported by [FirebaseDataConnect] in its [CacheSettings] setting.
3433
*/
35-
enum class Storage {
34+
public enum class Storage {
3635
MEMORY,
3736
PERSISTENT,
3837
}
@@ -67,15 +66,14 @@ internal class CacheSettings(
6766
* changes.
6867
*
6968
* @return a string representation of this object, which includes the class name and the values of
70-
* all properties.
69+
* all public properties.
7170
*/
7271
override fun toString(): String {
7372
return "CacheSettings(storage=$storage)"
7473
}
7574
}
7675

7776
/** Creates and returns a new [CacheSettings] object with the given property values. */
78-
// TODO: make public when offline caching goes public
79-
internal fun CacheSettings.copy(
77+
public fun CacheSettings.copy(
8078
storage: CacheSettings.Storage = this.storage,
8179
): CacheSettings = CacheSettings(storage = storage)

firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/DataConnectSettings.kt

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,22 @@ import java.util.Objects
3131
* @property sslEnabled Whether to use SSL for the connection; if `true`, then the connection will
3232
* be encrypted using SSL and, if false, the connection will _not_ be encrypted and all network
3333
* transmission will happen in plaintext.
34+
* @property cacheSettings The local caching settings; if `null` then do not perform any local
35+
* caching.
3436
*/
3537
public class DataConnectSettings(
3638
public val host: String = "firebasedataconnect.googleapis.com",
37-
public val sslEnabled: Boolean = true
39+
public val sslEnabled: Boolean = true,
40+
public val cacheSettings: CacheSettings?,
3841
) {
3942

43+
// TODO(BreakingChange): Delete this constructor and set the default value for `cacheSettings`
44+
// in the primary constructor.
45+
public constructor(
46+
host: String = "firebasedataconnect.googleapis.com",
47+
sslEnabled: Boolean = true,
48+
) : this(host = host, sslEnabled = sslEnabled, cacheSettings = null)
49+
4050
/**
4151
* Compares this object with another object for equality.
4252
*
@@ -46,7 +56,10 @@ public class DataConnectSettings(
4656
* object.
4757
*/
4858
override fun equals(other: Any?): Boolean =
49-
(other is DataConnectSettings) && other.host == host && other.sslEnabled == sslEnabled
59+
(other is DataConnectSettings) &&
60+
other.host == host &&
61+
other.sslEnabled == sslEnabled &&
62+
other.cacheSettings == cacheSettings
5063

5164
/**
5265
* Calculates and returns the hash code for this object.
@@ -56,7 +69,8 @@ public class DataConnectSettings(
5669
* @return the hash code for this object, that incorporates the values of this object's public
5770
* properties.
5871
*/
59-
override fun hashCode(): Int = Objects.hash(DataConnectSettings::class, host, sslEnabled)
72+
override fun hashCode(): Int =
73+
Objects.hash(DataConnectSettings::class, host, sslEnabled, cacheSettings)
6074

6175
/**
6276
* Returns a string representation of this object, useful for debugging.
@@ -70,13 +84,25 @@ public class DataConnectSettings(
7084
* @return a string representation of this object, which includes the class name and the values of
7185
* all public properties.
7286
*/
73-
override fun toString(): String = "DataConnectSettings(host=$host, sslEnabled=$sslEnabled)"
87+
override fun toString(): String =
88+
"DataConnectSettings(host=$host, sslEnabled=$sslEnabled, cacheSettings=$cacheSettings)"
7489
}
7590

91+
/** Creates and returns a new [DataConnectSettings] instance with the given property values. */
92+
// TODO(BreakingChange): Delete this method and set the default value for `cacheSettings` in the
93+
// remaining copy() method.
94+
public fun DataConnectSettings.copy(
95+
host: String = this.host,
96+
sslEnabled: Boolean = this.sslEnabled,
97+
): DataConnectSettings =
98+
DataConnectSettings(host = host, sslEnabled = sslEnabled, cacheSettings = cacheSettings)
99+
76100
/** Creates and returns a new [DataConnectSettings] instance with the given property values. */
77101
public fun DataConnectSettings.copy(
78102
host: String = this.host,
79-
sslEnabled: Boolean = this.sslEnabled
80-
): DataConnectSettings = DataConnectSettings(host = host, sslEnabled = sslEnabled)
103+
sslEnabled: Boolean = this.sslEnabled,
104+
cacheSettings: CacheSettings?,
105+
): DataConnectSettings =
106+
DataConnectSettings(host = host, sslEnabled = sslEnabled, cacheSettings = cacheSettings)
81107

82108
internal fun DataConnectSettings.isDefaultHost() = host == DataConnectSettings().host

firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/QueryRef.kt

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,42 @@ import kotlinx.serialization.modules.SerializersModule
3434
* might be added to this interface or contracts of the existing methods can be changed.
3535
*/
3636
public interface QueryRef<Data, Variables> : OperationRef<Data, Variables> {
37-
override suspend fun execute(): QueryResult<Data, Variables>
37+
38+
/**
39+
* Executes this operation with the fetch policy [FetchPolicy.PREFER_CACHE] and returns the
40+
* result.
41+
*/
42+
// TODO(BreakingChange) Implement the method here to call execute(PREFER_CACHE) instead of
43+
// having QueryRefImpl do it.
44+
public override suspend fun execute(): QueryResult<Data, Variables>
45+
46+
/** Executes this operation with the given fetch policy, and returns the result. */
47+
public suspend fun execute(fetchPolicy: FetchPolicy): QueryResult<Data, Variables>
48+
49+
/** The caching policy to use in [QueryRef.execute]. */
50+
public enum class FetchPolicy {
51+
52+
/**
53+
* If the query has a cached result that has not expired, then return it without any
54+
* communication with the server, just as [CACHE_ONLY] would do. Otherwise, if there is no
55+
* cached data for the query or the cached data has expired, then get the latest result from the
56+
* server, just as [SERVER_ONLY] would do.
57+
*/
58+
PREFER_CACHE,
59+
60+
/**
61+
* Return the query result from the cache without any communication with the server. If there is
62+
* no cached data for the query then return an empty/null result, just as the server would have
63+
* returned in that case.
64+
*/
65+
CACHE_ONLY,
66+
67+
/**
68+
* Unconditionally get the latest result from the server, even if there is a locally-cached
69+
* result for the query. The local cache will be updated with the result, if successful.
70+
*/
71+
SERVER_ONLY,
72+
}
3873

3974
/**
4075
* Subscribes to a query to be notified of updates to the query's data when the query is executed.
@@ -87,4 +122,13 @@ public interface QueryRef<Data, Variables> : OperationRef<Data, Variables> {
87122
*/
88123
public interface QueryResult<Data, Variables> : OperationResult<Data, Variables> {
89124
override val ref: QueryRef<Data, Variables>
125+
126+
/** The source of the query results provided by this object. */
127+
public val dataSource: DataSource
128+
}
129+
130+
/** Indicator of the source of a query's results. */
131+
public enum class DataSource {
132+
CACHE,
133+
SERVER,
90134
}

firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/FirebaseDataConnectImpl.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import android.content.Context
2020
import com.google.firebase.FirebaseApp
2121
import com.google.firebase.appcheck.interop.InteropAppCheckTokenProvider
2222
import com.google.firebase.auth.internal.InternalAuthProvider
23+
import com.google.firebase.dataconnect.CacheSettings
2324
import com.google.firebase.dataconnect.ConnectorConfig
2425
import com.google.firebase.dataconnect.DataConnectSettings
2526
import com.google.firebase.dataconnect.FirebaseDataConnect
@@ -239,6 +240,19 @@ internal class FirebaseDataConnectImpl(
239240
backendInfoFromEmulatorSettings
240241
}
241242

243+
val cacheSettings =
244+
settings.cacheSettings?.run {
245+
val dbFile =
246+
when (storage) {
247+
CacheSettings.Storage.MEMORY -> null
248+
CacheSettings.Storage.PERSISTENT -> {
249+
val dbName = "dataconnect_" + calculateCacheDbUniqueName(backendInfo)
250+
context.getDatabasePath(dbName)
251+
}
252+
}
253+
DataConnectGrpcRPCs.CacheSettings(dbFile)
254+
}
255+
242256
logger.debug { "connecting to Data Connect backend: $backendInfo" }
243257
val grpcMetadata =
244258
DataConnectGrpcMetadata.forSystemVersions(
@@ -255,7 +269,7 @@ internal class FirebaseDataConnectImpl(
255269
sslEnabled = backendInfo.sslEnabled,
256270
blockingCoroutineDispatcher = blockingDispatcher,
257271
grpcMetadata = grpcMetadata,
258-
cacheSettings = null, // TODO: pass cache settings once implemented
272+
cacheSettings = cacheSettings,
259273
parentLogger = logger,
260274
)
261275

firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/QueryRefImpl.kt

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818

1919
package com.google.firebase.dataconnect.core
2020

21+
import com.google.firebase.dataconnect.DataSource
2122
import com.google.firebase.dataconnect.FirebaseDataConnect
2223
import com.google.firebase.dataconnect.QueryRef
24+
import com.google.firebase.dataconnect.QueryRef.FetchPolicy
2325
import com.google.firebase.dataconnect.QueryResult
2426
import com.google.firebase.dataconnect.QuerySubscription
2527
import java.util.Objects
@@ -48,8 +50,12 @@ internal class QueryRefImpl<Data, Variables>(
4850
dataSerializersModule = dataSerializersModule,
4951
variablesSerializersModule = variablesSerializersModule,
5052
) {
51-
override suspend fun execute(): QueryResultImpl =
52-
dataConnect.queryManager.execute(this).let { QueryResultImpl(it.ref.getOrThrow()) }
53+
override suspend fun execute(): QueryResultImpl = execute(FetchPolicy.PREFER_CACHE)
54+
55+
override suspend fun execute(fetchPolicy: FetchPolicy): QueryResultImpl =
56+
dataConnect.queryManager.execute(this).let {
57+
QueryResultImpl(it.ref.getOrThrow(), DataSource.SERVER)
58+
}
5359

5460
override fun subscribe(): QuerySubscription<Data, Variables> = QuerySubscriptionImpl(this)
5561

@@ -134,16 +140,18 @@ internal class QueryRefImpl<Data, Variables>(
134140
"variablesSerializersModule=$variablesSerializersModule" +
135141
")"
136142

137-
inner class QueryResultImpl(data: Data) :
143+
inner class QueryResultImpl(data: Data, override val dataSource: DataSource) :
138144
QueryResult<Data, Variables>, OperationRefImpl<Data, Variables>.OperationResultImpl(data) {
139145

140146
override val ref = this@QueryRefImpl
141147

142148
override fun equals(other: Any?) =
143-
other is QueryRefImpl<*, *>.QueryResultImpl && super.equals(other)
149+
other is QueryRefImpl<*, *>.QueryResultImpl &&
150+
super.equals(other) &&
151+
other.dataSource == dataSource
144152

145-
override fun hashCode() = Objects.hash(QueryResultImpl::class, data, ref)
153+
override fun hashCode() = Objects.hash(QueryResultImpl::class, data, ref, dataSource)
146154

147-
override fun toString() = "QueryResultImpl(data=$data, ref=$ref)"
155+
override fun toString() = "QueryResultImpl(data=$data, ref=$ref, dataSource=$dataSource)"
148156
}
149157
}

firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/QuerySubscriptionImpl.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
package com.google.firebase.dataconnect.core
2020

21+
import com.google.firebase.dataconnect.DataSource
2122
import com.google.firebase.dataconnect.QuerySubscriptionResult
2223
import com.google.firebase.dataconnect.util.NullableReference
2324
import com.google.firebase.dataconnect.util.SequencedReference
@@ -106,7 +107,7 @@ internal class QuerySubscriptionImpl<Data, Variables>(query: QueryRefImpl<Data,
106107
override val query: QueryRefImpl<Data, Variables>,
107108
val sequencedResult: SequencedReference<Result<Data>>
108109
) : QuerySubscriptionResult<Data, Variables> {
109-
override val result = sequencedResult.ref.map { query.QueryResultImpl(it) }
110+
override val result = sequencedResult.ref.map { query.QueryResultImpl(it, DataSource.SERVER) }
110111

111112
override fun equals(other: Any?) =
112113
other is QuerySubscriptionImpl<*, *>.QuerySubscriptionResultImpl &&

0 commit comments

Comments
 (0)