Repository: graphql-java-kickstart/graphql-java-tools (kotlin)

Issue:
Set schema description for introspection when instantiating GraphQLSchema
<!-- ⚠️ Please ensure you are requesting the feature in the correct repository! -->

__I want to suggest an idea and checked that ...__

- [X] ... to my best knowledge, my idea wouldn't break something for other users
- [X] ... the documentation does not mention anything about my idea
- [X] ... there are no open or closed issues that are related to my idea

## Description

The GraphQL Specification provides for introspection of the [Schema description](https://spec.graphql.org/October2021/#sec-The-__Schema-Type).

`graphql-java` allows for a description to be provided in the `SchemaDefinition` [constructor](https://github.com/graphql-java/graphql-java/blob/9e53ca9bae1bc4f15a3de96d96a1b2b94ffd5031/src/main/java/graphql/language/SchemaDefinition.java#L38).

`graphql-java-tools` does not currently pass this through when instantiating `GraphQLSchema`.

### Use Cases

To be able to describe a graph at schema level.

Pull request description:
Resolves #595

## Checklist
<!-- Change [ ] to [x] to indicate you acknowledge the check. -->
- [X] Pull requests follows the [contribution guide](https://github.com/graphql-java-kickstart/graphql-java-tools/wiki/Contribution-guide)
- [X] New or modified functionality is covered by tests

## Description
Set description in `GraphQLSchema` object instantiated in `SchemaObjects.toSchema`

Patch:
diff --git a/src/main/kotlin/graphql/kickstart/tools/RootTypeInfo.kt b/src/main/kotlin/graphql/kickstart/tools/RootTypeInfo.kt
index e2044dc4..71ae0f9f 100644
--- a/src/main/kotlin/graphql/kickstart/tools/RootTypeInfo.kt
+++ b/src/main/kotlin/graphql/kickstart/tools/RootTypeInfo.kt
@@ -1,5 +1,6 @@
 package graphql.kickstart.tools
 
+import graphql.language.Description
 import graphql.language.SchemaDefinition
 import graphql.language.TypeName
 
@@ -9,25 +10,29 @@ import graphql.language.TypeName
 internal class RootTypeInfo private constructor(
     private val queryType: TypeName?,
     private val mutationType: TypeName?,
-    private val subscriptionType: TypeName?
+    private val subscriptionType: TypeName?,
+    private val description: Description?
 ) {
     companion object {
         const val DEFAULT_QUERY_NAME = "Query"
         const val DEFAULT_MUTATION_NAME = "Mutation"
         const val DEFAULT_SUBSCRIPTION_NAME = "Subscription"
+        val DEFAULT_DESCRIPTION: String? = null // According to the GraphQL Specification description should be a string or `null`
 
         fun fromSchemaDefinitions(definitions: List<SchemaDefinition>): RootTypeInfo {
             val queryType = definitions.lastOrNull()?.operationTypeDefinitions?.find { it.name == "query" }?.typeName
             val mutationType = definitions.lastOrNull()?.operationTypeDefinitions?.find { it.name == "mutation" }?.typeName
             val subscriptionType = definitions.lastOrNull()?.operationTypeDefinitions?.find { it.name == "subscription" }?.typeName
+            val description = definitions.lastOrNull()?.description
 
-            return RootTypeInfo(queryType, mutationType, subscriptionType)
+            return RootTypeInfo(queryType, mutationType, subscriptionType, description)
         }
     }
 
     fun getQueryName() = queryType?.name ?: DEFAULT_QUERY_NAME
     fun getMutationName() = mutationType?.name ?: DEFAULT_MUTATION_NAME
     fun getSubscriptionName() = subscriptionType?.name ?: DEFAULT_SUBSCRIPTION_NAME
+    fun getDescription() = description?.content ?: DEFAULT_DESCRIPTION
 
     fun isMutationRequired() = mutationType != null
     fun isSubscriptionRequired() = subscriptionType != null
diff --git a/src/main/kotlin/graphql/kickstart/tools/SchemaObjects.kt b/src/main/kotlin/graphql/kickstart/tools/SchemaObjects.kt
index eebdc488..206ae721 100644
--- a/src/main/kotlin/graphql/kickstart/tools/SchemaObjects.kt
+++ b/src/main/kotlin/graphql/kickstart/tools/SchemaObjects.kt
@@ -13,13 +13,15 @@ data class SchemaObjects(
     val mutation: GraphQLObjectType?,
     val subscription: GraphQLObjectType?,
     val dictionary: Set<GraphQLType>,
-    val codeRegistryBuilder: GraphQLCodeRegistry.Builder
+    val codeRegistryBuilder: GraphQLCodeRegistry.Builder,
+    val description: String?
 ) {
     /**
      * Makes a GraphQLSchema with query, mutation and subscription.
      */
     fun toSchema(): GraphQLSchema {
         return GraphQLSchema.newSchema()
+            .description(description)
             .query(query)
             .mutation(mutation)
             .subscription(subscription)
diff --git a/src/main/kotlin/graphql/kickstart/tools/SchemaParser.kt b/src/main/kotlin/graphql/kickstart/tools/SchemaParser.kt
index 75adc3cb..34ff518f 100644
--- a/src/main/kotlin/graphql/kickstart/tools/SchemaParser.kt
+++ b/src/main/kotlin/graphql/kickstart/tools/SchemaParser.kt
@@ -103,7 +103,7 @@ class SchemaParser internal constructor(
         val additionalObjects = objects.filter { o -> o != query && o != subscription && o != mutation }
 
         val types = (additionalObjects.toSet() as Set<GraphQLType>) + inputObjects + enums + interfaces + unions
-        return SchemaObjects(query, mutation, subscription, types, codeRegistryBuilder)
+        return SchemaObjects(query, mutation, subscription, types, codeRegistryBuilder, rootInfo.getDescription())
     }
 
     /**


Test patch:
diff --git a/src/test/kotlin/graphql/kickstart/tools/SchemaParserTest.kt b/src/test/kotlin/graphql/kickstart/tools/SchemaParserTest.kt
index ece86bc4..d382a3cb 100644
--- a/src/test/kotlin/graphql/kickstart/tools/SchemaParserTest.kt
+++ b/src/test/kotlin/graphql/kickstart/tools/SchemaParserTest.kt
@@ -574,6 +574,57 @@ class SchemaParserTest {
         assertEquals(schema.queryType.getFieldDefinition("empty").description, "")
     }
 
+    @Test
+    fun `parser should include schema descriptions when declared`() {
+        val schema = SchemaParser.newParser()
+            .schemaString(
+                """
+                "This is a schema level description"
+                schema {
+                  query: SubstituteQuery
+                }
+
+                type SubstituteQuery {
+                    description: String
+                    comment: String
+                    omitted: String
+                    both: String
+                    empty: String
+                }
+                """)
+            .resolvers(object : GraphQLQueryResolver {})
+            .options(SchemaParserOptions.newOptions().allowUnimplementedResolvers(true).build())
+            .build()
+            .makeExecutableSchema()
+
+        assertEquals(schema.description, "This is a schema level description")
+    }
+
+    @Test
+    fun `parser should return null schema description when not declared`() {
+        val schema = SchemaParser.newParser()
+            .schemaString(
+                """
+                schema {
+                  query: SubstituteQuery
+                }
+
+                type SubstituteQuery {
+                    description: String
+                    comment: String
+                    omitted: String
+                    both: String
+                    empty: String
+                }
+                """)
+            .resolvers(object : GraphQLQueryResolver {})
+            .options(SchemaParserOptions.newOptions().allowUnimplementedResolvers(true).build())
+            .build()
+            .makeExecutableSchema()
+
+        assertNull(schema.description)
+    }
+
     enum class EnumType {
         TEST
     }