Skip to content

Commit

Permalink
dev: DapperIntegrationTests.cs (#184)
Browse files Browse the repository at this point in the history
  • Loading branch information
KirillKurdyukov committed Sep 11, 2024
1 parent 314a874 commit af7938c
Show file tree
Hide file tree
Showing 5 changed files with 233 additions and 21 deletions.
35 changes: 16 additions & 19 deletions examples/src/DapperExample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,25 @@
using Dapper;
using Ydb.Sdk.Ado;

// TODO SQL Parser @Id -> $Id

// Init Users table
await new YdbConnection().ExecuteAsync("""
CREATE TABLE Users(
Id Int32,
Name Text,
Email Text,
PRIMARY KEY (Id)
);
""");

await new YdbConnection().ExecuteAsync("INSERT INTO Users(Id, Name, Email) VALUES ($Id, $Name, $Email)",
new Dictionary<string, object> { { "$Id", 1 }, { "$Name", "Name" }, { "$Email", "Email" } });

Console.WriteLine(await new YdbConnection().QuerySingleAsync<User>("SELECT * FROM Users WHERE Id = $Id",
new Dictionary<string, object> { { "$Id", 1 } }));

Console.WriteLine(await new YdbConnection().QuerySingleAsync<User>("SELECT * FROM Users WHERE Id = $Id",
await using var connection = await new YdbDataSource().OpenConnectionAsync();

await connection.ExecuteAsync("""
CREATE TABLE Users(
Id Int32,
Name Text,
Email Text,
PRIMARY KEY (Id)
);
""");

await connection.ExecuteAsync("INSERT INTO Users(Id, Name, Email) VALUES ($Id, $Name, $Email)",
new User { Id = 1, Name = "Name", Email = "Email" });

Console.WriteLine(await connection.QuerySingleAsync<User>("SELECT * FROM Users WHERE Id = $Id",
new { Id = 1 }));

await new YdbConnection().ExecuteAsync("DROP TABLE Users");
await connection.ExecuteAsync("DROP TABLE Users");

internal class User
{
Expand Down
4 changes: 3 additions & 1 deletion src/Ydb.Sdk/src/Ado/YdbCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,13 @@ protected override YdbDataReader ExecuteDbDataReader(CommandBehavior behavior)
protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior behavior,
CancellationToken cancellationToken)
{
if (YdbConnection.LastReader is { IsClosed: false })
if (YdbConnection.IsBusy)
{
throw new YdbOperationInProgressException(YdbConnection);
}

YdbConnection.EnsureConnectionOpen();

var ydbParameters = DbParameterCollection.YdbParameters;
var (sql, paramNames) = SqlParser.Parse(CommandText);
var preparedSql = new StringBuilder();
Expand Down
2 changes: 1 addition & 1 deletion src/Ydb.Sdk/src/Ado/YdbConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ protected override YdbCommand CreateDbCommand()
return CreateDbCommand();
}

private void EnsureConnectionOpen()
internal void EnsureConnectionOpen()
{
if (ConnectionState == ConnectionState.Closed)
{
Expand Down
212 changes: 212 additions & 0 deletions src/Ydb.Sdk/tests/Dapper/DapperIntegrationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;
using Dapper;
using Xunit;
using Ydb.Sdk.Ado;

namespace Ydb.Sdk.Tests.Dapper;

public class DapperIntegrationTests
{
private static readonly TemporaryTables<DapperIntegrationTests> Tables = new();

[Fact]
public async Task DapperYqlTutorialTests()
{
SqlMapper.SetTypeMap(
typeof(Episode),
new CustomPropertyTypeMap(
typeof(Episode),
(type, columnName) =>
type.GetProperties().FirstOrDefault(prop =>
prop.GetCustomAttributes(false)
.OfType<ColumnAttribute>()
.Any(attr => attr.Name == columnName)) ?? throw new InvalidOperationException()));

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

await connection.ExecuteAsync(Tables.CreateTables); // create tables
await connection.ExecuteAsync(Tables.UpsertData); // adding data to table

var selectedEpisodes = (await connection.QueryAsync<Episode>($@"
SELECT
series_id,
season_id,
episode_id,
title,
air_date
FROM {Tables.Episodes}
WHERE
series_id = @series_id -- List of conditions to build the result
AND season_id > @season_id -- Logical AND is used for complex conditions
ORDER BY -- Sorting the results.
series_id, -- ORDER BY sorts the values by one or multiple
season_id, -- columns. Columns are separated by commas.
episode_id
LIMIT 3 -- LIMIT N after ORDER BY means
-- ""get top N"" or ""get bottom N"" results,
; -- depending on sort order.
", new { series_id = 1, season_id = 1 })).ToArray();

Assert.Equal(
new[]
{
new Episode
{
SeriesId = 1, SeasonId = 2, EpisodeId = 1, Title = "The Work Outing",
AirDate = new DateTime(2006, 8, 24)
},
new Episode
{
SeriesId = 1, SeasonId = 2, EpisodeId = 2, Title = "Return of the Golden Child",
AirDate = new DateTime(2007, 8, 31)
},
new Episode
{
SeriesId = 1, SeasonId = 2, EpisodeId = 3, Title = "Moss and the German",
AirDate = new DateTime(2007, 9, 7)
}
}, selectedEpisodes);


var selectedTitlesSeasonAndSeries = (await connection.QueryAsync<dynamic>($@"
SELECT
sa.title AS season_title, -- sa and sr are ""join names"",
sr.title AS series_title, -- table aliases declared below using AS.
sr.series_id, -- They are used to avoid
sa.season_id -- ambiguity in the column names used.
FROM
{Tables.Seasons} AS sa
INNER JOIN
{Tables.Series} AS sr
ON sa.series_id = sr.series_id
WHERE sa.series_id = @series_id
ORDER BY -- Sorting of the results.
sr.series_id,
sa.season_id -- ORDER BY sorts the values by one column
; -- or multiple columns.
-- Columns are separated by commas.", new { series_id = 1 })).ToArray();

for (var i = 0; i < selectedTitlesSeasonAndSeries.Length; i++)
{
Assert.Equal("IT Crowd", selectedTitlesSeasonAndSeries[i].series_title);
Assert.Equal("Season " + (i + 1), selectedTitlesSeasonAndSeries[i].season_title);
}

var transaction = connection.BeginTransaction();
var episode1 = new Episode
{ SeriesId = 2, SeasonId = 5, EpisodeId = 13, Title = "Test Episode", AirDate = new DateTime(2018, 8, 27) };
var episode2 = new Episode
{
SeriesId = 2, SeasonId = 5, EpisodeId = 12, Title = "Test Episode !!!", AirDate = new DateTime(2018, 8, 27)
};

var parameters1 = new DynamicParameters();
parameters1.Add("series_id", episode1.SeriesId, DbType.UInt64);
parameters1.Add("season_id", episode1.SeasonId, DbType.UInt64);
parameters1.Add("episode_id", episode1.EpisodeId, DbType.UInt64);
parameters1.Add("title", episode1.Title, DbType.String);
parameters1.Add("air_date", episode1.AirDate, DbType.Date);

await connection.ExecuteAsync($@"
UPSERT INTO {Tables.Episodes}
(
series_id,
season_id,
episode_id,
title,
air_date
)
VALUES
(
@series_id,
@season_id,
@episode_id,
@title,
@air_date
);
;", parameters1, transaction);
await using (var otherConn = new YdbConnection())
{
await otherConn.OpenAsync();

Assert.Null(await otherConn.QuerySingleOrDefaultAsync(
$"SELECT * FROM {Tables.Episodes} WHERE series_id = @p1 AND season_id = @p2 AND episode_id = @p3",
new { p1 = episode1.SeriesId, p2 = episode1.SeasonId, p3 = episode1.EpisodeId }));
}

var parameters2 = new DynamicParameters();
parameters2.Add("series_id", episode2.SeriesId, DbType.UInt64);
parameters2.Add("season_id", episode2.SeasonId, DbType.UInt64);
parameters2.Add("episode_id", episode2.EpisodeId, DbType.UInt64);
parameters2.Add("title", episode2.Title, DbType.String);
parameters2.Add("air_date", episode2.AirDate, DbType.Date);

await connection.ExecuteAsync($@"
UPSERT INTO {Tables.Episodes}
(
series_id,
season_id,
episode_id,
title,
air_date
)
VALUES
(
@series_id,
@season_id,
@episode_id,
@title,
@air_date
);
;", parameters2, transaction);
await transaction.CommitAsync();

var rollbackTransaction = connection.BeginTransaction();
await connection.ExecuteAsync($@"
INSERT INTO {Tables.Episodes}
(
series_id,
season_id,
episode_id,
title,
air_date
)
VALUES
(
2,
5,
21,
""Test 21"",
Date(""2018-08-27"")
), -- Rows are separated by commas.
(
2,
5,
22,
""Test 22"",
Date(""2018-08-27"")
)
;
;", transaction: rollbackTransaction);
await rollbackTransaction.RollbackAsync();

Assert.Equal((ulong)72, await connection.ExecuteScalarAsync<ulong>($"SELECT COUNT(*) FROM {Tables.Episodes}"));

await connection.ExecuteAsync(Tables.DeleteTables);
}

private record Episode
{
[Column("series_id")] public uint SeriesId { get; set; }
[Column("season_id")] public uint SeasonId { get; set; }
[Column("episode_id")] public uint EpisodeId { get; set; }
[Column("title")] public string Title { get; set; } = null!;
[Column("air_date")] public DateTime AirDate { get; set; }
}
}
1 change: 1 addition & 0 deletions src/Ydb.Sdk/tests/Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Dapper" Version="2.1.35" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0-rc.1.23419.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="Moq" Version="4.20.70" />
Expand Down

0 comments on commit af7938c

Please sign in to comment.