diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index b82f24f..0b0dcab 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -36,7 +36,7 @@ jobs: - run: dotnet restore - run: dotnet build --no-restore -c Release -p:Version=${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }} - run: dotnet pack --no-build --no-restore --nologo --output=dist -c Release - - run: gh release create "v${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}" --notes-file CHANGELOG.md "dist/FruityFoundation.Base.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" "dist/FruityFoundation.Db.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" "dist/FruityFoundation.FsBase.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" "dist/FruityFoundation.DataAccess.Abstractions.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" "dist/FruityFoundation.DataAccess.Core.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" + - run: gh release create "v${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}" --notes-file CHANGELOG.md "dist/FruityFoundation.Base.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" "dist/FruityFoundation.Db.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" "dist/FruityFoundation.FsBase.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" "dist/FruityFoundation.DataAccess.Abstractions.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" "dist/FruityFoundation.DataAccess.Core.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" "dist/FruityFoundation.DataAccess.Sqlite.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" env: GH_TOKEN: ${{ github.token }} - name: Publish to NuGet @@ -48,3 +48,4 @@ jobs: dotnet nuget push "FruityFoundation.DataAccess.Abstractions.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" --api-key=${{ secrets.NUGET_API_KEY }} --source=https://api.nuget.org/v3/index.json --skip-duplicate dotnet nuget push "FruityFoundation.DataAccess.Abstractions.FSharp.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" --api-key=${{ secrets.NUGET_API_KEY }} --source=https://api.nuget.org/v3/index.json --skip-duplicate dotnet nuget push "FruityFoundation.DataAccess.Core.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" --api-key=${{ secrets.NUGET_API_KEY }} --source=https://api.nuget.org/v3/index.json --skip-duplicate + dotnet nuget push "FruityFoundation.DataAccess.Sqlite.${{ steps.generate-version.outputs.RELEASE_VERSION_NUMBER }}.nupkg" --api-key=${{ secrets.NUGET_API_KEY }} --source=https://api.nuget.org/v3/index.json --skip-duplicate diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..32969e5 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,5 @@ + + + true + + diff --git a/FruityFoundation.DataAccess.Core/DbConnectionFactory.cs b/FruityFoundation.DataAccess.Core/DbConnectionFactory.cs deleted file mode 100644 index 7a9c3fc..0000000 --- a/FruityFoundation.DataAccess.Core/DbConnectionFactory.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Data.Common; -using FruityFoundation.DataAccess.Abstractions; -using Microsoft.Extensions.DependencyInjection; - -namespace FruityFoundation.DataAccess.Core; - -public class DbConnectionFactory : IDbConnectionFactory -{ - private readonly IServiceProvider _serviceProvider; - - public DbConnectionFactory(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - - public INonTransactionalDbConnection CreateConnection() - { - var nonTxConnection = _serviceProvider.GetRequiredService>(); - return nonTxConnection; - } - - public INonTransactionalDbConnection CreateReadOnlyConnection() - { - var nonTxConnection = _serviceProvider.GetRequiredService>(); - return nonTxConnection; - } -} diff --git a/FruityFoundation.DataAccess.Core/FruityFoundation.DataAccess.Core.csproj b/FruityFoundation.DataAccess.Core/FruityFoundation.DataAccess.Core.csproj index 30a0b16..8902fb2 100644 --- a/FruityFoundation.DataAccess.Core/FruityFoundation.DataAccess.Core.csproj +++ b/FruityFoundation.DataAccess.Core/FruityFoundation.DataAccess.Core.csproj @@ -22,7 +22,6 @@ - diff --git a/FruityFoundation.DataAccess.Core/ServiceCollectionExtensions.cs b/FruityFoundation.DataAccess.Core/ServiceCollectionExtensions.cs deleted file mode 100644 index dfa19c1..0000000 --- a/FruityFoundation.DataAccess.Core/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using FruityFoundation.DataAccess.Abstractions; -using Microsoft.Extensions.DependencyInjection; - -namespace FruityFoundation.DataAccess.Core; - -[ExcludeFromCodeCoverage(Justification = "Dependency injection helpers")] -public static class ServiceCollectionExtensions -{ - public static void AddDataAccessCore( - this IServiceCollection services, - Func> readWriteConnectionImplementationFactory, - Func> readOnlyConnectionImplementationFactory - ) - { - services.AddTransient>(readWriteConnectionImplementationFactory); - services.AddTransient>(readOnlyConnectionImplementationFactory); - services.AddSingleton(); - } -} diff --git a/FruityFoundation.DataAccess.Sqlite/FruityFoundation.DataAccess.Sqlite.csproj b/FruityFoundation.DataAccess.Sqlite/FruityFoundation.DataAccess.Sqlite.csproj new file mode 100644 index 0000000..4c61bb6 --- /dev/null +++ b/FruityFoundation.DataAccess.Sqlite/FruityFoundation.DataAccess.Sqlite.csproj @@ -0,0 +1,29 @@ + + + + enable + enable + true + Kyle Ratti + https://github.com/kyleratti/FruityFoundation + 1.12.2 + true + LICENSE + net8.0;net6.0 + + + + + + + + + + + + + + + + + diff --git a/FruityFoundation.DataAccess.Sqlite/ServiceCollectionExtensions.cs b/FruityFoundation.DataAccess.Sqlite/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..8bc3ca3 --- /dev/null +++ b/FruityFoundation.DataAccess.Sqlite/ServiceCollectionExtensions.cs @@ -0,0 +1,36 @@ +using System.Diagnostics.CodeAnalysis; +using FruityFoundation.DataAccess.Abstractions; +using Microsoft.Extensions.DependencyInjection; + +namespace FruityFoundation.DataAccess.Sqlite; + +[ExcludeFromCodeCoverage(Justification = "Dependency injection helpers")] +public static class ServiceCollectionExtensions +{ + public static void AddSqliteDataAccess( + this IServiceCollection services, + Func getReadWriteConnectionString, + Func getReadOnlyConnectionString + ) + { + services.AddScoped>(serviceProvider => + { + var connectionFactory = serviceProvider.GetRequiredService(); + + return connectionFactory.CreateConnection(); + }); + + services.AddScoped>(serviceProvider => + { + var connectionFactory = serviceProvider.GetRequiredService(); + + return connectionFactory.CreateReadOnlyConnection(); + }); + + services.AddSingleton(serviceProvider => + new SqliteDbConnectionFactory( + serviceProvider, + getReadOnlyConnectionString: getReadOnlyConnectionString, + getReadWriteConnectionString: getReadWriteConnectionString)); + } +} diff --git a/FruityFoundation.DataAccess.Sqlite/SqliteDbConnectionFactory.cs b/FruityFoundation.DataAccess.Sqlite/SqliteDbConnectionFactory.cs new file mode 100644 index 0000000..9cb7150 --- /dev/null +++ b/FruityFoundation.DataAccess.Sqlite/SqliteDbConnectionFactory.cs @@ -0,0 +1,40 @@ +using FruityFoundation.DataAccess.Abstractions; +using FruityFoundation.DataAccess.Core; +using Microsoft.Data.Sqlite; + +namespace FruityFoundation.DataAccess.Sqlite; + +public class SqliteDbConnectionFactory : IDbConnectionFactory +{ + private readonly IServiceProvider _serviceProvider; + private readonly Func _getReadWriteConnectionString; + private readonly Func _getReadOnlyConnectionString; + + public SqliteDbConnectionFactory( + IServiceProvider serviceProvider, + Func getReadWriteConnectionString, + Func getReadOnlyConnectionString) + { + _serviceProvider = serviceProvider; + _getReadWriteConnectionString = getReadWriteConnectionString; + _getReadOnlyConnectionString = getReadOnlyConnectionString; + } + + /// + public INonTransactionalDbConnection CreateConnection() + { + var connectionString = _getReadWriteConnectionString(_serviceProvider); + var connection = new SqliteConnection(connectionString); + + return new NonTransactionalDbConnection(connection); + } + + /// + public INonTransactionalDbConnection CreateReadOnlyConnection() + { + var connectionString = _getReadOnlyConnectionString(_serviceProvider); + var connection = new SqliteConnection(connectionString); + + return new NonTransactionalDbConnection(connection); + } +} diff --git a/FruityFoundation.Tests.DataAccess.Abstractions.FSharp/FruityFoundation.Tests.DataAccess.Abstractions.FSharp.fsproj b/FruityFoundation.Tests.DataAccess.Abstractions.FSharp/FruityFoundation.Tests.DataAccess.Abstractions.FSharp.fsproj index 7c3288d..7a91cfc 100644 --- a/FruityFoundation.Tests.DataAccess.Abstractions.FSharp/FruityFoundation.Tests.DataAccess.Abstractions.FSharp.fsproj +++ b/FruityFoundation.Tests.DataAccess.Abstractions.FSharp/FruityFoundation.Tests.DataAccess.Abstractions.FSharp.fsproj @@ -26,6 +26,7 @@ + diff --git a/FruityFoundation.Tests.DataAccess.Sqlite/FruityFoundation.Tests.DataAccess.Sqlite.csproj b/FruityFoundation.Tests.DataAccess.Sqlite/FruityFoundation.Tests.DataAccess.Sqlite.csproj new file mode 100644 index 0000000..4054c9f --- /dev/null +++ b/FruityFoundation.Tests.DataAccess.Sqlite/FruityFoundation.Tests.DataAccess.Sqlite.csproj @@ -0,0 +1,29 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + diff --git a/FruityFoundation.Tests.DataAccess.Sqlite/SqliteDbConnectionFactoryTests.cs b/FruityFoundation.Tests.DataAccess.Sqlite/SqliteDbConnectionFactoryTests.cs new file mode 100644 index 0000000..ead2e49 --- /dev/null +++ b/FruityFoundation.Tests.DataAccess.Sqlite/SqliteDbConnectionFactoryTests.cs @@ -0,0 +1,39 @@ +using FruityFoundation.DataAccess.Abstractions; +using FruityFoundation.DataAccess.Sqlite; + +namespace FruityFoundation.Tests.DataAccess.Sqlite; + +public class SqliteDbConnectionFactoryTests +{ + [Test] + public void CreateConnection_WithValidConnectionString_ReturnsNonTransactionalDbConnection_ReadWrite() + { + // Arrange + var connectionFactory = new SqliteDbConnectionFactory( + serviceProvider: null!, + getReadWriteConnectionString: _ => "Data Source=:memory:", + getReadOnlyConnectionString: null!); + + // Act + var result = connectionFactory.CreateConnection(); + + // Assert + Assert.That(result, Is.InstanceOf>()); + } + + [Test] + public void CreateReadOnlyConnection_WithValidConnectionString_ReturnsNonTransactionalDbConnection_ReadOnly() + { + // Arrange + var connectionFactory = new SqliteDbConnectionFactory( + serviceProvider: null!, + getReadWriteConnectionString: null!, + getReadOnlyConnectionString: _ => "Data Source=:memory:"); + + // Act + var result = connectionFactory.CreateReadOnlyConnection(); + + // Assert + Assert.That(result, Is.InstanceOf>()); + } +} diff --git a/FruityFoundation.Tests.FsBase/FruityFoundation.Tests.FsBase.fsproj b/FruityFoundation.Tests.FsBase/FruityFoundation.Tests.FsBase.fsproj index 1e2d1e4..d5fc0b6 100644 --- a/FruityFoundation.Tests.FsBase/FruityFoundation.Tests.FsBase.fsproj +++ b/FruityFoundation.Tests.FsBase/FruityFoundation.Tests.FsBase.fsproj @@ -30,6 +30,7 @@ + diff --git a/FruityFoundation.Tests.FsBaseInterop/FruityFoundation.Tests.FsBaseInterop.csproj b/FruityFoundation.Tests.FsBaseInterop/FruityFoundation.Tests.FsBaseInterop.csproj index fe56c82..f77053d 100644 --- a/FruityFoundation.Tests.FsBaseInterop/FruityFoundation.Tests.FsBaseInterop.csproj +++ b/FruityFoundation.Tests.FsBaseInterop/FruityFoundation.Tests.FsBaseInterop.csproj @@ -28,6 +28,7 @@ + diff --git a/FruityFoundation.sln b/FruityFoundation.sln index 3130355..ac16973 100644 --- a/FruityFoundation.sln +++ b/FruityFoundation.sln @@ -24,6 +24,10 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FruityFoundation.DataAccess EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FruityFoundation.Tests.DataAccess.Abstractions.FSharp", "FruityFoundation.Tests.DataAccess.Abstractions.FSharp\FruityFoundation.Tests.DataAccess.Abstractions.FSharp.fsproj", "{27F4FB64-7A51-4315-BDAA-6EE07736C976}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FruityFoundation.DataAccess.Sqlite", "FruityFoundation.DataAccess.Sqlite\FruityFoundation.DataAccess.Sqlite.csproj", "{2DB2E605-68E8-47E3-A183-985C1A52B56A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FruityFoundation.Tests.DataAccess.Sqlite", "FruityFoundation.Tests.DataAccess.Sqlite\FruityFoundation.Tests.DataAccess.Sqlite.csproj", "{A1AB7658-7310-490A-82BE-DAABCC204EA4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -70,6 +74,14 @@ Global {27F4FB64-7A51-4315-BDAA-6EE07736C976}.Debug|Any CPU.Build.0 = Debug|Any CPU {27F4FB64-7A51-4315-BDAA-6EE07736C976}.Release|Any CPU.ActiveCfg = Release|Any CPU {27F4FB64-7A51-4315-BDAA-6EE07736C976}.Release|Any CPU.Build.0 = Release|Any CPU + {2DB2E605-68E8-47E3-A183-985C1A52B56A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2DB2E605-68E8-47E3-A183-985C1A52B56A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2DB2E605-68E8-47E3-A183-985C1A52B56A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2DB2E605-68E8-47E3-A183-985C1A52B56A}.Release|Any CPU.Build.0 = Release|Any CPU + {A1AB7658-7310-490A-82BE-DAABCC204EA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1AB7658-7310-490A-82BE-DAABCC204EA4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1AB7658-7310-490A-82BE-DAABCC204EA4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1AB7658-7310-490A-82BE-DAABCC204EA4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {50A75644-A1C3-4495-9DEB-DBB12D9334B5} = {B44178DF-5B81-4029-90FA-2BF8E2A1EDBF} @@ -79,5 +91,7 @@ Global {B65527CC-218A-4EA3-93DC-985713B5DFF4} = {5C3A014A-7931-4A36-95F0-5EFE15AB06A3} {B2E0156B-B631-4C80-A129-59472D2D0A77} = {5C3A014A-7931-4A36-95F0-5EFE15AB06A3} {27F4FB64-7A51-4315-BDAA-6EE07736C976} = {B44178DF-5B81-4029-90FA-2BF8E2A1EDBF} + {2DB2E605-68E8-47E3-A183-985C1A52B56A} = {5C3A014A-7931-4A36-95F0-5EFE15AB06A3} + {A1AB7658-7310-490A-82BE-DAABCC204EA4} = {B44178DF-5B81-4029-90FA-2BF8E2A1EDBF} EndGlobalSection EndGlobal