Skip to content
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

Schema validation: interfaces #229 #243

Merged
61 changes: 58 additions & 3 deletions core/src/main/scala/caliban/validation/Validator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ object Validator {
def validateSchema(rootType: RootType): IO[ValidationError, Unit] =
IO.foreach(rootType.types.values) { t =>
t.kind match {
case __TypeKind.ENUM => validateEnum(t)
case __TypeKind.UNION => validateUnion(t)
case _ => IO.unit
case __TypeKind.ENUM => validateEnum(t)
case __TypeKind.UNION => validateUnion(t)
case __TypeKind.INTERFACE => validateInterface(t)
case _ => IO.unit
}
}
.unit
Expand Down Expand Up @@ -563,6 +564,60 @@ object Validator {
)
}

private def validateInterface(t: __Type): IO[ValidationError, Unit] = {
def validateName(name: String) = {
if (name.isEmpty) {
IO.fail(ValidationError("msg", "explanatory"))
} else if (name.startsWith("__")) {
IO.fail(ValidationError("msg", "explanatory"))
} else {
IO.unit
}
}
def validateFieldName(field: __Field): IO[ValidationError, Unit] = {
validateName(field.name)
}
def validateFieldArgumentsName(args: List[__InputValue]): IO[ValidationError, Unit] = {
IO.foreach(args){ arg => validateName(arg.name) }.unit
}

def validateFieldReturnOutputType(`type`: () => __Type): IO[ValidationError, Unit] = IO.unit
def validateFieldArgumentsInputType(args: List[__InputValue]): IO[ValidationError, Unit] = IO.unit

def validateInterfaceField(field: __Field): IO[ValidationError, Unit] =
for {
_ <- validateFieldName(field)
_ <- validateFieldReturnOutputType(field.`type`)
_ <- validateFieldArgumentsName(field.args)
_ <- validateFieldArgumentsInputType(field.args)
} yield ()

def duplicateFieldName(fields: List[__Field]): Option[__Field] =
fields.groupBy(_.name).collectFirst { case (_, f :: _ :: _) => f }

t.fields(__DeprecatedArgs(Some(true))) match {
case None | Some(Nil) =>
IO.fail(
ValidationError(
s"message",
"explanatory"
)
)
case Some(fields) =>
duplicateFieldName(fields) match {
case Some(value) =>
IO.fail(
ValidationError(
s"message with $value",
"explanatory"
)
)
case None =>
IO.foreach(fields){ validateInterfaceField }.unit
}
}
}

private def validateUnion(t: __Type): IO[ValidationError, Unit] = {

def isObject(t: __Type): Boolean = t.kind match {
Expand Down