Skip to content

Commit aefce22

Browse files
njlrxperiandri
authored andcommitted
Fixed the encoding of default values when performing introspection.
Includes an update of introspection tests (cherry picked from commit d7c61ed)
1 parent 141e7dd commit aefce22

File tree

3 files changed

+59
-65
lines changed

3 files changed

+59
-65
lines changed

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ open FSharp.Control.Reactive
1212
open System.Collections.Generic
1313
open System.Reactive.Linq
1414
open System.Reactive.Subjects
15+
open System.Text.Json
1516

1617
type private Channel = ISubject<obj>
1718

@@ -62,6 +63,8 @@ type SchemaConfig =
6263
SubscriptionProvider : ISubscriptionProvider
6364
/// Provider for the back-end of the live query subscription system.
6465
LiveFieldSubscriptionProvider : ILiveFieldSubscriptionProvider
66+
/// JSON serialization options
67+
JsonOptions : JsonSerializerOptions
6568
}
6669
/// Returns the default Subscription Provider, backed by Observable streams.
6770
static member DefaultSubscriptionProvider() =
@@ -131,7 +134,8 @@ type SchemaConfig =
131134
| :? GraphQLException as ex -> [ex]
132135
| ex -> [{ new IGQLError with member _.Message = ex.Message }]
133136
SubscriptionProvider = SchemaConfig.DefaultSubscriptionProvider()
134-
LiveFieldSubscriptionProvider = SchemaConfig.DefaultLiveFieldSubscriptionProvider() }
137+
LiveFieldSubscriptionProvider = SchemaConfig.DefaultLiveFieldSubscriptionProvider()
138+
JsonOptions = JsonSerializerOptions.Default }
135139
/// <summary>
136140
/// Default SchemaConfig with buffered stream support.
137141
/// This config modifies the stream directive to have two optional arguments: 'interval' and 'preferredBatchSize'.
@@ -223,14 +227,17 @@ type Schema<'Root> (query: ObjectDef<'Root>, ?mutation: ObjectDef<'Root>, ?subsc
223227

224228
let introspectInput (namedTypes: Map<string, IntrospectionTypeRef>) (inputDef: InputFieldDef) : IntrospectionInputVal =
225229
// We need this so a default value that is an option is not printed as "Some"
226-
let stringify =
230+
let unwrap =
227231
function
228-
| ObjectOption x -> string x
229-
| x -> string x
232+
| ObjectOption x -> x
233+
| x -> x
234+
let defaultValue =
235+
inputDef.DefaultValue
236+
|> Option.map (fun value -> JsonSerializer.Serialize(unwrap value, schemaConfig.JsonOptions))
230237
{ Name = inputDef.Name
231238
Description = inputDef.Description
232239
Type = introspectTypeRef (Option.isSome inputDef.DefaultValue) namedTypes inputDef.TypeDef
233-
DefaultValue = inputDef.DefaultValue |> Option.map stringify }
240+
DefaultValue = defaultValue }
234241

