Skip to content

Commit a3fbe55

Browse files
author
Håkan Rosenhorn
committed
Moved pieces of Executor to stand alone file to reduce cluttering and size
1 parent 4c61fce commit a3fbe55

File tree

6 files changed

+177
-80
lines changed

6 files changed

+177
-80
lines changed

src/main/scala/se/uprise/graphql/execution/Executor.scala

Lines changed: 12 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ case class ExecutionResult(data: Any, errors: List[GraphQLFormattedError])
4444

4545

4646
object Executor {
47+
private val extractor = ValueExtractor
48+
4749
def apply(schema: GraphQLSchema,
4850
root: Any,
4951
ast: DocumentContext,
@@ -100,16 +102,7 @@ object Executor {
100102
true
101103
}
102104

103-
/**
104-
* Prepares an object map of argument values given a list of argument
105-
* definitions and list of argument AST nodes.
106-
*/
107-
// FIXME: Better Type for variables (guessing some decendant of InputType)
108-
def getArgumentValues(argDefs: List[universe.Type],
109-
arguments: ArgumentsContext,
110-
variables: Map[String, Any]) = {
111105

112-
}
113106

114107
/**
115108
* Resolves the field on the given source object. In particular, this
@@ -124,15 +117,16 @@ object Executor {
124117
fieldASTs: List[FieldContext]): Any = {
125118
val fieldAST = fieldASTs.head
126119

127-
val resolveFn = getFieldDef(exeContext.schema, parentType, fieldAST)
128-
val args: List[universe.Type] = resolveFn.typeSignature.typeArgs
120+
val fieldDef = getFieldDef(exeContext.schema, parentType, fieldAST)
121+
//val args: List[universe.Type] = resolveFn.typeSignature.typeArgs
129122

130123

131-
getArgumentValues(
132-
args,
124+
val args = extractor.getArgumentValues(
125+
fieldDef.args,
133126
fieldAST.arguments(),
134127
exeContext.variables)
135128

129+
// Some dynamic reflection invocation on the resolve method symbol
136130
//parentType.
137131

138132
}
@@ -158,41 +152,19 @@ object Executor {
158152
// }
159153
// }
160154

161-
def isAnnotatedWithField(candidate: reflect.runtime.universe.Symbol) = {
162-
val qlFieldAnnotationType = universe.typeOf[QLField]
163-
val annotation: Option[reflect.runtime.universe.Annotation] = candidate.annotations.find(a => a.tpe == qlFieldAnnotationType)
164-
annotation match {
165-
case Some(value) => true
166-
case _ => false
167-
}
168-
}
169-
170-
// FIXME: This being what it is we get something going, refine, cache, make performant
171-
def getFields(candidate: GraphQLObjectType) = {
172-
val typ = universe.runtimeMirror(candidate.getClass.getClassLoader).classSymbol(candidate.getClass)
173155

174-
//val typ: universe.ClassSymbol = universe.runtimeMirror(clazzType.getClassLoader).classSymbol(clazzType)
175-
176-
val members: universe.MemberScope = typ.typeSignature.members
177-
val fields = members.flatMap({ entry =>
178-
isAnnotatedWithField(entry) match {
179-
case true => Some(entry.name.toString -> entry.asMethod)
180-
case _ => None
181-
}
182-
}).toMap
183-
fields
184-
}
185156

186157
def getFieldDef(schema: GraphQLSchema,
187158
parentType: GraphQLObjectType,
188-
fieldAST: FieldContext): universe.MethodSymbol = {
159+
fieldAST: FieldContext): GraphQLFieldDefinition = {
189160
val name = fieldAST.fieldName().NAME().getText
190161

191162
//FIXME: Implement support for the introspection
192163

193164
//parentType.get
194-
195-
getFields(parentType)(name)
165+
166+
parentType.getFields(parentType)(name)
167+
//getFields(parentType)(name)
196168
}
197169

198170

@@ -362,46 +334,12 @@ object Executor {
362334
case _ => List.empty
363335
}
364336

365-
val variables = getVariableValues(schema,
337+
val variables = extractor.getVariableValues(schema,
366338
definitions,
367339
variableValues
368340
)
369341

370342
ExecutionContext(schema, fragments, root, operation, variables, errors)
371343
}
372344

373-
374-
/**
375-
* Prepares an object map of variables of the correct type based on the provided
376-
* variable definitions and arbitrary input. If the input cannot be coerced
377-
* to match the variable definitions, a GraphQLError will be thrown.
378-
*/
379-
/*
380-
FIXME: Replace Any types with proper Types resolved from the variableValues
381-
Ex: query Example($size: Int) {
382-
variableValues = { size: 100 }
383-
*/
384-
385-
def getVariableValues(schema: GraphQLSchema,
386-
definitionASTs: List[VariableDefinitionContext] = List.empty,
387-
variableValues: Map[String, String] = Map.empty): Map[String, Any] = {
388-
389-
390-
// FIXME: Implement
391-
// definitionASTs map { definition =>
392-
// val varName = definition.variable().NAME().getText
393-
// }
394-
395-
Map.empty
396-
}
397-
398-
/**
399-
* Given a variable definition, and any value of input, return a value which
400-
* adheres to the variable definition, or throw an error.
401-
*/
402-
def getVariableValue(schema: GraphQLSchema,
403-
definitionAST: VariableDefinitionContext,
404-
input: String) = {
405-
406-
}
407345
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package se.uprise.graphql.execution
2+
3+
import se.uprise.graphql.types.{GraphQLFieldArgument, GraphQLInputType, GraphQLSchema}
4+
import se.uprise.parser.GraphQlParser.{VariableDefinitionContext, ArgumentsContext}
5+
6+
import scala.reflect.runtime._
7+
import scala.collection.JavaConversions._
8+
9+
object ValueExtractor {
10+
11+
/**
12+
* Prepares an object map of argument values given a list of argument
13+
* definitions and list of argument AST nodes.
14+
*/
15+
// FIXME: Better Type for variables (guessing some decendant of InputType)
16+
def getArgumentValues(argDefs: List[GraphQLFieldArgument[_ <: GraphQLInputType]],
17+
arguments: ArgumentsContext,
18+
variables: Map[String, Any]) = {
19+
20+
21+
//val finalResults = fields.keys.foldLeft(Map[String, Any]())((results: Map[String, Any], responseName) => {
22+
23+
// FIXME: Can we get null here?
24+
// arguments.argument().toList.map({ entry =>
25+
// val valueOrVariable = entry.valueOrVariable()
26+
// val valueOrVariable = entry.valueOrVariable()
27+
// entry.NAME().getText -> valueOrVariable
28+
// }).toMap
29+
30+
31+
}
32+
33+
34+
35+
/**
36+
* Prepares an object map of variables of the correct type based on the provided
37+
* variable definitions and arbitrary input. If the input cannot be coerced
38+
* to match the variable definitions, a GraphQLError will be thrown.
39+
*/
40+
/*
41+
FIXME: Replace Any types with proper Types resolved from the variableValues
42+
Ex: query Example($size: Int) {
43+
variableValues = { size: 100 }
44+
*/
45+
46+
def getVariableValues(schema: GraphQLSchema,
47+
definitionASTs: List[VariableDefinitionContext] = List.empty,
48+
variableValues: Map[String, String] = Map.empty): Map[String, Any] = {
49+
50+
51+
// FIXME: Implement
52+
// definitionASTs map { definition =>
53+
// val varName = definition.variable().NAME().getText
54+
// }
55+
56+
Map.empty
57+
}
58+
59+
60+
/**
61+
* Given a variable definition, and any value of input, return a value which
62+
* adheres to the variable definition, or throw an error.
63+
*/
64+
def getVariableValue(schema: GraphQLSchema,
65+
definitionAST: VariableDefinitionContext,
66+
input: String) = {
67+
68+
}
69+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package se.uprise.graphql.types
2+
3+
import se.uprise.graphql.annotation.QLField
4+
import se.uprise.parser.GraphQlParser.SelectionContext
5+
6+
import scala.reflect.runtime._
7+
8+
// FIXME: Better type for default value
9+
class GraphQLFieldArgument[T <: GraphQLInputType](name: String,
10+
description: String,
11+
defaultValue: Any)
12+
13+
// FIXME: Better type for default value
14+
// FIXME: Proper types for resolve method
15+
case class GraphQLFieldDefinition(name: String,
16+
description: String,
17+
args: List[GraphQLFieldArgument[_ <: GraphQLInputType]] = List.empty,
18+
resolve: universe.MethodSymbol,
19+
deprecationReason: String = "")
20+
21+
trait GraphQLFields {
22+
def getFields(entry: GraphQLObjectType): Map[String, GraphQLFieldDefinition]
23+
24+
// FIXME: We don't want to mess around with the reflection stuff. Look into macros and definition generation
25+
def isAnnotatedWithField(candidate: reflect.runtime.universe.Symbol) = {
26+
val qlFieldAnnotationType = universe.typeOf[QLField]
27+
val annotation: Option[reflect.runtime.universe.Annotation] = candidate.annotations.find(a => a.tpe == qlFieldAnnotationType)
28+
annotation match {
29+
case Some(value) => true
30+
case _ => false
31+
}
32+
}
33+
34+
def getClassFields(candidate: GraphQLObjectType) = {
35+
val typ = universe.runtimeMirror(candidate.getClass.getClassLoader).classSymbol(candidate.getClass)
36+
37+
//val typ: universe.ClassSymbol = universe.runtimeMirror(clazzType.getClassLoader).classSymbol(clazzType)
38+
39+
val members: universe.MemberScope = typ.typeSignature.members
40+
val fields = members.flatMap({ entry =>
41+
isAnnotatedWithField(entry) match {
42+
case true => Some(entry.name.toString -> entry.asMethod)
43+
case _ => None
44+
}
45+
}).toMap
46+
fields
47+
}
48+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
package se.uprise.graphql.types
22

3-
trait GraphQLInterfaceType extends GraphQLOutputType {
3+
trait GraphQLInterfaceType extends GraphQLOutputType with GraphQLFields {
44
}
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
package se.uprise.graphql.types
22

3-
trait GraphQLObjectType extends GraphQLOutputType {
4-
3+
trait GraphQLObjectType extends GraphQLOutputType with GraphQLFields {
54
}

src/test/scala/se/uprise/graphql/starwars/StarWars.scala

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ import se.uprise.graphql.annotation.{QLField, QLInterface, QLObject}
44
import se.uprise.graphql.types._
55

66
import scala.annotation.StaticAnnotation
7-
8-
9-
7+
import scala.reflect.runtime._
108

119

1210
@QLInterface(desc = "A character in the Star Wars Trilogy")
@@ -36,6 +34,18 @@ class Human(_id: String, _name: String, _friends: Seq[Int], _appearsIn: Seq[Int]
3634

3735
@QLField()
3836
def homePlanet = new GraphQLString(_homePlanet)
37+
38+
// This is the part we wish to auto generate
39+
override def getFields(entry: GraphQLObjectType): Map[String, GraphQLFieldDefinition] = {
40+
val fields = this.getClassFields(this)
41+
42+
Map(
43+
"id" -> new GraphQLFieldDefinition("id", "desc", List.empty, fields("id"), ""),
44+
"name" -> new GraphQLFieldDefinition("name", "desc", List.empty, fields("name"), ""),
45+
"friends" -> new GraphQLFieldDefinition("friends", "desc", List.empty, fields("friends"), ""),
46+
"homePlanet" -> new GraphQLFieldDefinition("homePlanet", "desc", List.empty, fields("homePlanet"), "")
47+
)
48+
}
3949
}
4050

4151
@QLObject(desc = "A mechanical creature in the Star Wars universe.")
@@ -52,6 +62,18 @@ class Droid(_id: String, _name: String, _friends: Seq[Int], _appearsIn: Seq[Int]
5262

5363
@QLField()
5464
def primaryFunction = new GraphQLString(_primaryFunction)
65+
66+
// This is the part we wish to auto generate
67+
override def getFields(entry: GraphQLObjectType): Map[String, GraphQLFieldDefinition] = {
68+
val fields = this.getClassFields(this)
69+
70+
Map(
71+
"id" -> new GraphQLFieldDefinition("id", "desc", List.empty, fields("id"), ""),
72+
"name" -> new GraphQLFieldDefinition("name", "desc", List.empty, fields("name"), ""),
73+
"friends" -> new GraphQLFieldDefinition("friends", "desc", List.empty, fields("friends"), ""),
74+
"primaryFunction" -> new GraphQLFieldDefinition("primaryFunction", "desc", List.empty, fields("primaryFunction"), "")
75+
)
76+
}
5577
}
5678

5779
@QLObject()
@@ -71,6 +93,27 @@ class Query extends GraphQLObjectType {
7193
def droid(id: GraphQLString): Droid = {
7294
Data.getCharacter(id.value).asInstanceOf[Droid]
7395
}
96+
97+
// This is the part we wish to auto generate
98+
override def getFields(entry: GraphQLObjectType): Map[String, GraphQLFieldDefinition] = {
99+
val fields = this.getClassFields(this)
100+
101+
Map(
102+
"hero" -> new GraphQLFieldDefinition("hero", "desc", List.empty, fields("hero"), ""),
103+
"human" -> new GraphQLFieldDefinition(
104+
"human",
105+
"desc",
106+
List(new GraphQLFieldArgument[GraphQLString]("id", "desc", "BLANK")),
107+
fields("human"),
108+
""),
109+
"droid" -> new GraphQLFieldDefinition(
110+
"droid",
111+
"desc",
112+
List(new GraphQLFieldArgument[GraphQLString]("id", "desc", "BLANK")),
113+
fields("droid"),
114+
"")
115+
)
116+
}
74117
}
75118

76119
class StarWarsSchema extends GraphQLSchema(new Query, None) {

0 commit comments

Comments
 (0)