Closed jmpicnic closed 5 years ago
Hi @jmpicnic Thanks for the kind words 😄
As I mentioned (briefly) here, any type you pass as an argument needs an instance of the ArgBuilder
typeclass, which defines how to turn an input GraphQL Value
into an actual value of that type.
In your case let's say you pass the enum as a String
:
implicit val thingTypeArgBuilder: ArgBuilder[ThingType] = {
case Value.StringValue(value) =>
Task(ThingType.withName(value)).mapError(ex => ExecutionError(s"Invalid input received for ThingType", Some(ex)))
case other => IO.fail(ExecutionError(s"Can't build a ThingType from input $other"))
}
You could also support passing the enum as a number by adding a case Value.IntValue
.
PS: you have "name"
instead of just name
in enumSchema
.
PS2: you decided to use a Scalar for your enum, which might be okay for your needs. In case you would like to have a GraphQL Enum type, you could do something like this:
implicit val thingTypeSchema: Schema[Any, ThingType] = new Schema[Any, ThingType] {
override def toType(isInput: Boolean): __Type =
Types.makeEnum(
Some("ThingType"),
None,
ThingType.values.toList.map(v => __EnumValue(v.toString, None, isDeprecated = false, None))
)
override def resolve(value: ThingType, arguments: Map[String, Value]): ZIO[Any, ExecutionError, ResolvedValue] =
UIO(EnumValue(value.toString))
}
Might even be possible to make it generic for any Enumeration.
Thanks a lot, and thanks for the patience. I did not see that part of the doc. I focused on the CustomTypes and missed that completely.
Cheers.
With two little generic functions, it is a breeze to get them working:
import caliban.schema
def enumSchema[E <: Enumeration](name: String) = schema.Schema.scalarSchema[E#Value]("name", None, e => caliban.ResponseValue.StringValue(e.toString))
def enumArgBuilder[E <: Enumeration](e: E) : ArgBuilder[E#Value] = {
case Value.StringValue(value) =>
Task(e.withName(value)).mapError(ex => ExecutionError(s"Invalid input received for Enumeration Value", Some(ex)))
case other => IO.fail(ExecutionError(s"Can't build The enumeration ${e.getClass} value from input $other"))
}
// simply used
implicit val thingTypeSchema = enumSchema[ThingType.type]("ThingType")
implicit val thingTypeArgBuilder = enumArgBuilder(ThingType)
Thanks
Miguel
Hello,
First, kudos to an amazingly clean GQL service. Impossible to make it any better.
I am stuck with some code that users Enumerations instead of sealed traits to express Enums. It was easy enough to create a schema for Enumeration types (see below).
My question is what do I need to provide the schema to be able to use the Enum type also as an "input type" in GQL.
Simply putting it in as a field in the arguments case class is not enough (not surprising). It complains that it misses the Query Case class Schema, probably because it does not know how to marshall the input into the internal type.
Any insights on how to provide the compiler with the right info/implcits will be more than welcome. If I come up with a general approach, I'll be glad to make it available.
Thanks
The barebones example code (that does not compile) looks like:
And the compiler error:
[error] MessageQuery.scala:34:27: could not find implicit value for parameter querySchema: caliban.schema.Schema[R,com.cruxsystems.ais.service.inspection.QueryWithEnum.Query] [error] val interpreter = graphQL(RootResolver(queryService))