Skip to content

Commit 3075d7e

Browse files
feat: supported uuid YDB type
1 parent 5a964cd commit 3075d7e

File tree

9 files changed

+143
-9
lines changed

9 files changed

+143
-9
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
- Supported UUID (Guid)
2+
13
## v0.7.3
24
- Fixed YdbDataReader: extract Json / Yson types
35

src/Ydb.Sdk/src/Ado/YdbDataReader.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ public override System.Type GetFieldType(int ordinal)
225225
typeof(string),
226226
YdbTypeId.String => typeof(byte[]),
227227
YdbTypeId.DecimalType => typeof(decimal),
228+
YdbTypeId.Uuid => typeof(Guid),
228229
_ => throw new YdbException($"Unsupported ydb type {type}")
229230
};
230231

@@ -339,6 +340,7 @@ public override object GetValue(int ordinal)
339340
YdbTypeId.Yson => ydbValue.GetYson(),
340341
YdbTypeId.String => ydbValue.GetString(),
341342
YdbTypeId.DecimalType => ydbValue.GetDecimal(),
343+
YdbTypeId.Uuid => ydbValue.GetUuid(),
342344
_ => throw new YdbException($"Unsupported ydb type {ydbValue.TypeId}")
343345
};
344346
}

src/Ydb.Sdk/src/Ado/YdbParameter.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ public sealed class YdbParameter : DbParameter
3131
{ DbType.DateTime2, YdbValue.MakeOptionalTimestamp() },
3232
{ DbType.DateTimeOffset, YdbValue.MakeOptionalTimestamp() },
3333
{ DbType.Decimal, YdbValue.MakeOptionalDecimal() },
34-
{ DbType.Currency, YdbValue.MakeOptionalDecimal() }
34+
{ DbType.Currency, YdbValue.MakeOptionalDecimal() },
35+
{ DbType.Guid, YdbValue.MakeOptionalUuid() }
3536
};
3637

3738
private string _parameterName = string.Empty;
@@ -165,7 +166,8 @@ string valueString when DbType is DbType.String or DbType.AnsiString or DbType.A
165166
_ => ThrowInvalidCast()
166167
},
167168
byte[] bytesValue when DbType is DbType.Binary or DbType.Object => YdbValue.MakeString(bytesValue),
168-
_ when DbType is DbType.VarNumeric or DbType.Xml or DbType.Guid or DbType.Time =>
169+
Guid guidValue when DbType is DbType.Guid or DbType.Object => YdbValue.MakeUuid(guidValue),
170+
_ when DbType is DbType.VarNumeric or DbType.Xml or DbType.Time =>
169171
throw new YdbException($"Ydb don't supported this DbType: {DbType}"),
170172
_ => ThrowInvalidCast()
171173
};

src/Ydb.Sdk/src/Value/YdbValueBuilder.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,17 @@ public static YdbValue MakeJsonDocument(string value)
122122
new Ydb.Value { TextValue = value });
123123
}
124124

125+
public static YdbValue MakeUuid(Guid guid)
126+
{
127+
var bytes = guid.ToByteArray();
128+
129+
var low = BitConverter.ToUInt64(bytes, 0);
130+
var high = BitConverter.ToUInt64(bytes, 8);
131+
132+
return new YdbValue(MakePrimitiveType(Type.Types.PrimitiveTypeId.Uuid),
133+
new Ydb.Value { Low128 = low, High128 = high });
134+
}
135+
125136
private static byte GetDecimalScale(decimal value)
126137
{
127138
var bits = decimal.GetBits(value);
@@ -237,9 +248,7 @@ public static YdbValue MakeList(IReadOnlyList<YdbValue> values)
237248
var value = new Ydb.Value();
238249
value.Items.Add(values.Select(v => v._protoValue));
239250

240-
return new YdbValue(
241-
new Type { ListType = new ListType { Item = values[0]._protoType } },
242-
value);
251+
return new YdbValue(new Type { ListType = new ListType { Item = values[0]._protoType } }, value);
243252
}
244253

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

257-
return new YdbValue(
258-
type,
259-
value);
266+
return new YdbValue(type, value);
260267
}
261268

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

