Skip to content

Commit

Permalink
Merge pull request #981 from filosganga/567-interface-implement-inter…
Browse files Browse the repository at this point in the history
…face

Add support for interface implementing interface
  • Loading branch information
yanns authored Mar 30, 2023
2 parents 7970fa7 + 732dfc8 commit 011f3d2
Show file tree
Hide file tree
Showing 22 changed files with 1,062 additions and 108 deletions.
56 changes: 54 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,43 @@ lazy val ast = project
ProblemFilters.exclude[DirectMissingMethodProblem]("sangria.ast.DirectiveDefinition.apply"),
ProblemFilters.exclude[DirectMissingMethodProblem]("sangria.ast.DirectiveDefinition.copy"),
ProblemFilters.exclude[DirectMissingMethodProblem]("sangria.ast.DirectiveDefinition.this"),
ProblemFilters.exclude[MissingTypesProblem]("sangria.ast.DirectiveDefinition$")
ProblemFilters.exclude[MissingTypesProblem]("sangria.ast.DirectiveDefinition$"),
ProblemFilters.exclude[IncompatibleResultTypeProblem](
"sangria.introspection.IntrospectionInterfaceType.*"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.introspection.IntrospectionInterfaceType.this"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.introspection.IntrospectionInterfaceType.copy"),
ProblemFilters.exclude[MissingTypesProblem]("sangria.ast.InterfaceTypeDefinition$"),
ProblemFilters.exclude[IncompatibleResultTypeProblem](
"sangria.ast.InterfaceTypeDefinition.*"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.ast.InterfaceTypeDefinition.this"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.ast.InterfaceTypeDefinition.copy"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.ast.InterfaceTypeDefinition.tupled"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.ast.InterfaceTypeDefinition.curried"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.ast.InterfaceTypeDefinition.<init>*"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.ast.InterfaceTypeDefinition.apply$default$*"),
ProblemFilters.exclude[MissingTypesProblem]("sangria.ast.InterfaceTypeExtensionDefinition$"),
ProblemFilters.exclude[IncompatibleResultTypeProblem](
"sangria.ast.InterfaceTypeExtensionDefinition.*"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.ast.InterfaceTypeExtensionDefinition.this"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.ast.InterfaceTypeExtensionDefinition.copy"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.ast.InterfaceTypeExtensionDefinition.tupled"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.ast.InterfaceTypeExtensionDefinition.curried"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.ast.InterfaceTypeExtensionDefinition.<init>*"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.ast.InterfaceTypeExtensionDefinition.apply$default$*")
),
apiURL := {
val ver = CrossVersion.binaryScalaVersion(scalaVersion.value)
Expand Down Expand Up @@ -140,7 +176,23 @@ lazy val core = project
ProblemFilters.exclude[DirectMissingMethodProblem]("sangria.schema.Field.subs"),
ProblemFilters.exclude[DirectMissingMethodProblem]("sangria.schema.Field.apply"),
ProblemFilters.exclude[DirectMissingMethodProblem]("sangria.execution.Resolver.*"),
ProblemFilters.exclude[DirectMissingMethodProblem]("sangria.execution.Resolver#*")
ProblemFilters.exclude[DirectMissingMethodProblem]("sangria.execution.Resolver#*"),
ProblemFilters.exclude[ReversedMissingMethodProblem](
"sangria.schema.AstSchemaBuilder.buildInterfaceType"),
ProblemFilters.exclude[ReversedMissingMethodProblem](
"sangria.schema.AstSchemaBuilder.extendInterfaceType"),
ProblemFilters.exclude[ReversedMissingMethodProblem](
"sangria.schema.IntrospectionSchemaBuilder.buildInterfaceType"),
ProblemFilters.exclude[MissingTypesProblem](
"sangria.introspection.IntrospectionInterfaceType$"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.introspection.IntrospectionInterfaceType.this"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.introspection.IntrospectionInterfaceType.tupled"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.introspection.IntrospectionInterfaceType.curried"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"sangria.introspection.IntrospectionInterfaceType.copy")
),
Test / testOptions += Tests.Argument(TestFrameworks.ScalaTest, "-oF"),
libraryDependencies ++= Seq(
Expand Down
45 changes: 45 additions & 0 deletions modules/ast/src/main/scala/sangria/ast/QueryAst.scala
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ case class ObjectTypeDefinition(
case class InterfaceTypeDefinition(
name: String,
fields: Vector[FieldDefinition],
interfaces: Vector[NamedType],
directives: Vector[Directive] = Vector.empty,
description: Option[StringValue] = None,
comments: Vector[Comment] = Vector.empty,
Expand All @@ -541,6 +542,27 @@ case class InterfaceTypeDefinition(
def rename(newName: String): InterfaceTypeDefinition = copy(name = newName)
}

object InterfaceTypeDefinition {

def apply(
name: String,
fields: Vector[FieldDefinition],
directives: Vector[Directive],
description: Option[StringValue],
comments: Vector[Comment],
trailingComments: Vector[Comment],
location: Option[AstLocation]): InterfaceTypeDefinition = new InterfaceTypeDefinition(
name,
fields,
Vector.empty,
directives,
description,
comments,
trailingComments,
location
)
}

/** @group typesystem
*/
case class UnionTypeDefinition(
Expand Down Expand Up @@ -619,15 +641,38 @@ case class ObjectTypeExtensionDefinition(
case class InterfaceTypeExtensionDefinition(
name: String,
fields: Vector[FieldDefinition],
interfaces: Vector[NamedType],
directives: Vector[Directive] = Vector.empty,
comments: Vector[Comment] = Vector.empty,
trailingComments: Vector[Comment] = Vector.empty,
location: Option[AstLocation] = None)
extends ObjectLikeTypeExtensionDefinition
with WithTrailingComments {

def rename(newName: String): InterfaceTypeExtensionDefinition = copy(name = newName)
}

object InterfaceTypeExtensionDefinition {

def apply(
name: String,
fields: Vector[FieldDefinition],
directives: Vector[Directive],
comments: Vector[Comment],
trailingComments: Vector[Comment],
location: Option[AstLocation]): InterfaceTypeExtensionDefinition =
InterfaceTypeExtensionDefinition(
name,
fields,
Vector.empty,
directives,
comments,
trailingComments,
location
)

}

/** @group typesystem
*/
case class InputObjectTypeExtensionDefinition(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ trait AstLiftable {

case ObjectTypeExtensionDefinition(n, i, f, d, c, tc, p) =>
q"_root_.sangria.ast.ObjectTypeExtensionDefinition($n, $i, $f, $d, $c, $tc, $p)"
case InterfaceTypeExtensionDefinition(n, f, d, c, tc, p) =>
q"_root_.sangria.ast.InterfaceTypeExtensionDefinition($n, $f, $d, $c, $tc, $p)"
case InterfaceTypeExtensionDefinition(n, f, i, d, c, tc, p) =>
q"_root_.sangria.ast.InterfaceTypeExtensionDefinition($n, $f, $i, $d, $c, $tc, $p)"
case InputObjectTypeExtensionDefinition(n, f, d, c, tc, p) =>
q"_root_.sangria.ast.InputObjectTypeExtensionDefinition($n, $f, $d, $c, $tc, $p)"
case UnionTypeExtensionDefinition(n, t, d, c, p) =>
Expand All @@ -97,8 +97,8 @@ trait AstLiftable {
q"_root_.sangria.ast.EnumTypeDefinition($n, $v, $d, $desc, $c, $tc, $p)"
case InputObjectTypeDefinition(n, f, d, desc, c, tc, p) =>
q"_root_.sangria.ast.InputObjectTypeDefinition($n, $f, $d, $desc, $c, $tc, $p)"
case InterfaceTypeDefinition(n, f, d, desc, c, tc, p) =>
q"_root_.sangria.ast.InterfaceTypeDefinition($n, $f, $d, $desc, $c, $tc, $p)"
case InterfaceTypeDefinition(n, f, i, d, desc, c, tc, p) =>
q"_root_.sangria.ast.InterfaceTypeDefinition($n, $f, $i, $d, $desc, $c, $tc, $p)"
case ObjectTypeDefinition(n, i, f, d, desc, c, tc, p) =>
q"_root_.sangria.ast.ObjectTypeDefinition($n, $i, $f, $d, $desc, $c, $tc, $p)"
case ScalarTypeDefinition(n, d, desc, c, p) =>
Expand Down
12 changes: 8 additions & 4 deletions modules/core/src/main/scala-3/sangria/macros/ToExprGivens.scala
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 +158,17 @@ trait ToExprGivens {
${ Expr(tc) },
${ Expr(p) })
}
case InterfaceTypeExtensionDefinition(n, f, d, c, tc, p) =>
case InterfaceTypeExtensionDefinition(n, f, i, d, c, tc, p) =>
'{
sangria.ast.InterfaceTypeExtensionDefinition(
${ Expr(n) },
${ Expr(f) },
${ Expr(i) },
${ Expr(d) },
${ Expr(c) },
${ Expr(tc) },
${ Expr(p) })
${ Expr(p) }
)
}
case InputObjectTypeExtensionDefinition(n, f, d, c, tc, p) =>
'{
Expand Down Expand Up @@ -237,16 +239,18 @@ trait ToExprGivens {
${ Expr(tc) },
${ Expr(p) })
}
case InterfaceTypeDefinition(n, f, d, desc, c, tc, p) =>
case InterfaceTypeDefinition(n, f, i, d, desc, c, tc, p) =>
'{
sangria.ast.InterfaceTypeDefinition(
${ Expr(n) },
${ Expr(f) },
${ Expr(i) },
${ Expr(d) },
${ Expr(desc) },
${ Expr(c) },
${ Expr(tc) },
${ Expr(p) })
${ Expr(p) }
)
}
case ObjectTypeDefinition(n, i, f, d, desc, c, tc, p) =>
'{
Expand Down
5 changes: 4 additions & 1 deletion modules/core/src/main/scala/sangria/ast/AstVisitor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -306,12 +306,14 @@ object AstVisitor {
case n @ InterfaceTypeDefinition(
_,
fields,
interfaces,
dirs,
description,
comment,
trailingComments,
_) =>
if (breakOrSkip(onEnter(n))) {
interfaces.foreach(d => loop(d))
fields.foreach(d => loop(d))
dirs.foreach(d => loop(d))
description.foreach(s => loop(s))
Expand Down Expand Up @@ -360,8 +362,9 @@ object AstVisitor {
tc.foreach(s => loop(s))
breakOrSkip(onLeave(n))
}
case n @ InterfaceTypeExtensionDefinition(_, fields, dirs, comment, tc, _) =>
case n @ InterfaceTypeExtensionDefinition(_, fields, ints, dirs, comment, tc, _) =>
if (breakOrSkip(onEnter(n))) {
ints.foreach(d => loop(d))
fields.foreach(d => loop(d))
dirs.foreach(d => loop(d))
comment.foreach(s => loop(s))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@ object IntrospectionParser {
possibleTypes = mapFieldOpt(tpe, "possibleTypes")
.map(um.getListValue)
.getOrElse(Vector.empty)
.map(i => parseNamedTypeRef(i, path :+ "possibleTypes"))
.map(i => parseNamedTypeRef(i, path :+ "possibleTypes")),
interfaces = mapFieldOpt(tpe, "interfaces")
.map(um.getListValue)
.getOrElse(Vector.empty)
.map(i => parseNamedTypeRef(i, path :+ "interfaces"))
)

private def parseUnion[In: InputUnmarshaller](tpe: In, path: Vector[String]) =
Expand Down
16 changes: 14 additions & 2 deletions modules/core/src/main/scala/sangria/introspection/model.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,21 @@ case class IntrospectionInterfaceType(
name: String,
description: Option[String],
fields: Seq[IntrospectionField],
possibleTypes: Seq[IntrospectionNamedTypeRef])
extends IntrospectionType {
interfaces: Seq[IntrospectionNamedTypeRef],
possibleTypes: Seq[IntrospectionNamedTypeRef]
) extends IntrospectionType {

val kind = TypeKind.Interface

}

object IntrospectionInterfaceType {
def apply(
name: String,
description: Option[String],
fields: Seq[IntrospectionField],
possibleTypes: Seq[IntrospectionNamedTypeRef]): IntrospectionInterfaceType =
IntrospectionInterfaceType(name, description, fields, Seq.empty, possibleTypes)
}

case class IntrospectionUnionType(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,10 +272,8 @@ package object introspection {
"interfaces",
OptionType(ListType(__Type)),
resolve = _.value._2 match {
case t: ObjectType[_, _] =>
case t: ObjectLikeType[_, _] =>
Some(t.allInterfaces.asInstanceOf[Vector[Type]].map(true -> _))
case _: InterfaceType[_, _] =>
Some(Vector.empty)
case _ => None
}
),
Expand Down
20 changes: 14 additions & 6 deletions modules/core/src/main/scala/sangria/renderer/QueryRenderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -668,12 +668,16 @@ object QueryRenderer {
renderDirs(dirs, config, indent, frontSep = true) +
renderInputFieldDefinitions(fields, itd, indent, config, frontSep = true)

case itd @ InterfaceTypeDefinition(name, fields, dirs, description, _, _, _) =>
case itd @ InterfaceTypeDefinition(name, fields, interfaces, dirs, description, _, _, _) =>
renderDescription(itd, prev, indent, config) +
renderComment(itd, description.orElse(prev), indent, config) +
indent.str + "interface" + config.mandatorySeparator + name +
renderDirs(dirs, config, indent, frontSep = true) +
renderFieldDefinitions(fields, itd, indent, config, frontSep = true)
(if (interfaces.nonEmpty) config.mandatorySeparator else "") +
renderInterfaces(interfaces, config, indent, withSep = false) +
(if (dirs.nonEmpty) config.separator else "") +
renderDirs(dirs, config, indent, withSep = false) +
(if (fields.nonEmpty) config.separator else "") +
renderFieldDefinitions(fields, itd, indent, config)

case utd @ UnionTypeDefinition(name, types, dirs, description, _, _) =>
val typesString =
Expand Down Expand Up @@ -728,11 +732,15 @@ object QueryRenderer {
renderDirs(dirs, config, indent, withSep = fields.nonEmpty) +
renderFieldDefinitions(fields, ted, indent, config)

case ext @ InterfaceTypeExtensionDefinition(name, fields, dirs, _, _, _) =>
case ext @ InterfaceTypeExtensionDefinition(name, fields, interfaces, dirs, _, _, _) =>
renderComment(ext, prev, indent, config) +
indent.str + "extend" + config.mandatorySeparator + "interface" + config.mandatorySeparator + name +
renderDirs(dirs, config, indent, frontSep = true) +
renderFieldDefinitions(fields, ext, indent, config, frontSep = true)
(if (interfaces.nonEmpty) config.mandatorySeparator else "") +
renderInterfaces(interfaces, config, indent, withSep = false) +
(if (dirs.nonEmpty) config.separator else "") +
renderDirs(dirs, config, indent, withSep = false) +
(if (fields.nonEmpty) config.separator else "") +
renderFieldDefinitions(fields, ext, indent, config)

case ext @ UnionTypeExtensionDefinition(name, types, dirs, _, _) =>
val typesString =
Expand Down
18 changes: 16 additions & 2 deletions modules/core/src/main/scala/sangria/renderer/SchemaRenderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ object SchemaRenderer {
def renderImplementedInterfaces(tpe: IntrospectionObjectType) =
tpe.interfaces.map(t => ast.NamedType(t.name)).toVector

def renderImplementedInterfaces(tpe: IntrospectionInterfaceType) =
tpe.interfaces.map(t => ast.NamedType(t.name)).toVector

def renderImplementedInterfaces(tpe: ObjectLikeType[_, _]) =
tpe.allInterfaces.map(t => ast.NamedType(t.name))

Expand Down Expand Up @@ -217,14 +220,25 @@ object SchemaRenderer {
ast.InterfaceTypeDefinition(
tpe.name,
renderFieldsI(tpe.fields),
description = renderDescription(tpe.description))
renderImplementedInterfaces(tpe),
Vector.empty,
renderDescription(tpe.description),
Vector.empty,
Vector.empty,
None
)

def renderInterface(tpe: InterfaceType[_, _]) =
ast.InterfaceTypeDefinition(
tpe.name,
renderFields(tpe.uniqueFields),
renderImplementedInterfaces(tpe),
tpe.astDirectives,
renderDescription(tpe.description))
renderDescription(tpe.description),
Vector.empty,
Vector.empty,
None
)

def renderUnion(tpe: IntrospectionUnionType) =
ast.UnionTypeDefinition(
Expand Down
Loading

0 comments on commit 011f3d2

Please sign in to comment.