Skip to content

Commit 68e33fb

Browse files
committed
Initial test for fixing issue #41
1 parent 3edf04a commit 68e33fb

3 files changed

Lines changed: 58 additions & 24 deletions

File tree

src/RepoDb.PostgreSql/DbHelpers/PostgreSqlDbHelper.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,12 @@ private static void HandleDbParameterPostCreation(NpgsqlParameter parameter)
284284
}
285285
else if (MaybeUpdateNpgsqlParameterCallback?.Invoke(ref value, np) == true)
286286
return value;
287+
#if NET
288+
else if (value is Half h)
289+
return (float)h; // Npgsql doesn't support Half, so convert to float
290+
#endif
291+
else if (value is IFormattable)
292+
return value; // Don't fall through for this case
287293
}
288294

289295
return base.ParameterValueToDb(value, parameter);

src/RepoDb/Extensions/DbCommandExtension.cs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using RepoDb.Exceptions;
1111
using RepoDb.Interfaces;
1212
using RepoDb.Options;
13+
using RepoDb.Reflection;
1314
using RepoDb.Resolvers;
1415

1516
namespace RepoDb.Extensions;
@@ -706,7 +707,7 @@ private static bool AutomaticConvert(DbField? dbField,
706707
return false;
707708

708709

709-
static object? AutomaticConvert(object? value, Type fromType, Type targetType)
710+
static object? AutomaticConvert(object value, Type fromType, Type targetType)
710711
{
711712
if (fromType == null || targetType == null || fromType == targetType)
712713
{
@@ -773,7 +774,7 @@ private static bool AutomaticConvert(DbField? dbField,
773774
return parser.Invoke(null, [value as string, CultureInfo.InvariantCulture]);
774775
}
775776
#if NET
776-
else if (targetType == typeof(Half))
777+
else if (targetType == typeof(Half) && fromType.IsBinaryIntFloatOrDecimal())
777778
{
778779
return (Half?)(float?)Convert.ChangeType(value, typeof(float), CultureInfo.InvariantCulture);
779780
}
@@ -790,14 +791,24 @@ private static bool AutomaticConvert(DbField? dbField,
790791
{
791792
return value;
792793
}
793-
794-
try
794+
else if (Compiler.TryConvertViaProvider(value, targetType, fromType, out var newValue))
795795
{
796-
return Convert.ChangeType(value, targetType, CultureInfo.InvariantCulture);
796+
return newValue;
797+
}
798+
else if (value is IConvertible)
799+
{
800+
try
801+
{
802+
return Convert.ChangeType(value, targetType, CultureInfo.InvariantCulture);
803+
}
804+
catch (InvalidCastException e)
805+
{
806+
throw new InvalidCastException($"While converting from {value?.GetType().FullName} to {targetType.FullName}: " + e.Message, e);
807+
}
797808
}
798-
catch (InvalidCastException e)
809+
else
799810
{
800-
throw new InvalidCastException($"While converting from {value?.GetType().FullName} to {targetType.FullName}: " + e.Message, e);
811+
return value;
801812
}
802813
}
803814
}

src/RepoDb/Reflection/Compiler.cs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,7 @@ Expression ConvertExpressionToSystemConvertExpression()
931931
result = Expression.Call(result, numberFormatMethod, [Expression.Constant(CultureInfo.InvariantCulture, typeof(IFormatProvider))]);
932932
}
933933
#if NET
934-
else if (toType == typeof(Half))
934+
else if (toType == typeof(Half) && (underlyingFromType.IsBinaryIntFloatOrDecimal() || underlyingFromType == StaticType.Object))
935935
{
936936
// System.Converter doesn't support half, nor does 99% of DotNet. Just fall through to float/single support and convert from there
937937

@@ -965,17 +965,16 @@ Expression ConvertExpressionToSystemConvertExpression()
965965
result = Expression.Condition(
966966
Expression.TypeIs(expression, underlyingToType),
967967
// This case happens in PostgreSql bulktests
968-
Expression.Convert(expression, underlyingToType),
969-
// And this case is currently not triggered in tests. Ultimate fallback but **SLOW** as it does runtime reflection. Not compiletime
970-
Expression.Convert(
971-
Expression.Call(systemChangeType,
972-
[
973-
ConvertExpressionToTypeExpression(result, StaticType.Object),
974-
Expression.Constant(fromType, typeof(Type)),
975-
Expression.Constant(underlyingToType, typeof(Type)),
976-
]),
977-
underlyingToType)
978-
);
968+
Expression.Convert(expression, typeof(object)),
969+
// And this currently doesn't happen in tests, but hard failing because IConverable doesn't support types causes quite some issues
970+
Expression.Call(systemChangeType,
971+
[
972+
ConvertExpressionToTypeExpression(result, StaticType.Object),
973+
Expression.Constant(fromType, typeof(Type)),
974+
Expression.Constant(underlyingToType, typeof(Type)),
975+
])
976+
);
977+
979978
}
980979

981980
// Do we need manual NULL handling?
@@ -1011,13 +1010,15 @@ Expression ConvertExpressionToSystemConvertExpression()
10111010

10121011
try
10131012
{
1014-
if (actualType is { } && ProviderSpecificTransforms.TryGetValue((actualType, conversionType), out var metaTransform)
1015-
&& Expression.Parameter(actualType) is { } param
1016-
&& metaTransform(param) is { } transform)
1013+
if (actualType is { } && Compiler.TryConvertViaProvider(value, conversionType, actualType, out var newValue))
10171014
{
1018-
return Expression.Lambda(transform, param).Compile(true).DynamicInvoke(value);
1015+
return newValue;
10191016
}
1020-
return Convert.ChangeType(value, conversionType, CultureInfo.InvariantCulture);
1017+
1018+
if (value is IConvertible) // Convert.ChangeType only supports system types that support IConvertable
1019+
return Convert.ChangeType(value, conversionType, CultureInfo.InvariantCulture);
1020+
else
1021+
return value; // We can't convert it... fall through to the db provider, etc.
10211022
}
10221023
catch (Exception ex)
10231024
{
@@ -1028,6 +1029,22 @@ static InvalidOperationException MakeException(Type? valueType, Type conversionT
10281029
=> new InvalidOperationException($"No declared converter found to convert value of type '{valueType?.FullName ?? "null"}' (declared as'{fromType.FullName}') to type '{conversionType.FullName}', even via final reflection fallback.", innerException);
10291030
}
10301031

1032+
internal static bool TryConvertViaProvider(object value, Type toType, Type valueType, out object? newValue)
1033+
{
1034+
// Perhaps the DB provider can do something smart here...
1035+
if (ProviderSpecificTransforms.TryGetValue((valueType, toType), out var metaTransform)
1036+
&& Expression.Parameter(valueType) is { } param
1037+
&& metaTransform(param) is { } transform)
1038+
{
1039+
newValue = Expression.Lambda(transform, param).Compile(true).DynamicInvoke(value);
1040+
return true;
1041+
}
1042+
else
1043+
{
1044+
newValue = null;
1045+
return false;
1046+
}
1047+
}
10311048

10321049
private static Expression ConvertExpressionToPropertyHandlerGetExpression(Expression expression,
10331050
Expression readerExpression,

0 commit comments

Comments
 (0)