Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: supported uuid YDB type #208

Merged
merged 4 commits into from
Oct 30, 2024
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
- Supported UUID (Guid)

## v0.7.3
- Fixed YdbDataReader: extract Json / Yson types

Expand Down
2 changes: 2 additions & 0 deletions src/Ydb.Sdk/src/Ado/YdbDataReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ public override System.Type GetFieldType(int ordinal)
typeof(string),
YdbTypeId.String => typeof(byte[]),
YdbTypeId.DecimalType => typeof(decimal),
YdbTypeId.Uuid => typeof(Guid),
_ => throw new YdbException($"Unsupported ydb type {type}")
};

Expand Down Expand Up @@ -339,6 +340,7 @@ public override object GetValue(int ordinal)
YdbTypeId.Yson => ydbValue.GetYson(),
YdbTypeId.String => ydbValue.GetString(),
YdbTypeId.DecimalType => ydbValue.GetDecimal(),
YdbTypeId.Uuid => ydbValue.GetUuid(),
_ => throw new YdbException($"Unsupported ydb type {ydbValue.TypeId}")
};
}
Expand Down
6 changes: 4 additions & 2 deletions src/Ydb.Sdk/src/Ado/YdbParameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public sealed class YdbParameter : DbParameter
{ DbType.DateTime2, YdbValue.MakeOptionalTimestamp() },
{ DbType.DateTimeOffset, YdbValue.MakeOptionalTimestamp() },
{ DbType.Decimal, YdbValue.MakeOptionalDecimal() },
{ DbType.Currency, YdbValue.MakeOptionalDecimal() }
{ DbType.Currency, YdbValue.MakeOptionalDecimal() },
{ DbType.Guid, YdbValue.MakeOptionalUuid() }
};

private string _parameterName = string.Empty;
Expand Down Expand Up @@ -165,7 +166,8 @@ string valueString when DbType is DbType.String or DbType.AnsiString or DbType.A
_ => 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 =>
Guid guidValue when DbType is DbType.Guid or DbType.Object => YdbValue.MakeUuid(guidValue),
_ when DbType is DbType.VarNumeric or DbType.Xml or DbType.Time =>
throw new YdbException($"Ydb don't supported this DbType: {DbType}"),
_ => ThrowInvalidCast()
};
Expand Down
24 changes: 18 additions & 6 deletions src/Ydb.Sdk/src/Value/YdbValueBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,17 @@ public static YdbValue MakeJsonDocument(string value)
new Ydb.Value { TextValue = value });
}

public static YdbValue MakeUuid(Guid guid)
{
var bytes = guid.ToByteArray();

var low = BitConverter.ToUInt64(bytes, 0);
var high = BitConverter.ToUInt64(bytes, 8);

return new YdbValue(MakePrimitiveType(Type.Types.PrimitiveTypeId.Uuid),
new Ydb.Value { Low128 = low, High128 = high });
}

private static byte GetDecimalScale(decimal value)
{
var bits = decimal.GetBits(value);
Expand Down Expand Up @@ -237,9 +248,7 @@ public static YdbValue MakeList(IReadOnlyList<YdbValue> values)
var value = new Ydb.Value();
value.Items.Add(values.Select(v => v._protoValue));

return new YdbValue(
new Type { ListType = new ListType { Item = values[0]._protoType } },
value);
return new YdbValue(new Type { ListType = new ListType { Item = values[0]._protoType } }, value);
}

public static YdbValue MakeTuple(IReadOnlyList<YdbValue> values)
Expand All @@ -254,9 +263,7 @@ public static YdbValue MakeTuple(IReadOnlyList<YdbValue> values)
var value = new Ydb.Value();
value.Items.Add(values.Select(v => v._protoValue));

return new YdbValue(
type,
value);
return new YdbValue(type, value);
}

public static YdbValue MakeStruct(IReadOnlyDictionary<string, YdbValue> members)
Expand Down Expand Up @@ -399,6 +406,11 @@ public static YdbValue MakeOptionalJsonDocument(string? value = null)
return MakeOptionalOf(value, YdbTypeId.JsonDocument, MakeJsonDocument);
}

