Skip to content
This repository has been archived by the owner on Oct 26, 2020. It is now read-only.

Commit

Permalink
Add description to Schema. Closes sangria-graphql#410
Browse files Browse the repository at this point in the history
  • Loading branch information
OlegIlyenko committed Oct 6, 2018
1 parent 99b8282 commit 343d7a5
Show file tree
Hide file tree
Showing 19 changed files with 492 additions and 364 deletions.
6 changes: 4 additions & 2 deletions src/main/scala/sangria/ast/QueryAst.scala
Original file line number Diff line number Diff line change
Expand Up @@ -467,9 +467,10 @@ case class DirectiveLocation(
case class SchemaDefinition(
operationTypes: Vector[OperationTypeDefinition],
directives: Vector[Directive] = Vector.empty,
description: Option[StringValue] = None,
comments: Vector[Comment] = Vector.empty,
trailingComments: Vector[Comment] = Vector.empty,
location: Option[AstLocation] = None) extends TypeSystemDefinition with WithTrailingComments with WithDirectives
location: Option[AstLocation] = None) extends TypeSystemDefinition with WithDescription with WithTrailingComments with WithDirectives

case class OperationTypeDefinition(
operation: OperationType,
Expand Down Expand Up @@ -921,10 +922,11 @@ object AstVisitor {
comment.foreach(s loop(s))
breakOrSkip(onLeave(n))
}
case n @ SchemaDefinition(ops, dirs, comment, trailingComments, _)
case n @ SchemaDefinition(ops, dirs, descr, comment, trailingComments, _)
if (breakOrSkip(onEnter(n))) {
ops.foreach(s loop(s))
dirs.foreach(s loop(s))
descr.foreach(s loop(s))
comment.foreach(s loop(s))
trailingComments.foreach(s loop(s))
breakOrSkip(onLeave(n))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ object IntrospectionParser {
mutationType = mapFieldOpt(schema, "mutationType") map (parseNamedTypeRef(_, path :+ "mutationType")),
subscriptionType = mapFieldOpt(schema, "subscriptionType") map (parseNamedTypeRef(_, path :+ "subscriptionType")),
types = um.getListValue(mapField(schema, "types", path)) map (parseType(_, path :+ "types")),
directives = mapFieldOpt(schema, "directives") map um.getListValue getOrElse Vector.empty map (i parseDirective(i, path :+ "directives")))
directives = mapFieldOpt(schema, "directives") map um.getListValue getOrElse Vector.empty map (i parseDirective(i, path :+ "directives")),
description = mapStringFieldOpt(schema, "description", path))

private def parseNamedTypeRef[In : InputUnmarshaller](in: In, path: Vector[String]) =
IntrospectionNamedTypeRef(mapStringFieldOpt(in, "kind", path) map TypeKind.fromString getOrElse TypeKind.Object, mapStringField(in, "name", path))
Expand Down
3 changes: 2 additions & 1 deletion src/main/scala/sangria/introspection/model.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ case class IntrospectionSchema(
mutationType: Option[IntrospectionNamedTypeRef],
subscriptionType: Option[IntrospectionNamedTypeRef],
types: Seq[IntrospectionType],
directives: Seq[IntrospectionDirective]
directives: Seq[IntrospectionDirective],
description: Option[String]
) {
def toAst = SchemaRenderer.schemaAstFromIntrospection(this)
def toAst(filter: SchemaFilter): Document = SchemaRenderer.schemaAstFromIntrospection(this, filter)
Expand Down
188 changes: 97 additions & 91 deletions src/main/scala/sangria/introspection/package.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sangria

import sangria.parser.QueryParser
import sangria.parser.DeliveryScheme.Throw
import sangria.schema._

import scala.util.Success
Expand Down Expand Up @@ -277,6 +278,7 @@ package object introspection {
"server. It exposes all available types and directives on " +
"the server, as well as the entry points for query, mutation, and subscription operations.",
fields = List[Field[Unit, Schema[Any, Any]]](
Field("description", OptionType(StringType), resolve = _.value.description),
Field("types", ListType(__Type), Some("A list of all types supported by this server."),
resolve = _.value.typeList map (true _)),
Field("queryType", __Type, Some("The type that query operations will be rooted at."),
Expand Down Expand Up @@ -320,95 +322,99 @@ package object introspection {
val IntrospectionTypesByName: Map[String, Type with Named] =
IntrospectionTypes.groupBy(_.name).mapValues(_.head)

lazy val Success(introspectionQuery) = QueryParser.parse(
"""
|query IntrospectionQuery {
| __schema {
| queryType { name }
| mutationType { name }
| subscriptionType { name }
| types {
| ...FullType
| }
| directives {
| name
| description
| locations
| args {
| ...InputValue
| }
| }
| }
|}
|fragment FullType on __Type {
| kind
| name
| description
| fields(includeDeprecated: true) {
| name
| description
| args {
| ...InputValue
| }
| type {
| ...TypeRef
| }
| isDeprecated
| deprecationReason
| }
| inputFields {
| ...InputValue
| }
| interfaces {
| ...TypeRef
| }
| enumValues(includeDeprecated: true) {
| name
| description
| isDeprecated
| deprecationReason
| }
| possibleTypes {
| ...TypeRef
| }
|}
|fragment InputValue on __InputValue {
| name
| description
| type { ...TypeRef }
| defaultValue
|}
|fragment TypeRef on __Type {
| kind
| name
| ofType {
| kind
| name
| ofType {
| kind
| name
| ofType {
| kind
| name
| ofType {
| kind
| name
| ofType {
| kind
| name
| ofType {
| kind
| name
| ofType {
| kind
| name
| }
| }
| }
| }
| }
| }
| }
|}
""".stripMargin)
def introspectionQuery: ast.Document = introspectionQuery()

def introspectionQuery(schemaDescription: Boolean = true): ast.Document =
QueryParser.parse(introspectionQueryString(schemaDescription))

def introspectionQueryString(schemaDescription: Boolean = true): String =
s"""query IntrospectionQuery {
| __schema {
| queryType { name }
| mutationType { name }
| subscriptionType { name }
| types {
| ...FullType
| }
| directives {
| name
| description
| locations
| args {
| ...InputValue
| }
| }
| ${if (schemaDescription) "description" else ""}
| }
|}
|fragment FullType on __Type {
| kind
| name
| description
| fields(includeDeprecated: true) {
| name
| description
| args {
| ...InputValue
| }
| type {
| ...TypeRef
| }
| isDeprecated
| deprecationReason
| }
| inputFields {
| ...InputValue
| }
| interfaces {
| ...TypeRef
| }
| enumValues(includeDeprecated: true) {
| name
| description
| isDeprecated
| deprecationReason
| }
| possibleTypes {
| ...TypeRef
| }
|}
|fragment InputValue on __InputValue {
| name
| description
| type { ...TypeRef }
| defaultValue
|}
|fragment TypeRef on __Type {
| kind
| name
| ofType {
| kind
| name
| ofType {
| kind
| name
| ofType {
| kind
| name
| ofType {
| kind
| name
| ofType {
| kind
| name
| ofType {
| kind
| name
| ofType {
| kind
| name
| }
| }
| }
| }
| }
| }
| }
|}""".stripMargin
}
4 changes: 2 additions & 2 deletions src/main/scala/sangria/macros/AstLiftable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ trait AstLiftable {

case DirectiveDefinition(n, a, l, desc, c, p)
q"_root_.sangria.ast.DirectiveDefinition($n, $a, $l, $desc, $c, $p)"
case SchemaDefinition(o, d, c, tc, p)
q"_root_.sangria.ast.SchemaDefinition($o, $d, $c, $tc, $p)"
case SchemaDefinition(o, d, desc, c, tc, p)
q"_root_.sangria.ast.SchemaDefinition($o, $d, $desc, $c, $tc, $p)"

case ObjectTypeExtensionDefinition(n, i, f, d, c, tc, p)
q"_root_.sangria.ast.ObjectTypeExtensionDefinition($n, $i, $f, $d, $c, $tc, $p)"
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/sangria/parser/QueryParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,8 @@ trait TypeSystemDefinitions { this: Parser with Tokens with Ignored with Directi
}

def SchemaDefinition = rule {
Comments ~ trackPos ~ schema ~ (DirectivesConst.? ~> (_ getOrElse Vector.empty)) ~ wsNoComment('{') ~ OperationTypeDefinition.+ ~ Comments ~ wsNoComment('}') ~> (
(comment, location, dirs, ops, tc) ast.SchemaDefinition(ops.toVector, dirs, comment, tc, location))
Description ~ Comments ~ trackPos ~ schema ~ (DirectivesConst.? ~> (_ getOrElse Vector.empty)) ~ wsNoComment('{') ~ OperationTypeDefinition.+ ~ Comments ~ wsNoComment('}') ~> (
(descr, comment, location, dirs, ops, tc) ast.SchemaDefinition(ops.toVector, dirs, descr, comment, tc, location))
}

def OperationTypeDefinition = rule {
Expand Down
10 changes: 3 additions & 7 deletions src/main/scala/sangria/renderer/QueryRenderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -573,13 +573,9 @@ object QueryRenderer {
case dl @ DirectiveLocation(name, _, _)
renderComment(dl, prev, indent, config) + indent.str + name

case sd @ SchemaDefinition(ops, dirs, _, _, _)
val renderedOps = ops.zipWithIndex map { case (op, idx)
(if (idx != 0 && shouldRenderComment(op, None, config)) config.lineBreak else "") +
renderNode(op, config, indent.inc)
} mkString config.mandatoryLineBreak

renderComment(sd, prev, indent, config) +
case sd @ SchemaDefinition(ops, dirs, description, _, _, _)
renderDescription(sd, prev, indent, config) +
renderComment(sd, description orElse prev, indent, config) +
indent.str + "schema" + config.separator +
renderDirs(dirs, config, indent) +
renderOperationTypeDefinitions(ops, sd, indent, config)
Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/sangria/renderer/SchemaRenderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -170,18 +170,18 @@ object SchemaRenderer {
val withMutation = schema.mutationType.fold(withQuery)(t withQuery :+ ast.OperationTypeDefinition(ast.OperationType.Mutation, ast.NamedType(t.name)))
val withSubs = schema.subscriptionType.fold(withMutation)(t withMutation :+ ast.OperationTypeDefinition(ast.OperationType.Subscription, ast.NamedType(t.name)))

Some(ast.SchemaDefinition(withSubs))
Some(ast.SchemaDefinition(withSubs, description = renderDescription(schema.description)))
}

private def renderSchemaDefinition(schema: Schema[_, _]): Option[ast.SchemaDefinition] =
if (isSchemaOfCommonNames(schema.query.name, schema.mutation.map(_.name), schema.subscription.map(_.name)))
if (isSchemaOfCommonNames(schema.query.name, schema.mutation.map(_.name), schema.subscription.map(_.name)) && schema.description.isEmpty && schema.astDirectives.isEmpty)
None
else {
val withQuery = Vector(ast.OperationTypeDefinition(ast.OperationType.Query, ast.NamedType(schema.query.name)))
val withMutation = schema.mutation.fold(withQuery)(t withQuery :+ ast.OperationTypeDefinition(ast.OperationType.Mutation, ast.NamedType(t.name)))
val withSubs = schema.subscription.fold(withMutation)(t withMutation :+ ast.OperationTypeDefinition(ast.OperationType.Subscription, ast.NamedType(t.name)))

Some(ast.SchemaDefinition(withSubs, schema.astDirectives))
Some(ast.SchemaDefinition(withSubs, schema.astDirectives, renderDescription(schema.description)))
}

private def isSchemaOfCommonNames(query: String, mutation: Option[String], subscription: Option[String]) =
Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/sangria/schema/AstSchemaBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ class DefaultAstSchemaBuilder[Ctx] extends AstSchemaBuilder[Ctx] {
mutation = mutationType,
subscription = subscriptionType,
additionalTypes = additionalTypes,
description = definition.flatMap(_.description.map(_.value)),
directives = directives,
astDirectives = definition.fold(Vector.empty[ast.Directive])(_.directives) ++ extensions.flatMap(_.directives),
astNodes = Vector(mat.document) ++ extensions ++ definition.toVector)
Expand All @@ -340,6 +341,7 @@ class DefaultAstSchemaBuilder[Ctx] extends AstSchemaBuilder[Ctx] {
subscription = subscriptionType,
additionalTypes = additionalTypes,
directives = directives,
description = originalSchema.description,
validationRules = originalSchema.validationRules,
astDirectives = originalSchema.astDirectives ++ extensions.flatMap(_.directives),
astNodes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ class DefaultIntrospectionSchemaBuilder[Ctx] extends IntrospectionSchemaBuilder[
mutation = mutationType,
subscription = subscriptionType,
additionalTypes = additionalTypes,
directives = directives)
directives = directives,
description = definition.description)

def buildObjectType(
definition: IntrospectionObjectType,
Expand Down
10 changes: 7 additions & 3 deletions src/main/scala/sangria/schema/Schema.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,12 @@ sealed trait MappedAbstractType[T] extends Type with AbstractType with OutputTyp
sealed trait NullableType
sealed trait UnmodifiedType

sealed trait Named {
def name: String
sealed trait HasDescription {
def description: Option[String]
}

sealed trait Named extends HasDescription {
def name: String

def rename(newName: String): this.type
}
Expand Down Expand Up @@ -756,10 +759,11 @@ case class Schema[Ctx, Val](
mutation: Option[ObjectType[Ctx, Val]] = None,
subscription: Option[ObjectType[Ctx, Val]] = None,
additionalTypes: List[Type with Named] = Nil,
description: Option[String] = None,
directives: List[Directive] = BuiltinDirectives,
validationRules: List[SchemaValidationRule] = SchemaValidationRule.default,
astDirectives: Vector[ast.Directive] = Vector.empty,
astNodes: Vector[ast.AstNode] = Vector.empty) extends HasAstInfo {
astNodes: Vector[ast.AstNode] = Vector.empty) extends HasAstInfo with HasDescription {
def extend(document: ast.Document, builder: AstSchemaBuilder[Ctx] = AstSchemaBuilder.default[Ctx]): Schema[Ctx, Val] =
AstSchemaMaterializer.extendSchema(this, document, builder)

Expand Down
Loading

0 comments on commit 343d7a5

Please sign in to comment.