Skip to content

Commit 257f673

Browse files
committed
make the new classes public, now that api council has approved the api changes (go/dataconnect:sdk:enums)
1 parent 01a1681 commit 257f673

File tree

7 files changed

+174
-30
lines changed

7 files changed

+174
-30
lines changed

firebase-dataconnect/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
- [changed] Ignore unknown fields in response data instead of throwing a
44
`DataConnectOperationException` with message "decoding data from the server's response failed: An
55
unknown field for index -3"
6-
- [changed] Internal code changes in preparation for user-defined enum support.
6+
- [changed] Added classes `EnumValue` and `EnumValueSerializer`. These classes are identical to
7+
those produced by the Data Connect code generator; however, a future version of the code generator
8+
will start using these classes from the SDK rather than generating them.
79
([#7153](https://github.com/firebase/firebase-android-sdk/pull/7153))
810

911
# 17.0.0

firebase-dataconnect/api.txt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,31 @@ package com.google.firebase.dataconnect {
9595
method public static com.google.firebase.dataconnect.DataConnectSettings copy(com.google.firebase.dataconnect.DataConnectSettings, String host = host, boolean sslEnabled = sslEnabled);
9696
}
9797

98+
public sealed interface EnumValue<T extends java.lang.Enum<? extends T>> {
99+
method public String getStringValue();
100+
method public T? getValue();
101+
property public abstract String stringValue;
102+
property public abstract T? value;
103+
}
104+
105+
public static final class EnumValue.Known<T extends java.lang.Enum<T>> implements com.google.firebase.dataconnect.EnumValue<T> {
106+
ctor public EnumValue.Known(T value);
107+
method public com.google.firebase.dataconnect.EnumValue.Known<T> copy(T value = value);
108+
method public String getStringValue();
109+
method public T getValue();
110+
property public String stringValue;
111+
property public T value;
112+
}
113+
114+
public static final class EnumValue.Unknown implements com.google.firebase.dataconnect.EnumValue {
115+
ctor public EnumValue.Unknown(String stringValue);
116+
method public com.google.firebase.dataconnect.EnumValue.Unknown copy(String stringValue = stringValue);
117+
method public String getStringValue();
118+
method public Void? getValue();
119+
property public String stringValue;
120+
property public Void? value;
121+
}
122+
98123
@kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.WARNING, message="This declaration is \"experimental\": its signature and/or semantics " + "may change in backwards-incompatible ways at any time without notice, " + "up to and including complete removal. " + "If you have a use case that relies on this declaration please open a " + "\"feature request\" issue at https://github.com/firebase/firebase-android-sdk " + "requesting this declaration\'s promotion from \"experimental\" to \"fully-supported\".") @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalFirebaseDataConnect {
99124
}
100125

@@ -346,6 +371,14 @@ package com.google.firebase.dataconnect.serializers {
346371
field public static final com.google.firebase.dataconnect.serializers.AnyValueSerializer INSTANCE;
347372
}
348373

374+
public class EnumValueSerializer<T extends java.lang.Enum<T>> implements kotlinx.serialization.KSerializer<com.google.firebase.dataconnect.EnumValue<? extends T>> {
375+
ctor public EnumValueSerializer(Iterable<? extends T> values);
376+
method public com.google.firebase.dataconnect.EnumValue<T> deserialize(kotlinx.serialization.encoding.Decoder decoder);
377+
method public kotlinx.serialization.descriptors.SerialDescriptor getDescriptor();
378+
method public void serialize(kotlinx.serialization.encoding.Encoder encoder, com.google.firebase.dataconnect.EnumValue<? extends T> value);
379+
property public kotlinx.serialization.descriptors.SerialDescriptor descriptor;
380+
}
381+
349382
public final class JavaTimeLocalDateSerializer implements kotlinx.serialization.KSerializer<java.time.LocalDate> {
350383
method public java.time.LocalDate deserialize(kotlinx.serialization.encoding.Decoder decoder);
351384
method public kotlinx.serialization.descriptors.SerialDescriptor getDescriptor();

firebase-dataconnect/src/androidTest/kotlin/com/google/firebase/dataconnect/EnumIntegrationTest.kt

Lines changed: 99 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@
1414
* limitations under the License.
1515
*/
1616

17+
@file:OptIn(ExperimentalFirebaseDataConnect::class)
18+
1719
package com.google.firebase.dataconnect
1820

21+
import com.google.firebase.dataconnect.EnumValue.Known
22+
import com.google.firebase.dataconnect.EnumValue.Unknown
23+
import com.google.firebase.dataconnect.serializers.EnumValueSerializer
1924
import com.google.firebase.dataconnect.testutil.DataConnectIntegrationTestBase
2025
import com.google.firebase.dataconnect.testutil.property.arbitrary.dataConnect
2126
import com.google.firebase.dataconnect.testutil.property.arbitrary.enumWithNull
@@ -94,9 +99,13 @@ class EnumIntegrationTest : DataConnectIntegrationTestBase() {
9499
val insertVariables = InsertNonNullableVariables(enumValue)
95100
val key = dataConnect.mutation(insertVariables).execute().data.key
96101
val queryVariables = GetNonNullableByKeyVariables(key)
97-
val queryRef = dataConnect.query(queryVariables)
102+
val queryRef =
103+
dataConnect
104+
.query(queryVariables)
105+
.withDataDeserializer(serializer<GetNonNullableByKeySubsetData>())
98106
val queryResult = queryRef.execute()
99-
queryResult.asClue { it.data.item.value shouldBe enumValue }
107+
val expectedValue = enumValue.toN5ekmae3jnSubsetEnumValue()
108+
queryResult.asClue { it.data.item.value shouldBe expectedValue }
100109
}
101110
}
102111

@@ -117,8 +126,8 @@ class EnumIntegrationTest : DataConnectIntegrationTestBase() {
117126

118127
@Test
119128
fun queryNonNullableByUndefinedEnumValue() = runTest {
120-
val tag = Arb.dataConnect.tag().next(rs)
121-
val (value1, value2, value3) = Arb.threeValues(Arb.enum<N5ekmae3jn>()).next(rs)
129+
val tag = Arb.dataConnect.tag().next()
130+
val (value1, value2, value3) = Arb.threeValues(Arb.enum<N5ekmae3jn>()).next()
122131
val insertVariables = Insert3NonNullableVariables(tag, value1, value2, value3)
123132
dataConnect.mutation(insertVariables).execute().data
124133
val queryVariables = GetNonNullableByTagAndValueVariables(tag, OptionalVariable.Undefined)
@@ -128,8 +137,8 @@ class EnumIntegrationTest : DataConnectIntegrationTestBase() {
128137

129138
@Test
130139
fun queryNonNullableByNullEnumValue() = runTest {
131-
val tag = Arb.dataConnect.tag().next(rs)
132-
val (value1, value2, value3) = Arb.threeValues(Arb.enum<N5ekmae3jn>()).next(rs)
140+
val tag = Arb.dataConnect.tag().next()
141+
val (value1, value2, value3) = Arb.threeValues(Arb.enum<N5ekmae3jn>()).next()
133142
val insertVariables = Insert3NonNullableVariables(tag, value1, value2, value3)
134143
dataConnect.mutation(insertVariables).execute()
135144
val queryVariables = GetNonNullableByTagAndValueVariables(tag, OptionalVariable.Value(null))
@@ -183,6 +192,15 @@ class EnumIntegrationTest : DataConnectIntegrationTestBase() {
183192
@Serializable data class Item(val value: N5ekmae3jn)
184193
}
185194

195+
@Serializable
196+
private data class GetNonNullableByKeySubsetData(val item: Item) {
197+
@Serializable
198+
data class Item(
199+
@Serializable(with = N5ekmae3jnSubset.Serializer::class)
200+
val value: EnumValue<N5ekmae3jnSubset>
201+
)
202+
}
203+
186204
//////////////////////////////////////////////////////////////////////////////////////////////////
187205
// Tests for EnumNullable table.
188206
//////////////////////////////////////////////////////////////////////////////////////////////////
@@ -227,9 +245,13 @@ class EnumIntegrationTest : DataConnectIntegrationTestBase() {
227245
val insertVariables = InsertNullableVariables(enumValue)
228246
val key = dataConnect.mutation(insertVariables).execute().data.key
229247
val queryVariables = GetNullableByKeyVariables(key)
230-
val queryRef = dataConnect.query(queryVariables)
248+
val queryRef =
249+
dataConnect
250+
.query(queryVariables)
251+
.withDataDeserializer(serializer<GetNullableByKeySubsetData>())
231252
val queryResult = queryRef.execute()
232-
queryResult.asClue { it.data.item.value shouldBe enumValue }
253+
val expectedValue = enumValue?.toN5ekmae3jnSubsetEnumValue()
254+
queryResult.asClue { it.data.item.value shouldBe expectedValue }
233255
}
234256
}
235257

@@ -306,6 +328,15 @@ class EnumIntegrationTest : DataConnectIntegrationTestBase() {
306328
@Serializable data class Item(val value: N5ekmae3jn?)
307329
}
308330

331+
@Serializable
332+
private data class GetNullableByKeySubsetData(val item: Item) {
333+
@Serializable
334+
data class Item(
335+
@Serializable(with = N5ekmae3jnSubset.Serializer::class)
336+
val value: EnumValue<N5ekmae3jnSubset>?
337+
)
338+
}
339+
309340
//////////////////////////////////////////////////////////////////////////////////////////////////
310341
// Tests for EnumNonNullableTableDefault table.
311342
//////////////////////////////////////////////////////////////////////////////////////////////////
@@ -377,9 +408,14 @@ class EnumIntegrationTest : DataConnectIntegrationTestBase() {
377408
val insertVariables = InsertNonNullableListOfNonNullableVariables(values)
378409
val key = dataConnect.mutation(insertVariables).execute().data.key
379410
val queryVariables = GetNonNullableListOfNonNullableByKeyVariables(key)
380-
val queryRef = dataConnect.query(queryVariables)
411+
val queryRef =
412+
dataConnect
413+
.query(queryVariables)
414+
.withDataDeserializer(serializer<GetNonNullableListOfNonNullableByKeySubsetData>())
381415
val queryResult = queryRef.execute()
382-
queryResult.asClue { it.data.item.value shouldBe values }
416+
val expectedEnumValues: List<EnumValue<N5ekmae3jnSubset>> =
417+
values.map { it.toN5ekmae3jnSubsetEnumValue() }
418+
queryResult.asClue { it.data.item.value shouldBe expectedEnumValues }
383419
}
384420
}
385421

@@ -397,6 +433,15 @@ class EnumIntegrationTest : DataConnectIntegrationTestBase() {
397433
@Serializable data class Item(val value: List<N5ekmae3jn?>)
398434
}
399435

436+
@Serializable
437+
private data class GetNonNullableListOfNonNullableByKeySubsetData(val item: Item) {
438+
@Serializable
439+
data class Item(
440+
val value:
441+
List<@Serializable(with = N5ekmae3jnSubset.Serializer::class) EnumValue<N5ekmae3jnSubset>?>?
442+
)
443+
}
444+
400445
//////////////////////////////////////////////////////////////////////////////////////////////////
401446
// Tests for EnumNonNullableListOfNullable table.
402447
//////////////////////////////////////////////////////////////////////////////////////////////////
@@ -437,9 +482,14 @@ class EnumIntegrationTest : DataConnectIntegrationTestBase() {
437482
val insertVariables = InsertNonNullableListOfNullableVariables(values)
438483
val key = dataConnect.mutation(insertVariables).execute().data.key
439484
val queryVariables = GetNonNullableListOfNullableByKeyVariables(key)
440-
val queryRef = dataConnect.query(queryVariables)
485+
val queryRef =
486+
dataConnect
487+
.query(queryVariables)
488+
.withDataDeserializer(serializer<GetNonNullableListOfNonNullableByKeySubsetData>())
441489
val queryResult = queryRef.execute()
442-
queryResult.asClue { it.data.item.value shouldBe values }
490+
val expectedEnumValues: List<EnumValue<N5ekmae3jnSubset>?> =
491+
values.map { it?.toN5ekmae3jnSubsetEnumValue() }
492+
queryResult.asClue { it.data.item.value shouldBe expectedEnumValues }
443493
}
444494
}
445495

@@ -499,9 +549,14 @@ class EnumIntegrationTest : DataConnectIntegrationTestBase() {
499549
val insertVariables = InsertNullableListOfNonNullableVariables(values)
500550
val key = dataConnect.mutation(insertVariables).execute().data.key
501551
val queryVariables = GetNullableListOfNonNullableByKeyVariables(key)
502-
val queryRef = dataConnect.query(queryVariables)
552+
val queryRef =
553+
dataConnect
554+
.query(queryVariables)
555+
.withDataDeserializer(serializer<GetNonNullableListOfNonNullableByKeySubsetData>())
503556
val queryResult = queryRef.execute()
504-
queryResult.asClue { it.data.item.value shouldBe values }
557+
val expectedEnumValues: List<EnumValue<N5ekmae3jnSubset>?> =
558+
values.map { it?.toN5ekmae3jnSubsetEnumValue() }
559+
queryResult.asClue { it.data.item.value shouldBe expectedEnumValues }
505560
}
506561
}
507562

@@ -561,9 +616,14 @@ class EnumIntegrationTest : DataConnectIntegrationTestBase() {
561616
val insertVariables = InsertNullableListOfNullableVariables(values)
562617
val key = dataConnect.mutation(insertVariables).execute().data.key
563618
val queryVariables = GetNullableListOfNullableByKeyVariables(key)
564-
val queryRef = dataConnect.query(queryVariables)
619+
val queryRef =
620+
dataConnect
621+
.query(queryVariables)
622+
.withDataDeserializer(serializer<GetNonNullableListOfNonNullableByKeySubsetData>())
565623
val queryResult = queryRef.execute()
566-
queryResult.asClue { it.data.item.value shouldBe values }
624+
val expectedEnumValues: List<EnumValue<N5ekmae3jnSubset>?> =
625+
values.map { it?.toN5ekmae3jnSubsetEnumValue() }
626+
queryResult.asClue { it.data.item.value shouldBe expectedEnumValues }
567627
}
568628
}
569629

