Skip to content

Commit b77d5be

Browse files
committed
Simplify tests: move temp-table lifecycle to TestBase;
1 parent aab0035 commit b77d5be

File tree

3 files changed

+266
-322
lines changed

3 files changed

+266
-322
lines changed

src/Ydb.Sdk/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
- Test: Refactor TestBase: add UsingTempTableAsync / UsingTempTablesAsync to remove DDL/cleanup boilerplate; test names and logic unchanged.
2+
- Feat Value: Add YdbList builder for List<Struct<...>> (protobuf-based); works with IBulkUpsertImporter.AddListAsync.
13
- Dev: LogLevel `Warning` -> `Debug` on DeleteSession has been `RpcException`.
24

35
## v0.22.0

src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/TestBase.cs

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1+
using System.Data;
12
using Xunit;
23
using Ydb.Sdk.Ado.Tests.Utils;
4+
using Ydb.Sdk.Ado.YdbType;
35

46
namespace Ydb.Sdk.Ado.Tests;
57

68
public abstract class TestBase : IAsyncLifetime
79
{
810
protected static string ConnectionString => TestUtils.ConnectionString;
911

12+
protected static readonly string[] IdNameColumns = ["Id", "Name"];
13+
1014
protected static YdbConnection CreateConnection() => new(
1115
new YdbConnectionStringBuilder(ConnectionString) { LoggerFactory = TestUtils.LoggerFactory }
1216
);
@@ -25,6 +29,200 @@ protected static async Task<YdbConnection> CreateOpenConnectionAsync()
2529
return connection;
2630
}
2731

