Skip to content

Commit

Permalink
Fragment applicability by possible type intersection
Browse files Browse the repository at this point in the history
  • Loading branch information
umazalakain committed Apr 10, 2024
1 parent 830bfc5 commit 735d231
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 12 deletions.
18 changes: 7 additions & 11 deletions modules/core/src/main/scala/compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,7 @@ object QueryCompiler {
f <- Elab.fragment(nme)
ctpe = c.tpe.underlyingNamed
subtpe <- Elab.liftR(s.definition(f.tpnme).toResult(s"Unknown type '${f.tpnme}' in type condition of fragment '$nme'"))
_ <- Elab.failure(s"Fragment '$nme' is not compatible with type '${c.tpe}'").whenA(!fragmentApplies(subtpe, ctpe))
_ <- Elab.failure(s"Fragment '$nme' is not compatible with type '${c.tpe}'").whenA(!fragmentApplies(s, subtpe, ctpe))
_ <- Elab.push(c.asType(subtpe), f.child)
ec <- transform(f.child)
_ <- Elab.pop
Expand All @@ -999,7 +999,7 @@ object QueryCompiler {
case Some(tpnme) =>
Elab.liftR(s.definition(tpnme).toResult(s"Unknown type '$tpnme' in type condition inline fragment"))
}
_ <- Elab.failure(s"Inline fragment with type condition '$subtpe' is not compatible with type '$ctpe'").whenA(!fragmentApplies(subtpe, ctpe))
_ <- Elab.failure(s"Inline fragment with type condition '$subtpe' is not compatible with type '$ctpe'").whenA(!fragmentApplies(s, subtpe, ctpe))
_ <- Elab.push(c.asType(subtpe), child)
ec <- transform(child)
_ <- Elab.pop
Expand All @@ -1014,15 +1014,11 @@ object QueryCompiler {
/**
* Tests the supplied type condition is satisfied by the supplied context type
*/
def fragmentApplies(typeCond: NamedType, ctpe: NamedType): Boolean =
(typeCond.dealias, ctpe.dealias) match {
case (u: UnionType, _) =>
u.members.exists(m => fragmentApplies(m, ctpe))
case (_, u: UnionType) =>
u.members.exists(m => fragmentApplies(typeCond, m))
case _ =>
typeCond <:< ctpe || ctpe <:< typeCond
}
def fragmentApplies(schema: Schema, typeCond: NamedType, ctpe: NamedType): Boolean = {
val typeCondPoss = schema.getPossibleTypes(typeCond)
val ctpePoss = schema.getPossibleTypes(ctpe.dealias)
typeCondPoss.exists(x => ctpePoss.exists(y => x =:= y))
}

def elaborateBinding(b: Binding, vars: Vars): Elab[Binding] =
Elab.liftR(Value.elaborateValue(b.value, vars).map(ev => b.copy(value = ev)))
Expand Down
17 changes: 16 additions & 1 deletion modules/core/src/main/scala/schema.scala
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,17 @@ trait Schema {
case _ => schemaType
}
}

def getPossibleTypes: NamedType => Set[NamedType] = {
case x: ObjectType => Set(x)
case x: InterfaceType => getSubtypingObjectTypes(x)
case x: UnionType => x.members.toSet
case _ => Set.empty
}

def getSubtypingObjectTypes(interface: InterfaceType): Set[NamedType] =
types.filter(_.isObject).filter(_ <:< interface).toSet

}

object Schema {
Expand Down Expand Up @@ -575,6 +586,8 @@ sealed trait Type extends Product {

def isUnion: Boolean = false

def isObject: Boolean = false

def /(pathElement: String): Path =
Path.from(this) / pathElement

Expand Down Expand Up @@ -784,7 +797,9 @@ case class ObjectType(
fields: List[Field],
interfaces: List[NamedType],
directives: List[Directive]
) extends TypeWithFields
) extends TypeWithFields {
override def isObject: Boolean = true
}

/**
* Object extensions allow additional fields to be added to a pre-existing object type
Expand Down

0 comments on commit 735d231

Please sign in to comment.