Skip to content

Commit 438ad28

Browse files
committed
planning phase finished
1 parent 853848d commit 438ad28

File tree

4 files changed

+33
-30
lines changed

4 files changed

+33
-30
lines changed

src/FSharp.Data.GraphQL/Execution.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ let resolveUnionType possibleTypesFn (uniondef: UnionDef) =
187187
match uniondef.ResolveType with
188188
| Some resolveType -> resolveType
189189
| None -> defaultResolveType possibleTypesFn uniondef
190-
190+
191191
let rec createCompletion (possibleTypesFn: TypeDef -> ObjectDef []) (returnDef: OutputDef): ResolveFieldContext -> obj -> Job<obj> =
192192
match returnDef with
193193
| Object objdef ->
@@ -215,7 +215,7 @@ let rec createCompletion (possibleTypesFn: TypeDef -> ObjectDef []) (returnDef:
215215
|> Seq.cast<obj>
216216
|> Seq.map (fun x -> innerfn innerCtx x)
217217
|> Job.conCollect
218-
return completed.ToArray() :> obj
218+
return box (completed.ToArray())
219219
| _ -> return raise (
220220
GraphQLException (sprintf "Expected to have enumerable value in field '%s' but got '%O'" ctx.ExecutionPlan.Data.Identifier (value.GetType())))
221221
}

