@@ -10,22 +10,65 @@ open FSharp
1010open FSharp.Data .GraphQL
1111open FSharp.Data .GraphQL .Types
1212open FSharp.Data .GraphQL .Server .Middleware
13- open FSharp.Data .GraphQL .Shared
1413open FSharp.Data .GraphQL .Parser
15- open FSharp.Data .GraphQL .Execution
1614open FSharp.Data .GraphQL .Ast
1715
1816#nowarn " 40"
1917
2018type Root = { clientId : int }
2119
22- and Subject =
20+ type GuidId = ValueObjectId of Guid
21+
22+ let private parseGuidId ( value : string ) =
23+ match Guid.TryParse value with
24+ | true , guid -> Ok ( ValueObjectId guid)
25+ | false , _ ->
26+ Error [
27+ { new IGQLError with
28+ member _.Message = $" Cannot coerce '{value}' to GuidID"
29+ }
30+ ]
31+
32+ let private guidIdToString ( ValueObjectId guidId ) = guidId.ToString " D"
33+
34+ let ValueObjectType =
35+ Define.WrappedScalar (
36+ name = " ValueObject" ,
37+ coerceInput =
38+ ( function
39+ | InputParameterValue.Variable value when value.ValueKind = JsonValueKind.String -> parseGuidId ( value.GetString ())
40+ | InputParameterValue.InlineConstant ( StringValue value) -> parseGuidId value
41+ | _ ->
42+ Error [
43+ { new IGQLError with
44+ member _. Message = " ValueObject must be provided as string"
45+ }
46+ ]),
47+ coerceOutput =
48+ ( function
49+ | :? GuidId as guid -> guidIdToString guid |> Some
50+ | _ -> None)
51+ )
52+
53+ type Subject =
2354 | A of A
2455 | B of B
2556
26- and A = { Id : int ; Value : string ; Subjects : int list }
57+ and A = {
58+ Id : int
59+ Value : string
60+ GuidValue : Guid
61+ ValueObject : GuidId
62+ Subjects : int list
63+ }
2764
28- and B = { Id : int ; Value : string ; Subjects : int list }
65+ and B = {
66+ Id : int
67+ Value : string
68+ GuidValue : Guid
69+ ValueObject : GuidId
70+ Subjects : int list
71+ }
2972
3073type Complex = {
3174 Id : int
@@ -43,12 +86,12 @@ type Property =
4386 | Community of Community
4487
4588let getExecutor ( expectedFilter : ObjectListFilter voption ) =
46- let a1 : A = { Id = 1 ; Value = " A1" ; Subjects = [ 2 ; 6 ] }
47- let a2 : A = { Id = 2 ; Value = " A2" ; Subjects = [ 1 ; 3 ; 5 ] }
48- let a3 : A = { Id = 3 ; Value = " A3" ; Subjects = [ 1 ; 2 ; 4 ] }
49- let b1 = { Id = 4 ; Value = " 1000" ; Subjects = [ 1 ; 5 ] }
50- let b2 = { Id = 5 ; Value = " 2000" ; Subjects = [ 3 ; 4 ; 6 ] }
51- let b3 = { Id = 6 ; Value = " 3000" ; Subjects = [ 1 ; 3 ; 5 ] }
89+ let a1 : A = { Id = 1 ; Value = " A1" ; GuidValue = Guid.Parse " 11111111-1111-1111-1111-111111111111 " ; ValueObject = ValueObjectId ( Guid.Parse " 11111111-1111-1111-1111-111111111111 " ); Subjects = [ 2 ; 6 ] }
90+ let a2 : A = { Id = 2 ; Value = " A2" ; GuidValue = Guid.Parse " 22222222-2222-2222-2222-222222222222 " ; ValueObject = ValueObjectId ( Guid.Parse " 22222222-2222-2222-2222-222222222222 " ); Subjects = [ 1 ; 3 ; 5 ] }
91+ let a3 : A = { Id = 3 ; Value = " A3" ; GuidValue = Guid.Parse " 33333333-3333-3333-3333-333333333333 " ; ValueObject = ValueObjectId ( Guid.Parse " 33333333-3333-3333-3333-333333333333 " ); Subjects = [ 1 ; 2 ; 4 ] }
92+ let b1 = { Id = 4 ; Value = " 1000" ; GuidValue = Guid.Parse " 44444444-4444-4444-4444-444444444444 " ; ValueObject = ValueObjectId ( Guid.Parse " 44444444-4444-4444-4444-444444444444 " ); Subjects = [ 1 ; 5 ] }
93+ let b2 = { Id = 5 ; Value = " 2000" ; GuidValue = Guid.Parse " 55555555-5555-5555-5555-555555555555 " ; ValueObject = ValueObjectId ( Guid.Parse " 55555555-5555-5555-5555-555555555555 " ); Subjects = [ 3 ; 4 ; 6 ] }
94+ let b3 = { Id = 6 ; Value = " 3000" ; GuidValue = Guid.Parse " 66666666-6666-6666-6666-666666666666 " ; ValueObject = ValueObjectId ( Guid.Parse " 66666666-6666-6666-6666-666666666666 " ); Subjects = [ 1 ; 3 ; 5 ] }
5295 let al = [ a1; a2; a3 ]
5396 let bl = [ b1; b2; b3 ]
5497 let p1 = Complex{ Id = 1 ; Name = " Complex 1" ; Discriminator = " Complex" ; Communities = [ 5 ]; Buildings = [ 3 ] }
@@ -90,6 +133,8 @@ let getExecutor (expectedFilter : ObjectListFilter voption) =
90133 fun () -> [
91134 Define.Field ( " id" , IntType, resolve = ( fun _ a -> a.Id))
92135 Define.Field ( " value" , StringType, resolve = ( fun _ a -> a.Value))
136+ Define.Field ( " guidValue" , GuidType, resolve = ( fun _ a -> a.GuidValue))
137+ Define.Field ( " valueObject" , ValueObjectType, resolve = ( fun _ a -> a.ValueObject))
93138 Define
94139 .Field(
95140 " subjects" ,
@@ -111,6 +156,8 @@ let getExecutor (expectedFilter : ObjectListFilter voption) =
111156 fun () -> [
112157 Define.Field ( " id" , IntType, resolve = ( fun _ b -> b.Id))
113158 Define.Field ( " value" , StringType, resolve = ( fun _ b -> b.Value))
159+ Define.Field ( " guidValue" , GuidType, resolve = ( fun _ b -> b.GuidValue))
160+ Define.Field ( " valueObject" , ValueObjectType, resolve = ( fun _ b -> b.ValueObject))
114161 Define
115162 .Field(
116163 " subjects" ,
@@ -1093,6 +1140,87 @@ let ``Object list filter: Must parse filter that references variables`` () =
10931140 data |> equals ( upcast expected)
10941141 result.Metadata.TryFind< ObjectListFilters> ( " filters" ) |> wantValueSome |> seqEquals [ expectedFilter ]
10951142
1143+ [<Fact>]
1144+ let ``Object list filter : Must parse inline filter variable backed by Guid scalar`` () =
1145+ let query =
1146+ parse
1147+ """ query testQuery($filter: Guid!) {
1148+ A (id : 1) {
1149+ id
1150+ value
1151+ subjects (filter : { guidValue : $filter }) { ...Value }
1152+ }
1153+ }
1154+
1155+ fragment Value on Subject {
1156+ ...on A {
1157+ id
1158+ value
1159+ }
1160+ ...on B {
1161+ id
1162+ value
1163+ }
1164+ }"""
1165+ let expected =
1166+ NameValueLookup.ofList [
1167+ " A" ,
1168+ upcast
1169+ NameValueLookup.ofList [
1170+ " id" , upcast 1
1171+ " value" , upcast " A1"
1172+ " subjects" ,
1173+ upcast
1174+ [
1175+ NameValueLookup.ofList [ " id" , upcast 2 ; " value" , upcast " A2" ]
1176+ NameValueLookup.ofList [ " id" , upcast 6 ; " value" , upcast " 3000" ]
1177+ ]
1178+ ]
1179+ ]
1180+
1181+ let guidText = " 22222222-2222-2222-2222-222222222222"
1182+ let filterValue = $" \" {guidText}\" " |> JsonDocument.Parse |> _. RootElement
1183+ let variables = ImmutableDictionary< string, JsonElement>. Empty.Add ( " filter" , filterValue)
1184+ let filter = Equals ({ FieldName = " guidvalue" ; Value = guidText }, null )
1185+ let expectedFilter : KeyValuePair < obj list , _ > = kvp ([ " A" ; " subjects" ]) filter
1186+ let result = executeAndVerifyFilter ( query, variables, filter)
1187+
1188+ ensureDirect result <| fun data errors ->
1189+ empty errors
1190+ data |> equals ( upcast expected)
1191+ result.Metadata.TryFind< ObjectListFilters> ( " filters" ) |> wantValueSome |> seqEquals [ expectedFilter ]
1192+
1193+ [<Fact>]
1194+ let ``Object list filter : Must parse inline filter variable backed by wrapped value object`` () =
1195+ let query =
1196+ parse
1197+ """ query testQuery($valueObject: ValueObject!) {
1198+ A (id : 1) {
1199+ id
1200+ value
1201+ subjects (filter : { valueObject : $valueObject }) { ...Value }
1202+ }
1203+ }
1204+
1205+ fragment Value on Subject {
1206+ ...on A {
1207+ id
1208+ value
1209+ }
1210+ ...on B {
1211+ id
1212+ value
1213+ }
1214+ }"""
1215+
1216+ let valueObjectText = " 22222222-2222-2222-2222-222222222222"
1217+ let valueObjectVariable = $" \" {valueObjectText}\" " |> JsonDocument.Parse |> _. RootElement
1218+ let variables = ImmutableDictionary< string, JsonElement>. Empty.Add ( " valueObject" , valueObjectVariable)
1219+ let result = executeWithVariables ( query, variables)
1220+
1221+ ensureDirect result <| fun _ errors ->
1222+ empty errors
1223+
10961224[<Fact>]
10971225let ``Object list filter : Must return empty filter when all discriminated union types are specified`` () =
10981226 let query =
0 commit comments