@@ -701,6 +761,15 @@ class EnumIntegrationTest : DataConnectIntegrationTestBase() {
701761
N3HWNCRWBP,
702762
}
703763

764+
@Suppress("SpellCheckingInspection", "unused")
765+
private enum class N5ekmae3jnSubset {
766+
DPSKD6HR3A,
767+
XGWGVMYTHJ,
768+
QJX7C7RD5T;
769+
770+
object Serializer : EnumValueSerializer<N5ekmae3jnSubset>(N5ekmae3jnSubset.entries)
771+
}
772+
704773
@Suppress("SpellCheckingInspection", "unused")
705774
private enum class S7yayynb25 {
706775
XJ27ZAXKD3,
@@ -714,6 +783,20 @@ class EnumIntegrationTest : DataConnectIntegrationTestBase() {
714783
/** The default number of iterations to use in property-based tests. */
715784
const val NUM_ITERATIONS = 10
716785

786+
@Suppress("SpellCheckingInspection")
787+
fun N5ekmae3jn.toN5ekmae3jnSubsetOrNull(): N5ekmae3jnSubset? =
788+
when (this) {
789+
N5ekmae3jn.DPSKD6HR3A -> N5ekmae3jnSubset.DPSKD6HR3A
790+
N5ekmae3jn.XGWGVMYTHJ -> N5ekmae3jnSubset.XGWGVMYTHJ
791+
N5ekmae3jn.QJX7C7RD5T -> N5ekmae3jnSubset.QJX7C7RD5T
792+
else -> null
793+
}
794+
795+
@Suppress("SpellCheckingInspection")
796+
fun N5ekmae3jn.toN5ekmae3jnSubsetEnumValue(): EnumValue<N5ekmae3jnSubset> {
797+
return Known(toN5ekmae3jnSubsetOrNull() ?: return Unknown(name))
798+
}
799+
717800
fun FirebaseDataConnect.mutation(
718801
variables: InsertNonNullableVariables
719802
): MutationRef<InsertData, InsertNonNullableVariables> =

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

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,16 @@ package com.google.firebase.dataconnect
2020
* Stores the value of an `enum` or a string if the string does not correspond to one of the enum's
2121
* values.
2222
*/
23-
// TODO: Change the visibility of `EnumValue` to `public` once it gets approval
24-
// by Firebase API Council.
25-
internal sealed interface EnumValue<out T : Enum<out T>> {
23+
public sealed interface EnumValue<out T : Enum<out T>> {
24+
25+
/** [Known.value] in the case of [Known], or `null` in the case of [Unknown]. */
26+
public val value: T?
2627

2728
/**
28-
* The string value of the enum, either the [Enum.name] in the case of [Known] or the string whose
29-
* corresponding enum value was _not_ known, as in the case of [Unknown].
29+
* The string value of the enum, either the [Enum.name] of [Known.value] in the case of [Known] or
30+
* the `stringValue` given to the constructor in the case of [Unknown].
3031
*/
31-
val stringValue: String
32+
public val stringValue: String
3233

3334
/**
3435
* Represents an unknown enum value.
@@ -37,7 +38,13 @@ internal sealed interface EnumValue<out T : Enum<out T>> {
3738
* the older version that lacked the new enum value. Instead of failing, the unknown enum value
3839
* will be gracefully mapped to [Unknown].
3940
*/
40-
class Unknown(override val stringValue: String) : EnumValue<Nothing> {
41+
public class Unknown(
42+
/** The unknown string value. */
43+
public override val stringValue: String
44+
) : EnumValue<Nothing> {
45+
46+
/** Always `null`. */
47+
override val value: Nothing? = null
4148

4249
/**
4350
* Compares this object with another object for equality.
@@ -70,16 +77,20 @@ internal sealed interface EnumValue<out T : Enum<out T>> {
7077
override fun toString(): String = "Unknown($stringValue)"
7178

7279
/** Creates and returns a new [Unknown] instance with the given property values. */
73-
fun copy(stringValue: String = this.stringValue): Unknown = Unknown(stringValue)
80+
public fun copy(stringValue: String = this.stringValue): Unknown = Unknown(stringValue)
7481
}
7582

7683
/**
7784
* Represents a known enum value.
7885
*
7986
* @param value The enum value.
8087
*/
81-
class Known<T : Enum<T>>(val value: T) : EnumValue<T> {
88+
public class Known<T : Enum<T>>(
89+
/** The enum value wrapped by this object. */
90+
override val value: T
91+
) : EnumValue<T> {
8292

93+
/** [Enum.name] of [value]. */
8394
override val stringValue: String
8495
get() = value.name
8596

@@ -114,6 +125,6 @@ internal sealed interface EnumValue<out T : Enum<out T>> {
114125
override fun toString(): String = "Known(${value.name})"
115126

116127
/** Creates and returns a new [Known] instance with the given property values. */
117-
fun copy(value: T = this.value): Known<T> = Known(value)
128+
public fun copy(value: T = this.value): Known<T> = Known(value)
118129
}
119130
}

firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/serializers/EnumValueSerializer.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@ import kotlinx.serialization.encoding.Encoder
3232
* @param values The values of the enum to deserialize; for example, for an enum named `Foo` this
3333
* value should be `Foo.entries` or `Foo.values()`.
3434
*/
35-
// TODO: Change the visibility of `EnumValueSerializer` to `public` once it gets approval
36-
// by Firebase API Council.
37-
internal open class EnumValueSerializer<T : Enum<T>>(values: Iterable<T>) :
35+
public open class EnumValueSerializer<T : Enum<T>>(values: Iterable<T>) :
3836
KSerializer<EnumValue<T>> {
3937

4038
override val descriptor: SerialDescriptor =

firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/EnumValueKnownUnitTest.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ class EnumValueKnownUnitTest {
4545
}
4646
}
4747

48+
@Test
49+
fun `stringValue property should be the name of the enum`() = runTest {
50+
checkAll(propTestConfig, Arb.enum<Food>()) { enum ->
51+
val enumValue = EnumValue.Known(enum)
52+
enumValue.stringValue shouldBe enum.name
53+
}
54+
}
55+
4856
@Test
4957
fun `equals() should return true when invoked with itself`() = runTest {
5058
checkAll(propTestConfig, Arb.enum<Food>()) { enum ->

firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/EnumValueUnknownUnitTest.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.google.firebase.dataconnect.testutil.property.arbitrary.dataConnect
2222
import com.google.firebase.dataconnect.testutil.property.arbitrary.distinctPair
2323
import io.kotest.assertions.withClue
2424
import io.kotest.common.ExperimentalKotest
25+
import io.kotest.matchers.nulls.shouldBeNull
2526
import io.kotest.matchers.shouldBe
2627
import io.kotest.matchers.shouldNotBe
2728
import io.kotest.matchers.types.shouldBeSameInstanceAs
@@ -45,6 +46,14 @@ class EnumValueUnknownUnitTest {
4546
}
4647
}
4748

49+
@Test
50+
fun `value property should unconditionally be null`() = runTest {
51+
checkAll(propTestConfig, Arb.dataConnect.string()) { stringValue ->
52+
val enumValue = EnumValue.Unknown(stringValue)
53+
enumValue.value.shouldBeNull()
54+
}
55+
}
56+
4857
@Test
4958
fun `equals() should return true when invoked with itself`() = runTest {
5059
checkAll(propTestConfig, Arb.dataConnect.string()) { stringValue ->

0 commit comments

Comments
 (0)