Skip to content

Add SerializersModule support to QueryRef and MutationRef #6297

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 23, 2024
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
4 changes: 1 addition & 3 deletions firebase-dataconnect/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# Unreleased


# 16.0.0-beta01
* [feature] Add ability to specify SerializersModule when serializing.
* [feature] initial beta release.
36 changes: 32 additions & 4 deletions firebase-dataconnect/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ package com.google.firebase.dataconnect {
ctor public AnyValue(@NonNull String value);
ctor public AnyValue(boolean value);
ctor public AnyValue(double value);
method public <T> T decode(@NonNull kotlinx.serialization.DeserializationStrategy<? extends T> deserializer);
method public <T> T decode(@NonNull kotlinx.serialization.DeserializationStrategy<? extends T> deserializer, @Nullable kotlinx.serialization.modules.SerializersModule serializersModule = null);
method public inline <reified T> T decode();
method @NonNull public Object getValue();
property @NonNull public final Object value;
field @NonNull public static final com.google.firebase.dataconnect.AnyValue.Companion Companion;
}

public static final class AnyValue.Companion {
method @NonNull public <T> com.google.firebase.dataconnect.AnyValue encode(@Nullable T value, @NonNull kotlinx.serialization.SerializationStrategy<? super T> serializer);
method @NonNull public <T> com.google.firebase.dataconnect.AnyValue encode(@Nullable T value, @NonNull kotlinx.serialization.SerializationStrategy<? super T> serializer, @Nullable kotlinx.serialization.modules.SerializersModule serializersModule = null);
method public inline <reified T> com.google.firebase.dataconnect.AnyValue encode(@Nullable T value);
method @NonNull public com.google.firebase.dataconnect.AnyValue fromAny(@NonNull Object value);
method @Nullable public com.google.firebase.dataconnect.AnyValue fromNullableAny(@Nullable Object value);
Expand Down Expand Up @@ -55,8 +55,8 @@ package com.google.firebase.dataconnect {
method @NonNull public com.google.firebase.dataconnect.ConnectorConfig getConfig();
method @NonNull public com.google.firebase.dataconnect.DataConnectSettings getSettings();
method public int hashCode();
method @NonNull public <Data, Variables> com.google.firebase.dataconnect.MutationRef<Data,Variables> mutation(@NonNull String operationName, @Nullable Variables variables, @NonNull kotlinx.serialization.DeserializationStrategy<? extends Data> dataDeserializer, @NonNull kotlinx.serialization.SerializationStrategy<? super Variables> variablesSerializer, @Nullable com.google.firebase.dataconnect.generated.GeneratedMutation<?,Data,Variables> generatedMutation = null);
method @NonNull public <Data, Variables> com.google.firebase.dataconnect.QueryRef<Data,Variables> query(@NonNull String operationName, @Nullable Variables variables, @NonNull kotlinx.serialization.DeserializationStrategy<? extends Data> dataDeserializer, @NonNull kotlinx.serialization.SerializationStrategy<? super Variables> variablesSerializer, @Nullable com.google.firebase.dataconnect.generated.GeneratedQuery<?,Data,Variables> generatedQuery = null);
method @NonNull public <Data, Variables> com.google.firebase.dataconnect.MutationRef<Data,Variables> mutation(@NonNull String operationName, @Nullable Variables variables, @NonNull kotlinx.serialization.DeserializationStrategy<? extends Data> dataDeserializer, @NonNull kotlinx.serialization.SerializationStrategy<? super Variables> variablesSerializer, @Nullable kotlin.jvm.functions.Function1<? super com.google.firebase.dataconnect.FirebaseDataConnect.MutationRefOptionsBuilder<Data,Variables>,kotlin.Unit> optionsBuilder = null);
method @NonNull public <Data, Variables> com.google.firebase.dataconnect.QueryRef<Data,Variables> query(@NonNull String operationName, @Nullable Variables variables, @NonNull kotlinx.serialization.DeserializationStrategy<? extends Data> dataDeserializer, @NonNull kotlinx.serialization.SerializationStrategy<? super Variables> variablesSerializer, @Nullable kotlin.jvm.functions.Function1<? super com.google.firebase.dataconnect.FirebaseDataConnect.QueryRefOptionsBuilder<Data,Variables>,kotlin.Unit> optionsBuilder = null);
method @Nullable public suspend Object suspendingClose(@NonNull kotlin.coroutines.Continuation<? super kotlin.Unit>);
method @NonNull public String toString();
method public void useEmulator(@NonNull String host = "10.0.2.2", int port = 9399);
Expand All @@ -69,6 +69,30 @@ package com.google.firebase.dataconnect {
public static final class FirebaseDataConnect.Companion {
}

public static interface FirebaseDataConnect.MutationRefOptionsBuilder<Data, Variables> {
method @Nullable public kotlinx.serialization.modules.SerializersModule getDataSerializersModule();
method @Nullable public com.google.firebase.dataconnect.generated.GeneratedMutation<?,Data,Variables> getGeneratedMutation();
method @Nullable public kotlinx.serialization.modules.SerializersModule getVariablesSerializersModule();
method public void setDataSerializersModule(@Nullable kotlinx.serialization.modules.SerializersModule);
method public void setGeneratedMutation(@Nullable com.google.firebase.dataconnect.generated.GeneratedMutation<?,Data,Variables>);
method public void setVariablesSerializersModule(@Nullable kotlinx.serialization.modules.SerializersModule);
property @Nullable public abstract kotlinx.serialization.modules.SerializersModule dataSerializersModule;
property @Nullable public abstract com.google.firebase.dataconnect.generated.GeneratedMutation<?,Data,Variables> generatedMutation;
property @Nullable public abstract kotlinx.serialization.modules.SerializersModule variablesSerializersModule;
}

public static interface FirebaseDataConnect.QueryRefOptionsBuilder<Data, Variables> {
method @Nullable public kotlinx.serialization.modules.SerializersModule getDataSerializersModule();
method @Nullable public com.google.firebase.dataconnect.generated.GeneratedQuery<?,Data,Variables> getGeneratedQuery();
method @Nullable public kotlinx.serialization.modules.SerializersModule getVariablesSerializersModule();
method public void setDataSerializersModule(@Nullable kotlinx.serialization.modules.SerializersModule);
method public void setGeneratedQuery(@Nullable com.google.firebase.dataconnect.generated.GeneratedQuery<?,Data,Variables>);
method public void setVariablesSerializersModule(@Nullable kotlinx.serialization.modules.SerializersModule);
property @Nullable public abstract kotlinx.serialization.modules.SerializersModule dataSerializersModule;
property @Nullable public abstract com.google.firebase.dataconnect.generated.GeneratedQuery<?,Data,Variables> generatedQuery;
property @Nullable public abstract kotlinx.serialization.modules.SerializersModule variablesSerializersModule;
}

public final class FirebaseDataConnectKt {
method @NonNull public static com.google.firebase.dataconnect.FirebaseDataConnect getInstance(@NonNull com.google.firebase.dataconnect.FirebaseDataConnect.Companion, @NonNull com.google.firebase.FirebaseApp app, @NonNull com.google.firebase.dataconnect.ConnectorConfig config, @NonNull com.google.firebase.dataconnect.DataConnectSettings settings = com.google.firebase.dataconnect.DataConnectSettings());
method @NonNull public static com.google.firebase.dataconnect.FirebaseDataConnect getInstance(@NonNull com.google.firebase.dataconnect.FirebaseDataConnect.Companion, @NonNull com.google.firebase.dataconnect.ConnectorConfig config, @NonNull com.google.firebase.dataconnect.DataConnectSettings settings = com.google.firebase.dataconnect.DataConnectSettings());
Expand Down Expand Up @@ -98,16 +122,20 @@ package com.google.firebase.dataconnect {
method @Nullable public suspend Object execute(@NonNull kotlin.coroutines.Continuation<? super com.google.firebase.dataconnect.OperationResult<Data,Variables>>);
method @NonNull public com.google.firebase.dataconnect.FirebaseDataConnect getDataConnect();
method @NonNull public kotlinx.serialization.DeserializationStrategy<Data> getDataDeserializer();
method @Nullable public kotlinx.serialization.modules.SerializersModule getDataSerializersModule();
method @NonNull public String getOperationName();
method public Variables getVariables();
method @NonNull public kotlinx.serialization.SerializationStrategy<Variables> getVariablesSerializer();
method @Nullable public kotlinx.serialization.modules.SerializersModule getVariablesSerializersModule();
method public int hashCode();
method @NonNull public String toString();
property @NonNull public abstract com.google.firebase.dataconnect.FirebaseDataConnect dataConnect;
property @NonNull public abstract kotlinx.serialization.DeserializationStrategy<Data> dataDeserializer;
property @Nullable public abstract kotlinx.serialization.modules.SerializersModule dataSerializersModule;
property @NonNull public abstract String operationName;
property public abstract Variables variables;
property @NonNull public abstract kotlinx.serialization.SerializationStrategy<Variables> variablesSerializer;
property @Nullable public abstract kotlinx.serialization.modules.SerializersModule variablesSerializersModule;
}

public interface OperationResult<Data, Variables> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.google.protobuf.Value
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.serializer

/**
Expand Down Expand Up @@ -144,12 +145,16 @@ public class AnyValue internal constructor(internal val protoValue: Value) {
* Decodes the encapsulated value using the given deserializer.
*
* @param deserializer The deserializer for the decoder to use.
* @param serializersModule a [SerializersModule] to use during deserialization; may be `null`
* (the default) to _not_ use a [SerializersModule] to use during deserialization.
*
* @return the object of type `T` created by decoding the encapsulated value using the given
* deserializer.
*/
public fun <T> decode(deserializer: DeserializationStrategy<T>): T =
decodeFromValue(deserializer, protoValue)
public fun <T> decode(
deserializer: DeserializationStrategy<T>,
serializersModule: SerializersModule? = null
): T = decodeFromValue(protoValue, deserializer, serializersModule)

/**
* Decodes the encapsulated value using the _default_ serializer for the return type, as computed
Expand Down Expand Up @@ -198,12 +203,17 @@ public class AnyValue internal constructor(internal val protoValue: Value) {
*
* @param value the value to serialize.
* @param serializer the serializer for the encoder to use.
* @param serializersModule a [SerializersModule] to use during serialization; may be `null`
* (the default) to _not_ use a [SerializersModule] to use during serialization.
*
* @return a new `AnyValue` object whose encapsulated value is the encoding of the given value
* when decoded with the given serializer.
*/
public fun <T> encode(value: T, serializer: SerializationStrategy<T>): AnyValue =
AnyValue(encodeToValue(serializer, value))
public fun <T> encode(
value: T,
serializer: SerializationStrategy<T>,
serializersModule: SerializersModule? = null
): AnyValue = AnyValue(encodeToValue(value, serializer, serializersModule))

/**
* Encodes the given value using the given _default_ serializer for the given object, as
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import com.google.firebase.dataconnect.generated.GeneratedQuery
import kotlinx.coroutines.CoroutineScope
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.modules.SerializersModule

/**
* Firebase Data Connect is Firebase's first relational database solution for app developers to
Expand Down Expand Up @@ -196,43 +197,87 @@ public interface FirebaseDataConnect : AutoCloseable {
*/
public fun useEmulator(host: String = "10.0.2.2", port: Int = 9399)

/** Options that can be specified when creating a [QueryRef] via the [query] method. */
public interface QueryRefOptionsBuilder<Data, Variables> {

/**
* The [GeneratedQuery] object that is creating the query; may be `null` if not being created
* from an SDK that was generated by the Data Connect toolkit. The value of this property does
* not affect the runtime behavior, but is used for runtime checks and gathering metrics on
* generated SDK usage.
*/
public var generatedQuery: GeneratedQuery<*, Data, Variables>?

/**
* A [SerializersModule] to use when encoding the query's variables. May be `null` (the default)
* to _not_ use a [SerializersModule] when encoding the variables.
*/
public var variablesSerializersModule: SerializersModule?

/**
* A [SerializersModule] to use when decoding the query's response data. May be `null` (the
* default) to _not_ use a [SerializersModule] when decoding the response data.
*/
public var dataSerializersModule: SerializersModule?
}

/**
* Creates and returns a [QueryRef] for running the specified query.
* @param operationName The value for [QueryRef.operationName] of the returned object.
* @param variables The value for [QueryRef.variables] of the returned object.
* @param dataDeserializer The value for [QueryRef.dataDeserializer] of the returned object.
* @param variablesSerializer The value for [QueryRef.variablesSerializer] of the returned object.
* @param generatedQuery The [GeneratedQuery] object that is invoking this method; this argument
* may be `null` if not being called from the an SDK that was generated by the Data Connect tools.
* The value of this argument does not affect the runtime behavior, but is used for runtime checks
* and gathering metrics on generated SDK usage.
* @param optionsBuilder A method that will be called to provide optional information when
* creating the [QueryRef]; may be `null` (the default) to not perform any customization.
*/
public fun <Data, Variables> query(
operationName: String,
variables: Variables,
dataDeserializer: DeserializationStrategy<Data>,
variablesSerializer: SerializationStrategy<Variables>,
generatedQuery: GeneratedQuery<*, Data, Variables>? = null,
optionsBuilder: (QueryRefOptionsBuilder<Data, Variables>.() -> Unit)? = null,
): QueryRef<Data, Variables>

/** Options that can be specified when creating a [MutationRef] via the [mutation] method. */
public interface MutationRefOptionsBuilder<Data, Variables> {

/**
* The [GeneratedMutation] object that is creating the mutation; may be `null` if not being
* created from an SDK that was generated by the Data Connect toolkit. The value of this
* property does not affect the runtime behavior, but is used for runtime checks and gathering
* metrics on generated SDK usage.
*/
public var generatedMutation: GeneratedMutation<*, Data, Variables>?

/**
* A [SerializersModule] to use when encoding the mutation's variables. May be `null` (the
* default) to use some unspecified [SerializersModule] when encoding the variables.
*/
public var variablesSerializersModule: SerializersModule?

/**
* A [SerializersModule] to use when decoding the mutation's response data. May be `null` (the
* default) to _not_ use a [SerializersModule] when decoding the response data.
*/
public var dataSerializersModule: SerializersModule?
}

/**
* Creates and returns a [MutationRef] for running the specified mutation.
* @param operationName The value for [MutationRef.operationName] of the returned object.
* @param variables The value for [MutationRef.variables] of the returned object.
* @param dataDeserializer The value for [MutationRef.dataDeserializer] of the returned object.
* @param variablesSerializer The value for [MutationRef.variablesSerializer] of the returned
* object.
* @param generatedMutation The [GeneratedMutation] object that is invoking this method; this
* argument may be `null` if not being called from the an SDK that was generated by the Data
* Connect tools. The value of this argument does not affect the runtime behavior, but is used for
* runtime checks and gathering metrics on generated SDK usage.
* @param optionsBuilder A method that will be called to provide optional information when
* creating the [MutationRef]; may be `null` (the default) to not perform any customization.
*/
public fun <Data, Variables> mutation(
operationName: String,
variables: Variables,
dataDeserializer: DeserializationStrategy<Data>,
variablesSerializer: SerializationStrategy<Variables>,
generatedMutation: GeneratedMutation<*, Data, Variables>? = null,
optionsBuilder: (MutationRefOptionsBuilder<Data, Variables>.() -> Unit)? = null,
): MutationRef<Data, Variables>

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package com.google.firebase.dataconnect

import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.modules.SerializersModule

/**
* Information about a Firebase Data Connect "operation" (i.e. a query or mutation).
Expand Down Expand Up @@ -143,6 +144,18 @@ public interface OperationRef<Data, Variables> {
*/
public val variablesSerializer: SerializationStrategy<Variables>

/**
* A [SerializersModule] to use when encoding the variables using [variablesSerializer]. May be
* `null`, to not use a [SerializersModule].
*/
public val variablesSerializersModule: SerializersModule?

/**
* A [SerializersModule] to use when decoding the response data using [dataDeserializer]. May be
* `null`, to not use a [SerializersModule].
*/
public val dataSerializersModule: SerializersModule?

/**
* Executes this operation and returns the result.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import google.firebase.dataconnect.proto.executeQueryRequest
import io.grpc.Status
import io.grpc.StatusException
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.modules.SerializersModule

internal class DataConnectGrpcClient(
projectId: String,
Expand Down Expand Up @@ -148,9 +149,10 @@ internal fun GraphqlError.toDataConnectError() =
)

internal fun <T> DataConnectGrpcClient.OperationResult.deserialize(
dataDeserializer: DeserializationStrategy<T>
deserializer: DeserializationStrategy<T>,
serializersModule: SerializersModule?,
): T =
if (dataDeserializer === DataConnectUntypedData) {
if (deserializer === DataConnectUntypedData) {
@Suppress("UNCHECKED_CAST")
DataConnectUntypedData(data?.toMap(), errors) as T
} else if (data === null) {
Expand All @@ -163,7 +165,7 @@ internal fun <T> DataConnectGrpcClient.OperationResult.deserialize(
throw DataConnectException("operation failed: errors=$errors (data=$data)")
} else {
try {
decodeFromStruct(dataDeserializer, data)
decodeFromStruct(data, deserializer, serializersModule)
} catch (dataConnectException: DataConnectException) {
throw dataConnectException
} catch (throwable: Throwable) {
Expand Down
Loading
Loading