409+
public static YdbValue MakeOptionalUuid(Guid? value = null)
410+
{
411+
return MakeOptionalOf(value, YdbTypeId.Uuid, MakeUuid);
412+
}
413+
402414
public static YdbValue MakeOptionalDecimal(decimal? value = null)
403415
{
404416
return MakeOptionalOf(value, YdbTypeId.DecimalType, MakeDecimal);

src/Ydb.Sdk/src/Value/YdbValueCast.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ public static explicit operator decimal(YdbValue value)
152152
return GetOptionalPrimitive<decimal>(value);
153153
}
154154

155+
public static explicit operator Guid?(YdbValue value)
156+
{
157+
return GetOptionalPrimitive<Guid>(value);
158+
}
155159

156160
private static T? GetOptionalPrimitive<T>(YdbValue value) where T : struct
157161
{
@@ -192,6 +196,7 @@ private static T GetObject<T>(YdbValue value)
192196
YdbTypeId.Json => value.GetJson(),
193197
YdbTypeId.JsonDocument => value.GetJsonDocument(),
194198
YdbTypeId.DecimalType => value.GetDecimal(),
199+
YdbTypeId.Uuid => value.GetUuid(),
195200
_ => throw new InvalidCastException($"Cannot cast YDB type {value.TypeId} to {typeof(T).Name}.")
196201
});
197202
}

src/Ydb.Sdk/src/Value/YdbValueParser.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace Ydb.Sdk.Value;
1+
using System.ComponentModel;
2+
3+
namespace Ydb.Sdk.Value;
24

35
public partial class YdbValue
46
{
@@ -127,6 +129,23 @@ public string GetJsonDocument()
127129
return _protoValue.TextValue;
128130
}
129131

132+
public Guid GetUuid()
133+
{
134+
EnsurePrimitiveTypeId(Type.Types.PrimitiveTypeId.Uuid);
135+
136+
var high = _protoValue.High128;
137+
var low = _protoValue.Low128;
138+
139+
var lowBytes = BitConverter.GetBytes(low);
140+
var highBytes = BitConverter.GetBytes(high);
141+
142+
var guidBytes = new byte[16];
143+
Array.Copy(lowBytes, 0, guidBytes, 0, 8);
144+
Array.Copy(highBytes, 0, guidBytes, 8, 8);
145+
146+
return new Guid(guidBytes);
147+
}
148+
130149
public decimal GetDecimal()
131150
{
132151
EnsureType(Type.TypeOneofCase.DecimalType);
@@ -258,6 +277,11 @@ public decimal GetDecimal()
258277
return GetOptional()?.GetJsonDocument();
259278
}
260279

280+
public Guid? GetOptionalUuid()
281+
{
282+
return GetOptional()?.GetUuid();
283+
}
284+
261285
public decimal? GetOptionalDecimal()
262286
{
263287
return GetOptional()?.GetDecimal();

src/Ydb.Sdk/tests/Ado/YdbCommandTests.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,34 @@ public async Task ExecuteScalarAsync_WhenSetYdbParameterThenPrepare_ReturnThisVa
6868
Assert.Equal(data.Expected, await dbCommand.ExecuteScalarAsync());
6969
}
7070

