From 9059864d694a7e22d96dc6504524a91506dd1314 Mon Sep 17 00:00:00 2001 From: Kyri Petrou Date: Fri, 24 Nov 2023 09:04:37 +1100 Subject: [PATCH 1/4] Use ZQuery.foreach to avoid unnecessary `.map` of steps to queries --- .../scala/caliban/execution/Executor.scala | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/core/src/main/scala/caliban/execution/Executor.scala b/core/src/main/scala/caliban/execution/Executor.scala index 87a3b13409..e2e4bdc812 100644 --- a/core/src/main/scala/caliban/execution/Executor.scala +++ b/core/src/main/scala/caliban/execution/Executor.scala @@ -37,16 +37,16 @@ object Executor { val wrapPureValues = fieldWrappers.exists(_.wrapPureValues) type ExecutionQuery[+A] = ZQuery[R, ExecutionError, A] - val execution = request.operationType match { + val execution = request.operationType match { case OperationType.Query => queryExecution case OperationType.Mutation => QueryExecution.Sequential case OperationType.Subscription => QueryExecution.Sequential } - def collectAll[E, A](as: List[ZQuery[R, E, A]]): ZQuery[R, E, List[A]] = + def collectAll[In, E, A](in: List[In])(as: In => ZQuery[R, E, A]): ZQuery[R, E, List[A]] = execution match { - case QueryExecution.Sequential => ZQuery.collectAll(as) - case QueryExecution.Parallel => ZQuery.collectAllPar(as) - case QueryExecution.Batched => ZQuery.collectAllBatched(as) + case QueryExecution.Sequential => ZQuery.foreach(in)(as) + case QueryExecution.Parallel => ZQuery.foreachPar(in)(as) + case QueryExecution.Batched => ZQuery.foreachBatched(in)(as) } def reduceStep( @@ -172,40 +172,40 @@ object Executor { } def makeObjectQuery(steps: List[(String, ReducedStep[R], FieldInfo)]) = { - var resolved: mutable.HashMap[String, ResponseValue] = null + def newMap() = new mutable.HashMap[String, ResponseValue]((steps.size / 0.75d).toInt + 1, 0.75d) - val queries = - if (wrapPureValues) steps.map((objectFieldQuery _).tupled) + var pures: mutable.HashMap[String, ResponseValue] = null + val _steps = + if (wrapPureValues) steps else { - val queries = List.newBuilder[ExecutionQuery[(String, ResponseValue)]] + val queries = List.newBuilder[(String, ReducedStep[R], FieldInfo)] var remaining = steps - while (!remaining.isEmpty) { remaining.head match { case (name, PureStep(value), _) => - if (null == resolved) resolved = new mutable.HashMap[String, ResponseValue]() - resolved.update(name, value) - case (name, step, info) => - queries += objectFieldQuery(name, step, info) + if (pures eq null) pures = newMap() + pures.update(name, value) + case step => queries += step } remaining = remaining.tail } queries.result() } - if (null == resolved) collectAll(queries).map(ObjectValue.apply) - else - collectAll(queries).map { results => + val resolved = pures // Avoids placing of var into Function1 which will convert it to ObjectRef by the Scala compiler + collectAll(_steps)((objectFieldQuery _).tupled).map { results => + if (resolved eq null) ObjectValue(results) + else { results.foreach(kv => resolved.update(kv._1, kv._2)) ObjectValue(steps.map { case (name, _, _) => name -> resolved(name) }) } + } + } def makeListQuery(steps: List[ReducedStep[R]], areItemsNullable: Boolean) = - collectAll( - if (areItemsNullable) steps.map(loop(_).catchAll(handleError)) - else steps.map(loop) - ).map(ListValue.apply) + collectAll(steps)(if (areItemsNullable) loop(_).catchAll(handleError) else loop) + .map(ListValue.apply) def loop(step: ReducedStep[R]): ExecutionQuery[ResponseValue] = step match { From 35180a48a21214b2a6676eb7073cb4aedc1e95a8 Mon Sep 17 00:00:00 2001 From: Kyri Petrou Date: Fri, 24 Nov 2023 09:07:43 +1100 Subject: [PATCH 2/4] fmt --- core/src/main/scala/caliban/execution/Executor.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/caliban/execution/Executor.scala b/core/src/main/scala/caliban/execution/Executor.scala index e2e4bdc812..cf7a01e5ce 100644 --- a/core/src/main/scala/caliban/execution/Executor.scala +++ b/core/src/main/scala/caliban/execution/Executor.scala @@ -192,7 +192,8 @@ object Executor { queries.result() } - val resolved = pures // Avoids placing of var into Function1 which will convert it to ObjectRef by the Scala compiler + val resolved = + pures // Avoids placing of var into Function1 which will convert it to ObjectRef by the Scala compiler collectAll(_steps)((objectFieldQuery _).tupled).map { results => if (resolved eq null) ObjectValue(results) else { From 603cb9e777b4ebe01940484201dd36b0d1057332 Mon Sep 17 00:00:00 2001 From: Kyri Petrou Date: Fri, 24 Nov 2023 17:56:53 +1100 Subject: [PATCH 3/4] Fix Scala 2.12 compilation --- .../main/scala/caliban/execution/Executor.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/src/main/scala/caliban/execution/Executor.scala b/core/src/main/scala/caliban/execution/Executor.scala index cf7a01e5ce..ec4f388750 100644 --- a/core/src/main/scala/caliban/execution/Executor.scala +++ b/core/src/main/scala/caliban/execution/Executor.scala @@ -172,10 +172,10 @@ object Executor { } def makeObjectQuery(steps: List[(String, ReducedStep[R], FieldInfo)]) = { - def newMap() = new mutable.HashMap[String, ResponseValue]((steps.size / 0.75d).toInt + 1, 0.75d) + def newMap() = new java.util.HashMap[String, ResponseValue](Math.ceil(steps.size / 0.75d).toInt) - var pures: mutable.HashMap[String, ResponseValue] = null - val _steps = + var pures: java.util.HashMap[String, ResponseValue] = null + val _steps = if (wrapPureValues) steps else { val queries = List.newBuilder[(String, ReducedStep[R], FieldInfo)] @@ -184,7 +184,7 @@ object Executor { remaining.head match { case (name, PureStep(value), _) => if (pures eq null) pures = newMap() - pures.update(name, value) + pures.putIfAbsent(name, value) case step => queries += step } remaining = remaining.tail @@ -192,13 +192,13 @@ object Executor { queries.result() } - val resolved = - pures // Avoids placing of var into Function1 which will convert it to ObjectRef by the Scala compiler + // Avoids placing of var into Function1 which will convert it to ObjectRef by the Scala compiler + val resolved = pures collectAll(_steps)((objectFieldQuery _).tupled).map { results => if (resolved eq null) ObjectValue(results) else { - results.foreach(kv => resolved.update(kv._1, kv._2)) - ObjectValue(steps.map { case (name, _, _) => name -> resolved(name) }) + results.foreach(kv => resolved.put(kv._1, kv._2)) + ObjectValue(steps.map { case (name, _, _) => name -> resolved.get(name) }) } } From a82b5ce660be70ade5251e2860760f858f506701 Mon Sep 17 00:00:00 2001 From: Kyri Petrou Date: Sat, 25 Nov 2023 09:59:31 +0100 Subject: [PATCH 4/4] Reuse calculateMapCapacity helper --- core/src/main/scala/caliban/execution/Executor.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/caliban/execution/Executor.scala b/core/src/main/scala/caliban/execution/Executor.scala index 40477c25f3..779a27e79f 100644 --- a/core/src/main/scala/caliban/execution/Executor.scala +++ b/core/src/main/scala/caliban/execution/Executor.scala @@ -172,7 +172,7 @@ object Executor { } def makeObjectQuery(steps: List[(String, ReducedStep[R], FieldInfo)]) = { - def newMap() = new java.util.HashMap[String, ResponseValue](Math.ceil(steps.size / 0.75d).toInt) + def newMap() = new java.util.HashMap[String, ResponseValue](calculateMapCapacity(steps.size)) var pures: java.util.HashMap[String, ResponseValue] = null val _steps =