Skip to content

Commit

Permalink
YdbValue.Null -> Optional<?>(Null) (#179)
Browse files Browse the repository at this point in the history
  • Loading branch information
KirillKurdyukov committed Sep 5, 2024
1 parent 61b7f11 commit b0dc132
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 157 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
- Fixed bug: parameter type mismatch, when setting optional with null

## v0.6.2
- Fixed bug: adding correct placeholders to all logging calls with parameters

Expand Down
173 changes: 105 additions & 68 deletions src/Ydb.Sdk/src/Ado/YdbParameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,38 @@
using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
using Ydb.Sdk.Value;
using static System.String;

namespace Ydb.Sdk.Ado;

public sealed class YdbParameter : DbParameter
{
private string _parameterName = Empty;
private static readonly Dictionary<DbType, YdbValue> YdbNullByDbType = new()
{
{ DbType.String, YdbValue.MakeOptionalUtf8() },
{ DbType.AnsiString, YdbValue.MakeOptionalUtf8() },
{ DbType.AnsiStringFixedLength, YdbValue.MakeOptionalUtf8() },
{ DbType.StringFixedLength, YdbValue.MakeOptionalUtf8() },
{ DbType.Int32, YdbValue.MakeOptionalInt32() },
{ DbType.Int64, YdbValue.MakeOptionalInt64() },
{ DbType.Boolean, YdbValue.MakeOptionalBool() },
{ DbType.UInt32, YdbValue.MakeOptionalUint32() },
{ DbType.UInt64, YdbValue.MakeOptionalUint64() },
{ DbType.SByte, YdbValue.MakeOptionalInt8() },
{ DbType.Int16, YdbValue.MakeOptionalInt16() },
{ DbType.UInt16, YdbValue.MakeOptionalUint16() },
{ DbType.Double, YdbValue.MakeOptionalDouble() },
{ DbType.Single, YdbValue.MakeOptionalFloat() },
{ DbType.Date, YdbValue.MakeOptionalDate() },
{ DbType.DateTime, YdbValue.MakeOptionalDatetime() },
{ DbType.Binary, YdbValue.MakeOptionalString() },
{ DbType.Byte, YdbValue.MakeOptionalUint8() },
{ DbType.DateTime2, YdbValue.MakeOptionalTimestamp() },
{ DbType.DateTimeOffset, YdbValue.MakeOptionalTimestamp() },
{ DbType.Decimal, YdbValue.MakeOptionalDecimal() },
{ DbType.Currency, YdbValue.MakeOptionalDecimal() }
};

private string _parameterName = string.Empty;

public YdbParameter()
{
Expand Down Expand Up @@ -46,7 +71,7 @@ public override string ParameterName
set => _parameterName = value ?? throw new YdbException("ParameterName must not be null!");
}

[AllowNull] [DefaultValue("")] public override string SourceColumn { get; set; } = Empty;
[AllowNull] [DefaultValue("")] public override string SourceColumn { get; set; } = string.Empty;
public override object? Value { get; set; }
public override bool SourceColumnNullMapping { get; set; }
public override int Size { get; set; }
Expand All @@ -55,44 +80,84 @@ internal YdbValue YdbValue
{
get
{
if (Value is YdbValue ydbValue)
return Value switch
{
return ydbValue;
}

return DbType switch
{
DbType.Object when Value is not null => PrepareThenReturnYdbValue(),
DbType.String or DbType.AnsiString or DbType.AnsiStringFixedLength or DbType.StringFixedLength when
Value is string valueString => YdbValue.MakeUtf8(valueString),
DbType.Int32 when Value is int or sbyte or byte or short or ushort =>
YdbValue.MakeInt32(Convert.ToInt32(Value)),
DbType.Int64 when Value is long or sbyte or byte or short or ushort or int or uint =>
YdbValue.MakeInt64(Convert.ToInt64(Value)),
DbType.Boolean when Value is bool boolValue => YdbValue.MakeBool(boolValue),
DbType.UInt32 when Value is uint or byte or ushort => YdbValue.MakeUint32(Convert.ToUInt32(Value)),
DbType.UInt64
when Value is ulong or byte or ushort or uint => YdbValue.MakeUint64(Convert.ToUInt64(Value)),
DbType.SByte when Value is sbyte sbyteValue => YdbValue.MakeInt8(sbyteValue),
DbType.Int16 when Value is short or sbyte or byte => YdbValue.MakeInt16(Convert.ToInt16(Value)),
DbType.UInt16 when Value is ushort or byte => YdbValue.MakeUint16(Convert.ToUInt16(Value)),
DbType.Double when Value is double or float => YdbValue.MakeDouble(Convert.ToDouble(Value)),
DbType.Single when Value is float floatValue => YdbValue.MakeFloat(floatValue),
DbType.Date when Value is DateTime dateTimeValue => YdbValue.MakeDate(dateTimeValue),
DbType.Time or DbType.DateTime
when Value is DateTime dateTimeValue => YdbValue.MakeDatetime(dateTimeValue),
DbType.DateTime2 when Value is DateTime dateTime => YdbValue.MakeTimestamp(dateTime),
DbType.DateTimeOffset when Value is DateTimeOffset dateTimeOffset =>
YdbValue ydbValue => ydbValue,
null or DBNull when YdbNullByDbType.TryGetValue(DbType, out var value) => value,
string valueString when DbType is DbType.String or DbType.AnsiString or DbType.AnsiStringFixedLength
or DbType.StringFixedLength or DbType.Object => YdbValue.MakeUtf8(valueString),
bool boolValue when DbType is DbType.Boolean or DbType.Object => YdbValue.MakeBool(boolValue),
DateTime dateTimeValue => DbType switch
{
DbType.Date => YdbValue.MakeDate(dateTimeValue),
DbType.DateTime => YdbValue.MakeDatetime(dateTimeValue),
DbType.DateTime2 or DbType.Object => YdbValue.MakeTimestamp(dateTimeValue),
_ => ThrowInvalidCast()
},
DateTimeOffset dateTimeOffset when DbType is DbType.DateTimeOffset or DbType.Object =>
YdbValue.MakeTimestamp(dateTimeOffset.UtcDateTime),
DbType.Decimal or DbType.Currency
when Value is decimal decimalValue => YdbValue.MakeDecimal(decimalValue),
DbType.Binary when Value is byte[] bytes => YdbValue.MakeString(bytes),
DbType.Byte when Value is byte valueByte => YdbValue.MakeUint8(valueByte),
DbType.VarNumeric or DbType.Xml or DbType.Guid => throw new YdbException(
$"Ydb don't supported this DbType: {DbType}"),
_ when !Enum.IsDefined(typeof(DbType), DbType) =>
throw new ArgumentOutOfRangeException(nameof(DbType), DbType, null),
_ when Value is null => YdbValue.Null,
float floatValue => DbType switch
{
DbType.Single or DbType.Object => YdbValue.MakeFloat(floatValue),
DbType.Double => YdbValue.MakeDouble(floatValue),
_ => ThrowInvalidCast()
},
double doubleValue when DbType is DbType.Double or DbType.Object => YdbValue.MakeDouble(doubleValue),
int intValue => DbType switch
{
DbType.Int32 or DbType.Object => YdbValue.MakeInt32(intValue),
DbType.Int64 => YdbValue.MakeInt64(intValue),
_ => ThrowInvalidCast()
},
long longValue when DbType is DbType.Int64 or DbType.Object => YdbValue.MakeInt64(longValue),
decimal decimalValue when DbType is DbType.Decimal or DbType.Currency or DbType.Object =>
YdbValue.MakeDecimal(decimalValue),
ulong ulongValue when DbType is DbType.UInt64 or DbType.Object => YdbValue.MakeUint64(ulongValue),
uint uintValue => DbType switch
{
DbType.UInt32 or DbType.Object => YdbValue.MakeUint32(uintValue),
DbType.UInt64 => YdbValue.MakeUint64(uintValue),
DbType.Int64 => YdbValue.MakeInt64(uintValue),
_ => ThrowInvalidCast()
},
byte byteValue => DbType switch
{
DbType.Byte or DbType.Object => YdbValue.MakeUint8(byteValue),
DbType.Int64 => YdbValue.MakeInt64(byteValue),
DbType.Int32 => YdbValue.MakeInt32(byteValue),
DbType.Int16 => YdbValue.MakeInt16(byteValue),
DbType.UInt64 => YdbValue.MakeUint64(byteValue),
DbType.UInt32 => YdbValue.MakeUint32(byteValue),
DbType.UInt16 => YdbValue.MakeUint16(byteValue),
_ => ThrowInvalidCast()
},
sbyte sbyteValue => DbType switch
{
DbType.SByte or DbType.Object => YdbValue.MakeInt8(sbyteValue),
DbType.Int64 => YdbValue.MakeInt64(sbyteValue),
DbType.Int32 => YdbValue.MakeInt32(sbyteValue),
DbType.Int16 => YdbValue.MakeInt16(sbyteValue),
_ => ThrowInvalidCast()
},
ushort ushortValue => DbType switch
{
DbType.UInt16 or DbType.Object => YdbValue.MakeUint16(ushortValue),
DbType.Int64 => YdbValue.MakeInt64(ushortValue),
DbType.Int32 => YdbValue.MakeInt32(ushortValue),
DbType.UInt64 => YdbValue.MakeUint64(ushortValue),
DbType.UInt32 => YdbValue.MakeUint32(ushortValue),
_ => ThrowInvalidCast()
},
short shortValue => DbType switch
{
DbType.Int16 or DbType.Object => YdbValue.MakeInt16(shortValue),
DbType.Int64 => YdbValue.MakeInt64(shortValue),
DbType.Int32 => YdbValue.MakeInt32(shortValue),
_ => ThrowInvalidCast()
},
byte[] bytesValue when DbType is DbType.Binary or DbType.Object => YdbValue.MakeString(bytesValue),
_ when DbType is DbType.VarNumeric or DbType.Xml or DbType.Guid or DbType.Time =>
throw new YdbException($"Ydb don't supported this DbType: {DbType}"),
_ => ThrowInvalidCast()
};
}
Expand All @@ -101,34 +166,6 @@ DbType.Decimal or DbType.Currency
private YdbValue ThrowInvalidCast()
{
throw new InvalidCastException(
$"Writing values of '{Value?.GetType()}' is not supported for parameters having DbType '{DbType}'");
}

private YdbValue PrepareThenReturnYdbValue()
{
DbType = Value switch
{
string => DbType.String,
int => DbType.Int32,
uint => DbType.UInt32,
long => DbType.Int64,
ulong => DbType.UInt64,
bool => DbType.Boolean,
byte => DbType.Byte,
sbyte => DbType.SByte,
float => DbType.Single,
double => DbType.Double,
short => DbType.Int16,
ushort => DbType.UInt16,
decimal => DbType.Decimal,
byte[] => DbType.Binary,
Guid => DbType.Guid,
DateTime => DbType.DateTime,
DateTimeOffset => DbType.DateTimeOffset,
_ => throw new YdbException($"Error converting {Value?.GetType().ToString() ?? "null"} to YdbValue")
};
IsNullable = false;

return YdbValue;
$"Writing value of '{Value?.GetType().ToString() ?? "null"}' is not supported for parameters having DbType '{DbType}'");
}
}
Loading

0 comments on commit b0dc132

Please sign in to comment.