Skip to content

Commit 9b9039b

Browse files
committed
Updateв schema, add type coercion guide, bug report, tools
* Added bug report for InputObject array type mismatch with analysis and test cases * Added type coercion guide for ObjectListFilter with usage and API docs * Introduced format-changed-files.ps1 to batch-format changed F# files via Fantomas * Updated schema snapshots for relay-style connections and new scalars * Refactored field_aliases.fsx for relay-style friends connection * Optimized TypeCoercion.fs to use Utf8JsonWriter for value coercion * Added prompt template for automated PR/issue description generation
1 parent edad98f commit 9b9039b

1 file changed

Lines changed: 37 additions & 18 deletions

File tree

src/FSharp.Data.GraphQL.Server.Middleware/TypeCoercion.fs

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace FSharp.Data.GraphQL.Server.Middleware
22

33
open System
4+
open System.Buffers
45
open System.Collections.Generic
56
open System.Reflection
67
open System.Text.Json
@@ -102,39 +103,57 @@ module TypeCoercion =
102103
|> ValueOption.defaultValue fieldName
103104

104105
/// <summary>
105-
/// Converts a boxed GraphQL scalar primitive to its JSON text representation so that <see cref="JsonSerializer.Deserialize"/> can produce the
106-
/// correct CLR value. Strings and enum-like values are JSON-quoted (<c>"value"</c>); numbers and booleans are emitted as raw JSON tokens.
106+
/// Writes a boxed GraphQL scalar primitive as a JSON token directly into <paramref name="writer"/>. Strings become JSON strings; numbers and
107+
/// booleans become raw JSON tokens. Returns <c>true</c> if the value was written; <c>false</c> if the type is unsupported.
107108
/// </summary>
108-
let private toJsonString (value : obj) : string voption =
109+
let private writeJsonValue (value : obj) (writer : Utf8JsonWriter) : bool =
109110
match value with
110-
| :? string as s -> ValueSome $"\"{JsonEncodedText.Encode(s)}\""
111-
| :? bool as b -> ValueSome (if b then "true" else "false")
112-
| :? int64 as n -> ValueSome (string n)
113-
| :? int as n -> ValueSome (string n)
114-
| :? double as n -> ValueSome (sprintf "%g" n)
115-
| :? float32 as n -> ValueSome (sprintf "%g" n)
116-
| :? decimal as n -> ValueSome (string n)
117-
| _ -> ValueNone
111+
| :? string as s ->
112+
writer.WriteStringValue s
113+
true
114+
| :? bool as b ->
115+
writer.WriteBooleanValue b
116+
true
117+
| :? int64 as n ->
118+
writer.WriteNumberValue n
119+
true
120+
| :? int as n ->
121+
writer.WriteNumberValue n
122+
true
123+
| :? double as n ->
124+
writer.WriteNumberValue n
125+
true
126+
| :? float32 as n ->
127+
writer.WriteNumberValue n
128+
true
129+
| :? decimal as n ->
130+
writer.WriteNumberValue n
131+
true
132+
| _ ->
133+
false
118134

119135
// Suppress nullness warnings for the obj / objnull mixture.
120136
#nowarn "3261"
121137
/// <summary>
122-
/// Tries to coerce a value into <paramref name="targetType"/> using STJ deserialization. Primitives are first rendered as a JSON string via
123-
/// <see cref="toJsonString"/> then parsed with <see cref="JsonDocument.Parse"/> and deserialized. Already-correct values pass through unchanged.
138+
/// Tries to coerce a value into <paramref name="targetType"/> using STJ deserialization. Primitives are written directly as JSON bytes via
139+
/// <see cref="writeJsonValue"/> into an <see cref="ArrayBufferWriter{T}"/>, then deserialized from <c>ReadOnlySpan&lt;byte&gt;</c>.
140+
/// Already-correct values pass through unchanged. No intermediate string or <see cref="JsonDocument"/> is allocated.
124141
/// </summary>
125142
let tryCoerceValue (jsonOptions : JsonSerializerOptions voption) (targetType : Type) (value : objnull) : obj voption =
126143
if isNull value then
127144
ValueNone
128145
elif targetType.IsInstanceOfType value then
129146
ValueSome value
130147
else
131-
match toJsonString value with
132-
| ValueNone -> ValueNone
133-
| ValueSome json ->
148+
let buffer = ArrayBufferWriter<byte> 64
149+
use writer = new Utf8JsonWriter (buffer)
150+
if not (writeJsonValue value writer) then
151+
ValueNone
152+
else
153+
writer.Flush ()
134154
try
135155
let opts = jsonOptions |> ValueOption.defaultValue JsonSerializerOptions.Default
136-
use doc = JsonDocument.Parse json
137-
doc.Deserialize (targetType, opts) |> ValueSome
156+
JsonSerializer.Deserialize (buffer.WrittenSpan, targetType, opts) |> ValueSome
138157
with _ ->
139158
ValueNone
140159

0 commit comments

Comments
 (0)