public static YdbValue MakeOptionalUuid(Guid? value = null)
{
return MakeOptionalOf(value, YdbTypeId.Uuid, MakeUuid);
}

public static YdbValue MakeOptionalDecimal(decimal? value = null)
{
return MakeOptionalOf(value, YdbTypeId.DecimalType, MakeDecimal);
Expand Down
5 changes: 5 additions & 0 deletions src/Ydb.Sdk/src/Value/YdbValueCast.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ public static explicit operator decimal(YdbValue value)
return GetOptionalPrimitive<decimal>(value);
}

public static explicit operator Guid?(YdbValue value)
{
return GetOptionalPrimitive<Guid>(value);
}

private static T? GetOptionalPrimitive<T>(YdbValue value) where T : struct
{
Expand Down Expand Up @@ -192,6 +196,7 @@ private static T GetObject<T>(YdbValue value)
YdbTypeId.Json => value.GetJson(),
YdbTypeId.JsonDocument => value.GetJsonDocument(),
YdbTypeId.DecimalType => value.GetDecimal(),
YdbTypeId.Uuid => value.GetUuid(),
_ => throw new InvalidCastException($"Cannot cast YDB type {value.TypeId} to {typeof(T).Name}.")
});
}
Expand Down
22 changes: 22 additions & 0 deletions src/Ydb.Sdk/src/Value/YdbValueParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,23 @@ public string GetJsonDocument()
return _protoValue.TextValue;
}

public Guid GetUuid()
{
EnsurePrimitiveTypeId(Type.Types.PrimitiveTypeId.Uuid);

var high = _protoValue.High128;
var low = _protoValue.Low128;

var lowBytes = BitConverter.GetBytes(low);
var highBytes = BitConverter.GetBytes(high);

var guidBytes = new byte[16];
Array.Copy(lowBytes, 0, guidBytes, 0, 8);
Array.Copy(highBytes, 0, guidBytes, 8, 8);

return new Guid(guidBytes);
}

public decimal GetDecimal()
{
EnsureType(Type.TypeOneofCase.DecimalType);
Expand Down Expand Up @@ -258,6 +275,11 @@ public decimal GetDecimal()
return GetOptional()?.GetJsonDocument();
}

public Guid? GetOptionalUuid()
{
return GetOptional()?.GetUuid();
}

public decimal? GetOptionalDecimal()
{
return GetOptional()?.GetDecimal();
Expand Down
64 changes: 64 additions & 0 deletions src/Ydb.Sdk/tests/Ado/YdbCommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,33 @@ public async Task ExecuteScalarAsync_WhenSetYdbParameterThenPrepare_ReturnThisVa
Assert.Equal(data.Expected, await dbCommand.ExecuteScalarAsync());
}

[Theory]
[ClassData(typeof(YdbParameterTests.TestDataGenerator))]
public async Task ExecuteScalarAsync_WhenDbTypeIsObject_ReturnThisValue<T>(YdbParameterTests.Data<T> data)
{
if (data.IsNullable)
{
return;
}

await using var connection = new YdbConnection();
await connection.OpenAsync();

var dbCommand = connection.CreateCommand();

dbCommand.CommandText = "SELECT @var;";

var dbParameter = new YdbParameter
{
ParameterName = "@var",
Value = data.Expected,
IsNullable = data.IsNullable
};
dbCommand.Parameters.Add(dbParameter);

Assert.Equal(data.Expected, await dbCommand.ExecuteScalarAsync());
}

[Fact]
public async Task ExecuteScalarAsync_WhenNoDbTypeParameter_ReturnThisValue()
{
Expand Down Expand Up @@ -404,4 +431,41 @@ public async Task ExecuteScalar_WhenSelectNull_ReturnNull()

Assert.Null(await new YdbCommand(ydbConnection) { CommandText = "SELECT NULL" }.ExecuteScalarAsync());
}

