Skip to content

Enable SDL schema Apollo Plugin support #2417

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
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,38 @@ import java.io.IOException
import java.util.Locale

internal object GraphSDLSchemaParser {
private val builtInScalarTypes = listOf(
GraphSdlSchema.TypeDefinition.Scalar(
name = "Int",
description = "The `Int` scalar type represents non-fractional signed whole numeric values. " +
"Int can represent values between -(2^31) and 2^31 - 1. ",
directives = emptyList()
),
GraphSdlSchema.TypeDefinition.Scalar(
name = "Float",
description = "The `Float` scalar type represents signed double-precision fractional values as specified by " +
"[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).",
directives = emptyList()
),
GraphSdlSchema.TypeDefinition.Scalar(
name = "String",
description = "The `String` scalar type represents textual data, represented as UTF-8 character sequences. " +
"The String type is most often used by GraphQL to represent free-form human-readable text.",
directives = emptyList()
),
GraphSdlSchema.TypeDefinition.Scalar(
name = "Boolean",
description = "The `Boolean` scalar type represents `true` or `false`.",
directives = emptyList()
),
GraphSdlSchema.TypeDefinition.Scalar(
name = "ID",
description = "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. " +
"The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. " +
"When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.",
directives = emptyList()
)
)

fun File.parse(): GraphSdlSchema {
val document = try {
Expand Down Expand Up @@ -77,6 +109,7 @@ internal object GraphSDLSchemaParser {
ctx.scalarTypeDefinition()?.parse()
)
}
?.plus(builtInScalarTypes)
?.associateBy { it.name }

val schemaDefinition = schemaDefinition().firstOrNull()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import com.apollographql.apollo.compiler.parser.error.ParseException
import com.apollographql.apollo.compiler.parser.introspection.IntrospectionSchema
import com.apollographql.apollo.compiler.parser.sdl.GraphSDLSchemaParser.parse
import java.io.File
import java.util.Locale

internal data class GraphSdlSchema(
data class GraphSdlSchema(
val schema: Schema,
val typeDefinitions: Map<String, TypeDefinition>
) {
Expand Down Expand Up @@ -122,7 +121,7 @@ internal data class GraphSdlSchema(
}
}

internal fun GraphSdlSchema.toIntrospectionSchema(): IntrospectionSchema {
fun GraphSdlSchema.toIntrospectionSchema(): IntrospectionSchema {
return IntrospectionSchema(
queryType = schema.queryRootOperationType.typeName,
mutationType = schema.mutationRootOperationType.typeName,
Expand Down Expand Up @@ -226,35 +225,13 @@ private fun GraphSdlSchema.TypeDefinition.Scalar.toIntrospectionType(): Introspe
private fun GraphSdlSchema.TypeRef.toIntrospectionType(schema: GraphSdlSchema): IntrospectionSchema.TypeRef {
return when (this) {
is GraphSdlSchema.TypeRef.Named -> {
when (typeName.toLowerCase(Locale.ENGLISH)) {
"int" -> IntrospectionSchema.TypeRef(
kind = IntrospectionSchema.Kind.SCALAR,
name = "Int"
)
"float" -> IntrospectionSchema.TypeRef(
kind = IntrospectionSchema.Kind.SCALAR,
name = "Float"
)
"string" -> IntrospectionSchema.TypeRef(
kind = IntrospectionSchema.Kind.SCALAR,
name = "String"
)
"boolean" -> IntrospectionSchema.TypeRef(
kind = IntrospectionSchema.Kind.SCALAR,
name = "Boolean"
)
"id" -> IntrospectionSchema.TypeRef(
kind = IntrospectionSchema.Kind.SCALAR,
name = "ID"
)
else -> IntrospectionSchema.TypeRef(
kind = schema.typeDefinitions[typeName]?.toIntrospectionType() ?: throw ParseException(
message = "Undefined GraphQL schema type `$typeName`",
sourceLocation = sourceLocation
),
name = typeName
)
}
IntrospectionSchema.TypeRef(
kind = schema.typeDefinitions[typeName]?.toIntrospectionType() ?: throw ParseException(
message = "Undefined GraphQL schema type `$typeName`",
sourceLocation = sourceLocation
),
name = typeName
)
}

is GraphSdlSchema.TypeRef.NonNull -> IntrospectionSchema.TypeRef(
Expand Down
50 changes: 50 additions & 0 deletions apollo-compiler/src/test/sdl/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2556,6 +2556,56 @@
"interfaces": [],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "SCALAR",
"name": "ID",
"description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "SCALAR",
"name": "String",
"description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "SCALAR",
"name": "Int",
"description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. ",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "SCALAR",
"name": "Boolean",
"description": "The `Boolean` scalar type represents `true` or `false`.",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "SCALAR",
"name": "Float",
"description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": null
}
],
"directives": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import com.apollographql.apollo.compiler.NullableValueType
import com.apollographql.apollo.compiler.OperationIdGenerator
import com.apollographql.apollo.compiler.parser.graphql.GraphQLDocumentParser
import com.apollographql.apollo.compiler.parser.introspection.IntrospectionSchema
import com.apollographql.apollo.compiler.parser.sdl.GraphSdlSchema
import com.apollographql.apollo.compiler.parser.sdl.toIntrospectionSchema
import org.gradle.api.DefaultTask
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
Expand Down Expand Up @@ -105,12 +107,13 @@ abstract class ApolloGenerateSourcesTask : DefaultTask() {

@TaskAction
fun taskAction() {

val realSchemaFile = schemaFile.get().asFile

outputDir.get().asFile.deleteRecursively()

val schema = IntrospectionSchema.invoke(realSchemaFile)
val introspectionSchema = if (realSchemaFile.extension == "json") {
IntrospectionSchema.invoke(realSchemaFile)
} else {
GraphSdlSchema(realSchemaFile).toIntrospectionSchema()
}

val packageNameProvider = DefaultPackageNameProvider(
rootFolders = rootFolders.get().map { project.file(it) },
Expand All @@ -127,7 +130,9 @@ abstract class ApolloGenerateSourcesTask : DefaultTask() {
NullableValueType.values().joinToString(separator = "\n") { it.value })
}

val codeGenerationIR = GraphQLDocumentParser(schema, packageNameProvider).parse(files)
outputDir.get().asFile.deleteRecursively()

val codeGenerationIR = GraphQLDocumentParser(introspectionSchema, packageNameProvider).parse(files)
val args = GraphQLCompiler.Arguments(
ir = codeGenerationIR,
outputDir = outputDir.get().asFile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ abstract class DefaultCompilationUnit @Inject constructor(
| }
""".trimMargin()
}
return "ApolloGraphQL: By default only one schema.json file is supported.\nPlease use multiple services instead:\napollo {\n$services\n}"
return "ApolloGraphQL: By default only one schema.[json | sdl] file is supported.\n" +
"Please use multiple services instead:\napollo {\n$services\n}"
}

fun resolveDirectories(project: Project, sourceFolderProvider: Provider<String>, sourceSetNames: List<String>): List<String> {
Expand Down Expand Up @@ -147,16 +148,18 @@ abstract class DefaultCompilationUnit @Inject constructor(
}
} else {
val candidates = directories.flatMap { srcDir ->
srcDir.walkTopDown().filter { it.name == "schema.json" }.toList()
srcDir.walkTopDown().filter { it.name == "schema.json" || it.name == "schema.sdl" }.toList()
}

require(candidates.size <= 1) {
multipleSchemaError(candidates)
}

require(candidates.size == 1) {
"ApolloGraphQL: cannot find schema.json. Please specify it explicitely. Looked under:\n" +
directories.map { it.absolutePath }.joinToString("\n")
"ApolloGraphQL: cannot find schema.[json | sdl]. Please specify it explicitely. Looked under:\n" +
directories.joinToString("\n") { it.absolutePath }
}

return candidates.first().path
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
query FeedRepositoryQuery($type: FeedType!, $limit: Int!) {
feed(type: $type, limit: $limit) {
repository {
name
}
}
}
Loading