@@ -12,15 +12,16 @@ open FSharp.Data.GraphQL.Ast
1212
1313[<Struct>]
1414type GraphQLMultipartSection =
15- | Form of Form : FormMultipartSection
16- | File of File : FileMultipartSection
17- static member FromSection ( section : MultipartSection ) =
15+ | Form of Form : FormMultipartSection
16+ | File of File : FileMultipartSection
17+
18+ static member FromSection ( section : MultipartSection ) =
1819 match section with
1920 | null -> ValueNone
2021 | _ ->
21- match section.AsFormDataSection() with
22+ match section.AsFormDataSection () with
2223 | null ->
23- match section.AsFileSection() with
24+ match section.AsFileSection () with
2425 | null -> ValueNone
2526 | x -> ValueSome ( File x)
2627 | x -> ValueSome ( Form x)
@@ -33,14 +34,21 @@ type GraphQLMultipartSection =
3334/// <remarks> For more information, see https://github.com/jaydenseric/graphql-multipart-request-spec. </remarks>
3435[<Struct>]
3536type MultipartRequest =
36- /// Contains the list of operations of this request.
37- /// If the request is not batched, then the single operation will be inside this list as a singleton.
38- { Operations : GQLRequestContent list }
37+ /// Contains the list of operations of this request.
38+ /// If the request is not batched, then the single operation will be inside this list as a singleton.
39+ {
40+ Operations : GQLRequestContent list
41+ }
3942
4043/// Contains tools for working with GraphQL multipart requests.
4144module MultipartRequest =
4245
43- let private parseOperations ( jsonOptions : JsonSerializerOptions ) ( operations : GQLRequestContent list ) ( map : IDictionary < string , string >) ( files : IDictionary < string , File >) =
46+ let private parseOperations
47+ ( jsonOptions : JsonSerializerOptions )
48+ ( operations : GQLRequestContent list )
49+ ( map : IDictionary < string , string >)
50+ ( files : IDictionary < string , File >)
51+ =
4452
4553 let mapOperation ( operationIndex : int voption ) ( operation : GQLRequestContent ) =
4654 let findFile ( varName : string ) ( varValue : JsonElement ) = seq {
@@ -50,8 +58,9 @@ module MultipartRequest =
5058 | ( true , v) -> Some v
5159 | _ -> None)
5260 |> Seq.map ( fun key ->
53- key |> Option.map ( fun key ->
54- match files.TryGetValue( key) with
61+ key
62+ |> Option.map ( fun key ->
63+ match files.TryGetValue ( key) with
5564 | ( true , v) -> Some v
5665 | _ -> None)
5766 |> Option.flatten)
@@ -66,40 +75,47 @@ module MultipartRequest =
6675 |> Seq.choose ( fun kvp -> if kvp.Key = varName then Some files.[ kvp.Value] else None)
6776 |> List.ofSeq
6877 match found with
69- | [ x ] -> Some x
78+ | [ x ] -> Some x
7079 | _ -> None
7180 let pickSingleFileFromMap varName =
7281 map
7382 |> Seq.choose ( fun kvp -> if kvp.Key = varName then Some files.[ kvp.Value] else None)
7483 |> Seq.exactlyOne
75- let pickFileRequestFromMap ( request : UploadRequest ) varName : UploadRequest =
76- { Single = pickSingleFileFromMap $" %s {varName}.single"
77- Multiple = pickMultipleFilesFromMap request.Multiple.Length $" %s {varName}.multiple"
78- NullableMultiple = request.NullableMultiple |> Option.map ( fun x -> pickMultipleFilesFromMap x.Length $" %s {varName}.nullableMultiple" )
79- NullableMultipleNullable = request.NullableMultipleNullable |> Option.map ( fun x -> tryPickMultipleFilesFromMap x.Length $" %s {varName}.nullableMultipleNullable" ) }
84+ let pickFileRequestFromMap ( request : UploadRequest ) varName : UploadRequest = {
85+ Single = pickSingleFileFromMap $" %s {varName}.single"
86+ Multiple = pickMultipleFilesFromMap request.Multiple.Length $" %s {varName}.multiple"
87+ NullableMultiple =
88+ request.NullableMultiple
89+ |> Option.map ( fun x -> pickMultipleFilesFromMap x.Length $" %s {varName}.nullableMultiple" )
90+ NullableMultipleNullable =
91+ request.NullableMultipleNullable
92+ |> Option.map ( fun x -> tryPickMultipleFilesFromMap x.Length $" %s {varName}.nullableMultipleNullable" )
93+ }
8094 let rec isUpload ( t : InputType ) =
8195 match t with
8296 | NamedType tname -> tname = " Upload" || tname = " UploadRequest"
83- | ListType t | NonNullType t -> isUpload t
97+ | ListType t
98+ | NonNullType t -> isUpload t
8499 let ast = Parser.parse operation.Query
85100 let varDefs =
86101 ast.Definitions
87- |> List.choose ( function OperationDefinition def -> Some def.VariableDefinitions | _ -> None)
102+ |> List.choose ( function
103+ | OperationDefinition def -> Some def.VariableDefinitions
104+ | _ -> None)
88105 |> List.collect id
89106 let varDef = varDefs |> List.find ( fun x -> x.VariableName = varName)
90- if isUpload varDef.Type
91- then
107+ if isUpload varDef.Type then
92108 match varValue.ValueKind with
93109 | JsonValueKind.Object ->
94- let request = varValue.Deserialize< UploadRequest>( jsonOptions)
110+ let request = varValue.Deserialize< UploadRequest> ( jsonOptions)
95111 let varName =
96112 match operationIndex with
97113 | ValueSome operationIndex -> $" %i {operationIndex}.variables.%s {varName}"
98114 | ValueNone -> $" variables.%s {varName}"
99115 yield pickFileRequestFromMap request varName
100116 | JsonValueKind.Array ->
101117 let files =
102- varValue.EnumerateArray()
118+ varValue.EnumerateArray ()
103119 |> Seq.mapi ( fun valueIndex _ ->
104120 let varName =
105121 match operationIndex with
@@ -117,49 +133,58 @@ module MultipartRequest =
117133 | Some File -> yield file
118134 | None -> ()
119135 }
120- { operation with Variables = operation.Variables |> Skippable.map ( Map.map ( fun k v -> findFile k v)) }
136+ {
137+ operation with
138+ Variables =
139+ operation.Variables
140+ |> Skippable.map ( Map.map ( fun k v -> findFile k v))
141+ }
121142
122143 match operations with
123144 | [ operation ] -> [ mapOperation ValueNone operation ]
124- | operations -> operations |> List.mapi ( fun ix operation -> mapOperation ( ValueSome ix) operation)
145+ | operations ->
146+ operations
147+ |> List.mapi ( fun ix operation -> mapOperation ( ValueSome ix) operation)
125148
126149 /// Reads a GraphQL multipart request from a MultipartReader.
127- let read ( jsonOptions : JsonSerializerOptions ) cancellationToken ( reader : MultipartReader ) =
128- task {
129- let mutable section : GraphQLMultipartSection voption = ValueNone
130- let readNextSection () =
131- task {
132- let! next = reader.ReadNextSectionAsync cancellationToken
133- section <- GraphQLMultipartSection.FromSection( next)
150+ let read ( jsonOptions : JsonSerializerOptions ) cancellationToken ( reader : MultipartReader ) = task {
151+ let mutable section : GraphQLMultipartSection voption = ValueNone
152+ let readNextSection () = task {
153+ let! next = reader.ReadNextSectionAsync cancellationToken
154+ section <- GraphQLMultipartSection.FromSection ( next)
155+ }
156+ let mutable operations : string = null
157+ let mutable map : IDictionary < string , string > = null
158+ let files = Dictionary< string, File> ()
159+ do ! readNextSection ()
160+ while not section.IsNone do
161+ match section.Value with
162+ | Form section ->
163+ let! value = section.GetValueAsync ()
164+ match section.Name with
165+ | " operations" -> operations <- value
166+ | " map" ->
167+ map <-
168+ JsonSerializer.Deserialize< Map< string, string list>> ( value, jsonOptions)
169+ |> Seq.map ( fun kvp -> kvp.Value.Head, kvp.Key)
170+ |> Map.ofSeq
171+ | _ -> failwithf $""" Error reading multipart request. Unexpected section name "%s {section.Name}"."""
172+ | File section ->
173+ let stream = new System.IO.MemoryStream ( 4096 )
174+ do ! section.FileStream.CopyToAsync ( stream, cancellationToken)
175+ stream.Position <- 0 L
176+ let value = {
177+ Name = section.FileName
178+ ContentType = section.Section.ContentType
179+ Content = stream
134180 }
135- let mutable operations : string = null
136- let mutable map : IDictionary < string , string > = null
137- let files = Dictionary< string, File>()
181+ files.Add ( section.Name, value)
138182 do ! readNextSection ()
139- while not section.IsNone do
140- match section.Value with
141- | Form section ->
142- let! value = section.GetValueAsync()
143- match section.Name with
144- | " operations" ->
145- operations <- value
146- | " map" ->
147- map <- JsonSerializer.Deserialize< Map< string, string list>>( value, jsonOptions)
148- |> Seq.map ( fun kvp -> kvp.Value.Head, kvp.Key)
149- |> Map.ofSeq
150- | _ -> failwithf $""" Error reading multipart request. Unexpected section name "%s {section.Name}"."""
151- | File section ->
152- let stream = new System.IO.MemoryStream( 4096 )
153- do ! section.FileStream.CopyToAsync( stream, cancellationToken)
154- stream.Position <- 0 L
155- let value = { Name = section.FileName; ContentType = section.Section.ContentType; Content = stream }
156- files.Add( section.Name, value)
157- do ! readNextSection ()
158- let operations =
159- let jsonElement = ( JsonDocument.Parse operations) .RootElement
160- match jsonElement.ValueKind with
161- | JsonValueKind.Array -> jsonElement.Deserialize< GQLRequestContent list>( jsonOptions)
162- | JsonValueKind.Object -> [ jsonElement.Deserialize< GQLRequestContent>( jsonOptions) ]
163- | _ -> failwith " Unexpected operations value."
164- return { Operations = parseOperations jsonOptions operations map files }
165- }
183+ let operations =
184+ let jsonElement = ( JsonDocument.Parse operations) .RootElement
185+ match jsonElement.ValueKind with
186+ | JsonValueKind.Array -> jsonElement.Deserialize< GQLRequestContent list> ( jsonOptions)
187+ | JsonValueKind.Object -> [ jsonElement.Deserialize< GQLRequestContent> ( jsonOptions) ]
188+ | _ -> failwith " Unexpected operations value."
189+ return { Operations = parseOperations jsonOptions operations map files }
190+ }
0 commit comments