Skip to content

Commit d2c4344

Browse files
authored
Add coordinate tree (#737)
* Add coordinate tree * Update NadelCoordinatesTreeTest.kt
1 parent fe33085 commit d2c4344

18 files changed

Lines changed: 630 additions & 20 deletions

lib/src/main/java/graphql/nadel/definition/coordinates/NadelAppliedDirectiveArgumentCoordinates.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ data class NadelAppliedDirectiveArgumentCoordinates(
88
override val name: String,
99
) : NadelSchemaMemberCoordinates,
1010
NadelChildCoordinates {
11+
override val kind = NadelCoordinateKind.AppliedDirectiveArgument
1112
override val level: Int = parent.level + 1
1213

1314
override fun resolve(schema: GraphQLSchema): GraphQLAppliedDirectiveArgument {

lib/src/main/java/graphql/nadel/definition/coordinates/NadelAppliedDirectiveCoordinates.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ data class NadelAppliedDirectiveCoordinates(
88
override val name: String,
99
) : NadelSchemaMemberCoordinates,
1010
NadelChildCoordinates {
11+
override val kind = NadelCoordinateKind.AppliedDirective
1112
override val level: Int = parent.level + 1
1213

1314
override fun resolve(schema: GraphQLSchema): GraphQLAppliedDirective {

lib/src/main/java/graphql/nadel/definition/coordinates/NadelArgumentCoordinates.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ data class NadelArgumentCoordinates(
1010
NadelChildCoordinates,
1111
NadelAppliedDirectiveParentCoordinates,
1212
NadelInputCoordinates {
13+
override val kind = NadelCoordinateKind.Argument
1314
override val level: Int = parent.level + 1
1415

1516
override fun resolve(schema: GraphQLSchema): GraphQLArgument? {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package graphql.nadel.definition.coordinates
2+
3+
enum class NadelCoordinateKind {
4+
AppliedDirective,
5+
AppliedDirectiveArgument,
6+
Argument,
7+
Directive,
8+
Enum,
9+
EnumValue,
10+
Field,
11+
InputObject,
12+
InputObjectField,
13+
Interface,
14+
Object,
15+
Scalar,
16+
Union,
17+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package graphql.nadel.definition.coordinates
2+
3+
data class NadelCoordinatesNode internal constructor(
4+
val kind: NadelCoordinateKind,
5+
val name: String,
6+
val children: List<NadelCoordinatesNode>,
7+
)
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package graphql.nadel.definition.coordinates
2+
3+
/**
4+
* Converts a flat [Set] of [NadelSchemaMemberCoordinates] to and from an equivalent tree.
5+
*
6+
* Each coordinate carries its full parent chain, so serializing the flat [Set] repeats shared ancestors
7+
* once per descendant. In the tree each coordinate appears once and parents are shared via nesting.
8+
*/
9+
object NadelCoordinatesTree {
10+
fun toTree(coordinates: Set<NadelSchemaMemberCoordinates>): List<NadelCoordinatesNode> {
11+
val builders = LinkedHashMap<NadelSchemaMemberCoordinates, MutableNode>()
12+
val roots = mutableListOf<MutableNode>()
13+
14+
fun ensure(coordinate: NadelSchemaMemberCoordinates): MutableNode {
15+
return builders.getOrPut(coordinate) {
16+
val node = MutableNode(coordinate.kind, coordinate.name)
17+
val parent = coordinate.parentOrNull
18+
if (parent == null) {
19+
roots.add(node)
20+
} else {
21+
ensure(parent).children.add(node)
22+
}
23+
node
24+
}
25+
}
26+
27+
coordinates
28+
.asSequence()
29+
.sorted()
30+
.forEach(::ensure)
31+
32+
return roots.map { it.toNode() }
33+
}
34+
35+
fun fromTree(nodes: List<NadelCoordinatesNode>): Set<NadelSchemaMemberCoordinates> {
36+
val coordinates = LinkedHashSet<NadelSchemaMemberCoordinates>()
37+
38+
fun visit(node: NadelCoordinatesNode, parent: NadelSchemaMemberCoordinates?) {
39+
val coordinate = if (parent == null) buildRoot(node) else buildChild(parent, node)
40+
coordinates.add(coordinate)
41+
node.children.forEach { child ->
42+
visit(child, coordinate)
43+
}
44+
}
45+
46+
nodes.forEach { node ->
47+
visit(node, parent = null)
48+
}
49+
50+
return coordinates
51+
}
52+
53+
private fun buildRoot(node: NadelCoordinatesNode): NadelSchemaMemberCoordinates {
54+
return when (node.kind) {
55+
NadelCoordinateKind.Object -> NadelObjectCoordinates(node.name)
56+
NadelCoordinateKind.Interface -> NadelInterfaceCoordinates(node.name)
57+
NadelCoordinateKind.Union -> NadelUnionCoordinates(node.name)
58+
NadelCoordinateKind.Enum -> NadelEnumCoordinates(node.name)
59+
NadelCoordinateKind.InputObject -> NadelInputObjectCoordinates(node.name)
60+
NadelCoordinateKind.Scalar -> NadelScalarCoordinates(node.name)
61+
NadelCoordinateKind.Directive -> NadelDirectiveCoordinates(node.name)
62+
NadelCoordinateKind.Field,
63+
NadelCoordinateKind.InputObjectField,
64+
NadelCoordinateKind.Argument,
65+
NadelCoordinateKind.EnumValue,
66+
NadelCoordinateKind.AppliedDirective,
67+
NadelCoordinateKind.AppliedDirectiveArgument,
68+
-> error("${node.kind} cannot be a top level coordinate")
69+
}
70+
}
71+
72+
private fun buildChild(
73+
parent: NadelSchemaMemberCoordinates,
74+
node: NadelCoordinatesNode,
75+
): NadelSchemaMemberCoordinates {
76+
return when (node.kind) {
77+
NadelCoordinateKind.Field -> (parent as NadelFieldContainerCoordinates).field(node.name)
78+
NadelCoordinateKind.Argument -> (parent as NadelArgumentParentCoordinates).argument(node.name)
79+
NadelCoordinateKind.AppliedDirective -> (parent as NadelAppliedDirectiveParentCoordinates).appliedDirective(node.name)
80+
NadelCoordinateKind.InputObjectField -> (parent as NadelInputObjectCoordinates).field(node.name)
81+
NadelCoordinateKind.EnumValue -> (parent as NadelEnumCoordinates).enumValue(node.name)
82+
NadelCoordinateKind.AppliedDirectiveArgument -> (parent as NadelAppliedDirectiveCoordinates).argument(node.name)
83+
NadelCoordinateKind.Object,
84+
NadelCoordinateKind.Interface,
85+
NadelCoordinateKind.Union,
86+
NadelCoordinateKind.Enum,
87+
NadelCoordinateKind.InputObject,
88+
NadelCoordinateKind.Scalar,
89+
NadelCoordinateKind.Directive,
90+
-> error("${node.kind} cannot be a child coordinate")
91+
}
92+
}
93+
94+
private class MutableNode(
95+
private val kind: NadelCoordinateKind,
96+
private val name: String,
97+
) {
98+
val children = mutableListOf<MutableNode>()
99+
100+
fun toNode(): NadelCoordinatesNode {
101+
return NadelCoordinatesNode(
102+
kind = kind,
103+
name = name,
104+
children = children.map { it.toNode() },
105+
)
106+
}
107+
}
108+
}

lib/src/main/java/graphql/nadel/definition/coordinates/NadelDirectiveCoordinates.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ data class NadelDirectiveCoordinates(
88
) : NadelSchemaMemberCoordinates,
99
NadelTopLevelDefinitionCoordinates,
1010
NadelArgumentParentCoordinates {
11+
override val kind = NadelCoordinateKind.Directive
12+
1113
override fun resolve(schema: GraphQLSchema): GraphQLDirective? {
1214
return schema.getDirective(name)
1315
}

lib/src/main/java/graphql/nadel/definition/coordinates/NadelEnumCoordinates.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ data class NadelEnumCoordinates(
88
) : NadelSchemaMemberCoordinates,
99
NadelTypeCoordinates,
1010
NadelAppliedDirectiveParentCoordinates {
11+
override val kind = NadelCoordinateKind.Enum
12+
1113
override fun resolve(schema: GraphQLSchema): GraphQLEnumType? {
1214
return schema.getType(name) as GraphQLEnumType?
1315
}

lib/src/main/java/graphql/nadel/definition/coordinates/NadelEnumValueCoordinates.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ data class NadelEnumValueCoordinates(
99
) : NadelSchemaMemberCoordinates,
1010
NadelChildCoordinates,
1111
NadelAppliedDirectiveParentCoordinates {
12+
override val kind = NadelCoordinateKind.EnumValue
1213
override val level: Int = parent.level + 1
1314

1415
override fun resolve(schema: GraphQLSchema): GraphQLEnumValueDefinition? {

lib/src/main/java/graphql/nadel/definition/coordinates/NadelFieldCoordinates.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ data class NadelFieldCoordinates(
1010
NadelChildCoordinates,
1111
NadelArgumentParentCoordinates,
1212
NadelAppliedDirectiveParentCoordinates {
13+
override val kind = NadelCoordinateKind.Field
1314
override val level: Int = parent.level + 1
1415

1516
override fun resolve(schema: GraphQLSchema): GraphQLFieldDefinition? {

0 commit comments

Comments
 (0)