From 1a71136bef4ca8694edc8b1e031650d57c1a8874 Mon Sep 17 00:00:00 2001 From: adimiko Date: Fri, 9 Feb 2024 18:49:46 +0100 Subject: [PATCH 1/2] Added MySQL --- Directory.Packages.props | 2 + TransactionContext.sln | 14 +++++ source/TransactionContext.MySql/Extensions.cs | 19 +++++++ .../Internals/MySqlConnectionFactory.cs | 14 +++++ .../TransactionContext.MySql.csproj | 17 ++++++ .../MySqlTransactionContextTests.cs | 49 +++++++++++++++++ .../SeedWork/MySqlContainerTest.cs | 53 +++++++++++++++++++ .../TransactionContext.MySql.Tests.csproj | 33 ++++++++++++ 8 files changed, 201 insertions(+) create mode 100644 source/TransactionContext.MySql/Extensions.cs create mode 100644 source/TransactionContext.MySql/Internals/MySqlConnectionFactory.cs create mode 100644 source/TransactionContext.MySql/TransactionContext.MySql.csproj create mode 100644 tests/TransactionContext.MySql.Tests/MySqlTransactionContextTests.cs create mode 100644 tests/TransactionContext.MySql.Tests/SeedWork/MySqlContainerTest.cs create mode 100644 tests/TransactionContext.MySql.Tests/TransactionContext.MySql.Tests.csproj diff --git a/Directory.Packages.props b/Directory.Packages.props index f23bb8d..7287975 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -9,9 +9,11 @@ + + diff --git a/TransactionContext.sln b/TransactionContext.sln index 73fb453..b7c0de1 100644 --- a/TransactionContext.sln +++ b/TransactionContext.sln @@ -21,6 +21,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransactionContext.SqlServe EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransactionContext.SqlServer.Tests", "tests\TransactionContext.SqlServer.Tests\TransactionContext.SqlServer.Tests.csproj", "{6807862B-1C93-4669-9764-E09F3516C021}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransactionContext.MySql", "source\TransactionContext.MySql\TransactionContext.MySql.csproj", "{51BACCCA-9C40-4765-99BB-FC706E289521}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransactionContext.MySql.Tests", "tests\TransactionContext.MySql.Tests\TransactionContext.MySql.Tests.csproj", "{2D129245-CB43-4937-A6AC-6D8F54F4B355}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -55,6 +59,14 @@ Global {6807862B-1C93-4669-9764-E09F3516C021}.Debug|Any CPU.Build.0 = Debug|Any CPU {6807862B-1C93-4669-9764-E09F3516C021}.Release|Any CPU.ActiveCfg = Release|Any CPU {6807862B-1C93-4669-9764-E09F3516C021}.Release|Any CPU.Build.0 = Release|Any CPU + {51BACCCA-9C40-4765-99BB-FC706E289521}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {51BACCCA-9C40-4765-99BB-FC706E289521}.Debug|Any CPU.Build.0 = Debug|Any CPU + {51BACCCA-9C40-4765-99BB-FC706E289521}.Release|Any CPU.ActiveCfg = Release|Any CPU + {51BACCCA-9C40-4765-99BB-FC706E289521}.Release|Any CPU.Build.0 = Release|Any CPU + {2D129245-CB43-4937-A6AC-6D8F54F4B355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2D129245-CB43-4937-A6AC-6D8F54F4B355}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D129245-CB43-4937-A6AC-6D8F54F4B355}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2D129245-CB43-4937-A6AC-6D8F54F4B355}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -67,6 +79,8 @@ Global {8239CE17-8D34-4344-8F67-A071C393F8AD} = {5A6575AC-81E5-4E97-909F-BBE634A2BD14} {1FD6D29F-8D6F-479E-8AAA-6D024F3D6579} = {6004A5FC-0B64-464C-977A-5E721E8567B7} {6807862B-1C93-4669-9764-E09F3516C021} = {5A6575AC-81E5-4E97-909F-BBE634A2BD14} + {51BACCCA-9C40-4765-99BB-FC706E289521} = {6004A5FC-0B64-464C-977A-5E721E8567B7} + {2D129245-CB43-4937-A6AC-6D8F54F4B355} = {5A6575AC-81E5-4E97-909F-BBE634A2BD14} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {48C38B93-C350-4CC9-BCDD-CE256D01DD7E} diff --git a/source/TransactionContext.MySql/Extensions.cs b/source/TransactionContext.MySql/Extensions.cs new file mode 100644 index 0000000..d0d0840 --- /dev/null +++ b/source/TransactionContext.MySql/Extensions.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.DependencyInjection; +using MySqlConnector; +using System.Data.Common; +using TransactionContext.Configurators; +using TransactionContext.MySql.Internals; + +namespace TransactionContext.MySql +{ + public static class Extensions + { + public static void UseMySql( + this IDbProviderConfigurator configurator, + string connectionString) + { + configurator.Services.AddSingleton(new MySqlConnectionFactory(connectionString)); + configurator.Services.AddScoped(); + } + } +} diff --git a/source/TransactionContext.MySql/Internals/MySqlConnectionFactory.cs b/source/TransactionContext.MySql/Internals/MySqlConnectionFactory.cs new file mode 100644 index 0000000..0241d0a --- /dev/null +++ b/source/TransactionContext.MySql/Internals/MySqlConnectionFactory.cs @@ -0,0 +1,14 @@ +using System.Data.Common; +using MySqlConnector; + +namespace TransactionContext.MySql.Internals +{ + internal sealed class MySqlConnectionFactory : IDbConnectionFactory + { + private readonly string _connectionString; + + public MySqlConnectionFactory(string connectionString) => _connectionString = connectionString; + + public DbConnection Create() => new MySqlConnection(_connectionString); + } +} diff --git a/source/TransactionContext.MySql/TransactionContext.MySql.csproj b/source/TransactionContext.MySql/TransactionContext.MySql.csproj new file mode 100644 index 0000000..0c46b9f --- /dev/null +++ b/source/TransactionContext.MySql/TransactionContext.MySql.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + diff --git a/tests/TransactionContext.MySql.Tests/MySqlTransactionContextTests.cs b/tests/TransactionContext.MySql.Tests/MySqlTransactionContextTests.cs new file mode 100644 index 0000000..a003d7b --- /dev/null +++ b/tests/TransactionContext.MySql.Tests/MySqlTransactionContextTests.cs @@ -0,0 +1,49 @@ +using Dapper; +using TransactionContext.MySql.Tests.SeedWork; +using TransactionContext.Tests.SeedWork; +using Xunit; + +namespace TransactionContext.MySql.Tests +{ + public sealed class MySqlTransactionContextTests : MySqlContainerTest + { + [Fact] + public async Task BasicTest() + { + // Arrange + const int numberOfCustomers = 100; + + for (var i = 0; i < numberOfCustomers; i++) + { + var customerId = Guid.NewGuid(); + var orderId = Guid.NewGuid(); + + TransactionContext.Add(CustomerSQL.Insert, new { CustomerId = customerId, Name = $"name{i}" }); + TransactionContext.Add(OrderSQL.Insert, new { OrderId = orderId, CustomerId = customerId }); + + TransactionContext.Add(OrderItemSQL.Insert, new { OrderItemId = Guid.NewGuid(), OrderId = orderId, Name = $"Name{i}", Amount = i + 1 }); + TransactionContext.Add(OrderItemSQL.Insert, new { OrderItemId = Guid.NewGuid(), OrderId = orderId, Name = $"Name{i}", Amount = i + 1 }); + TransactionContext.Add(OrderItemSQL.Insert, new { OrderItemId = Guid.NewGuid(), OrderId = orderId, Name = $"Name{i}", Amount = i + 1 }); + TransactionContext.Add(OrderItemSQL.Insert, new { OrderItemId = Guid.NewGuid(), OrderId = orderId, Name = $"Name{i}", Amount = i + 1 }); + } + + // Act + await TransactionContext.Commit(); + + // Assert + const string selectCustomersSql = "SELECT CustomerId, Name FROM Customers"; + using var connection = DbConnectionFactory.Create(); + var customers = await connection.QueryAsync(selectCustomersSql); + + const string selectOrdersSql = "SELECT OrderId, CustomerId FROM Orders"; + var orders = await connection.QueryAsync(selectOrdersSql); + + const string selectOrderItemssSql = "SELECT OrderItemId, OrderId, Name, Amount FROM OrderItems"; + var orderItems = await connection.QueryAsync(selectOrderItemssSql); + + Assert.Equal(numberOfCustomers, customers.Count()); + Assert.Equal(numberOfCustomers, orders.Count()); + Assert.Equal(4 * numberOfCustomers, orderItems.Count()); + } + } +} diff --git a/tests/TransactionContext.MySql.Tests/SeedWork/MySqlContainerTest.cs b/tests/TransactionContext.MySql.Tests/SeedWork/MySqlContainerTest.cs new file mode 100644 index 0000000..e5f213a --- /dev/null +++ b/tests/TransactionContext.MySql.Tests/SeedWork/MySqlContainerTest.cs @@ -0,0 +1,53 @@ +using Dapper; +using Microsoft.Extensions.DependencyInjection; +using System; +using Testcontainers.MySql; +using Xunit; + +namespace TransactionContext.MySql.Tests.SeedWork +{ + public abstract class MySqlContainerTest : IAsyncLifetime + { + private readonly MySqlContainer _container = new MySqlBuilder().Build(); + + protected ITransactionContext TransactionContext { get; private set; } + + protected IDbConnectionFactory DbConnectionFactory { get; private set; } + + public async Task InitializeAsync() + { + await _container.StartAsync(); + + var connectionString = _container.GetConnectionString(); + + IServiceCollection services = new ServiceCollection(); + + services.AddTransactionContext(x => x.UseMySql(connectionString)); + + var provider = services.BuildServiceProvider(); + + TransactionContext = provider.GetRequiredService(); + DbConnectionFactory = provider.GetRequiredService(); + + await CreateDb(); + } + + public Task DisposeAsync() + { + return _container.DisposeAsync().AsTask(); + } + + private Task CreateDb() + { + const string customerSql = "CREATE TABLE IF NOT EXISTS Customers(CustomerId CHAR(36), Name VARCHAR(100))"; + const string orderSql = "CREATE TABLE IF NOT EXISTS Orders(OrderId CHAR(36), CustomerId CHAR(36))"; + const string orderItemSql = "CREATE TABLE IF NOT EXISTS OrderItems(OrderItemId CHAR(36), OrderId CHAR(36), Name VARCHAR(100), Amount INT)"; + + TransactionContext.Add(customerSql); + TransactionContext.Add(orderSql); + TransactionContext.Add(orderItemSql); + + return TransactionContext.Commit(); + } + } +} diff --git a/tests/TransactionContext.MySql.Tests/TransactionContext.MySql.Tests.csproj b/tests/TransactionContext.MySql.Tests/TransactionContext.MySql.Tests.csproj new file mode 100644 index 0000000..5ea8aa3 --- /dev/null +++ b/tests/TransactionContext.MySql.Tests/TransactionContext.MySql.Tests.csproj @@ -0,0 +1,33 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + From d4ec4fb81c1b5f3b668e93961b74a6e6cda6abc1 Mon Sep 17 00:00:00 2001 From: adimiko Date: Fri, 9 Feb 2024 18:52:55 +0100 Subject: [PATCH 2/2] Updated README --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index bf59445..5bfb73a 100644 --- a/README.md +++ b/README.md @@ -41,3 +41,13 @@ dotnet add package TransactionContext.SqlServer ```csharp services.AddTransactionContext(x => x.UseSqlServer(connectionString)); ``` + +### MySql +#### Add package +```csharp +dotnet add package TransactionContext.MySql +``` +#### Register dependencies +```csharp +services.AddTransactionContext(x => x.UseMySql(connectionString)); +```