Skip to content

Commit f200f69

Browse files
feat: supported uuid YDB type (#208)
1 parent 676c69e commit f200f69

File tree

9 files changed

+139
-9
lines changed

9 files changed

+139
-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: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,23 @@ public string GetJsonDocument()
127127
return _protoValue.TextValue;
128128
}
129129

130+
public Guid GetUuid()
131+
{
132+
EnsurePrimitiveTypeId(Type.Types.PrimitiveTypeId.Uuid);
133+
134+
var high = _protoValue.High128;
135+
var low = _protoValue.Low128;
136+
137+
var lowBytes = BitConverter.GetBytes(low);
138+
var highBytes = BitConverter.GetBytes(high);
139+
140+
var guidBytes = new byte[16];
141+
Array.Copy(lowBytes, 0, guidBytes, 0, 8);
142+
Array.Copy(highBytes, 0, guidBytes, 8, 8);
143+
144+
return new Guid(guidBytes);
145+
}
146+
130147
public decimal GetDecimal()
131148
{
132149
EnsureType(Type.TypeOneofCase.DecimalType);
@@ -258,6 +275,11 @@ public decimal GetDecimal()
258275
return GetOptional()?.GetJsonDocument();
259276
}
260277

278+
public Guid? GetOptionalUuid()
279+
{
280+
return GetOptional()?.GetUuid();
281+
}
282+
261283
public decimal? GetOptionalDecimal()
262284
{
263285
return GetOptional()?.GetDecimal();

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

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,33 @@ 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>(YdbParameterTests.Data<T> data)
74+
{
75+
if (data.IsNullable)
76+
{
77+
return;
78+
}
79+
80+
await using var connection = new YdbConnection();
81+
await connection.OpenAsync();
82+
83+
var dbCommand = connection.CreateCommand();
84+
85+
dbCommand.CommandText = "SELECT @var;";
86+
87+
var dbParameter = new YdbParameter
88+
{
89+
ParameterName = "@var",
90+
Value = data.Expected,
91+
IsNullable = data.IsNullable
92+
};
93+
dbCommand.Parameters.Add(dbParameter);
94+
95+
Assert.Equal(data.Expected, await dbCommand.ExecuteScalarAsync());
96+
}
97+
7198
[Fact]
7299
public async Task ExecuteScalarAsync_WhenNoDbTypeParameter_ReturnThisValue()
73100
{
@@ -404,4 +431,41 @@ public async Task ExecuteScalar_WhenSelectNull_ReturnNull()
404431

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

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ public void YdbValue_WhenUnCastTypes_ThrowInvalidCastException()
8080
[Theory]
8181
[InlineData(DbType.VarNumeric, "VarNumeric")]
8282
[InlineData(DbType.Xml, "Xml")]
83-
[InlineData(DbType.Guid, "Guid")]
8483
[InlineData(DbType.Time, "Time")]
8584
public void YdbValue_WhenNoSupportedDbType_ThrowException(DbType dbType, string name)
8685
{
@@ -183,6 +182,17 @@ public class TestDataGenerator : IEnumerable<object[]>
183182
new object[] { new Data<double>(DbType.Double, 123.45, value => value.GetDouble()) },
184183
new object[] { new Data<double?>(DbType.Double, 123.45, value => value.GetDouble(), true) },
185184
new object[] { new Data<double?>(DbType.Double, null, value => value.GetOptionalDouble()) },
185+
new object[]
186+
{
187+
new Data<Guid>(DbType.Guid, new Guid("6E73B41C-4EDE-4D08-9CFB-B7462D9E498B"),
188+
value => value.GetUuid())
189+
},
190+
new object[]
191+
{
192+
new Data<Guid?>(DbType.Guid, new Guid("6E73B41C-4EDE-4D08-9CFB-B7462D9E498B"),
193+
value => value.GetUuid(), true)
194+
},
195+
new object[] { new Data<Guid?>(DbType.Guid, null, value => value.GetOptionalUuid()) },
186196
new object[] { new Data<DateTime>(DbType.Date, new DateTime(2021, 08, 21), value => value.GetDate()) },
187197
new object[]
188198
{

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.GetOptionalUuid())
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)