32+
private static string CreateIdNameTableSql(string table, string idType = "Int32", bool nameNullable = false) => $"""
33+
CREATE TABLE {table} (
34+
Id {idType},
35+
Name Text{(nameNullable ? "?" : "")},
36+
PRIMARY KEY (Id)
37+
)
38+
""";
39+
40+
private static string CreateAllTypesTableSql(string table) => @$"
41+
CREATE TABLE {table} (
42+
id INT32,
43+
bool_column BOOL,
44+
bigint_column INT64,
45+
smallint_column INT16,
46+
tinyint_column INT8,
47+
float_column FLOAT,
48+
double_column DOUBLE,
49+
decimal_column DECIMAL(22,9),
50+
uint8_column UINT8,
51+
uint16_column UINT16,
52+
uint32_column UINT32,
53+
uint64_column UINT64,
54+
text_column TEXT,
55+
binary_column BYTES,
56+
json_column JSON,
57+
jsondocument_column JSONDOCUMENT,
58+
date_column DATE,
59+
datetime_column DATETIME,
60+
timestamp_column TIMESTAMP,
61+
interval_column INTERVAL,
62+
PRIMARY KEY (id)
63+
)
64+
";
65+
66+
private static async Task UsingTempTableCoreAsync(
67+
YdbConnection conn,
68+
Func<string, string> createSqlFactory,
69+
Func<YdbConnection, string, Task> body,
70+
Func<string, string>? dropSqlFactory = null)
71+
{
72+
var table = $"tmp_{Guid.NewGuid():N}";
73+
74+
await using (var create = conn.CreateCommand())
75+
{
76+
create.CommandText = createSqlFactory(table);
77+
await create.ExecuteNonQueryAsync();
78+
}
79+
80+
try
81+
{
82+
await body(conn, table);
83+
}
84+
finally
85+
{
86+
await using var drop = conn.CreateCommand();
87+
drop.CommandText = (dropSqlFactory ?? (t => $"DROP TABLE {t}"))(table);
88+
try { await drop.ExecuteNonQueryAsync(); } catch { /* ignore */ }
89+
}
90+
}
91+
92+
private static async Task UsingTempTableAsync(
93+
Func<string, string> createSqlFactory,
94+
Func<YdbConnection, string, Task> body,
95+
Func<string, string>? dropSqlFactory = null)
96+
{
97+
await using var conn = await CreateOpenConnectionAsync();
98+
await UsingTempTableCoreAsync(conn, createSqlFactory, body, dropSqlFactory);
99+
}
100+
101+
protected static Task WithIdNameTableAsync(
102+
Func<YdbConnection, string, Task> body,
103+
string idType = "Int32",
104+
bool nameNullable = false) =>
105+
UsingTempTableAsync(t => CreateIdNameTableSql(t, idType, nameNullable), body);
106+
107+
protected static Task WithAllTypesTableAsync(Func<YdbConnection, string, Task> body) =>
108+
UsingTempTableAsync(CreateAllTypesTableSql, body);
109+
110+
private static async Task UsingTempTablesCoreAsync(
111+
YdbConnection conn,
112+
int count,
113+
Func<string[], string[]> createSqlsFactory,
114+
Func<YdbConnection, string[], Task> body,
115+
Func<string[], string[]>? dropSqlsFactory = null)
116+
{
117+
var names = Enumerable.Range(0, count).Select(_ => $"tmp_{Guid.NewGuid():N}").ToArray();
118+
119+
foreach (var sql in createSqlsFactory(names))
120+
{
121+
await using var cmd = conn.CreateCommand();
122+
cmd.CommandText = sql;
123+
await cmd.ExecuteNonQueryAsync();
124+
}
125+
126+
try
127+
{
128+
await body(conn, names);
129+
}
130+
finally
131+
{
132+
var drops = (dropSqlsFactory ?? (ts => ts.Select(t => $"DROP TABLE {t}").ToArray()))(names);
133+
foreach (var sql in drops)
134+
{
135+
await using var cmd = conn.CreateCommand();
136+
cmd.CommandText = sql;
137+
try { await cmd.ExecuteNonQueryAsync(); } catch { /* ignore */ }
138+
}
139+
}
140+
}
141+
142+
private static async Task UsingTempTablesAsync(
143+
int count,
144+
Func<string[], string[]> createSqlsFactory,
145+
Func<YdbConnection, string[], Task> body,
146+
Func<string[], string[]>? dropSqlsFactory = null)
147+
{
148+
await using var conn = await CreateOpenConnectionAsync();
149+
await UsingTempTablesCoreAsync(conn, count, createSqlsFactory, body, dropSqlsFactory);
150+
}
151+
152+
protected static Task WithTwoIdNameTablesAsync(
153+
Func<YdbConnection, string[], Task> body,
154+
string idType = "Int32",
155+
bool nameNullable = false) =>
156+
UsingTempTablesAsync(
157+
2,
158+
tables => tables.Select(t => CreateIdNameTableSql(t, idType, nameNullable)).ToArray(),
159+
body
160+
);
161+
162+
protected static async Task<int> CountAsync(YdbConnection c, string table)
163+
{
164+
await using var cmd = c.CreateCommand();
165+
cmd.CommandText = $"SELECT COUNT(*) FROM {table}";
166+
return Convert.ToInt32(await cmd.ExecuteScalarAsync());
167+
}
168+
169+
protected static async Task<List<string>> ReadNamesAsync(YdbConnection c, string table)
170+
{
171+
var names = new List<string>();
172+
await using var cmd = c.CreateCommand();
173+
cmd.CommandText = $"SELECT Name FROM {table} ORDER BY Id";
174+
await using var r = await cmd.ExecuteReaderAsync();
175+
while (await r.ReadAsync()) names.Add(r.GetString(0));
176+
return names;
177+
}
178+
179+
protected static async Task ImportAsync(YdbConnection c, string table, params object[][] rows)
180+
{
181+
var importer = c.BeginBulkUpsertImport(table, IdNameColumns);
182+
foreach (var row in rows) await importer.AddRowAsync(row);
183+
await importer.FlushAsync();
184+
}
185+
186+
protected static async Task ImportRangeAsync(YdbConnection c, string table, int n, string prefix)
187+
{
188+
var importer = c.BeginBulkUpsertImport(table, IdNameColumns);
189+
foreach (var row in Enumerable.Range(0, n).Select(i => new object[] { i, $"{prefix}{i}" }))
190+
await importer.AddRowAsync(row);
191+
await importer.FlushAsync();
192+
}
193+
194+
protected static void PrepareAllTypesInsert(YdbCommand cmd, string table)
195+
{
196+
cmd.CommandText = @$"
197+
INSERT INTO {table}
198+
(id, bool_column, bigint_column, smallint_column, tinyint_column, float_column, double_column, decimal_column,
199+
uint8_column, uint16_column, uint32_column, uint64_column, text_column, binary_column, json_column,
200+
jsondocument_column, date_column, datetime_column, timestamp_column, interval_column) VALUES
201+
(@name1, @name2, @name3, @name4, @name5, @name6, @name7, @name8, @name9, @name10, @name11, @name12, @name13, @name14,
202+
@name15, @name16, @name17, @name18, @name19, @name20);
203+
";
204+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name1", DbType = DbType.Int32, Value = null });
205+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name2", DbType = DbType.Boolean, Value = null });
206+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name3", DbType = DbType.Int64, Value = null });
207+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name4", DbType = DbType.Int16, Value = null });
208+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name5", DbType = DbType.SByte, Value = null });
209+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name6", DbType = DbType.Single, Value = null });
210+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name7", DbType = DbType.Double, Value = null });
211+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name8", DbType = DbType.Decimal, Value = null });
212+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name9", DbType = DbType.Byte, Value = null });
213+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name10", DbType = DbType.UInt16, Value = null });
214+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name11", DbType = DbType.UInt32, Value = null });
215+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name12", DbType = DbType.UInt64, Value = null });
216+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name13", DbType = DbType.String, Value = null });
217+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name14", DbType = DbType.Binary, Value = null });
218+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name15", YdbDbType = YdbDbType.Json });
219+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name16", YdbDbType = YdbDbType.JsonDocument });
220+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name17", DbType = DbType.Date, Value = null });
221+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name18", DbType = DbType.DateTime, Value = null });
222+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name19", DbType = DbType.DateTime2, Value = null });
223+
cmd.Parameters.Add(new YdbParameter { ParameterName = "name20", YdbDbType = YdbDbType.Interval });
224+
}
225+
28226
public async Task InitializeAsync() => await OnInitializeAsync().ConfigureAwait(false);
29227

30228
public async Task DisposeAsync() => await OnDisposeAsync().ConfigureAwait(false);

0 commit comments

Comments
 (0)