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
  • Loading branch information
xperiandri committed Feb 15, 2024
1 parent 5b3c30d commit f23f1c5
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 f23f1c5

Please sign in to comment.