Skip to content

Commit 859c99c

Browse files
Added tests for input records list and fixed missing ExecuteInput on input objects (#509)
* Added tests for input records list * Fixed crash of input objects list creation from variables --------- Co-authored-by: Andrii Chebukin <[email protected]>
1 parent c184046 commit 859c99c

File tree

3 files changed

+199
-0
lines changed

3 files changed

+199
-0
lines changed

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

+7
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,13 @@ let rec internal compileByType
317317
| _ -> Ok null
318318

319319
| List (Input innerDef) ->
320+
match innerDef with
321+
| InputObject inputObjDef
322+
| Nullable (InputObject inputObjDef) ->
323+
let inner = compileByType inputObjectPath inputSource (inputDef, innerDef)
324+
inputObjDef.ExecuteInput <- inner
325+
| _ -> ()
326+
320327
let isArray = inputDef.Type.IsArray
321328
// TODO: Improve creation of inner
322329
let inner index = compileByType ((box index) :: inputObjectPath) inputSource (innerDef, innerDef)

tests/FSharp.Data.GraphQL.Tests/FSharp.Data.GraphQL.Tests.fsproj

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
<Compile Include="Variables and Inputs\OptionalsNormalizationTests.fs" />
5656
<Compile Include="Variables and Inputs\SkippablesNormalizationTests.fs" />
5757
<Compile Include="Variables and Inputs\InputRecordTests.fs" />
58+
<Compile Include="Variables and Inputs\InputRecordListTests.fs" />
5859
<Compile Include="Variables and Inputs\InputObjectValidatorTests.fs" />
5960
<Compile Include="Variables and Inputs\InputScalarAndAutoFieldScalarTests.fs" />
6061
<Compile Include="Variables and Inputs\InputComplexTests.fs" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
// The MIT License (MIT)
2+
3+
module FSharp.Data.GraphQL.Tests.InputRecordListTests
4+
5+
#nowarn "25"
6+
7+
open Xunit
8+
open System.Collections.Immutable
9+
open System.Text.Json
10+
open System.Text.Json.Serialization
11+
12+
open FSharp.Data.GraphQL
13+
open FSharp.Data.GraphQL.Types
14+
open FSharp.Data.GraphQL.Parser
15+
open FSharp.Data.GraphQL.Tests.InputRecordTests
16+
17+
let schema verify =
18+
let schema =
19+
Schema (
20+
query =
21+
Define.Object (
22+
"Query",
23+
[ Define.Field (
24+
"recordInputs",
25+
StringType,
26+
[ Define.Input ("records", ListOf InputRecordType)
27+
Define.Input ("recordsOptional", Nullable (ListOf (Nullable InputRecordOptionalType)))
28+
Define.Input ("recordsNested", ListOf (Nullable InputRecordNestedType)) ],
29+
(fun ctx name ->
30+
let _ = ctx.Arg<InputRecord list> "records"
31+
let _ = ctx.TryArg<list<InputRecordOptional option>> "recordsOptional"
32+
let recordNested =
33+
ctx.Arg<list<InputRecordNested option>> "recordsNested"
34+
|> List.tryHead
35+
|> Option.flatten
36+
match verify, recordNested with
37+
| Nothing, _ -> ()
38+
| AllInclude, Some recordNested -> recordNested.s |> ValueOption.iter _.VerifyAllInclude
39+
| AllSkip, Some recordNested -> recordNested.s |> ValueOption.iter _.VerifyAllSkip
40+
| SkipAndIncludeNull, Some recordNested -> recordNested.s |> ValueOption.iter _.VerifySkipAndIncludeNull
41+
| _ -> ()
42+
stringifyInput ctx name
43+
)
44+
) // TODO: add all args stringificaiton
45+
Define.Field (
46+
"objectInputs",
47+
StringType,
48+
[ Define.Input ("object", InputObjectType)
49+
Define.Input ("objectOptional", Nullable InputObjectOptionalType) ],
50+
stringifyInput
51+
) ] // TODO: add all args stringificaiton
52+
)
53+
)
54+
55+
Executor schema
56+
57+
[<Fact>]
58+
let ``Execute handles creation of inline empty input records list`` () =
59+
let query =
60+
"""{
61+
recordInputs(
62+
records: [],
63+
recordsOptional: [],
64+
recordsNested: []
65+
)
66+
}"""
67+
let result = sync <| (schema AllInclude).AsyncExecute(parse query)
68+
ensureDirect result <| fun data errors -> empty errors
69+
70+
[<Fact>]
71+
let ``Execute handles creation of inline input records list with all fields`` () =
72+
let query =
73+
"""{
74+
recordInputs(
75+
records: [{ a: "a", b: "b", c: "c" }],
76+
recordsOptional: [{ a: "a", b: "b", c: "c" }],
77+
recordsNested: [{
78+
a: { a: "a", b: "b", c: "c" },
79+
b: { a: "a", b: "b", c: "c" },
80+
c: { a: "a", b: "b", c: "c" },
81+
s: { a: "a", b: "b", c: "c" },
82+
l: [{ a: "a", b: "b", c: "c" }]
83+
}]
84+
)
85+
}"""
86+
let result = sync <| (schema AllInclude).AsyncExecute(parse query)
87+
ensureDirect result <| fun data errors -> empty errors
88+
89+
[<Fact>]
90+
let ``Execute handles creation of inline input records list with optional null fields`` () =
91+
let query =
92+
"""{
93+
recordInputs(
94+
records: [{ a: "a", b: "b", c: "c" }],
95+
recordsOptional: [null],
96+
recordsNested: [{ a: { a: "a", b: "b", c: "c" }, b: null, c: null, s: null, l: [] }]
97+
)
98+
}"""
99+
let result = sync <| (schema Nothing).AsyncExecute(parse query)
100+
ensureDirect result <| fun data errors -> empty errors
101+
102+
[<Fact>]
103+
let ``Execute handles creation of inline input records list with mandatory only fields`` () =
104+
let query =
105+
"""{
106+
recordInputs(
107+
records: [{ a: "a", b: "b", c: "c" }],
108+
recordsNested: [{ a: { a: "a", b: "b", c: "c" }, l: [{ a: "a", b: "b", c: "c" }] }]
109+
)
110+
}"""
111+
let result = sync <| (schema Nothing).AsyncExecute(parse query)
112+
ensureDirect result <| fun data errors -> empty errors
113+
114+
let variablesWithAllInputs (record, optRecord, skippable) =
115+
$"""
116+
{{
117+
"records":[%s{record}],
118+
"optRecords":[%s{optRecord}],
119+
"nestedRecords":[ {{ "a": {record}, "b": {optRecord}, "c": {optRecord}, "s": {skippable}, "l": [{record}] }}]
120+
}}
121+
"""
122+
123+
let paramsWithValues variables =
124+
JsonDocument
125+
.Parse(variables : string)
126+
.RootElement.Deserialize<ImmutableDictionary<string, JsonElement>> (serializerOptions)
127+
128+
[<Fact>]
129+
let ``Execute handles creation of input records list from variables with all fields`` () =
130+
let query =
131+
"""query (
132+
$records: [InputRecord!]!,
133+
$optRecords: [InputRecordOptional],
134+
$nestedRecords: [InputRecordNested]!
135+
) {
136+
recordInputs(
137+
records: $records,
138+
recordsOptional: $optRecords,
139+
recordsNested: $nestedRecords
140+
)
141+
}"""
142+
let testInputObject = """{"a":"a","b":"b","c":"c"}"""
143+
let params' =
144+
variablesWithAllInputs(testInputObject, testInputObject, testInputObject) |> paramsWithValues
145+
let result = sync <| (schema AllInclude).AsyncExecute(parse query, variables = params')
146+
//let expected = NameValueLookup.ofList [ "recordInputs", upcast testInputObject ]
147+
ensureDirect result <| fun data errors ->
148+
empty errors
149+
//data |> equals (upcast expected)
150+
151+
[<Fact>]
152+
let ``Execute handles creation of input records list from variables with optional null fields`` () =
153+
let query =
154+
"""query (
155+
$records: [InputRecord!]!,
156+
$optRecords: [InputRecordOptional],
157+
$nestedRecords: [InputRecordNested]!
158+
) {
159+
recordInputs(
160+
records: $records,
161+
recordsOptional: $optRecords,
162+
recordsNested: $nestedRecords
163+
)
164+
}"""
165+
let testInputObject = """{"a":"a","b":"b","c":"c"}"""
166+
let testInputSkippable = """{ "a": null, "b": null, "c": null }"""
167+
let params' = variablesWithAllInputs(testInputObject, "null", testInputSkippable) |> paramsWithValues
168+
let result = sync <| (schema SkipAndIncludeNull).AsyncExecute(parse query, variables = params')
169+
ensureDirect result <| fun data errors -> empty errors
170+
171+
[<Fact>]
172+
let ``Execute handles creation of input records from variables with mandatory only fields`` () =
173+
let variablesWithAllInputs (record) =
174+
$"""
175+
{{
176+
"record":%s{record},
177+
"list":[%s{record}]
178+
}}
179+
"""
180+
181+
let query =
182+
"""query ($record: InputRecord!, $list: [InputRecord!]!){
183+
recordInputs(
184+
records: [$record],
185+
recordsNested: [{ a: $record, l: $list }]
186+
)
187+
}"""
188+
let testInputObject = """{"a":"a","b":"b","c":"c"}"""
189+
let params' = variablesWithAllInputs testInputObject |> paramsWithValues
190+
let result = sync <| (schema AllSkip).AsyncExecute(parse query, variables = params')
191+
ensureDirect result <| fun data errors -> empty errors

0 commit comments

Comments
 (0)