Skip to content

Commit f23f1c5

Browse files
committed
Fixed ability to skip interface implementations and union cases in query according to
1 parent 5b3c30d commit f23f1c5

File tree

2 files changed

+23
-98
lines changed

2 files changed

+23
-98
lines changed

src/FSharp.Data.GraphQL.Server/Execution.fs

+3-6
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ let rec private direct (returnDef : OutputDef) (ctx : ResolveFieldContext) (path
375375
| kind -> failwithf "Unexpected value of ctx.ExecutionPlan.Kind: %A" kind
376376
match Map.tryFind resolvedDef.Name typeMap with
377377
| Some fields -> executeObjectFields fields name resolvedDef ctx path value
378-
| None -> KeyValuePair(name, null) |> ResolverResult.data |> AsyncVal.wrap
378+
| None -> KeyValuePair(name, obj()) |> ResolverResult.data |> AsyncVal.wrap
379379

380380
| Union uDef ->
381381
let possibleTypesFn = ctx.Schema.GetPossibleTypes
@@ -387,7 +387,7 @@ let rec private direct (returnDef : OutputDef) (ctx : ResolveFieldContext) (path
387387
| kind -> failwithf "Unexpected value of ctx.ExecutionPlan.Kind: %A" kind
388388
match Map.tryFind resolvedDef.Name typeMap with
389389
| Some fields -> executeObjectFields fields name resolvedDef ctx path (uDef.ResolveValue value)
390-
| None -> KeyValuePair(name, null) |> ResolverResult.data |> AsyncVal.wrap
390+
| None -> KeyValuePair(name, obj()) |> ResolverResult.data |> AsyncVal.wrap
391391

392392
| _ -> failwithf "Unexpected value of returnDef: %O" returnDef
393393

@@ -509,10 +509,7 @@ and private executeResolvers (ctx : ResolveFieldContext) (path : FieldPath) (par
509509
| Ok None when ctx.ExecutionInfo.IsNullable -> return Ok (KeyValuePair(name, null), None, [])
510510
| Error errs -> return Error errs
511511
| Ok None -> return Error (nullResolverError name path ctx)
512-
| Ok (Some v) ->
513-
match! onSuccess ctx path parent v with
514-
| Ok (kvp, _, _) when not ctx.ExecutionInfo.IsNullable && kvp.Value = null -> return Error (nullResolverError name path ctx)
515-
| result -> return result
512+
| Ok (Some v) -> return! onSuccess ctx path parent v
516513
}
517514

518515
match info.Kind, returnDef with

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

+20-92
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,6 @@ let schemaWithInterface =
7676
"pets",
7777
ListOf PetType,
7878
fun _ _ -> [ { Name = "Odie"; Woofs = true } :> IPet; { Name = "Garfield"; Meows = false } ]
79-
)
80-
Define.Field (
81-
"nullablePets",
82-
ListOf (Nullable PetType),
83-
fun _ _ -> [ { Name = "Odie"; Woofs = true } :> IPet |> Some; { Name = "Garfield"; Meows = false } :> IPet |> Some ]
8479
) ]
8580
),
8681
config = { SchemaConfig.Default with Types = [ CatType; DogType ] }
@@ -117,7 +112,7 @@ let ``Execute handles execution of abstract types: isTypeOf is used to resolve r
117112
data |> equals (upcast expected)
118113

119114
[<Fact>]
120-
let ``Execute handles execution of abstract types: not specified Interface types produce error`` () =
115+
let ``Execute handles execution of abstract types: not specified Interface types must be empty objects`` () =
121116
let query =
122117
"""{
123118
pets {
@@ -129,48 +124,18 @@ let ``Execute handles execution of abstract types: not specified Interface types
129124
}"""
130125

131126
let result = sync <| schemaWithInterface.Value.AsyncExecute (parse query)
132-
ensureRequestError result <| fun [ petsError ] ->
133-
petsError |> ensureExecutionError "Non-Null field pets resolved as a null!" [ "pets"; 1 ]
134127

135-
let query =
136-
"""{
137-
pets {
138-
... on Cat {
139-
name
140-
meows
141-
}
142-
}
143-
}"""
144-
145-
let result = sync <| schemaWithInterface.Value.AsyncExecute (parse query)
146-
ensureRequestError result <| fun [ petsError ] ->
147-
petsError |> ensureExecutionError "Non-Null field pets resolved as a null!" [ "pets"; 0 ]
148-
149-
[<Fact>]
150-
let ``Execute handles execution of abstract types: not specified Interface types must be filtered out if they allow null`` () =
151-
let query =
152-
"""{
153-
nullablePets {
154-
... on Dog {
155-
name
156-
woofs
157-
}
158-
}
159-
}"""
160-
161-
let result = sync <| schemaWithInterface.Value.AsyncExecute (parse query)
162-
163-
let expected =
164-
NameValueLookup.ofList
165-
[ "nullablePets", upcast [ NameValueLookup.ofList [ "name", "Odie" :> obj; "woofs", upcast true ] :> obj; null ] ]
128+
let expected = NameValueLookup.ofList [ "name", "Odie" :> obj; "woofs", upcast true ]
166129