src/FSharp.Data.GraphQL/Planning.fs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ let objectData(ctx: PlanningContext, parentDef: ObjectDef, field: Field, include
7373
| None ->
7474
raise (GraphQLException (sprintf "No field '%s' was defined in object definition '%s'" field.Name parentDef.Name))
7575

76-
let abstractionData(ctx: PlanningContext, parentDef: AbstractDef, field: Field, typeCondition: string option, includer: Includer) : Map<string, PlanningData> =
76+
let rec abstractionData (ctx:PlanningContext) (parentDef: AbstractDef) (field: Field) typeCondition includer : Map<string, PlanningData> =
7777
let objDefs = ctx.Schema.GetPossibleTypes parentDef
7878
match typeCondition with
7979
| None ->
@@ -106,8 +106,12 @@ let abstractionData(ctx: PlanningContext, parentDef: AbstractDef, field: Field,
106106
Map.ofList [ objDef.Name, data ]
107107
| None -> Map.empty
108108
| None ->
109-
let pname = parentDef :?> NamedDef
110-
raise (GraphQLException (sprintf "An abstract type '%s' has no relation with a type named '%s'" pname.Name typeName))
109+
match ctx.Schema.TryFindType typeName with
110+
| Some (Abstract abstractDef) ->
111+
abstractionData ctx abstractDef field None includer
112+
| _ ->
113+
let pname = parentDef :?> NamedDef
114+
raise (GraphQLException (sprintf "There is no object type named '%s' that is a possible type of '%s'" typeName pname.Name))
111115

112116
let private directiveIncluder (directive: Directive) : Includer =
113117
fun variables ->
@@ -121,17 +125,15 @@ let private directiveIncluder (directive: Directive) : Includer =
121125

122126
let incl: Includer = fun _ -> true
123127
let excl: Includer = fun _ -> false
124-
let private getIncluder (directives: Directive list) : Includer =
128+
let private getIncluder (directives: Directive list) topIncluder : Includer =
125129
directives
126130
|> List.fold (fun acc directive ->
127131
match directive.Name with
128132
| "skip" ->
129-
let excluder = directiveIncluder directive >> not
130-
fun vars -> acc vars && excluder vars
133+
fun vars -> acc vars && not(directiveIncluder directive vars)
131134
| "include" ->
132-
let includer = directiveIncluder directive
133-
fun vars -> acc vars && includer vars
134-
| _ -> acc) incl
135+
fun vars -> acc vars && (directiveIncluder directive vars)
136+
| _ -> acc) topIncluder
135137

136138
let private doesFragmentTypeApply (schema: ISchema) fragment (objectType: ObjectDef) =
137139
match fragment.TypeCondition with
@@ -142,7 +144,7 @@ let private doesFragmentTypeApply (schema: ISchema) fragment (objectType: Object
142144
| Some conditionalType when conditionalType.Name = objectType.Name -> true
143145
| Some (Abstract conditionalType) -> schema.IsPossibleType conditionalType objectType
144146
| _ -> false
145-
147+
146148
let rec private plan (ctx: PlanningContext) (data: PlanningData) (typedef: TypeDef) : ExecutionPlanInfo =
147149
match typedef with
148150
| Leaf leafDef -> planLeaf ctx data leafDef
@@ -157,7 +159,8 @@ and private planSelection (ctx: PlanningContext) (data: PlanningData) (selection
157159
selectionSet
158160
|> List.fold(fun (fields: ExecutionPlanInfo list) selection ->
159161
//FIXME: includer is not passed along from top level fragments (both inline and spreads)
160-
let includer = getIncluder selection.Directives
162+
let includer = getIncluder selection.Directives data.Include
163+
let innerData = { data with Include = includer }
161164
match selection with
162165
| Field field ->
163166
let identifier = field.AliasOrName
@@ -176,13 +179,13 @@ and private planSelection (ctx: PlanningContext) (data: PlanningData) (selection
176179
match ctx.Document.Definitions |> List.tryFind (function FragmentDefinition f -> f.Name.Value = spreadName | _ -> false) with
177180
| Some (FragmentDefinition fragment) when doesFragmentTypeApply ctx.Schema fragment parentDef ->
178181
// retrieve fragment data just as it was normal selection set
179-
let (SelectFields(_, fragmentFields)) = planSelection ctx data fragment.SelectionSet visitedFragments
182+
let (SelectFields(_, fragmentFields)) = planSelection ctx innerData fragment.SelectionSet visitedFragments
180183
// filter out already existing fields
181184
List.mergeBy (fun field -> field.Data.Identifier) fields fragmentFields
182185
| _ -> fields
183186
| InlineFragment fragment when doesFragmentTypeApply ctx.Schema fragment parentDef ->
184187
// retrieve fragment data just as it was normal selection set
185-
let (SelectFields(_, fragmentFields)) = planSelection ctx data fragment.SelectionSet visitedFragments
188+
let (SelectFields(_, fragmentFields)) = planSelection ctx innerData fragment.SelectionSet visitedFragments
186189
// filter out already existing fields
187190
List.mergeBy (fun field -> field.Data.Identifier) fields fragmentFields
188191
| _ -> fields
@@ -200,10 +203,11 @@ and private planAbstraction (ctx:PlanningContext) (data: PlanningData) (selectio
200203
let plannedTypeFields =
201204
selectionSet
202205
|> List.fold(fun (fields: Map<string, ExecutionPlanInfo list>) selection ->
203-
let includer = getIncluder selection.Directives
206+
let includer = getIncluder selection.Directives data.Include
207+
let innerData = { data with Include = includer }
204208
match selection with
205209
| Field field ->
206-
abstractionData(ctx, parentDef, field, typeCondition, includer)
210+
abstractionData ctx parentDef field typeCondition includer
207211
|> Map.map (fun typeName data -> [ plan ctx data data.Definition.Type ])
208212
|> Map.merge (fun typeName oldVal newVal -> oldVal @ newVal) fields
209213
| FragmentSpread spread ->
@@ -215,13 +219,13 @@ and private planAbstraction (ctx:PlanningContext) (data: PlanningData) (selectio
215219
match ctx.Document.Definitions |> List.tryFind (function FragmentDefinition f -> f.Name.Value = spreadName | _ -> false) with
216220
| Some (FragmentDefinition fragment) ->
217221
// retrieve fragment data just as it was normal selection set
218-
let (ResolveAbstraction(_, fragmentFields)) = planAbstraction ctx data fragment.SelectionSet visitedFragments fragment.TypeCondition
222+
let (ResolveAbstraction(_, fragmentFields)) = planAbstraction ctx innerData fragment.SelectionSet visitedFragments fragment.TypeCondition
219223
// filter out already existing fields
220224
Map.merge (fun typeName oldVal newVal -> oldVal @ newVal) fields fragmentFields
221225
| _ -> fields
222226
| InlineFragment fragment ->
223227
// retrieve fragment data just as it was normal selection set
224-
let (ResolveAbstraction(_, fragmentFields)) = planAbstraction ctx data fragment.SelectionSet visitedFragments fragment.TypeCondition
228+
let (ResolveAbstraction(_, fragmentFields)) = planAbstraction ctx innerData fragment.SelectionSet visitedFragments fragment.TypeCondition
225229
// filter out already existing fields
226230
Map.merge (fun typeName oldVal newVal -> oldVal @ newVal) fields fragmentFields
227231
| _ -> fields

tests/FSharp.Data.GraphQL.Tests/SchemaTests.fs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,9 @@ let ``Object type should be able to merge fields with matching signatures from d
2626
Define.Field("speed", Int)
2727
Define.Field("acceleration", Int) ])
2828
equals [ MovableType :> InterfaceDef; upcast Movable2Type ] (PersonType.Implements |> Array.toList )
29-
equals [ Define.Field("name", String) :> FieldDef; upcast Define.Field("speed", Int); upcast Define.Field("acceleration", Int) ] (( PersonType :> ObjectDef).Fields |> Map.toList |> List.map snd)
29+
let expected =
30+
//NOTE: under normal conditions field order shouldn't matter in object definitions
31+
[ Define.Field("acceleration", Int) :> FieldDef
32+
upcast Define.Field("name", String)
33+
upcast Define.Field("speed", Int) ]
34+
equals expected (( PersonType :> ObjectDef).Fields |> Map.toList |> List.map snd)

tests/FSharp.Data.GraphQL.Tests/UnionInterfaceTests.fs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ type Person =
3535
{ Name: string; Pets: Pet list; Friends: INamed list }
3636
interface INamed with
3737
member x.Name = x.Name
38-
39-
38+
4039
let NamedType = Define.Interface<INamed>(
4140
name = "Named",
4241
fields = [ Define.Field("name", String) ])
@@ -158,13 +157,11 @@ let ``Executes union types`` () =
158157
box <| NameValueLookup.ofList [
159158
"__typename", box "Cat"
160159
"name", upcast "Garfield"
161-
"barks", null
162160
"meows", upcast false]
163161
upcast NameValueLookup.ofList [
164162
"__typename", box "Dog"
165163
"name", upcast "Odie"
166-
"barks", upcast true
167-
"meows", null]]]
164+
"barks", upcast true]]]
168165
noErrors actual
169166
actual.["data"] |> equals (upcast expected)
170167

@@ -222,14 +219,11 @@ let ``Executes interface types`` () =
222219
"friends", upcast [
223220
box <| NameValueLookup.ofList [
224221
"__typename", box "Person"
225-
"name", upcast "Liz"
226-
"barks", null
227-
"meows", null]
222+
"name", upcast "Liz" ]
228223
upcast NameValueLookup.ofList [
229224
"__typename", box "Dog"
230225
"name", upcast "Odie"
231-
"barks", upcast true
232-
"meows", null]]]
226+
"barks", upcast true ]]]
233227
noErrors actual
234228
actual.["data"] |> equals (upcast expected)
235229

0 commit comments

Comments
 (0)