235242
let introspectField (namedTypes: Map<string, IntrospectionTypeRef>) (fdef: FieldDef) =
236243
{ Name = fdef.Name

src/FSharp.Data.GraphQL.Shared/Helpers/Reflection.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ open System.Collections.Immutable
1111
/// General helper functions and types.
1212
module Helpers =
1313

14-
/// Casts a System.Object to an option to a System.Object option.
14+
/// Casts a System.Object to a System.Object option.
1515
let optionCast (value: obj) =
1616
if isNull value then None
1717
else

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

Lines changed: 46 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ let inputFieldQuery = """{
4545
let ``Input field must be marked as nullable when defaultValue is provided`` () =
4646
let root = Define.Object("Query", [
4747
Define.Field("onlyField", StringType, "The only field", [
48-
Define.Input("in", StringType, defaultValue = "1")
48+
Define.Input("inInt", IntType, defaultValue = 1)
49+
Define.Input("inString", StringType, defaultValue = "this is a default value")
4950
], fun _ _ -> "Only value")
5051
])
5152
let schema = Schema(root)
@@ -57,23 +58,29 @@ let ``Input field must be marked as nullable when defaultValue is provided`` ()
5758
"name", upcast "onlyField"
5859
"args", upcast [
5960
NameValueLookup.ofList [
60-
"name", upcast "in"
61+
"name", upcast "inInt"
6162
"type", upcast NameValueLookup.ofList [
6263
"kind", upcast "SCALAR"
63-
"name", upcast "String"
64+
"name", upcast "Int"
6465
]
6566
"defaultValue", upcast "1"
6667
]
68+
NameValueLookup.ofList [
69+
"name", upcast "inString"
70+
"type", upcast NameValueLookup.ofList [
71+
"kind", upcast "SCALAR"
72+
"name", upcast "String"
73+
]
74+
"defaultValue", upcast "\"this is a default value\""
75+
]
6776
]
6877
]
6978
]
7079
]
7180
]
72-
match result with
73-
| Direct(data, errors) ->
74-
empty errors
75-
data |> equals (upcast expected)
76-
| response -> fail $"Expected a Direct GQLResponse but got {Environment.NewLine}{response}"
81+
ensureDirect result <| fun data errors ->
82+
empty errors
83+
data |> equals (upcast expected)
7784

7885
[<Fact>]
7986
let ``Input field must be marked as non-nullable when defaultValue is not provided`` () =
@@ -103,11 +110,9 @@ let ``Input field must be marked as non-nullable when defaultValue is not provid
103110
]
104111
]
105112
]
106-
match result with
107-
| Direct(data, errors) ->
108-
empty errors
109-
data |> equals (upcast expected)
110-
| response -> fail $"Expected a Direct GQLResponse but got {Environment.NewLine}{response}"
113+
ensureDirect result <| fun data errors ->
114+
empty errors
115+
data |> equals (upcast expected)
111116

112117
[<Fact>]
113118
let ``Input field must be marked as nullable when its type is nullable`` () =
@@ -137,11 +142,9 @@ let ``Input field must be marked as nullable when its type is nullable`` () =
137142
]
138143
]
139144
]
140-
match result with
141-
| Direct(data, errors) ->
142-
empty errors
143-
data |> equals (upcast expected)
144-
| response -> fail $"Expected a Direct GQLResponse but got {Environment.NewLine}{response}"
145+
ensureDirect result <| fun data errors ->
146+
empty errors
147+
data |> equals (upcast expected)
145148

146149
[<Fact>]
147150
let ``Input field must be marked as nullable when its type is nullable and have default value provided`` () =
@@ -164,18 +167,16 @@ let ``Input field must be marked as nullable when its type is nullable and have
164167
"kind", upcast "SCALAR"
165168
"name", upcast "String"
166169
]
167-
"defaultValue", upcast "1"
170+
"defaultValue", upcast "\"1\""
168171
]
169172
]
170173
]
171174
]
172175
]
173176
]
174-
match result with
175-
| Direct(data, errors) ->
176-
empty errors
177-
data |> equals (upcast expected)
178-
| response -> fail $"Expected a Direct GQLResponse but got {Environment.NewLine}{response}"
177+
ensureDirect result <| fun data errors ->
178+
empty errors
179+
data |> equals (upcast expected)
179180

180181
[<Fact>]
181182
let ``Introspection schema must be serializable back and forth using json`` () =
@@ -282,8 +283,7 @@ let ``Introspection schema must be serializable back and forth using json`` () =
282283
}
283284
}"""
284285
let result = Executor(schema).AsyncExecute(query) |> sync
285-
match result with
286-
| Direct (data, errors) ->
286+
ensureDirect result <| fun data errors ->
287287
empty errors
288288
let additionalConverters = Seq.empty //seq { NameValueLookupConverter() :> JsonConverter }
289289
let json = JsonSerializer.Serialize(data, Json.getSerializerOptions additionalConverters)
@@ -296,7 +296,6 @@ let ``Introspection schema must be serializable back and forth using json`` () =
296296
let deserialized = JsonSerializer.Deserialize<IntrospectionResult>(json, skippableOptions)
297297
let expected = (schema :> ISchema).Introspected
298298
deserialized.__schema |> equals expected
299-
| response -> fail $"Expected a Direct GQLResponse but got {Environment.NewLine}{response}"
300299

301300
[<Fact>]
302301
let ``Core type definitions are considered nullable`` () =
@@ -325,11 +324,9 @@ let ``Core type definitions are considered nullable`` () =
325324
"kind", upcast "SCALAR"
326325
"name", upcast "String"
327326
"ofType", null]]
328-
match result with
329-
| Direct(data, errors) ->
330-
empty errors
331-
data |> equals (upcast expected)
332-
| response -> fail $"Expected a Direct GQLResponse but got {Environment.NewLine}{response}"
327+
ensureDirect result <| fun data errors ->
328+
empty errors
329+
data |> equals (upcast expected)
333330

