-
-
Notifications
You must be signed in to change notification settings - Fork 249
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
Fix oneOf
when multiple inputs have the same default
#2403
Conversation
When determining which subtype `ArgBuilder` to use, use the field instead of attempting to build each one. This ensures that if more than one subtype has the same default that the correct one is chosen.
After looking into this, I think there is a more fundamental issue with the ArgBuilder that is the root cause of this bug. Minimized repro with a test that should be passing but it's failing on current main test("case class with optional fields fails when input is `null`") {
case class Foo(a: Option[String])
case class Bar(foo: Foo) derives ArgBuilder.Auto
val out = ArgBuilder[Bar].build(NullValue)
assertTrue(out.isLeft)
} This is usually caught during validation, but in cases that Validation is disabled then |
Without #2323 the current Is there anything wrong with getting the exact |
There isn't something wrong with this concept (in fact, that would be the ideal approach). There was something that didn't feel right to me and took me a while to identify (that's why I didn't mention it my previous comment). The current approach works for both derived and user-defined e.g., if we were to change the definition of the implicit val fooStringAb: ArgBuilder[Foo.FooString] = new ArgBuilder[Foo.FooString] {
def build(input: InputValue): Either[ExecutionError, Foo.FooString] =
input match {
case ObjectValue(fields) if fields.contains("stringValue") =>
fields("stringValue") match {
case StringValue(value) => Right(Foo.FooString(value))
case _ => Left(ExecutionError("Expected stringValue to be a String"))
}
case _ =>
Left(ExecutionError("Expected stringValue to be present"))
}
} |
By the way I'll add a test for the above case since to make sure we don't accidentally introduce this regression in the future |
Ahh yes you could manually implement Someone could do something like this though: case class Arg1(s: String) extends Foo
object Arg1 {
implicit val argBuilder: ArgBuilder[Arg1] = {
case ObjectValue(fields) =>
fields.get("str") match {
case Some(StringValue(value)) => Right(Arg1(value))
}
}
}
}
case class Arg2(str: String) extends Foo
object Arg2 {
implicit val argBuilder: ArgBuilder[Arg2] = ArgBuilder.gen
} and never get a |
When determining which subtype
ArgBuilder
to use, use the field instead of attempting to build each one. This ensures that if more than one subtype has the same default then the correct one is chosen.