71+
[Theory]
72+
[ClassData(typeof(YdbParameterTests.TestDataGenerator))]
73+
public async Task ExecuteScalarAsync_WhenDbTypeIsObject_ReturnThisValue<T>(
74+
YdbParameterTests.Data<T> data)
75+
{
76+
if (data.IsNullable)
77+
{
78+
return;
79+
}
80+
81+
await using var connection = new YdbConnection();
82+
await connection.OpenAsync();
83+
84+
var dbCommand = connection.CreateCommand();
85+
86+
dbCommand.CommandText = "SELECT @var;";
87+
88+
var dbParameter = new YdbParameter
89+
{
90+
ParameterName = "@var",
91+
Value = data.Expected,
92+
IsNullable = data.IsNullable
93+
};
94+
dbCommand.Parameters.Add(dbParameter);
95+
96+
Assert.Equal(data.Expected, await dbCommand.ExecuteScalarAsync());
97+
}
98+
7199
[Fact]
72100
public async Task ExecuteScalarAsync_WhenNoDbTypeParameter_ReturnThisValue()
73101
{
@@ -404,4 +432,41 @@ public async Task ExecuteScalar_WhenSelectNull_ReturnNull()
404432

405433
Assert.Null(await new YdbCommand(ydbConnection) { CommandText = "SELECT NULL" }.ExecuteScalarAsync());
406434
}
435+
436+
[Theory]
437+
[InlineData("123e4567-e89b-12d3-a456-426614174000")]
438+
[InlineData("2d9e498b-b746-9cfb-084d-de4e1cb4736e")]
439+
[InlineData("6E73B41C-4EDE-4D08-9CFB-B7462D9E498B")]
440+
public async Task Guid_WhenSelectUuid_ReturnThisUuid(string guid)
441+
{
442+
await using var ydbConnection = new YdbConnection();
443+
await ydbConnection.OpenAsync();
444+
445+
var actualGuid = await new YdbCommand(ydbConnection)
446+
{ CommandText = $"SELECT CAST('{guid}' AS UUID);" }
447+
.ExecuteScalarAsync();
448+
449+
Assert.Equal(new Guid(guid), actualGuid);
450+
Assert.Equal(guid.ToLower(), actualGuid?.ToString()); // Guid.ToString() method represents lowercase
451+
}
452+
453+
[Theory]
454+
[InlineData("123e4567-e89b-12d3-a456-426614174000")]
455+
[InlineData("2d9e498b-b746-9cfb-084d-de4e1cb4736e")]
456+
[InlineData("6E73B41C-4EDE-4D08-9CFB-B7462D9E498B")]
457+
public async Task Guid_WhenSetUuid_ReturnThisUtf8Uuid(string guid)
458+
{
459+
await using var ydbConnection = new YdbConnection();
460+
await ydbConnection.OpenAsync();
461+
462+
var ydbCommand = new YdbCommand(ydbConnection)
463+
{
464+
CommandText = "SELECT CAST(@guid AS Text);"
465+
};
466+
ydbCommand.Parameters.Add(new YdbParameter("guid", DbType.Guid, new Guid(guid)));
467+
468+
var actualGuidText = await ydbCommand.ExecuteScalarAsync();
469+
470+
Assert.Equal(guid.ToLower(), actualGuidText); // Guid.ToString() method represents lowercase
471+
}
407472
}

src/Ydb.Sdk/tests/Ado/YdbParameterTests.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,17 @@ public class TestDataGenerator : IEnumerable<object[]>
183183
new object[] { new Data<double>(DbType.Double, 123.45, value => value.GetDouble()) },
184184
new object[] { new Data<double?>(DbType.Double, 123.45, value => value.GetDouble(), true) },
185185
new object[] { new Data<double?>(DbType.Double, null, value => value.GetOptionalDouble()) },
186+
new object[]
187+
{
188+
new Data<Guid>(DbType.Guid, new Guid("6E73B41C-4EDE-4D08-9CFB-B7462D9E498B"),
189+
value => value.GetUuid())
190+
},
191+
new object[]
192+
{
193+
new Data<Guid?>(DbType.Guid, new Guid("6E73B41C-4EDE-4D08-9CFB-B7462D9E498B"),
194+
value => value.GetUuid(), true)
195+
},
196+
new object[] { new Data<Guid?>(DbType.Guid, null, value => value.GetOptionalUuid()) },
186197
new object[] { new Data<DateTime>(DbType.Date, new DateTime(2021, 08, 21), value => value.GetDate()) },
187198
new object[]
188199
{

src/Ydb.Sdk/tests/Value/YdbValueTests.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,17 @@ private class TestDataGenerator : IEnumerable<object[]>
8686
new object[] { new Data<double>(123.45, YdbValue.MakeDouble, value => value.GetDouble()) },
8787
new object[] { new Data<double?>(123.45, YdbValue.MakeOptionalDouble, value => value.GetOptionalDouble()) },
8888
new object[] { new Data<double?>(null, YdbValue.MakeOptionalDouble, value => value.GetOptionalDouble()) },
89+
new object[]
90+
{
91+
new Data<Guid>(new Guid("6E73B41C-4EDE-4D08-9CFB-B7462D9E498B"), YdbValue.MakeUuid,
92+
value => value.GetUuid())
93+
},
94+
new object[]
95+
{
96+
new Data<Guid?>(new Guid("6E73B41C-4EDE-4D08-9CFB-B7462D9E498B"), YdbValue.MakeOptionalUuid,
97+
value => value.GetUuid())
98+
},
99+
new object[] { new Data<Guid?>(null, YdbValue.MakeOptionalUuid, value => value.GetOptionalUuid()) },
89100
new object[]
90101
{ new Data<DateTime>(new DateTime(2021, 08, 21), YdbValue.MakeDate, value => value.GetDate()) },
91102
new object[]

0 commit comments

Comments
 (0)