Skip to content

Commit cd0161c

Browse files
next iteration
1 parent 1e3bc4f commit cd0161c

File tree

4 files changed

+226
-151
lines changed

4 files changed

+226
-151
lines changed

src/Ydb.Sdk/src/Ado/Internal/YdbPrimitiveTypeInfo.cs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,28 +45,28 @@ private YdbPrimitiveTypeInfo(Type.Types.PrimitiveTypeId primitiveTypeId, Func<ob
4545

4646
internal static YdbPrimitiveTypeInfo? TryResolve(System.Type type)
4747
{
48-
if (type == typeof(bool)) return Bool;
48+
if (type.IsAssignableFrom(typeof(bool))) return Bool;
4949

50-
if (type == typeof(sbyte)) return Int8;
51-
if (type == typeof(short)) return Int16;
52-
if (type == typeof(int)) return Int32;
53-
if (type == typeof(long)) return Int64;
50+
if (type.IsAssignableFrom(typeof(sbyte))) return Int8;
51+
if (type.IsAssignableFrom(typeof(short))) return Int16;
52+
if (type.IsAssignableFrom(typeof(int))) return Int32;
53+
if (type.IsAssignableFrom(typeof(long))) return Int64;
5454

55-
if (type == typeof(byte)) return Uint8;
56-
if (type == typeof(ushort)) return Uint16;
57-
if (type == typeof(uint)) return Uint32;
58-
if (type == typeof(ulong)) return Uint64;
55+
if (type.IsAssignableFrom(typeof(byte))) return Uint8;
56+
if (type.IsAssignableFrom(typeof(ushort))) return Uint16;
57+
if (type.IsAssignableFrom(typeof(uint))) return Uint32;
58+
if (type.IsAssignableFrom(typeof(ulong))) return Uint64;
5959

60-
if (type == typeof(float)) return Float;
61-
if (type == typeof(double)) return Double;
60+
if (type.IsAssignableFrom(typeof(float))) return Float;
61+
if (type.IsAssignableFrom(typeof(double))) return Double;
6262

63-
if (type == typeof(byte[]) || type == typeof(MemoryStream)) return Bytes;
64-
if (type == typeof(string)) return Text;
65-
if (type == typeof(Guid)) return Uuid;
63+
if (type.IsAssignableFrom(typeof(byte[])) || type.IsAssignableFrom(typeof(MemoryStream))) return Bytes;
64+
if (type.IsAssignableFrom(typeof(string))) return Text;
65+
if (type.IsAssignableFrom(typeof(Guid))) return Uuid;
6666

67-
if (type == typeof(DateOnly)) return Date;
68-
if (type == typeof(DateTime)) return Timestamp;
69-
if (type == typeof(TimeSpan)) return Interval;
67+
if (type.IsAssignableFrom(typeof(DateOnly))) return Date;
68+
if (type.IsAssignableFrom(typeof(DateTime))) return Timestamp;
69+
if (type.IsAssignableFrom(typeof(TimeSpan))) return Interval;
7070

7171
return null;
7272
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ _ when YdbDbType.HasFlag(YdbDbType.List) && value is IList itemsValue =>
267267
{ Type = YdbPrimitiveTypeInfo.Timestamp.YdbType, Value = PackTimestamp(dateTimeValue) },
268268
DateOnly dateOnlyValue => new TypedValue
269269
{ Type = YdbPrimitiveTypeInfo.Date.YdbType, Value = PackDate(dateOnlyValue.ToDateTime(TimeOnly.MinValue)) },
270-
byte[] bytesValue => new TypedValue
270+
byte[] bytesValue when value.GetType().GetElementType() == typeof(byte) /* array covariance */ => new TypedValue
271271
{ Type = YdbPrimitiveTypeInfo.Bytes.YdbType, Value = PackBytes(bytesValue) },
272272
string stringValue => new TypedValue
273273
{ Type = YdbPrimitiveTypeInfo.Text.YdbType, Value = PackText(stringValue) },
@@ -315,7 +315,7 @@ private TypedValue PackList(IList items, YdbDbType ydbDbType = YdbDbType.Unspeci
315315
return new TypedValue { Type = type.ListType(), Value = value };
316316
}
317317

318-
if (ydbDbType == YdbDbType.Decimal || elementType == typeof(decimal))
318+
if (ydbDbType == YdbDbType.Decimal || elementType.IsAssignableFrom(typeof(decimal)))
319319
{
320320
var value = new Ydb.Value();
321321
var isOptional = false;
@@ -344,7 +344,8 @@ private TypedValue PackList(IList items, YdbDbType ydbDbType = YdbDbType.Unspeci
344344
return new TypedValue { Type = type.ListType(), Value = value };
345345
}
346346

347-
return (from object? item in items select PackObject(item)).ToArray().List();
347+
return (from object? item in items select PackObject(item ?? throw ValueTypeNotSupportedException)).ToArray()
348+
.List();
348349
}
349350

350351
private InvalidOperationException ValueTypeNotSupportedException =>

src/Ydb.Sdk/test/Ydb.Sdk.Ado.Dapper.Tests/DapperIntegrationTests.cs

Lines changed: 62 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -14,41 +14,23 @@ public class DapperIntegrationTests : TestBase
1414
[Fact]
1515
public async Task DapperYqlTutorialTests()
1616
{
17-
SqlMapper.SetTypeMap(
18-
typeof(Episode),
19-
new CustomPropertyTypeMap(
20-
typeof(Episode),
21-
(type, columnName) =>
22-
type.GetProperties().FirstOrDefault(prop =>
23-
prop.GetCustomAttributes(false)
24-
.OfType<ColumnAttribute>()
25-
.Any(attr => attr.Name == columnName)) ?? throw new InvalidOperationException()));
17+
SqlMapper.SetTypeMap(typeof(Episode), new CustomPropertyTypeMap(typeof(Episode), (type, columnName) =>
18+
type.GetProperties().FirstOrDefault(prop => prop.GetCustomAttributes(false)
19+
.OfType<ColumnAttribute>()
20+
.Any(attr => attr.Name == columnName)) ?? throw new InvalidOperationException()));
2621

2722
await using var connection = await CreateOpenConnectionAsync();
2823
await connection.ExecuteAsync(Tables.CreateTables); // create tables
2924
await connection.ExecuteAsync(Tables.UpsertData); // adding data to table
30-
var selectedEpisodes = (await connection.QueryAsync<Episode>($@"
31-
SELECT
32-
series_id,
33-
season_id,
34-
episode_id,
35-
title,
36-
air_date
37-
38-
FROM {Tables.Episodes}
39-
WHERE
40-
series_id = @series_id -- List of conditions to build the result
41-
AND season_id > @season_id -- Logical AND is used for complex conditions
42-
43-
ORDER BY -- Sorting the results.
44-
series_id, -- ORDER BY sorts the values by one or multiple
45-
season_id, -- columns. Columns are separated by commas.
46-
episode_id
47-
48-
LIMIT 3 -- LIMIT N after ORDER BY means
49-
-- ""get top N"" or ""get bottom N"" results,
50-
; -- depending on sort order.
51-
", new { series_id = 1, season_id = 1 })).ToArray();
25+
var selectedEpisodes = (await connection.QueryAsync<Episode>(
26+
$"""
27+
SELECT series_id, season_id, episode_id, title, air_date
28+
FROM {Tables.Episodes}
29+
WHERE series_id = @series_id AND season_id > @season_id
30+
ORDER BY series_id, season_id, episode_id
31+
LIMIT 3;
32+
""", new { series_id = 1, season_id = 1 }))
33+
.ToArray();
5234

5335
Assert.Equal(
5436
new[]
@@ -71,24 +53,14 @@ LIMIT 3 -- LIMIT N after ORDER BY means
7153
}, selectedEpisodes);
7254

7355

74-
var selectedTitlesSeasonAndSeries = (await connection.QueryAsync<dynamic>($@"
75-
SELECT
76-
sa.title AS season_title, -- sa and sr are ""join names"",
77-
sr.title AS series_title, -- table aliases declared below using AS.
78-
sr.series_id, -- They are used to avoid
79-
sa.season_id -- ambiguity in the column names used.
80-
81-
FROM
82-
{Tables.Seasons} AS sa
83-
INNER JOIN
84-
{Tables.Series} AS sr
85-
ON sa.series_id = sr.series_id
86-
WHERE sa.series_id = @series_id
87-
ORDER BY -- Sorting of the results.
88-
sr.series_id,
89-
sa.season_id -- ORDER BY sorts the values by one column
90-
; -- or multiple columns.
91-
-- Columns are separated by commas.", new { series_id = 1 })).ToArray();
56+
var selectedTitlesSeasonAndSeries = (await connection.QueryAsync<dynamic>(
57+
$"""
58+
SELECT sa.title AS season_title, sr.title AS series_title, sr.series_id, sa.season_id
59+
FROM {Tables.Seasons} AS sa
60+
INNER JOIN {Tables.Series} AS sr
61+
ON sa.series_id = sr.series_id
62+
WHERE sa.series_id = @series_id ORDER BY sr.series_id, sa.season_id;
63+
""", new { series_id = 1 })).ToArray();
9264

9365
for (var i = 0; i < selectedTitlesSeasonAndSeries.Length; i++)
9466
{
@@ -111,24 +83,11 @@ ORDER BY -- Sorting of the results.
11183
parameters1.Add("title", episode1.Title, DbType.String);
11284
parameters1.Add("air_date", episode1.AirDate, DbType.Date);
11385

114-
await connection.ExecuteAsync($@"
115-
UPSERT INTO {Tables.Episodes}
116-
(
117-
series_id,
118-
season_id,
119-
episode_id,
120-
title,
121-
air_date
122-
)
123-
VALUES
124-
(
125-
@series_id,
126-
@season_id,
127-
@episode_id,
128-
@title,
129-
@air_date
130-
);
131-
;", parameters1, transaction);
86+
await connection.ExecuteAsync(
87+
$"""
88+
UPSERT INTO {Tables.Episodes} (series_id, season_id, episode_id, title, air_date)
89+
VALUES (@series_id, @season_id, @episode_id, @title, @air_date );
90+
""", parameters1, transaction);
13291
await using (var otherConn = await CreateOpenConnectionAsync())
13392
{
13493
Assert.Null(await otherConn.QuerySingleOrDefaultAsync(
@@ -164,32 +123,12 @@ UPSERT INTO {Tables.Episodes}
164123
await transaction.CommitAsync();
165124

166125
var rollbackTransaction = connection.BeginTransaction();
167-
await connection.ExecuteAsync($@"
168-
INSERT INTO {Tables.Episodes}
169-
(
170-
series_id,
171-
season_id,
172-
episode_id,
173-
title,
174-
air_date
175-
)
176-
VALUES
177-
(
178-
2,
179-
5,
180-
21,
181-
""Test 21"",
182-
Date(""2018-08-27"")
183-
), -- Rows are separated by commas.
184-
(
185-
2,
186-
5,
187-
22,
188-
""Test 22"",
189-
Date(""2018-08-27"")
190-
)
191-
;
192-
;", transaction: rollbackTransaction);
126+
await connection.ExecuteAsync(
127+
$"""
128+
INSERT INTO {Tables.Episodes} (series_id, season_id, episode_id, title, air_date) VALUES
129+
(2, 5, 21, "Test 21", Date("2018-08-27")),
130+
(2, 5, 22, "Test 22", Date("2018-08-27"));
131+
""", transaction: rollbackTransaction);
193132
await rollbackTransaction.RollbackAsync();
194133

195134
Assert.Equal((ulong)72, await connection.ExecuteScalarAsync<ulong>($"SELECT COUNT(*) FROM {Tables.Episodes}"));
@@ -203,37 +142,38 @@ public async Task NullableFieldSupported()
203142
var tableName = "DapperNullableTypes_" + Random.Shared.Next();
204143

205144
await using var connection = await CreateOpenConnectionAsync();
206-
await connection.ExecuteAsync(@$"
207-
CREATE TABLE {tableName} (
208-
Id INT32,
209-
BoolColumn BOOL,
210-
LongColumn INT64,
211-
ShortColumn INT16,
212-
SbyteColumn INT8,
213-
FloatColumn FLOAT,
214-
DoubleColumn DOUBLE,
215-
DecimalColumn DECIMAL(22,9),
216-
ByteColumn UINT8,
217-
UshortColumn UINT16,
218-
UintColumn UINT32,
219-
UlongColumn UINT64,
220-
TextColumn TEXT,
221-
BytesColumn BYTES,
222-
TimestampColumn TIMESTAMP,
223-
PRIMARY KEY (Id)
224-
)
225-
");
145+
await connection.ExecuteAsync($"""
146+
CREATE TABLE {tableName} (
147+
Id INT32,
148+
BoolColumn BOOL,
149+
LongColumn INT64,
150+
ShortColumn INT16,
151+
SbyteColumn INT8,
152+
FloatColumn FLOAT,
153+
DoubleColumn DOUBLE,
154+
DecimalColumn DECIMAL(22,9),
155+
ByteColumn UINT8,
156+
UshortColumn UINT16,
157+
UintColumn UINT32,
158+
UlongColumn UINT64,
159+
TextColumn TEXT,
160+
BytesColumn BYTES,
161+
TimestampColumn TIMESTAMP,
162+
PRIMARY KEY (Id)
163+
)
164+
""");
226165

227166
var entity = new NullableFields();
228167
SqlMapper.AddTypeMap(typeof(DateTime), DbType.DateTime2);
229168

230-
await connection.ExecuteAsync($@"
231-
INSERT INTO {tableName} (Id, BoolColumn, LongColumn, ShortColumn, SbyteColumn, FloatColumn, DoubleColumn, DecimalColumn,
232-
ByteColumn, UshortColumn, UintColumn, UlongColumn, TextColumn, BytesColumn, TimestampColumn)
233-
VALUES (@Id, @BoolColumn, @LongColumn, @ShortColumn, @SbyteColumn,
234-
@FloatColumn, @DoubleColumn, @DecimalColumn,
235-
@ByteColumn, @UshortColumn, @UintColumn,
236-
@UlongColumn, @TextColumn, @BytesColumn, @TimestampColumn)", entity);
169+
await connection.ExecuteAsync(
170+
$"""
171+
INSERT INTO {tableName} (Id, BoolColumn, LongColumn, ShortColumn, SbyteColumn, FloatColumn, DoubleColumn,
172+
DecimalColumn, ByteColumn, UshortColumn, UintColumn, UlongColumn, TextColumn, BytesColumn, TimestampColumn)
173+
VALUES (@Id, @BoolColumn, @LongColumn, @ShortColumn, @SbyteColumn, @FloatColumn, @DoubleColumn,
174+
@DecimalColumn, @ByteColumn, @UshortColumn, @UintColumn, @UlongColumn, @TextColumn, @BytesColumn,
175+
@TimestampColumn)
176+
""", entity);
237177

238178
Assert.Equal(entity,
239179
await connection.QuerySingleAsync<NullableFields>($"SELECT * FROM {tableName} WHERE Id IS NULL"));
@@ -273,7 +213,7 @@ public async Task Read_Json_JsonDocument_Yson_Fields()
273213
Assert.Equal("{a=1u}"u8.ToArray(), jsonModel.Yson);
274214
}
275215

276-
private class NullableFields
216+
private record NullableFields
277217
{
278218
#pragma warning disable CollectionNeverQueried.Local
279219
public int? Id { get; init; }
@@ -294,7 +234,7 @@ private class NullableFields
294234
#pragma warning restore CollectionNeverQueried.Local
295235
}
296236

297-
private class Episode
237+
private record Episode
298238
{
299239
[Column("series_id")] public uint SeriesId { get; init; }
300240
[Column("season_id")] public uint SeasonId { get; init; }

0 commit comments

Comments
 (0)