Skip to content

Commit f02df03

Browse files
authored
Refactor type handler hierarchy (#3711)
Closes #3710
1 parent ab7df53 commit f02df03

28 files changed

Lines changed: 301 additions & 470 deletions

src/Directory.Build.props

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
<GenerateDocumentationFile>true</GenerateDocumentationFile>
66
</PropertyGroup>
77

8+
<ItemGroup>
9+
<Compile Include="..\Shared\*.cs" />
10+
</ItemGroup>
11+
812
<ItemGroup>
913
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
1014
</ItemGroup>

src/Npgsql.Json.NET/Internal/JsonHandler.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics.CodeAnalysis;
23
using System.Threading;
34
using System.Threading.Tasks;
45
using Newtonsoft.Json;
@@ -27,61 +28,60 @@ class JsonHandler : Npgsql.Internal.TypeHandlers.JsonHandler
2728
public JsonHandler(PostgresType postgresType, NpgsqlConnector connector, JsonSerializerSettings settings)
2829
: base(postgresType, connector, isJsonb: false) => _settings = settings;
2930

30-
protected override async ValueTask<T> Read<T>(NpgsqlReadBuffer buf, int len, bool async, FieldDescription? fieldDescription = null)
31+
protected override async ValueTask<T> ReadCustom<T>(NpgsqlReadBuffer buf, int len, bool async, FieldDescription? fieldDescription = null)
3132
{
3233
if (typeof(T) == typeof(string) ||
3334
typeof(T) == typeof(char[]) ||
3435
typeof(T) == typeof(ArraySegment<char>) ||
3536
typeof(T) == typeof(char) ||
3637
typeof(T) == typeof(byte[]))
3738
{
38-
return await base.Read<T>(buf, len, async, fieldDescription);
39+
return await base.ReadCustom<T>(buf, len, async, fieldDescription);
3940
}
4041

4142
// JSON.NET returns null if no JSON content was found. This means null may get returned even if T is a non-nullable reference
4243
// type (for value types, an exception will be thrown).
4344
return JsonConvert.DeserializeObject<T>(await base.Read<string>(buf, len, async, fieldDescription), _settings)!;
4445
}
4546

46-
protected override int ValidateAndGetLength<T2>(T2 value, ref NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter)
47+
protected override int ValidateAndGetLengthCustom<T2>([DisallowNull] T2 value, ref NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter)
4748
{
4849
if (typeof(T2) == typeof(string) ||
4950
typeof(T2) == typeof(char[]) ||
5051
typeof(T2) == typeof(ArraySegment<char>) ||
5152
typeof(T2) == typeof(char) ||
5253
typeof(T2) == typeof(byte[]))
5354
{
54-
return base.ValidateAndGetLength(value, ref lengthCache, parameter);
55+
return base.ValidateAndGetLengthCustom(value, ref lengthCache, parameter);
5556
}
5657

5758
var serialized = JsonConvert.SerializeObject(value, _settings);
5859
if (parameter != null)
5960
parameter.ConvertedValue = serialized;
60-
return base.ValidateAndGetLength(serialized, ref lengthCache, parameter);
61+
return base.ValidateAndGetLengthCustom(serialized, ref lengthCache, parameter);
6162
}
6263

63-
protected override Task WriteWithLength<T2>(T2 value, NpgsqlWriteBuffer buf, NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter, bool async, CancellationToken cancellationToken = default)
64+
protected override Task WriteWithLengthCustom<T2>([DisallowNull] T2 value, NpgsqlWriteBuffer buf, NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter, bool async, CancellationToken cancellationToken = default)
6465
{
6566
if (typeof(T2) == typeof(string) ||
6667
typeof(T2) == typeof(char[]) ||
6768
typeof(T2) == typeof(ArraySegment<char>) ||
6869
typeof(T2) == typeof(char) ||
6970
typeof(T2) == typeof(byte[]))
7071
{
71-
return base.WriteWithLength(value, buf, lengthCache, parameter, async, cancellationToken);
72+
return base.WriteWithLengthCustom(value, buf, lengthCache, parameter, async, cancellationToken);
7273
}
7374

7475
// User POCO, read serialized representation from the validation phase
7576
var serialized = parameter?.ConvertedValue != null
7677
? (string)parameter.ConvertedValue
7778
: JsonConvert.SerializeObject(value, _settings);
78-
return base.WriteWithLength(serialized, buf, lengthCache, parameter, async, cancellationToken);
79+
return base.WriteWithLengthCustom(serialized, buf, lengthCache, parameter, async, cancellationToken);
7980
}
8081

8182
public override int ValidateObjectAndGetLength(object value, ref NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter)
8283
{
83-
if (value is DBNull ||
84-
value is string ||
84+
if (value is string ||
8585
value is char[] ||
8686
value is ArraySegment<char> ||
8787
value is char ||
@@ -93,9 +93,10 @@ value is char ||
9393
return ValidateAndGetLength(value, ref lengthCache, parameter);
9494
}
9595

96-
public override Task WriteObjectWithLength(object value, NpgsqlWriteBuffer buf, NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter, bool async, CancellationToken cancellationToken = default)
96+
public override Task WriteObjectWithLength(object? value, NpgsqlWriteBuffer buf, NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter, bool async, CancellationToken cancellationToken = default)
9797
{
98-
if (value is DBNull ||
98+
if (value is null ||
99+
value is DBNull ||
99100
value is string ||
100101
value is char[] ||
101102
value is ArraySegment<char> ||

src/Npgsql.Json.NET/Internal/JsonbHandler.cs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics.CodeAnalysis;
23
using System.Threading;
34
using System.Threading.Tasks;
45
using Newtonsoft.Json;
@@ -27,61 +28,60 @@ class JsonbHandler : Npgsql.Internal.TypeHandlers.JsonHandler
2728
public JsonbHandler(PostgresType postgresType, NpgsqlConnector connector, JsonSerializerSettings settings)
2829
: base(postgresType, connector, isJsonb: true) => _settings = settings;
2930

30-
protected override async ValueTask<T> Read<T>(NpgsqlReadBuffer buf, int len, bool async, FieldDescription? fieldDescription = null)
31+
protected override async ValueTask<T> ReadCustom<T>(NpgsqlReadBuffer buf, int len, bool async, FieldDescription? fieldDescription = null)
3132
{
3233
if (typeof(T) == typeof(string) ||
3334
typeof(T) == typeof(char[]) ||
3435
typeof(T) == typeof(ArraySegment<char>) ||
3536
typeof(T) == typeof(char) ||
3637
typeof(T) == typeof(byte[]))
3738
{
38-
return await base.Read<T>(buf, len, async, fieldDescription);
39+
return await base.ReadCustom<T>(buf, len, async, fieldDescription);
3940
}
4041

4142
// JSON.NET returns null if no JSON content was found. This means null may get returned even if T is a non-nullable reference
4243
// type (for value types, an exception will be thrown).
4344
return JsonConvert.DeserializeObject<T>(await base.Read<string>(buf, len, async, fieldDescription), _settings)!;
4445
}
4546

46-
protected override int ValidateAndGetLength<T2>(T2 value, ref NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter)
47+
protected override int ValidateAndGetLengthCustom<T2>([DisallowNull] T2 value, ref NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter)
4748
{
4849
if (typeof(T2) == typeof(string) ||
4950
typeof(T2) == typeof(char[]) ||
5051
typeof(T2) == typeof(ArraySegment<char>) ||
5152
typeof(T2) == typeof(char) ||
5253
typeof(T2) == typeof(byte[]))
5354
{
54-
return base.ValidateAndGetLength(value, ref lengthCache, parameter);
55+
return base.ValidateAndGetLengthCustom(value, ref lengthCache, parameter);
5556
}
5657

5758
var serialized = JsonConvert.SerializeObject(value, _settings);
5859
if (parameter != null)
5960
parameter.ConvertedValue = serialized;
60-
return base.ValidateAndGetLength(serialized, ref lengthCache, parameter);
61+
return base.ValidateAndGetLengthCustom(serialized, ref lengthCache, parameter);
6162
}
6263

63-
protected override Task WriteWithLength<T2>(T2 value, NpgsqlWriteBuffer buf, NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter, bool async, CancellationToken cancellationToken = default)
64+
protected override Task WriteWithLengthCustom<T2>([DisallowNull] T2 value, NpgsqlWriteBuffer buf, NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter, bool async, CancellationToken cancellationToken = default)
6465
{
6566
if (typeof(T2) == typeof(string) ||
6667
typeof(T2) == typeof(char[]) ||
6768
typeof(T2) == typeof(ArraySegment<char>) ||
6869
typeof(T2) == typeof(char) ||
6970
typeof(T2) == typeof(byte[]))
7071
{
71-
return base.WriteWithLength(value, buf, lengthCache, parameter, async, cancellationToken);
72+
return base.WriteWithLengthCustom(value, buf, lengthCache, parameter, async, cancellationToken);
7273
}
7374

7475
// User POCO, read serialized representation from the validation phase
7576
var serialized = parameter?.ConvertedValue != null
7677
? (string)parameter.ConvertedValue
7778
: JsonConvert.SerializeObject(value, _settings);
78-
return base.WriteWithLength(serialized, buf, lengthCache, parameter, async, cancellationToken);
79+
return base.WriteWithLengthCustom(serialized, buf, lengthCache, parameter, async, cancellationToken);
7980
}
8081

8182
public override int ValidateObjectAndGetLength(object value, ref NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter)
8283
{
83-
if (value is DBNull ||
84-
value is string ||
84+
if (value is string ||
8585
value is char[] ||
8686
value is ArraySegment<char> ||
8787
value is char ||
@@ -90,12 +90,13 @@ value is char ||
9090
return base.ValidateObjectAndGetLength(value, ref lengthCache, parameter);
9191
}
9292

93-
return ValidateAndGetLength(value, ref lengthCache, parameter);
93+
return ValidateAndGetLengthCustom(value, ref lengthCache, parameter);
9494
}
9595

96-
public override Task WriteObjectWithLength(object value, NpgsqlWriteBuffer buf, NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter, bool async, CancellationToken cancellationToken = default)
96+
public override Task WriteObjectWithLength(object? value, NpgsqlWriteBuffer buf, NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter, bool async, CancellationToken cancellationToken = default)
9797
{
98-
if (value is DBNull ||
98+
if (value is null ||
99+
value is DBNull ||
99100
value is string ||
100101
value is char[] ||
101102
value is ArraySegment<char> ||
@@ -105,7 +106,7 @@ value is char ||
105106
return base.WriteObjectWithLength(value, buf, lengthCache, parameter, async, cancellationToken);
106107
}
107108

108-
return WriteWithLength(value, buf, lengthCache, parameter, async, cancellationToken);
109+
return WriteWithLengthCustom(value, buf, lengthCache, parameter, async, cancellationToken);
109110
}
110111
}
111112
}

src/Npgsql.SourceGenerators/TypeHandler.snbtxt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,25 @@ namespace {{ namespace }}
1111
{
1212
partial class {{ type_name }}
1313
{
14-
{{ validate_access }} override int ValidateObjectAndGetLength(object value, {{ is_simple ? "" : "ref NpgsqlLengthCache? lengthCache, " }} NpgsqlParameter? parameter)
14+
public override int ValidateObjectAndGetLength(object value, ref NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter)
1515
=> value switch
1616
{
1717
{{ for interface in interfaces }}
1818
{{ interface.handled_type }} converted => (({{ interface.name }})this).ValidateAndGetLength(converted, {{ is_simple ? "" : "ref lengthCache, " }}parameter),
1919
{{ end }}
2020

21-
DBNull => -1,
22-
null => -1,
2321
_ => throw new InvalidCastException($"Can't write CLR type {value.GetType()} with handler type {{ type_name }}")
2422
};
2523

26-
public override Task WriteObjectWithLength(object value, NpgsqlWriteBuffer buf, NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter, bool async, CancellationToken cancellationToken = default)
24+
public override Task WriteObjectWithLength(object? value, NpgsqlWriteBuffer buf, NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter, bool async, CancellationToken cancellationToken = default)
2725
=> value switch
2826
{
2927
{{ for interface in interfaces }}
30-
{{ interface.handled_type }} converted => WriteWithLengthInternal(converted, buf, lengthCache, parameter, async, cancellationToken),
28+
{{ interface.handled_type }} converted => WriteWithLength(converted, buf, lengthCache, parameter, async, cancellationToken),
3129
{{ end }}
3230

33-
DBNull => WriteWithLengthInternal(DBNull.Value, buf, lengthCache, parameter, async, cancellationToken),
34-
null => WriteWithLengthInternal(DBNull.Value, buf, lengthCache, parameter, async, cancellationToken),
31+
DBNull => WriteWithLength(DBNull.Value, buf, lengthCache, parameter, async, cancellationToken),
32+
null => WriteWithLength(DBNull.Value, buf, lengthCache, parameter, async, cancellationToken),
3533
_ => throw new InvalidCastException($"Can't write CLR type {value.GetType()} with handler type {{ type_name }}")
3634
};
3735
}

src/Npgsql.SourceGenerators/TypeHandlerSourceGenerator.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ void AugmentTypeHandler(INamedTypeSymbol typeSymbol, ClassDeclarationSyntax clas
7373
TypeName = FormatTypeName(typeSymbol),
7474
Namespace = typeSymbol.ContainingNamespace.ToDisplayString(),
7575
IsSimple = isSimple,
76-
ValidateAccess = isSimple ? "protected" : "public",
7776
Interfaces = interfaces.Select(i => new
7877
{
7978
Name = FormatTypeName(i),

0 commit comments

Comments
 (0)