Skip to content

Commit e9ea4fe

Browse files
authored
Utility to decode [SchemaProto] and [EntityTypeProto] (#4833)
1 parent de2ae41 commit e9ea4fe

File tree

5 files changed

+158
-0
lines changed

5 files changed

+158
-0
lines changed

java/arcs/core/data/proto/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ arcs_kt_library(
3636
deps = [
3737
":recipe_java_proto",
3838
"//java/arcs/core/data",
39+
"//java/arcs/core/type",
3940
],
4041
)
4142

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2020 Google LLC.
3+
*
4+
* This code may only be used under the BSD style license found at
5+
* http://polymer.github.io/LICENSE.txt
6+
*
7+
* Code distributed by Google as part of this project is also subject to an additional IP rights
8+
* grant found at
9+
* http://polymer.github.io/PATENTS.txt
10+
*/
11+
12+
package arcs.core.data.proto
13+
14+
import arcs.core.data.FieldName
15+
import arcs.core.data.FieldType
16+
import arcs.core.data.Schema
17+
import arcs.core.data.SchemaFields
18+
import arcs.core.data.SchemaName
19+
20+
/**
21+
* Returns the names in the [SchemaProto] as List<SchemaName>.
22+
*/
23+
fun SchemaProto.decodeNames(): List<SchemaName> = getNamesList().map { SchemaName(it) }
24+
25+
/**
26+
* Returns the fields in the [SchemaProto] as a Kotlin [SchemaFields] instance.
27+
*/
28+
fun SchemaProto.decodeFields(): SchemaFields {
29+
val singletons = mutableMapOf<FieldName, FieldType>()
30+
val collections = mutableMapOf<FieldName, FieldType>()
31+
for ((name, type) in getFieldsMap()) {
32+
when (type.getDataCase()) {
33+
TypeProto.DataCase.PRIMITIVE -> singletons[name] = type.decodeAsFieldType()
34+
// TODO: TypeProto.DataCase.COLLECTIONS
35+
// TODO: TypeProto.DataCase.REFERENCE
36+
TypeProto.DataCase.DATA_NOT_SET ->
37+
throw IllegalArgumentException("Unknown data field in TypeProto.")
38+
else ->
39+
throw NotImplementedError(
40+
"decodeFields for ${type.getDataCase().name} is not implemented.")
41+
}
42+
}
43+
return SchemaFields(singletons, collections)
44+
}
45+
46+
/**
47+
* Converts a [SchemaProto] proto instance into a Kotlin [Schema] instance.
48+
*/
49+
fun SchemaProto.decode() = Schema(names = decodeNames(), fields = decodeFields(), hash = "")
50+
// TODO: hash

java/arcs/core/data/proto/TypeProtoDecoders.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111

1212
package arcs.core.data.proto
1313

14+
import arcs.core.data.EntityType
1415
import arcs.core.data.FieldType
1516
import arcs.core.data.PrimitiveType
17+
import arcs.core.type.Type
1618

1719
/**
1820
* Converts a [PrimitiveTypeProto] protobuf instance into a Kotlin [PrimitiveType] instance.
@@ -47,3 +49,26 @@ fun TypeProto.decodeAsFieldType(): FieldType =
4749
throw IllegalArgumentException(
4850
"Cannot decode a ${getDataCase().name} type to a [FieldType].")
4951
}
52+
53+
/**
54+
* Converts a [EntityTypeProto] protobuf instance into a Kotlin [EntityType] instance.
55+
*/
56+
fun EntityTypeProto.decode() = EntityType(getSchema().decode())
57+
58+
/**
59+
* Converts a [TypeProto] protobuf instance into a Kotlin [Type] instance.
60+
*/
61+
fun TypeProto.decode(): Type =
62+
// TODO: optional, RefinementExpression.
63+
when (getDataCase()) {
64+
TypeProto.DataCase.ENTITY -> getEntity().decode()
65+
TypeProto.DataCase.COLLECTION, TypeProto.DataCase.REFERENCE,
66+
TypeProto.DataCase.TUPLE, TypeProto.DataCase.VARIABLE ->
67+
throw NotImplementedError(
68+
"Decoding of a ${getDataCase().name} type to a [Type] is not implemented.")
69+
TypeProto.DataCase.DATA_NOT_SET ->
70+
throw IllegalArgumentException("Unknown data field in TypeProto.")
71+
else ->
72+
throw IllegalArgumentException(
73+
"Cannot decode a ${getDataCase().name} type to a [FieldType].")
74+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package arcs.core.data.proto
2+
3+
import arcs.core.data.*
4+
import arcs.core.testutil.assertThrows
5+
import arcs.core.testutil.fail
6+
import arcs.repoutils.runfilesDir
7+
import com.google.common.truth.Truth.assertThat
8+
import com.google.protobuf.Message.Builder
9+
import com.google.protobuf.Message
10+
import com.google.protobuf.TextFormat
11+
import java.io.File
12+
import org.junit.Test
13+
import org.junit.runner.RunWith
14+
import org.junit.runners.JUnit4
15+
16+
/**
17+
* Decodes the text proto [protoText] for [SchemaProto] as [Schema].
18+
*/
19+
fun decodeSchemaProtoText(protoText: String): Schema {
20+
val builder = SchemaProto.newBuilder()
21+
TextFormat.getParser().merge(protoText, builder)
22+
return builder.build().decode()
23+
}
24+
25+
@RunWith(JUnit4::class)
26+
class SchemaProtoDecoderTest {
27+
@Test
28+
fun decodesNamesInSchemaProto() {
29+
val schemaProtoText = """
30+
names: "Thing"
31+
names: "Object"
32+
""".trimIndent()
33+
val schema = decodeSchemaProtoText(schemaProtoText)
34+
assertThat(schema.names).isEqualTo(listOf(SchemaName("Thing"), SchemaName("Object")))
35+
}
36+
37+
@Test
38+
fun decodesSingletonsInSchemaProto() {
39+
val schemaProtoText = """
40+
fields {
41+
key: "text"
42+
value: {
43+
primitive: TEXT
44+
}
45+
}
46+
fields {
47+
key: "bool"
48+
value: {
49+
primitive: BOOLEAN
50+
}
51+
}
52+
""".trimIndent()
53+
val schema = decodeSchemaProtoText(schemaProtoText)
54+
assertThat(schema.fields.singletons).isEqualTo(
55+
mapOf("text" to FieldType.Text, "bool" to FieldType.Boolean))
56+
}
57+
}

javatests/arcs/core/data/proto/TypeProtoDecodersTest.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,29 @@ class TypeProtoDecodersTest {
6262
checkPrimitive("""variable: { name: "Blah"}""", PrimitiveType.Text)
6363
}
6464
}
65+
66+
@Test
67+
fun decodesEntityTypeProtoAsEntityType() {
68+
val entityTypeProto = """
69+
entity {
70+
schema {
71+
names: "Person"
72+
fields: {
73+
key: "name"
74+
value: { primitive: TEXT }
75+
}
76+
}
77+
}
78+
""".trimIndent()
79+
val entityType = parseTypeProtoText(entityTypeProto).decode()
80+
val expectedSchema = Schema(
81+
names = listOf(SchemaName("Person")),
82+
fields = SchemaFields(singletons=mapOf("name" to FieldType.Text), collections=mapOf()),
83+
hash = ""
84+
)
85+
when (entityType) {
86+
is EntityType -> assertThat(entityType.entitySchema).isEqualTo(expectedSchema)
87+
else -> fail("TypeProto should have been decoded to [EntityType].")
88+
}
89+
}
6590
}

0 commit comments

Comments
 (0)