[Theory]
[InlineData("123e4567-e89b-12d3-a456-426614174000")]
[InlineData("2d9e498b-b746-9cfb-084d-de4e1cb4736e")]
[InlineData("6E73B41C-4EDE-4D08-9CFB-B7462D9E498B")]
public async Task Guid_WhenSelectUuid_ReturnThisUuid(string guid)
{
await using var ydbConnection = new YdbConnection();
await ydbConnection.OpenAsync();

var actualGuid = await new YdbCommand(ydbConnection)
{ CommandText = $"SELECT CAST('{guid}' AS UUID);" }
.ExecuteScalarAsync();

Assert.Equal(new Guid(guid), actualGuid);
Assert.Equal(guid.ToLower(), actualGuid?.ToString()); // Guid.ToString() method represents lowercase
}

[Theory]
[InlineData("123e4567-e89b-12d3-a456-426614174000")]
[InlineData("2d9e498b-b746-9cfb-084d-de4e1cb4736e")]
[InlineData("6E73B41C-4EDE-4D08-9CFB-B7462D9E498B")]
public async Task Guid_WhenSetUuid_ReturnThisUtf8Uuid(string guid)
{
await using var ydbConnection = new YdbConnection();
await ydbConnection.OpenAsync();

var ydbCommand = new YdbCommand(ydbConnection)
{
CommandText = "SELECT CAST(@guid AS Text);"
};
ydbCommand.Parameters.Add(new YdbParameter("guid", DbType.Guid, new Guid(guid)));

var actualGuidText = await ydbCommand.ExecuteScalarAsync();

Assert.Equal(guid.ToLower(), actualGuidText); // Guid.ToString() method represents lowercase
}
}
12 changes: 11 additions & 1 deletion src/Ydb.Sdk/tests/Ado/YdbParameterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ public void YdbValue_WhenUnCastTypes_ThrowInvalidCastException()
[Theory]
[InlineData(DbType.VarNumeric, "VarNumeric")]
[InlineData(DbType.Xml, "Xml")]
[InlineData(DbType.Guid, "Guid")]
[InlineData(DbType.Time, "Time")]
public void YdbValue_WhenNoSupportedDbType_ThrowException(DbType dbType, string name)
{
Expand Down Expand Up @@ -183,6 +182,17 @@ public class TestDataGenerator : IEnumerable<object[]>
new object[] { new Data<double>(DbType.Double, 123.45, value => value.GetDouble()) },
new object[] { new Data<double?>(DbType.Double, 123.45, value => value.GetDouble(), true) },
new object[] { new Data<double?>(DbType.Double, null, value => value.GetOptionalDouble()) },
new object[]
{
new Data<Guid>(DbType.Guid, new Guid("6E73B41C-4EDE-4D08-9CFB-B7462D9E498B"),
value => value.GetUuid())
},
new object[]
{
new Data<Guid?>(DbType.Guid, new Guid("6E73B41C-4EDE-4D08-9CFB-B7462D9E498B"),
value => value.GetUuid(), true)
},
new object[] { new Data<Guid?>(DbType.Guid, null, value => value.GetOptionalUuid()) },
new object[] { new Data<DateTime>(DbType.Date, new DateTime(2021, 08, 21), value => value.GetDate()) },
new object[]
{
Expand Down
11 changes: 11 additions & 0 deletions src/Ydb.Sdk/tests/Value/YdbValueTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ private class TestDataGenerator : IEnumerable<object[]>
new object[] { new Data<double>(123.45, YdbValue.MakeDouble, value => value.GetDouble()) },
new object[] { new Data<double?>(123.45, YdbValue.MakeOptionalDouble, value => value.GetOptionalDouble()) },
new object[] { new Data<double?>(null, YdbValue.MakeOptionalDouble, value => value.GetOptionalDouble()) },
new object[]
{
new Data<Guid>(new Guid("6E73B41C-4EDE-4D08-9CFB-B7462D9E498B"), YdbValue.MakeUuid,
value => value.GetUuid())
},
new object[]
{
new Data<Guid?>(new Guid("6E73B41C-4EDE-4D08-9CFB-B7462D9E498B"), YdbValue.MakeOptionalUuid,
value => value.GetOptionalUuid())
},
new object[] { new Data<Guid?>(null, YdbValue.MakeOptionalUuid, value => value.GetOptionalUuid()) },
new object[]
{ new Data<DateTime>(new DateTime(2021, 08, 21), YdbValue.MakeDate, value => value.GetDate()) },
new object[]
Expand Down
Loading