167130
ensureDirect result <| fun data errors ->
168131
empty errors
169-
data |> equals (upcast expected)
132+
let [| dog; emptyObj |] = data["pets"] :?> obj array
133+
dog |> equals (upcast expected)
134+
emptyObj.GetType() |> equals typeof<obj>
170135

171136
let query =
172137
"""{
173-
nullablePets {
138+
pets {
174139
... on Cat {
175140
name
176141
meows
@@ -180,14 +145,13 @@ let ``Execute handles execution of abstract types: not specified Interface types
180145

181146
let result = sync <| schemaWithInterface.Value.AsyncExecute (parse query)
182147

183-
let expected =
184-
NameValueLookup.ofList
185-
[ "nullablePets",
186-
upcast [ null; NameValueLookup.ofList [ "name", "Garfield" :> obj; "meows", upcast false ] :> obj ] ]
148+
let expected = NameValueLookup.ofList [ "name", "Garfield" :> obj; "meows", upcast false ]
187149

188150
ensureDirect result <| fun data errors ->
189151
empty errors
190-
data |> equals (upcast expected)
152+
let [| emptyObj; cat|] = data["pets"] :?> obj array
153+
cat |> equals (upcast expected)
154+
emptyObj.GetType() |> equals typeof<obj>
191155

192156
[<Fact>]
193157
let ``Execute handles execution of abstract types: absent field resolution produces errors for Interface`` () =
@@ -282,11 +246,6 @@ let schemaWithUnion =
282246
"pets",
283247
ListOf PetType,
284248
fun _ _ -> [ DogCase { Name = "Odie"; Woofs = true }; CatCase { Name = "Garfield"; Meows = false } ]
285-
)
286-
Define.Field (
287-
"nullablePets",
288-
ListOf (Nullable PetType),
289-
fun _ _ -> [ DogCase { Name = "Odie"; Woofs = true } |> Some; CatCase { Name = "Garfield"; Meows = false } |> Some ]
290249
) ]
291250
)
292251
)
@@ -323,7 +282,7 @@ let ``Execute handles execution of abstract types: isTypeOf is used to resolve r
323282
data |> equals (upcast expected)
324283

325284
[<Fact>]
326-
let ``Execute handles execution of abstract types: not specified Union types produce error`` () =
285+
let ``Execute handles execution of abstract types: not specified Union types must be empty objects`` () =
327286
let query =
328287
"""{
329288
pets {
@@ -335,48 +294,18 @@ let ``Execute handles execution of abstract types: not specified Union types pro
335294
}"""
336295

337296
let result = sync <| schemaWithUnion.Value.AsyncExecute (parse query)
338-
ensureRequestError result <| fun [ petsError ] ->
339-
petsError |> ensureExecutionError "Non-Null field pets resolved as a null!" [ "pets"; 1 ]
340297

341-
let query =
342-
"""{
343-
pets {
344-
... on Cat {
345-
name
346-
meows
347-
}
348-
}
349-
}"""
350-
351-
let result = sync <| schemaWithUnion.Value.AsyncExecute (parse query)
352-
ensureRequestError result <| fun [ petsError ] ->
353-
petsError |> ensureExecutionError "Non-Null field pets resolved as a null!" [ "pets"; 0 ]
354-
355-
[<Fact>]
356-
let ``Execute handles execution of abstract types: not specified Union types must be filtered out`` () =
357-
let query =
358-
"""{
359-
nullablePets {
360-
... on Dog {
361-
name
362-
woofs
363-
}
364-
}
365-
}"""
366-
367-
let result = sync <| schemaWithUnion.Value.AsyncExecute (parse query)
368-
369-
let expected =
370-
NameValueLookup.ofList
371-
[ "nullablePets", upcast [ NameValueLookup.ofList [ "name", "Odie" :> obj; "woofs", upcast true ] :> obj; null ] ]
298+
let expected = NameValueLookup.ofList [ "name", "Odie" :> obj; "woofs", upcast true ]
372299

373300
ensureDirect result <| fun data errors ->
374301
empty errors
375-
data |> equals (upcast expected)
302+
let [| dog; emptyObj |] = data["pets"] :?> obj array
303+
dog |> equals (upcast expected)
304+
emptyObj.GetType() |> equals typeof<obj>
376305

377306
let query =
378307
"""{
379-
nullablePets {
308+
pets {
380309
... on Cat {
381310
name
382311
meows
@@ -386,14 +315,13 @@ let ``Execute handles execution of abstract types: not specified Union types mus
386315

387316
let result = sync <| schemaWithUnion.Value.AsyncExecute (parse query)
388317

389-
let expected =
390-
NameValueLookup.ofList
391-
[ "nullablePets",
392-
upcast [ null; NameValueLookup.ofList [ "name", "Garfield" :> obj; "meows", upcast false ] :> obj ] ]
318+
let expected = NameValueLookup.ofList [ "name", "Garfield" :> obj; "meows", upcast false ]
393319

394320
ensureDirect result <| fun data errors ->
395321
empty errors
396-
data |> equals (upcast expected)
322+
let [| emptyObj; cat|] = data["pets"] :?> obj array
323+
cat |> equals (upcast expected)
324+
emptyObj.GetType() |> equals typeof<obj>
397325

398326
[<Fact>]
399327
let ``Execute handles execution of abstract types: absent field resolution produces errors for Union`` () =

0 commit comments

Comments
 (0)