Skip to content

Commit

Permalink
Fill in error path and location when a field wrapper fails
Browse files Browse the repository at this point in the history
  • Loading branch information
ghostdogpr committed Jun 1, 2024
1 parent 73e694f commit 76e4e9a
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 12 deletions.
36 changes: 25 additions & 11 deletions core/src/main/scala/caliban/execution/Executor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -313,16 +313,6 @@ object Executor {
private def calculateMapCapacity(nMappings: Int): Int =
Math.ceil(nMappings / 0.75d).toInt

private def effectfulExecutionError(
path: List[PathValue],
locationInfo: Option[LocationInfo],
cause: Cause[Throwable]
): Cause[ExecutionError] =
cause.failureOption orElse cause.defects.headOption match {
case Some(e: ExecutionError) => Cause.fail(e.copy(path = path.reverse, locationInfo = locationInfo))
case other => Cause.fail(ExecutionError("Effect failure", path.reverse, locationInfo, other))
}

private def fieldInfo(
field: Field,
aliasedName: String,
Expand Down Expand Up @@ -394,7 +384,19 @@ object Executor {
wrappers match {
case Nil => query
case wrapper :: tail =>
val q = if (isPure && !wrapper.wrapPureValues) query else wrapper.wrap(query, fieldInfo)
val q =
if (isPure && !wrapper.wrapPureValues) query
else
wrapper
.wrap(query, fieldInfo)
.mapErrorCause(e =>
effectfulExecutionError(
PathValue.Key(fieldInfo.name) :: fieldInfo.path,
Some(fieldInfo.details.locationInfo),
e
)
)

loop(q, tail)
}
loop(query, fieldWrappers)
Expand Down Expand Up @@ -508,6 +510,18 @@ object Executor {
}
}

private def effectfulExecutionError(
path: List[PathValue],
locationInfo: Option[LocationInfo],
cause: Cause[Throwable]
): Cause[ExecutionError] =
cause.failureOption orElse cause.defects.headOption match {
case Some(e: ExecutionError) if e.path.isEmpty =>
Cause.fail(e.copy(path = path.reverse, locationInfo = locationInfo))
case Some(e: ExecutionError) => Cause.fail(e)
case other => Cause.fail(ExecutionError("Effect failure", path.reverse, locationInfo, other))
}

// The implicit classes below are for methods that don't exist in Scala 2.12 so we add them as syntax methods instead
private implicit class EnrichedListOps[+A](private val list: List[A]) extends AnyVal {
def partitionMap[A1, A2](f: A => Either[A1, A2]): (List[A1], List[A2]) = {
Expand Down
25 changes: 24 additions & 1 deletion core/src/test/scala/caliban/wrappers/WrappersSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import caliban.TestUtils._
import caliban.Value.{ IntValue, StringValue }
import caliban.execution.{ ExecutionRequest, FieldInfo }
import caliban.introspection.adt.{ __Directive, __DirectiveLocation }
import caliban.parsing.adt.{ Directive, Document }
import caliban.parsing.adt.{ Directive, Document, LocationInfo }
import caliban.schema.Annotations.GQLDirective
import caliban.schema.{ ArgBuilder, GenericSchema, Schema }
import caliban.schema.Schema.auto._
Expand Down Expand Up @@ -94,6 +94,29 @@ object WrappersSpec extends ZIOSpecDefault {
counter2 <- ref2.get
} yield assertTrue(counter1 == 4, counter2 == 1)
},
test("Failures in FieldWrapper have a path and location") {
case class Query(a: A)
case class A(b: B)
case class B(c: Int)

val wrapper = new FieldWrapper[Any](true) {
def wrap[R1 <: Any](
query: ZQuery[R1, ExecutionError, ResponseValue],
info: FieldInfo
): ZQuery[R1, ExecutionError, ResponseValue] =
if (info.name == "c") ZQuery.fail(ExecutionError("error"))
else query
}
for {
interpreter <- (graphQL(RootResolver(Query(A(B(1))))) @@ wrapper).interpreter.orDie
query = gqldoc("""{ a { b { c } } }""")
result <- interpreter.execute(query)
firstError = result.errors.head.asInstanceOf[ExecutionError]
} yield assertTrue(
firstError.path.mkString(",") == """"a","b","c"""",
firstError.locationInfo.contains(LocationInfo(11, 1))
)
},
test("Max fields") {
case class A(b: B)
case class B(c: Int)
Expand Down

0 comments on commit 76e4e9a

Please sign in to comment.