Skip to content

Commit

Permalink
Fixed ability to skip interface implementations and union cases in qu…
Browse files Browse the repository at this point in the history
…ery according to spec
  • Loading branch information
xperiandri committed Feb 15, 2024
1 parent 08b75ff commit 7585751
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 98 deletions.
9 changes: 3 additions & 6 deletions src/FSharp.Data.GraphQL.Server/Execution.fs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ let rec private direct (returnDef : OutputDef) (ctx : ResolveFieldContext) (path
| kind -> failwithf "Unexpected value of ctx.ExecutionPlan.Kind: %A" kind
match Map.tryFind resolvedDef.Name typeMap with
| Some fields -> executeObjectFields fields name resolvedDef ctx path value
| None -> KeyValuePair(name, null) |> ResolverResult.data |> AsyncVal.wrap
| None -> KeyValuePair(name, obj()) |> ResolverResult.data |> AsyncVal.wrap

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

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

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

match info.Kind, returnDef with
Expand Down
112 changes: 20 additions & 92 deletions tests/FSharp.Data.GraphQL.Tests/AbstractionTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,6 @@ let schemaWithInterface =
"pets",
ListOf PetType,
fun _ _ -> [ { Name = "Odie"; Woofs = true } :> IPet; { Name = "Garfield"; Meows = false } ]
)
Define.Field (
"nullablePets",
ListOf (Nullable PetType),
fun _ _ -> [ { Name = "Odie"; Woofs = true } :> IPet |> Some; { Name = "Garfield"; Meows = false } :> IPet |> Some ]
) ]
),
config = { SchemaConfig.Default with Types = [ CatType; DogType ] }
Expand Down Expand Up @@ -117,7 +112,7 @@ let ``Execute handles execution of abstract types: isTypeOf is used to resolve r
data |> equals (upcast expected)

[<Fact>]
let ``Execute handles execution of abstract types: not specified Interface types produce error`` () =
let ``Execute handles execution of abstract types: not specified Interface types must be empty objects`` () =
let query =
"""{
pets {
Expand All @@ -129,48 +124,18 @@ let ``Execute handles execution of abstract types: not specified Interface types
}"""

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

let query =
"""{
pets {
... on Cat {
name
meows
}
}
}"""

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

[<Fact>]
let ``Execute handles execution of abstract types: not specified Interface types must be filtered out if they allow null`` () =
let query =
"""{
nullablePets {
... on Dog {
name
woofs
}
}
}"""

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

let expected =
NameValueLookup.ofList
[ "nullablePets", upcast [ NameValueLookup.ofList [ "name", "Odie" :> obj; "woofs", upcast true ] :> obj; null ] ]
let expected = NameValueLookup.ofList [ "name", "Odie" :> obj; "woofs", upcast true ]

ensureDirect result <| fun data errors ->
empty errors
data |> equals (upcast expected)
let [| dog; emptyObj |] = data["pets"] :?> obj array
dog |> equals (upcast expected)
emptyObj.GetType() |> equals typeof<obj>

let query =
"""{
nullablePets {
pets {
... on Cat {
name
meows
Expand All @@ -180,14 +145,13 @@ let ``Execute handles execution of abstract types: not specified Interface types

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

let expected =
NameValueLookup.ofList
[ "nullablePets",
upcast [ null; NameValueLookup.ofList [ "name", "Garfield" :> obj; "meows", upcast false ] :> obj ] ]
let expected = NameValueLookup.ofList [ "name", "Garfield" :> obj; "meows", upcast false ]

ensureDirect result <| fun data errors ->
empty errors
data |> equals (upcast expected)
let [| emptyObj; cat|] = data["pets"] :?> obj array
cat |> equals (upcast expected)
emptyObj.GetType() |> equals typeof<obj>

[<Fact>]
let ``Execute handles execution of abstract types: absent field resolution produces errors for Interface`` () =
Expand Down Expand Up @@ -282,11 +246,6 @@ let schemaWithUnion =
"pets",
ListOf PetType,
fun _ _ -> [ DogCase { Name = "Odie"; Woofs = true }; CatCase { Name = "Garfield"; Meows = false } ]
)
Define.Field (
"nullablePets",
ListOf (Nullable PetType),
fun _ _ -> [ DogCase { Name = "Odie"; Woofs = true } |> Some; CatCase { Name = "Garfield"; Meows = false } |> Some ]
) ]
)
)
Expand Down Expand Up @@ -323,7 +282,7 @@ let ``Execute handles execution of abstract types: isTypeOf is used to resolve r
data |> equals (upcast expected)

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

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

let query =
"""{
pets {
... on Cat {
name
meows
}
}
}"""

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

[<Fact>]
let ``Execute handles execution of abstract types: not specified Union types must be filtered out`` () =
let query =
"""{
nullablePets {
... on Dog {
name
woofs
}
}
}"""

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

let expected =
NameValueLookup.ofList
[ "nullablePets", upcast [ NameValueLookup.ofList [ "name", "Odie" :> obj; "woofs", upcast true ] :> obj; null ] ]
let expected = NameValueLookup.ofList [ "name", "Odie" :> obj; "woofs", upcast true ]

ensureDirect result <| fun data errors ->
empty errors
data |> equals (upcast expected)
let [| dog; emptyObj |] = data["pets"] :?> obj array
dog |> equals (upcast expected)
emptyObj.GetType() |> equals typeof<obj>

let query =
"""{
nullablePets {
pets {
... on Cat {
name
meows
Expand All @@ -386,14 +315,13 @@ let ``Execute handles execution of abstract types: not specified Union types mus

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

let expected =
NameValueLookup.ofList
[ "nullablePets",
upcast [ null; NameValueLookup.ofList [ "name", "Garfield" :> obj; "meows", upcast false ] :> obj ] ]
let expected = NameValueLookup.ofList [ "name", "Garfield" :> obj; "meows", upcast false ]

ensureDirect result <| fun data errors ->
empty errors
data |> equals (upcast expected)
let [| emptyObj; cat|] = data["pets"] :?> obj array
cat |> equals (upcast expected)
emptyObj.GetType() |> equals typeof<obj>

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

0 comments on commit 7585751

Please sign in to comment.