1111using Npgsql . TypeMapping ;
1212using NpgsqlTypes ;
1313
14+ #if NET6_0_OR_GREATER || NETSTANDARD2_0 || NETSTANDARD2_1
15+ using System . Text . Json . Nodes ;
16+ #endif
17+
1418namespace Npgsql . Internal . TypeHandlers ;
1519
1620/// <summary>
@@ -66,11 +70,25 @@ protected internal override int ValidateAndGetLengthCustom<TAny>([DisallowNull]
6670 if ( lengthCache . IsPopulated )
6771 return lengthCache . Get ( ) ;
6872
69- var data = SerializeJsonDocument ( ( JsonDocument ) ( object ) value ! ) ;
73+ var data = SerializeJsonDocument ( ( JsonDocument ) ( object ) value ) ;
7074 if ( parameter != null )
7175 parameter . ConvertedValue = data ;
7276 return lengthCache . Set ( data . Length + _headerLen ) ;
7377 }
78+
79+ #if NET6_0_OR_GREATER || NETSTANDARD2_0 || NETSTANDARD2_1
80+ if ( typeof ( TAny ) == typeof ( JsonObject ) || typeof ( TAny ) == typeof ( JsonArray ) )
81+ {
82+ lengthCache ??= new NpgsqlLengthCache ( 1 ) ;
83+ if ( lengthCache . IsPopulated )
84+ return lengthCache . Get ( ) ;
85+
86+ var data = SerializeJsonObject ( ( JsonNode ) ( object ) value ) ;
87+ if ( parameter != null )
88+ parameter . ConvertedValue = data ;
89+ return lengthCache . Set ( data . Length + _headerLen ) ;
90+ }
91+ #endif
7492
7593 // User POCO, need to serialize. At least internally ArrayPool buffers are used...
7694 var s = JsonSerializer . Serialize ( value , _serializerOptions ) ;
@@ -94,30 +112,39 @@ protected override async Task WriteWithLengthCustom<TAny>([DisallowNull] TAny va
94112 buf . WriteByte ( JsonbProtocolVersion ) ;
95113
96114 if ( typeof ( TAny ) == typeof ( string ) )
97- await _textHandler . Write ( ( string ) ( object ) value ! , buf , lengthCache , parameter , async, cancellationToken ) ;
115+ await _textHandler . Write ( ( string ) ( object ) value , buf , lengthCache , parameter , async, cancellationToken ) ;
98116 else if ( typeof ( TAny ) == typeof ( char [ ] ) )
99- await _textHandler . Write ( ( char [ ] ) ( object ) value ! , buf , lengthCache , parameter , async, cancellationToken ) ;
117+ await _textHandler . Write ( ( char [ ] ) ( object ) value , buf , lengthCache , parameter , async, cancellationToken ) ;
100118 else if ( typeof ( TAny ) == typeof ( ArraySegment < char > ) )
101- await _textHandler . Write ( ( ArraySegment < char > ) ( object ) value ! , buf , lengthCache , parameter , async, cancellationToken ) ;
119+ await _textHandler . Write ( ( ArraySegment < char > ) ( object ) value , buf , lengthCache , parameter , async, cancellationToken ) ;
102120 else if ( typeof ( TAny ) == typeof ( char ) )
103- await _textHandler . Write ( ( char ) ( object ) value ! , buf , lengthCache , parameter , async, cancellationToken ) ;
121+ await _textHandler . Write ( ( char ) ( object ) value , buf , lengthCache , parameter , async, cancellationToken ) ;
104122 else if ( typeof ( TAny ) == typeof ( byte [ ] ) )
105- await _textHandler . Write ( ( byte [ ] ) ( object ) value ! , buf , lengthCache , parameter , async, cancellationToken ) ;
123+ await _textHandler . Write ( ( byte [ ] ) ( object ) value , buf , lengthCache , parameter , async, cancellationToken ) ;
106124 else if ( typeof ( TAny ) == typeof ( ReadOnlyMemory < byte > ) )
107- await _textHandler . Write ( ( ReadOnlyMemory < byte > ) ( object ) value ! , buf , lengthCache , parameter , async, cancellationToken ) ;
125+ await _textHandler . Write ( ( ReadOnlyMemory < byte > ) ( object ) value , buf , lengthCache , parameter , async, cancellationToken ) ;
108126 else if ( typeof ( TAny ) == typeof ( JsonDocument ) )
109127 {
110128 var data = parameter ? . ConvertedValue != null
111129 ? ( byte [ ] ) parameter . ConvertedValue
112- : SerializeJsonDocument ( ( JsonDocument ) ( object ) value ! ) ;
130+ : SerializeJsonDocument ( ( JsonDocument ) ( object ) value ) ;
131+ await buf . WriteBytesRaw ( data , async , cancellationToken ) ;
132+ }
133+ #if NET6_0_OR_GREATER || NETSTANDARD2_0 || NETSTANDARD2_1
134+ else if ( typeof ( TAny ) == typeof ( JsonObject ) || typeof ( TAny ) == typeof ( JsonArray ) )
135+ {
136+ var data = parameter? . ConvertedValue != null
137+ ? ( byte [ ] ) parameter . ConvertedValue
138+ : SerializeJsonObject ( ( JsonNode ) ( object ) value ) ;
113139 await buf . WriteBytesRaw ( data , async , cancellationToken ) ;
114140 }
141+ #endif
115142 else
116143 {
117144 // User POCO, read serialized representation from the validation phase
118145 var s = parameter ? . ConvertedValue != null
119146 ? ( string ) parameter . ConvertedValue
120- : JsonSerializer . Serialize ( value ! , value ! . GetType ( ) , _serializerOptions ) ;
147+ : JsonSerializer . Serialize ( value , value . GetType ( ) , _serializerOptions ) ;
121148
122149 await _textHandler . Write ( s , buf , lengthCache , parameter , async , cancellationToken ) ;
123150 }
@@ -151,6 +178,10 @@ public override int ValidateObjectAndGetLength(object value, ref NpgsqlLengthCac
151178 byte [ ] s => ValidateAndGetLength ( s , ref lengthCache , parameter ) ,
152179 ReadOnlyMemory < byte > s => ValidateAndGetLength ( s , ref lengthCache , parameter ) ,
153180 JsonDocument jsonDocument => ValidateAndGetLength ( jsonDocument , ref lengthCache , parameter ) ,
181+ #if NET6_0_OR_GREATER || NETSTANDARD2_0 || NETSTANDARD2_1
182+ JsonObject jsonObject => ValidateAndGetLength ( jsonObject , ref lengthCache , parameter ) ,
183+ JsonArray jsonArray => ValidateAndGetLength ( jsonArray , ref lengthCache , parameter ) ,
184+ #endif
154185 _ => ValidateAndGetLength( value , ref lengthCache , parameter )
155186 } ;
156187
@@ -172,6 +203,10 @@ public override async Task WriteObjectWithLength(object? value, NpgsqlWriteBuffe
172203 byte [ ] s => WriteWithLengthCustom ( s , buf , lengthCache , parameter , async , cancellationToken ) ,
173204 ReadOnlyMemory < byte > s => WriteWithLengthCustom ( s , buf , lengthCache , parameter , async , cancellationToken ) ,
174205 JsonDocument jsonDocument => WriteWithLengthCustom ( jsonDocument , buf , lengthCache , parameter , async , cancellationToken ) ,
206+ #if NET6_0_OR_GREATER || NETSTANDARD2_0 || NETSTANDARD2_1
207+ JsonObject jsonObject => WriteWithLengthCustom( jsonObject, buf , lengthCache , parameter , async , cancellationToken ) ,
208+ JsonArray jsonArray => WriteWithLengthCustom ( jsonArray , buf , lengthCache , parameter , async , cancellationToken ) ,
209+ #endif
175210 _ => WriteWithLengthCustom ( value , buf , lengthCache , parameter , async , cancellationToken ) ,
176211 } ) ;
177212 }
@@ -243,4 +278,17 @@ byte[] SerializeJsonDocument(JsonDocument document)
243278 writer . Flush ( ) ;
244279 return stream . ToArray ( ) ;
245280 }
281+
282+ #if NET6_0_OR_GREATER || NETSTANDARD2_0 || NETSTANDARD2_1
283+ byte [ ] SerializeJsonObject ( JsonNode jsonObject )
284+ {
285+ // TODO: Writing is currently really inefficient - please don't criticize :)
286+ // We need to implement one-pass writing to serialize directly to the buffer (or just switch to pipelines).
287+ using var stream = new MemoryStream ( ) ;
288+ using var writer = new Utf8JsonWriter ( stream ) ;
289+ jsonObject . WriteTo ( writer ) ;
290+ writer . Flush ( ) ;
291+ return stream . ToArray ( ) ;
292+ }
293+ #endif
246294}
0 commit comments