334331
type User = { FirstName: string; LastName: string }
335332
type UserInput = { Name: string }
@@ -391,11 +388,9 @@ let ``Default field type definitions are considered non-null`` () =
391388
"kind", upcast "SCALAR"
392389
"name", upcast "String"
393390
"ofType", null]]]]]]
394-
match result with
395-
| Direct(data, errors) ->
396-
empty errors
397-
data |> equals (upcast expected)
398-
| response -> fail $"Expected a Direct GQLResponse but got {Environment.NewLine}{response}"
391+
ensureDirect result <| fun data errors ->
392+
empty errors
393+
data |> equals (upcast expected)
399394

400395
[<Fact>]
401396
let ``Nullabe field type definitions are considered nullable`` () =
@@ -433,11 +428,9 @@ let ``Nullabe field type definitions are considered nullable`` () =
433428
"kind", upcast "SCALAR"
434429
"name", upcast "String"
435430
"ofType", null]]]]]
436-
match result with
437-
| Direct(data, errors) ->
438-
empty errors
439-
data |> equals (upcast expected)
440-
| response -> fail $"Expected a Direct GQLResponse but got {Environment.NewLine}{response}"
431+
ensureDirect result <| fun data errors ->
432+
empty errors
433+
data |> equals (upcast expected)
441434

442435
[<Fact>]
443436
let ``Default field args type definitions are considered non-null`` () =
@@ -482,11 +475,9 @@ let ``Default field args type definitions are considered non-null`` () =
482475
"kind", upcast "SCALAR"
483476
"name", upcast "Int"
484477
"ofType", null]]]]]]]]
485-
match result with
486-
| Direct(data, errors) ->
487-
empty errors
488-
data |> equals (upcast expected)
489-
| response -> fail $"Expected a Direct GQLResponse but got {Environment.NewLine}{response}"
478+
ensureDirect result <| fun data errors ->
479+
empty errors
480+
data |> equals (upcast expected)
490481

491482
[<Fact>]
492483
let ``Nullable field args type definitions are considered nullable`` () =
@@ -528,11 +519,9 @@ let ``Nullable field args type definitions are considered nullable`` () =
528519
"kind", upcast "SCALAR"
529520
"name", upcast "Int"
530521
"ofType", null ]]]]]]]
531-
match result with
532-
| Direct(data, errors) ->
533-
empty errors
534-
data |> equals (upcast expected)
535-
| response -> fail $"Expected a Direct GQLResponse but got {Environment.NewLine}{response}"
522+
ensureDirect result <| fun data errors ->
523+
empty errors
524+
data |> equals (upcast expected)
536525

537526
[<Fact>]
538527
let ``Introspection executes an introspection query`` () =
@@ -910,7 +899,7 @@ let ``Introspection executes an introspection query`` () =
910899
"kind", upcast "SCALAR"
911900
"name", upcast "Boolean"
912901
"ofType", null]
913-
"defaultValue", upcast "False"];]
902+
"defaultValue", upcast "false"];]
914903
"type", upcast NameValueLookup.ofList [
915904
"kind", upcast "LIST"
916905
"name", null
@@ -934,7 +923,7 @@ let ``Introspection executes an introspection query`` () =
934923
"kind", upcast "SCALAR"
935924
"name", upcast "Boolean"
936925
"ofType", null]
937-
"defaultValue", upcast "False"];]
926+
"defaultValue", upcast "false"];]
938927
"type", upcast NameValueLookup.ofList [
939928
"kind", upcast "LIST"
940929
"name", null
@@ -1410,8 +1399,6 @@ let ``Introspection executes an introspection query`` () =
14101399
upcast "FRAGMENT_SPREAD";
14111400
upcast "INLINE_FRAGMENT";]
14121401
"args", upcast []]]]]
1413-
match result with
1414-
| Direct(data, errors) ->
1415-
empty errors
1416-
data |> equals (upcast expected)
1417-
| response -> fail $"Expected a Direct GQLResponse but got {Environment.NewLine}{response}"
1402+
ensureDirect result <| fun data errors ->
1403+
empty errors
1404+
data |> equals (upcast expected)

0 commit comments

Comments
 (0)