Skip to content

Commit 66cd446

Browse files
authored
[release-2.x] fix converting introspection to SDL (#4316)
* fix converting introspection to SDL * add a flag that keeps the old behaviour in places where we might still need it
1 parent b6defa3 commit 66cd446

File tree

6 files changed

+806
-21
lines changed

6 files changed

+806
-21
lines changed

apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/parser/introspection/introspection2sdl.kt

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,24 @@ import okio.buffer
55
import okio.sink
66
import java.io.File
77

8-
fun IntrospectionSchema.toSDL(file: File) {
8+
/**
9+
* Previous versions of this method used to encode defaultValues as Json elements. For an example:
10+
* "defaultValue": [0, 1]
11+
*
12+
* This is wrong. The spec mandates defaultValue to be GraphQL encoded String:
13+
* "defaultValue": "[0, 1]"
14+
*
15+
* For backward compatibility, use [legacyDefaultValues] = true
16+
*/
17+
fun IntrospectionSchema.toSDL(file: File, legacyDefaultValues: Boolean) {
918
file.sink().buffer().use {
10-
toSDL(it)
19+
toSDL(it, legacyDefaultValues)
1120
}
1221
}
1322

14-
fun IntrospectionSchema.toSDL(sink: BufferedSink) {
23+
fun IntrospectionSchema.toSDL(file: File) = toSDL(file, true)
24+
25+
fun IntrospectionSchema.toSDL(sink: BufferedSink, legacyDefaultValues: Boolean) {
1526
val builtinsTypes = setOf(
1627
"Int", "Float", "String", "Boolean", "ID",
1728
"__Directive", "__DirectiveLocation", "__EnumValue", "__Field", "__InputValue", "__Schema", "__Type", "__TypeKind"
@@ -25,9 +36,9 @@ fun IntrospectionSchema.toSDL(sink: BufferedSink) {
2536
when (it) {
2637
is IntrospectionSchema.Type.Scalar -> it.toSDL(sink)
2738
is IntrospectionSchema.Type.Enum -> it.toSDL(sink)
28-
is IntrospectionSchema.Type.InputObject -> it.toSDL(sink)
29-
is IntrospectionSchema.Type.Interface -> it.toSDL(sink)
30-
is IntrospectionSchema.Type.Object -> it.toSDL(sink, allInterfaces)
39+
is IntrospectionSchema.Type.InputObject -> it.toSDL(sink, legacyDefaultValues)
40+
is IntrospectionSchema.Type.Interface -> it.toSDL(sink, legacyDefaultValues)
41+
is IntrospectionSchema.Type.Object -> it.toSDL(sink, allInterfaces, legacyDefaultValues)
3142
is IntrospectionSchema.Type.Union -> it.toSDL(sink)
3243
}
3344
// Add a newline as a separation
@@ -40,6 +51,8 @@ fun IntrospectionSchema.toSDL(sink: BufferedSink) {
4051
sink.writeUtf8("}\n")
4152
}
4253

54+
fun IntrospectionSchema.toSDL(sink: BufferedSink) = toSDL(sink, true)
55+
4356
private fun BufferedSink.writeDescription(description: String?, indent: String = "") {
4457
if (!description.isNullOrBlank()) {
4558
writeUtf8(
@@ -86,11 +99,11 @@ private fun IntrospectionSchema.Type.Enum.Value.toSDL(sink: BufferedSink) {
8699
sink.writeDeprecatedDirective(isDeprecated, deprecationReason)
87100
}
88101

89-
private fun IntrospectionSchema.Type.InputObject.toSDL(sink: BufferedSink) {
102+
private fun IntrospectionSchema.Type.InputObject.toSDL(sink: BufferedSink, legacyDefaultValues: Boolean) {
90103
sink.writeDescription(description)
91104
sink.writeUtf8("input $name {\n")
92105
inputFields.forEach {
93-
it.toSDL(sink)
106+
it.toSDL(sink, legacyDefaultValues)
94107
sink.writeUtf8("\n")
95108
}
96109
sink.writeUtf8("}\n")
@@ -132,33 +145,40 @@ private fun BufferedSink.writeValue(value: Any?) {
132145
}
133146
}
134147

135-
private fun IntrospectionSchema.InputField.toSDL(sink: BufferedSink) {
148+
private fun IntrospectionSchema.InputField.toSDL(sink: BufferedSink, legacyDefaultValues: Boolean) {
136149
sink.writeDescription(description, " ")
137150
sink.writeUtf8(" $name: ${type.asGraphQLType()}")
138151
if (defaultValue != null) {
139152
sink.writeUtf8(" = ")
140-
sink.writeValue(defaultValue)
153+
if (!legacyDefaultValues && defaultValue is String) {
154+
// defaultValue is already encoded as GraphQL, we can pass it verbatim
155+
sink.writeUtf8(defaultValue)
156+
} else {
157+
// legacy mode if we bump into an introspection schema that doesn't encode the default value
158+
sink.writeValue(defaultValue)
159+
}
160+
141161
}
142162
sink.writeDeprecatedDirective(isDeprecated, deprecationReason)
143163
}
144164

145-
private fun IntrospectionSchema.Type.Interface.toSDL(sink: BufferedSink) {
165+
private fun IntrospectionSchema.Type.Interface.toSDL(sink: BufferedSink, legacyDefaultValue: Boolean) {
146166
sink.writeDescription(description)
147167
sink.writeUtf8("interface $name {\n")
148168
fields?.forEach {
149-
it.toSDL(sink)
169+
it.toSDL(sink, legacyDefaultValue)
150170
sink.writeUtf8("\n")
151171
}
152172
sink.writeUtf8("}\n")
153173
}
154174

155-
private fun IntrospectionSchema.Field.toSDL(sink: BufferedSink) {
175+
private fun IntrospectionSchema.Field.toSDL(sink: BufferedSink, legacyDefaultValue: Boolean) {
156176
sink.writeDescription(description, " ")
157177
sink.writeUtf8(" $name")
158178
if (args.isNotEmpty()) {
159179
sink.writeUtf8("(")
160180
args.forEachIndexed { index, arg ->
161-
arg.toSDL(sink)
181+
arg.toSDL(sink, legacyDefaultValue)
162182
if (index != args.size - 1) {
163183
sink.writeUtf8(", ")
164184
}
@@ -169,20 +189,26 @@ private fun IntrospectionSchema.Field.toSDL(sink: BufferedSink) {
169189
sink.writeDeprecatedDirective(isDeprecated, deprecationReason)
170190
}
171191

172-
private fun IntrospectionSchema.Field.Argument.toSDL(sink: BufferedSink) {
192+
private fun IntrospectionSchema.Field.Argument.toSDL(sink: BufferedSink, legacyDefaultValue: Boolean) {
173193
if (!description.isNullOrBlank()) {
174194
// Write the description inline
175195
sink.writeUtf8("\"\"\"$description\"\"\" ")
176196
}
177197
sink.writeUtf8("$name: ${type.asGraphQLType()}")
178198
if (defaultValue != null) {
179199
sink.writeUtf8(" = ")
180-
sink.writeValue(defaultValue)
200+
if (!legacyDefaultValue && defaultValue is String) {
201+
// defaultValue is already encoded as GraphQL, we can pass it verbatim
202+
sink.writeUtf8(defaultValue)
203+
} else {
204+
// legacy mode if we bump into an introspection schema that doesn't encode the default value
205+
sink.writeValue(defaultValue)
206+
}
181207
}
182208
sink.writeDeprecatedDirective(isDeprecated, deprecationReason)
183209
}
184210

185-
private fun IntrospectionSchema.Type.Object.toSDL(sink: BufferedSink, interfaces: List<IntrospectionSchema.Type.Interface>) {
211+
private fun IntrospectionSchema.Type.Object.toSDL(sink: BufferedSink, interfaces: List<IntrospectionSchema.Type.Interface>, legacyDefaultValue: Boolean) {
186212
sink.writeDescription(description, "")
187213
sink.writeUtf8("type $name")
188214
val implements = interfaces.filter {
@@ -203,7 +229,7 @@ private fun IntrospectionSchema.Type.Object.toSDL(sink: BufferedSink, interfaces
203229
sink.writeUtf8(" {\n")
204230

205231
fields?.forEach {
206-
it.toSDL(sink)
232+
it.toSDL(sink, legacyDefaultValue)
207233
sink.writeUtf8("\n")
208234
}
209235

apollo-compiler/src/test/kotlin/com/apollographql/apollo/compiler/GraphSdlParseTest.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import com.apollographql.apollo.compiler.parser.introspection.IntrospectionSchem
66
import com.apollographql.apollo.compiler.parser.introspection.toSDL
77
import com.apollographql.apollo.compiler.parser.sdl.GraphSdlSchema
88
import com.apollographql.apollo.compiler.parser.sdl.toIntrospectionSchema
9-
import com.google.common.truth.Truth
109
import com.google.common.truth.Truth.assertThat
1110
import org.junit.Assert.assertEquals
1211
import org.junit.Assert.fail
@@ -84,6 +83,17 @@ class GraphSdlParseTest() {
8483
assertEquals(initialSchema, finalSchema)
8584
}
8685

86+
@Test
87+
fun `defaultValues are correctly written`() {
88+
val initialSchema = IntrospectionSchema(File("src/test/sdl/default-values.json")).normalize()
89+
val sdlFile = File("build/sdl-test/schema.sdl")
90+
sdlFile.parentFile.deleteRecursively()
91+
sdlFile.parentFile.mkdirs()
92+
initialSchema.toSDL(sdlFile, legacyDefaultValues = false)
93+
94+
assertEquals(File("src/test/sdl/default-values.sdl").readText(), sdlFile.readText())
95+
}
96+
8797
/**
8898
* use to make easier diffs
8999
*/

0 commit comments

Comments
 (0)