Skip to content

Commit

Permalink
replaced simple vector path with ExecutionPath (#143)
Browse files Browse the repository at this point in the history
  • Loading branch information
OlegIlyenko committed Jun 11, 2016
1 parent 2936845 commit 523ac7d
Show file tree
Hide file tree
Showing 15 changed files with 212 additions and 171 deletions.
2 changes: 1 addition & 1 deletion src/main/scala/sangria/execution/DeprecationTracker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ object NilDeprecationTracker extends DeprecationTracker {

object PrintingDeprecationTracker extends DeprecationTracker {
def deprecatedFieldUsed[Ctx](ctx: Context[Ctx, _]) =
println(s"Deprecated field '${ctx.parentType.name}.${ctx.field.name}' used at path '${ctx.path mkString "."}'.")
println(s"Deprecated field '${ctx.parentType.name}.${ctx.field.name}' used at path '${ctx.path}'.")

def deprecatedEnumValueUsed[T, Ctx](enum: EnumType[T], value: T, userContext: Ctx) =
println(s"Deprecated enum value '$value' used of enum '${enum.name}'.")
Expand Down
41 changes: 41 additions & 0 deletions src/main/scala/sangria/execution/ExecutionPath.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package sangria.execution

import sangria.marshalling.ResultMarshaller
import sangria.ast

case class ExecutionPath private (path: Vector[Any], cacheKeyPath: ExecutionPath.PathCacheKey) {
def +(fieldName: String) = new ExecutionPath(path :+ fieldName, cacheKey :+ fieldName)
def +(field: ast.Field) = new ExecutionPath(path :+ field.outputName, cacheKey :+ field.outputName)

def isEmpty = path.isEmpty
def nonEmpty = path.nonEmpty

/**
* @return last index in the path, if available
*/
def lastIndex: Option[Int] = path.lastOption.collect {case i: Int i}

/**
* @return the size of the path excluding the indexes
*/
def size = cacheKeyPath.size

def marshal(m: ResultMarshaller): m.Node = m.arrayNode(path.map {
case s: String m.scalarNode(s, "String", Set.empty)
case i: Int m.scalarNode(i, "Int", Set.empty)
})

def cacheKey: ExecutionPath.PathCacheKey = cacheKeyPath

override def toString = path.foldLeft("") {
case ("", str: String) str
case (acc, str: String) acc + "." + str
case (acc, idx: Int) acc + "[" + idx + "]"
}
}

object ExecutionPath {
type PathCacheKey = Vector[String]

val empty = new ExecutionPath(Vector.empty, Vector.empty)
}
14 changes: 7 additions & 7 deletions src/main/scala/sangria/execution/Executor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ case class Executor[Ctx, Root](
unmarshalledVariables valueCollector.getVariableValues(operation.variables)
fieldCollector = new FieldCollector[Ctx, Root](schema, queryAst, unmarshalledVariables, queryAst.sourceMapper, valueCollector, exceptionHandler)
tpe getOperationRootType(operation, queryAst.sourceMapper)
fields fieldCollector.collectFields(Vector.empty, tpe, Vector(operation))
fields fieldCollector.collectFields(ExecutionPath.empty, tpe, Vector(operation))
} yield {
val preparedFields = fields.fields.flatMap {
case CollectedField(_, astField, Success(_))
val allFields = tpe.getField(schema, astField.name).asInstanceOf[Vector[Field[Ctx, Root]]]
val field = allFields.head
val args = valueCollector.getFieldArgumentValues(Vector(astField.name), field.arguments, astField.arguments, unmarshalledVariables)
val args = valueCollector.getFieldArgumentValues(ExecutionPath.empty + astField, field.arguments, astField.arguments, unmarshalledVariables)

args.toOption.map(PreparedField(field, _))
case _ None
Expand Down Expand Up @@ -91,7 +91,7 @@ case class Executor[Ctx, Root](
unmarshalledVariables valueCollector.getVariableValues(operation.variables)
fieldCollector = new FieldCollector[Ctx, Root](schema, queryAst, unmarshalledVariables, queryAst.sourceMapper, valueCollector, exceptionHandler)
tpe getOperationRootType(operation, queryAst.sourceMapper)
fields fieldCollector.collectFields(Vector.empty, tpe, Vector(operation))
fields fieldCollector.collectFields(ExecutionPath.empty, tpe, Vector(operation))
} yield reduceQuerySafe(fieldCollector, valueCollector, unmarshalledVariables, tpe, fields, userContext) match {
case fut: Future[Ctx]
fut.flatMap(executeOperation(queryAst, operationName, variables, um, operation, queryAst.sourceMapper, valueCollector,
Expand Down Expand Up @@ -224,12 +224,12 @@ case class Executor[Ctx, Root](
// Using mutability here locally in order to reduce footprint
import scala.collection.mutable.ListBuffer

val argumentValuesFn = (path: Vector[String], argumentDefs: List[Argument[_]], argumentAsts: List[ast.Argument])
val argumentValuesFn = (path: ExecutionPath, argumentDefs: List[Argument[_]], argumentAsts: List[ast.Argument])
valueCollector.getFieldArgumentValues(path, argumentDefs, argumentAsts, variables)

val initialValues: Vector[Any] = reducers map (_.initial)

def loop(path: Vector[String], tpe: OutputType[_], astFields: Vector[ast.Field]): Seq[Any] =
def loop(path: ExecutionPath, tpe: OutputType[_], astFields: Vector[ast.Field]): Seq[Any] =
tpe match {
case OptionType(ofType) loop(path, ofType, astFields)
case ListType(ofType) loop(path, ofType, astFields)
Expand All @@ -240,7 +240,7 @@ case class Executor[Ctx, Root](
case (acc, CollectedField(_, _, Success(fields))) if objTpe.getField(schema, fields.head.name).nonEmpty
val astField = fields.head
val field = objTpe.getField(schema, astField.name).head
val newPath = path :+ astField.outputName
val newPath = path + astField
val childReduced = loop(newPath, field.fieldType, fields)

for (i reducers.indices) {
Expand Down Expand Up @@ -278,7 +278,7 @@ case class Executor[Ctx, Root](
case (acc, CollectedField(_, _, Success(astFields))) if rootTpe.getField(schema, astFields.head.name).nonEmpty =>
val astField = astFields.head
val field = rootTpe.getField(schema, astField.name).head
val path = Vector(astField.outputName)
val path = ExecutionPath.empty + astField
val childReduced = loop(path, field.fieldType, astFields)

for (i reducers.indices) {
Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/sangria/execution/FieldCollector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ class FieldCollector[Ctx, Val](
valueCollector: ValueCollector[Ctx, _],
exceptionHandler: Executor.ExceptionHandler) {

private val resultCache = TrieMap[(Vector[String], String), Try[CollectedFields]]()
private val resultCache = TrieMap[(ExecutionPath.PathCacheKey, String), Try[CollectedFields]]()

def collectFields(path: Vector[String], tpe: ObjectType[Ctx, _], selections: Vector[ast.SelectionContainer]): Try[CollectedFields] =
resultCache.getOrElseUpdate(path tpe.name, {
def collectFields(path: ExecutionPath, tpe: ObjectType[Ctx, _], selections: Vector[ast.SelectionContainer]): Try[CollectedFields] =
resultCache.getOrElseUpdate(path.cacheKey tpe.name, {
val builder: Try[CollectedFieldsBuilder] = Success(new CollectedFieldsBuilder)

selections.foldLeft(builder) {
Expand Down
24 changes: 12 additions & 12 deletions src/main/scala/sangria/execution/QueryReducer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@ trait QueryReducer[-Ctx, +Out] {
def reduceField[Val](
fieldAcc: Acc,
childrenAcc: Acc,
path: Vector[String],
path: ExecutionPath,
ctx: Ctx,
astFields: Vector[ast.Field],
parentType: ObjectType[Out, Val] @uncheckedVariance,
field: Field[Ctx, Val] @uncheckedVariance,
argumentValuesFn: (Vector[String], List[Argument[_]], List[ast.Argument]) Try[Args]): Acc
argumentValuesFn: (ExecutionPath, List[Argument[_]], List[ast.Argument]) Try[Args]): Acc

def reduceScalar[T](
path: Vector[String],
path: ExecutionPath,
ctx: Ctx,
tpe: ScalarType[T]): Acc

def reduceEnum[T](
path: Vector[String],
path: ExecutionPath,
ctx: Ctx,
tpe: EnumType[T]): Acc

Expand Down Expand Up @@ -60,12 +60,12 @@ class MeasureComplexity[Ctx](action: (Double, Ctx) ⇒ ReduceAction[Ctx, Ctx]) e
def reduceField[Val](
fieldAcc: Acc,
childrenAcc: Acc,
path: Vector[String],
path: ExecutionPath,
ctx: Ctx,
astFields: Vector[ast.Field],
parentType: ObjectType[Ctx, Val],
field: Field[Ctx, Val],
argumentValuesFn: (Vector[String], List[Argument[_]], List[ast.Argument]) Try[Args]): Acc = {
argumentValuesFn: (ExecutionPath, List[Argument[_]], List[ast.Argument]) Try[Args]): Acc = {
val estimate = field.complexity match {
case Some(fn)
argumentValuesFn(path, field.arguments, astFields.head.arguments) match {
Expand All @@ -79,12 +79,12 @@ class MeasureComplexity[Ctx](action: (Double, Ctx) ⇒ ReduceAction[Ctx, Ctx]) e
}

def reduceScalar[T](
path: Vector[String],
path: ExecutionPath,
ctx: Ctx,
tpe: ScalarType[T]): Acc = tpe.complexity

def reduceEnum[T](
path: Vector[String],
path: ExecutionPath,
ctx: Ctx,
tpe: EnumType[T]): Acc = initial

Expand All @@ -106,21 +106,21 @@ class TagCollector[Ctx, T](tagMatcher: PartialFunction[FieldTag, T], action: (Se
def reduceField[Val](
fieldAcc: Acc,
childrenAcc: Acc,
path: Vector[String],
path: ExecutionPath,
ctx: Ctx,
astFields: Vector[ast.Field],
parentType: ObjectType[Ctx, Val],
field: Field[Ctx, Val],
argumentValuesFn: (Vector[String], List[Argument[_]], List[ast.Argument]) Try[Args]): Acc =
argumentValuesFn: (ExecutionPath, List[Argument[_]], List[ast.Argument]) Try[Args]): Acc =
fieldAcc ++ childrenAcc ++ field.tags.collect {case t if tagMatcher.isDefinedAt(t) tagMatcher(t)}

def reduceScalar[ST](
path: Vector[String],
path: ExecutionPath,
ctx: Ctx,
tpe: ScalarType[ST]): Acc = initial

def reduceEnum[ET](
path: Vector[String],
path: ExecutionPath,
ctx: Ctx,
tpe: EnumType[ET]): Acc = initial

Expand Down
Loading

0 comments on commit 523ac7d

Please sign in to comment.