Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 0 additions & 100 deletions src/Npgsql.Json.NET/Internal/JsonHandler.cs

This file was deleted.

64 changes: 64 additions & 0 deletions src/Npgsql.Json.NET/Internal/JsonNetJsonHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Npgsql.BackendMessages;
using Npgsql.Internal;
using Npgsql.Internal.TypeHandlers;
using Npgsql.Internal.TypeHandling;
using Npgsql.PostgresTypes;

namespace Npgsql.Json.NET.Internal;

class JsonNetJsonHandler : JsonTextHandler
{
readonly JsonSerializerSettings _settings;

public JsonNetJsonHandler(PostgresType postgresType, NpgsqlConnector connector, bool isJsonb, JsonSerializerSettings settings)
: base(postgresType, connector.TextEncoding, isJsonb) => _settings = settings;

protected override async ValueTask<T> ReadCustom<T>(NpgsqlReadBuffer buf, int len, bool async, FieldDescription? fieldDescription)
{
if (IsSupportedAsText<T>())
return await base.ReadCustom<T>(buf, len, async, fieldDescription);

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

protected override int ValidateAndGetLengthCustom<TAny>([DisallowNull] TAny value, ref NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter)
{
if (IsSupportedAsText<TAny>())
return base.ValidateAndGetLengthCustom(value, ref lengthCache, parameter);

var serialized = JsonConvert.SerializeObject(value, _settings);
if (parameter != null)
parameter.ConvertedValue = serialized;
return base.ValidateAndGetLengthCustom(serialized, ref lengthCache, parameter);
}

protected override Task WriteWithLengthCustom<TAny>([DisallowNull] TAny value, NpgsqlWriteBuffer buf, NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter, bool async, CancellationToken cancellationToken = default)
{
if (IsSupportedAsText<TAny>())
return base.WriteWithLengthCustom(value, buf, lengthCache, parameter, async, cancellationToken);

// User POCO, read serialized representation from the validation phase
var serialized = parameter?.ConvertedValue != null
? (string)parameter.ConvertedValue
: JsonConvert.SerializeObject(value, _settings);
return base.WriteWithLengthCustom(serialized, buf, lengthCache, parameter, async, cancellationToken);
}

public override int ValidateObjectAndGetLength(object value, ref NpgsqlLengthCache? lengthCache, NpgsqlParameter? parameter)
=> IsSupported(value.GetType())
? base.ValidateObjectAndGetLength(value, ref lengthCache, parameter)
: ValidateAndGetLengthCustom(value, ref lengthCache, parameter);

public override Task WriteObjectWithLength(object? value, NpgsqlWriteBuffer buf, NpgsqlLengthCache? lengthCache,
NpgsqlParameter? parameter, bool async, CancellationToken cancellationToken = default)
=> value is null or DBNull || IsSupported(value.GetType())
? base.WriteObjectWithLength(value, buf, lengthCache, parameter, async, cancellationToken)
: WriteWithLengthCustom(value, buf, lengthCache, parameter, async, cancellationToken);
}
26 changes: 8 additions & 18 deletions src/Npgsql.Json.NET/Internal/JsonNetTypeHandlerResolver.cs
Original file line number Diff line number Diff line change
@@ -1,48 +1,38 @@
using System;
using System.Collections.Generic;
using System.Data;
using Newtonsoft.Json;
using Npgsql.Internal;
using Npgsql.Internal.TypeHandling;
using Npgsql.PostgresTypes;
using Npgsql.TypeMapping;
using NpgsqlTypes;

namespace Npgsql.Json.NET.Internal;

public class JsonNetTypeHandlerResolver : TypeHandlerResolver
{
readonly NpgsqlDatabaseInfo _databaseInfo;
readonly JsonbHandler _jsonbHandler;
readonly JsonHandler _jsonHandler;
readonly JsonNetJsonHandler _jsonNetJsonbHandler;
readonly JsonNetJsonHandler _jsonNetJsonHandler;
readonly Dictionary<Type, string> _dataTypeNamesByClrType;

internal JsonNetTypeHandlerResolver(
NpgsqlConnector connector,
Dictionary<Type, string> dataClrTypeNamesDataTypeNamesByClrClrType,
Dictionary<Type, string> dataTypeNamesByClrType,
JsonSerializerSettings settings)
{
_databaseInfo = connector.DatabaseInfo;

_jsonbHandler = new JsonbHandler(PgType("jsonb"), connector, settings);
_jsonHandler = new JsonHandler(PgType("json"), connector, settings);
_jsonNetJsonbHandler = new JsonNetJsonHandler(PgType("jsonb"), connector, isJsonb: true, settings);
_jsonNetJsonHandler = new JsonNetJsonHandler(PgType("json"), connector, isJsonb: false, settings);

_dataTypeNamesByClrType = dataClrTypeNamesDataTypeNamesByClrClrType;
_dataTypeNamesByClrType = dataTypeNamesByClrType;
}

public NpgsqlTypeHandler? ResolveNpgsqlDbType(NpgsqlDbType npgsqlDbType)
=> npgsqlDbType switch
{
NpgsqlDbType.Jsonb => _jsonbHandler,
NpgsqlDbType.Json => _jsonHandler,
_ => null
};

public override NpgsqlTypeHandler? ResolveByDataTypeName(string typeName)
=> typeName switch
{
"jsonb" => _jsonbHandler,
"json" => _jsonHandler,
"jsonb" => _jsonNetJsonbHandler,
"json" => _jsonNetJsonHandler,
_ => null
};

Expand Down
100 changes: 0 additions & 100 deletions src/Npgsql.Json.NET/Internal/JsonbHandler.cs

This file was deleted.

16 changes: 10 additions & 6 deletions src/Npgsql.Json.NET/NpgsqlJsonNetExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@ public static class NpgsqlJsonNetExtensions
/// <summary>
/// Sets up JSON.NET mappings for the PostgreSQL json and jsonb types.
/// </summary>
/// <param name="mapper">The type mapper to set up (global or connection-specific)</param>
/// <param name="jsonbClrTypes">A list of CLR types to map to PostgreSQL jsonb (no need to specify NpgsqlDbType.Jsonb)</param>
/// <param name="jsonClrTypes">A list of CLR types to map to PostgreSQL json (no need to specify NpgsqlDbType.Json)</param>
/// <param name="settings">Optional settings to customize JSON serialization</param>
/// <param name="mapper">The type mapper to set up.</param>
/// <param name="settings">Optional settings to customize JSON serialization.</param>
/// <param name="jsonbClrTypes">
/// A list of CLR types to map to PostgreSQL <c>jsonb</c> (no need to specify <see cref="NpgsqlDbType.Jsonb" />).
/// </param>
/// <param name="jsonClrTypes">
/// A list of CLR types to map to PostgreSQL <c>json</c> (no need to specify <see cref="NpgsqlDbType.Json" />).
/// </param>
public static INpgsqlTypeMapper UseJsonNet(
this INpgsqlTypeMapper mapper,
JsonSerializerSettings? settings = null,
Type[]? jsonbClrTypes = null,
Type[]? jsonClrTypes = null,
JsonSerializerSettings? settings = null)
Type[]? jsonClrTypes = null)
{
mapper.AddTypeResolverFactory(new JsonNetTypeHandlerResolverFactory(jsonbClrTypes, jsonClrTypes, settings));
return mapper;
Expand Down
2 changes: 2 additions & 0 deletions src/Npgsql.Json.NET/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
#nullable enable
static Npgsql.NpgsqlJsonNetExtensions.UseJsonNet(this Npgsql.TypeMapping.INpgsqlTypeMapper! mapper, Newtonsoft.Json.JsonSerializerSettings? settings = null, System.Type![]? jsonbClrTypes = null, System.Type![]? jsonClrTypes = null) -> Npgsql.TypeMapping.INpgsqlTypeMapper!
*REMOVED*static Npgsql.NpgsqlJsonNetExtensions.UseJsonNet(this Npgsql.TypeMapping.INpgsqlTypeMapper! mapper, System.Type![]? jsonbClrTypes = null, System.Type![]? jsonClrTypes = null, Newtonsoft.Json.JsonSerializerSettings? settings = null) -> Npgsql.TypeMapping.INpgsqlTypeMapper!
Loading