diff --git a/src/Nox.EntityFramework.SqlServer/SqlServerDatabaseProvider.cs b/src/Nox.EntityFramework.SqlServer/SqlServerDatabaseProvider.cs index 1b2e8cf56d..63b9daf611 100644 --- a/src/Nox.EntityFramework.SqlServer/SqlServerDatabaseProvider.cs +++ b/src/Nox.EntityFramework.SqlServer/SqlServerDatabaseProvider.cs @@ -13,9 +13,11 @@ public class SqlServerDatabaseProvider: NoxDatabaseConfigurator, INoxDatabasePro private static readonly Dictionary TypesConfiguration = new() { - { NoxType.Text, new SqlServerTextDatabaseConfigurator() }, //Use SqlServer Implementation - { NoxType.Number, new NumberDatabaseConfigurator() }, // use default implementation - { NoxType.Money, new MoneyDatabaseConfigurator() } // use default implementation + // Use default implementation for all types + { NoxType.Text, new SqlServerTextDatabaseConfigurator() }, + { NoxType.Number, new NumberDatabaseConfigurator() }, + { NoxType.Money, new MoneyDatabaseConfigurator() }, + { NoxType.CountryCode2, new CountryCode2Configurator() } }; private string _connectionString = string.Empty; diff --git a/src/Nox.EntityFramework.Sqlite/SqliteDatabaseProvider.cs b/src/Nox.EntityFramework.Sqlite/SqliteDatabaseProvider.cs index 56c88eca45..1af66120be 100644 --- a/src/Nox.EntityFramework.Sqlite/SqliteDatabaseProvider.cs +++ b/src/Nox.EntityFramework.Sqlite/SqliteDatabaseProvider.cs @@ -13,7 +13,8 @@ public sealed class SqliteDatabaseProvider : NoxDatabaseConfigurator, INoxDataba // Use default implementation for all types { NoxType.Text, new TextDatabaseConfigurator() }, { NoxType.Number, new NumberDatabaseConfigurator() }, - { NoxType.Money, new MoneyDatabaseConfigurator() } + { NoxType.Money, new MoneyDatabaseConfigurator() }, + { NoxType.CountryCode2, new CountryCode2Configurator() } }; public SqliteDatabaseProvider() : base(TypesConfiguration) diff --git a/src/Nox.Generator/Nox.Generator.csproj b/src/Nox.Generator/Nox.Generator.csproj index fc3ddf9f68..93475ce427 100644 --- a/src/Nox.Generator/Nox.Generator.csproj +++ b/src/Nox.Generator/Nox.Generator.csproj @@ -30,6 +30,7 @@ none false AnyCPU + True @@ -54,19 +55,17 @@ $(GetTargetPathDependsOn);GetDependencyTargetPaths + + True + + - - - - - + + + + + diff --git a/src/Nox.Types.EntityFramework/Exceptions/NoxEntityFrameworkException.cs b/src/Nox.Types.EntityFramework/Exceptions/NoxEntityFrameworkException.cs index 5f2c74fdf8..0855cfe860 100644 --- a/src/Nox.Types.EntityFramework/Exceptions/NoxEntityFrameworkException.cs +++ b/src/Nox.Types.EntityFramework/Exceptions/NoxEntityFrameworkException.cs @@ -1,18 +1,23 @@ +using System.Runtime.Serialization; + namespace Nox.Types.EntityFramework.Exceptions; +[Serializable] public class NoxEntityFrameworkException : Exception { public NoxEntityFrameworkException() { } - public NoxEntityFrameworkException(string message) - : base(message) + public NoxEntityFrameworkException(string message) : base(message) + { + } + + public NoxEntityFrameworkException(string message, Exception inner) : base(message, inner) { } - public NoxEntityFrameworkException(string message, Exception inner) - : base(message, inner) + protected NoxEntityFrameworkException(SerializationInfo info, StreamingContext context) : base(info, context) { } } \ No newline at end of file diff --git a/src/Nox.Types.EntityFramework/Types/CountryCode2/CountryCode2Configurator.cs b/src/Nox.Types.EntityFramework/Types/CountryCode2/CountryCode2Configurator.cs new file mode 100644 index 0000000000..0576fffeba --- /dev/null +++ b/src/Nox.Types.EntityFramework/Types/CountryCode2/CountryCode2Configurator.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Nox.Solution; +using Nox.Types.EntityFramework.Abstractions; + +namespace Nox.Types.EntityFramework.Types; + +public class CountryCode2Configurator : INoxTypeDatabaseConfigurator +{ + public void ConfigureEntityProperty(EntityTypeBuilder builder, NoxSimpleTypeDefinition property, bool isKey) + { + if (isKey) + { + builder.HasKey(property.Name); + } + + builder + .Property(property.Name) + .IsRequired(isKey || property.IsRequired) + .IsUnicode(false) + .IsFixedLength(true) + .HasMaxLength(2) + .HasConversion(); + } +} \ No newline at end of file diff --git a/src/Nox.Types.EntityFramework/Types/Money/MoneyDatabaseConfigurator.cs b/src/Nox.Types.EntityFramework/Types/Money/MoneyDatabaseConfigurator.cs index 08bdd87835..906ebb03d9 100644 --- a/src/Nox.Types.EntityFramework/Types/Money/MoneyDatabaseConfigurator.cs +++ b/src/Nox.Types.EntityFramework/Types/Money/MoneyDatabaseConfigurator.cs @@ -9,7 +9,7 @@ public class MoneyDatabaseConfigurator : INoxTypeDatabaseConfigurator public void ConfigureEntityProperty(EntityTypeBuilder builder, NoxSimpleTypeDefinition property, bool isKey) { - //Todo Default values from static property in the Nox.Type + // TODO: Default values from static property in the Nox.Type var typeOptions = property.MoneyTypeOptions ?? new MoneyTypeOptions(); if (isKey) diff --git a/src/SampleWebApp/SampleWebApp.csproj b/src/SampleWebApp/SampleWebApp.csproj index 1417f416dd..ebeaeb5f94 100644 --- a/src/SampleWebApp/SampleWebApp.csproj +++ b/src/SampleWebApp/SampleWebApp.csproj @@ -13,6 +13,14 @@ Generated + + True + + + + True + + diff --git a/tests/Nox.Generator.Tests/Nox.Generator.Tests.csproj b/tests/Nox.Generator.Tests/Nox.Generator.Tests.csproj index 183863dc18..3733498362 100644 --- a/tests/Nox.Generator.Tests/Nox.Generator.Tests.csproj +++ b/tests/Nox.Generator.Tests/Nox.Generator.Tests.csproj @@ -5,6 +5,14 @@ false + + True + + + + True + + @@ -13,9 +21,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - - @@ -32,7 +37,6 @@ - @@ -43,7 +47,6 @@ - @@ -86,9 +89,6 @@ - - Always - Always diff --git a/tests/Nox.Solution.Tests/Nox.Solution.Tests.csproj b/tests/Nox.Solution.Tests/Nox.Solution.Tests.csproj index 928014b652..f3fb9f32e3 100644 --- a/tests/Nox.Solution.Tests/Nox.Solution.Tests.csproj +++ b/tests/Nox.Solution.Tests/Nox.Solution.Tests.csproj @@ -9,6 +9,14 @@ true + + True + + + + True + + diff --git a/tests/Nox.Generator.Tests/Database/Design/test.solution.nox.yaml b/tests/Nox.Tests/DatabaseIntegrationTests/Design/test.solution.nox.yaml similarity index 98% rename from tests/Nox.Generator.Tests/Database/Design/test.solution.nox.yaml rename to tests/Nox.Tests/DatabaseIntegrationTests/Design/test.solution.nox.yaml index 406937e071..f54fb15b80 100644 --- a/tests/Nox.Generator.Tests/Database/Design/test.solution.nox.yaml +++ b/tests/Nox.Tests/DatabaseIntegrationTests/Design/test.solution.nox.yaml @@ -118,8 +118,8 @@ domain: - name: MoneyTestField type: money - #- name: CountryCode2TestField - # type: countryCode2 + - name: CountryCode2TestField + type: countryCode2 #- name: GeoCoordTestField # type: latLong diff --git a/tests/Nox.Generator.Tests/Database/Models/AuditableEntityBase.cs b/tests/Nox.Tests/DatabaseIntegrationTests/Models/AuditableEntityBase.cs similarity index 100% rename from tests/Nox.Generator.Tests/Database/Models/AuditableEntityBase.cs rename to tests/Nox.Tests/DatabaseIntegrationTests/Models/AuditableEntityBase.cs diff --git a/tests/Nox.Generator.Tests/Database/Models/TestDatabaseWebAppDbContext.g.cs b/tests/Nox.Tests/DatabaseIntegrationTests/Models/TestDatabaseWebAppDbContext.g.cs similarity index 99% rename from tests/Nox.Generator.Tests/Database/Models/TestDatabaseWebAppDbContext.g.cs rename to tests/Nox.Tests/DatabaseIntegrationTests/Models/TestDatabaseWebAppDbContext.g.cs index 9d8c10a7a7..419fc663d0 100644 --- a/tests/Nox.Generator.Tests/Database/Models/TestDatabaseWebAppDbContext.g.cs +++ b/tests/Nox.Tests/DatabaseIntegrationTests/Models/TestDatabaseWebAppDbContext.g.cs @@ -5,7 +5,6 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Nox.Solution; -using System; using Nox.Types.EntityFramework.Abstractions; using TestDatabaseWebApp.Domain; diff --git a/tests/Nox.Generator.Tests/Database/Models/TestEntity.cs b/tests/Nox.Tests/DatabaseIntegrationTests/Models/TestEntity.cs similarity index 84% rename from tests/Nox.Generator.Tests/Database/Models/TestEntity.cs rename to tests/Nox.Tests/DatabaseIntegrationTests/Models/TestEntity.cs index b08f576244..c1f89c19a3 100644 --- a/tests/Nox.Generator.Tests/Database/Models/TestEntity.cs +++ b/tests/Nox.Tests/DatabaseIntegrationTests/Models/TestEntity.cs @@ -33,4 +33,9 @@ public partial class TestEntity : AuditableEntityBase /// (Optional) /// public Money? MoneyTestField { get; set; } = null!; + + /// + /// (Optional) + /// + public CountryCode2? CountryCode2TestField { get; set; } = null!; } diff --git a/tests/Nox.Tests/DatabaseIntegrationTests/SqlServerIntegrationTests.cs b/tests/Nox.Tests/DatabaseIntegrationTests/SqlServerIntegrationTests.cs new file mode 100644 index 0000000000..8695dcde33 --- /dev/null +++ b/tests/Nox.Tests/DatabaseIntegrationTests/SqlServerIntegrationTests.cs @@ -0,0 +1,43 @@ +using FluentAssertions; +using Nox.Types; +using TestDatabaseWebApp.Domain; + +namespace Nox.Tests.DatabaseIntegrationTests; + +public class SqlServerIntegrationTests : SqlServerTestBase +{ + // TODO: uncomment when automated and included into pipeline + //[Fact] + public void GeneratedEntity_SqlServer_CanSaveAndReadFields_AllTypes() + { + var text = "TestTextValue"; + var number = 123; + var money = 10; + var currencyCode = CurrencyCode.UAH; + var countryCode2 = "UA"; + + var newItem = new TestEntity() + { + Id = Text.From(countryCode2), + TextTestField = Text.From(text), + NumberTestField = Number.From(number), + MoneyTestField = Money.From(money, currencyCode), + CountryCode2TestField = CountryCode2.From(countryCode2) + }; + DbContext.TestEntities.Add(newItem); + DbContext.SaveChanges(); + + // Force the recreation of DBContext and ensure we have fresh data from database + RecreateDbContext(); + + var testEntity = DbContext.TestEntities.First(); + + // TODO: make it work without .Value + testEntity.Id.Value.Should().Be(countryCode2); + testEntity.TextTestField.Value.Should().Be(text); + testEntity.NumberTestField.Value.Should().Be(number); + testEntity.MoneyTestField!.Value.Amount.Should().Be(money); + testEntity.MoneyTestField.Value.CurrencyCode.Should().Be(currencyCode); + testEntity.CountryCode2TestField!.Value.Should().Be(countryCode2); + } +} \ No newline at end of file diff --git a/tests/Nox.Tests/DatabaseIntegrationTests/SqlServerTestBase.cs b/tests/Nox.Tests/DatabaseIntegrationTests/SqlServerTestBase.cs new file mode 100644 index 0000000000..51e817b123 --- /dev/null +++ b/tests/Nox.Tests/DatabaseIntegrationTests/SqlServerTestBase.cs @@ -0,0 +1,69 @@ +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore; +using Nox.EntityFramework.SqlServer; +using Nox.Solution; +using TestDatabaseWebApp.Infrastructure.Persistence; + +namespace Nox.Tests.DatabaseIntegrationTests; + +public abstract class SqlServerTestBase : IDisposable +{ + // TODO: currently works in manually set up database in docker + // include database setup into repository (mybae use localdb or express) + private const string _databaseNameTemplate = @"test_database_{0}"; + private const string _databasePassword = @""; + private static string _inMemoryConnectionString = @"Server=localhost;User Id=SA;Password=" + _databasePassword + ";TrustServerCertificate=True;"; + private static string _databaseName = string.Empty; + private const string _testSolutionFile = @"./DatabaseIntegrationTests/Design/test.solution.nox.yaml"; + private readonly SqlConnection _connection; + + protected TestDatabaseWebAppDbContext DbContext; + + protected SqlServerTestBase() + { + _connection = new SqlConnection(_inMemoryConnectionString); + _connection.Open(); + + _databaseName = string.Format(_databaseNameTemplate, DateTime.UtcNow.Ticks); + var databaseCreation = $"CREATE DATABASE {_databaseName}"; + var createDatabaseCommand = new SqlCommand(databaseCreation, _connection); + createDatabaseCommand.ExecuteNonQuery(); + + _connection.Close(); + _connection = new SqlConnection(_inMemoryConnectionString + $"Database={_databaseName};"); + _connection.Open(); + + DbContext = CreateDbContext(_connection); + } + + private static TestDatabaseWebAppDbContext CreateDbContext(SqlConnection connection) + { + var databaseConfigurator = new SqlServerDatabaseProvider(); + var solution = new NoxSolutionBuilder() + .UseYamlFile(_testSolutionFile) + .Build(); + + var options = new DbContextOptionsBuilder() + .UseSqlServer(connection) + .Options; + + var dbContext = new TestDatabaseWebAppDbContext(options, solution, databaseConfigurator); + dbContext.Database.EnsureCreated(); + + return dbContext; + } + + internal void RecreateDbContext() + { + var previousDbContext = DbContext; + DbContext = CreateDbContext(_connection); + previousDbContext.Dispose(); + } + + public void Dispose() + { + GC.SuppressFinalize(this); + DbContext?.Dispose(); + _connection.Dispose(); + } +} \ No newline at end of file diff --git a/tests/Nox.Generator.Tests/Database/SqliteIntegrationTests.cs b/tests/Nox.Tests/DatabaseIntegrationTests/SqliteIntegrationTests.cs similarity index 82% rename from tests/Nox.Generator.Tests/Database/SqliteIntegrationTests.cs rename to tests/Nox.Tests/DatabaseIntegrationTests/SqliteIntegrationTests.cs index ed18665099..e4a3377fc0 100644 --- a/tests/Nox.Generator.Tests/Database/SqliteIntegrationTests.cs +++ b/tests/Nox.Tests/DatabaseIntegrationTests/SqliteIntegrationTests.cs @@ -1,16 +1,13 @@ using FluentAssertions; using Nox.Types; -using System.Linq; -using Nox.Generator.Tests.Database; using TestDatabaseWebApp.Domain; -using Xunit; -namespace Nox.Generator.Test.DatabaseTests; +namespace Nox.Tests.DatabaseIntegrationTests; public class SqliteIntegrationTests : SqliteTestBase { [Fact] - public void GeneratedEntity_CanSaveAndReadFields_AllTypes() + public void GeneratedEntity_Sqlite_CanSaveAndReadFields_AllTypes() { // TODO: // array @@ -48,6 +45,7 @@ public void GeneratedEntity_CanSaveAndReadFields_AllTypes() var number = 123; var money = 10; var currencyCode = CurrencyCode.UAH; + var countryCode2 = "UA"; var newItem = new TestEntity() { @@ -55,6 +53,7 @@ public void GeneratedEntity_CanSaveAndReadFields_AllTypes() TextTestField = Text.From(text), NumberTestField = Number.From(number), MoneyTestField = Money.From(money, currencyCode), + CountryCode2TestField = CountryCode2.From(countryCode2) }; DbContext.TestEntities.Add(newItem); DbContext.SaveChanges(); @@ -68,7 +67,8 @@ public void GeneratedEntity_CanSaveAndReadFields_AllTypes() testEntity.Id.Value.Should().Be(text); testEntity.TextTestField.Value.Should().Be(text); testEntity.NumberTestField.Value.Should().Be(number); - testEntity.MoneyTestField.Value.Amount.Should().Be(money); + testEntity.MoneyTestField!.Value.Amount.Should().Be(money); testEntity.MoneyTestField.Value.CurrencyCode.Should().Be(currencyCode); + testEntity.CountryCode2TestField!.Value.Should().Be(countryCode2); } } \ No newline at end of file diff --git a/tests/Nox.Generator.Tests/Database/SqliteTestBase.cs b/tests/Nox.Tests/DatabaseIntegrationTests/SqliteTestBase.cs similarity index 69% rename from tests/Nox.Generator.Tests/Database/SqliteTestBase.cs rename to tests/Nox.Tests/DatabaseIntegrationTests/SqliteTestBase.cs index ec43301979..0219520e94 100644 --- a/tests/Nox.Generator.Tests/Database/SqliteTestBase.cs +++ b/tests/Nox.Tests/DatabaseIntegrationTests/SqliteTestBase.cs @@ -1,24 +1,28 @@ -using System; -using Microsoft.Data.Sqlite; +using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Nox.EntityFramework.Sqlite; using Nox.Solution; using TestDatabaseWebApp.Infrastructure.Persistence; -namespace Nox.Generator.Tests.Database; +namespace Nox.Tests.DatabaseIntegrationTests; public abstract class SqliteTestBase : IDisposable { - //private const string _inMemoryConnectionStringTemplate = "DataSource=:memory:"; - private const string _inMemoryConnectionStringTemplate = @"DataSource=test_database_{0}.db"; + private const string _inMemoryConnectionStringTemplate = "DataSource=:memory:"; + //private const string _inMemoryConnectionStringTemplate = @"DataSource=test_database_{0}.db"; private static string _inMemoryConnectionString = string.Empty; - private const string _testSolutionFile = @"./Database/Design/test.solution.nox.yaml"; + private const string _relativeTestSolutionFile = @"./DatabaseIntegrationTests/Design/test.solution.nox.yaml"; + private static string _absoluteTestSolutionFile = string.Empty; private readonly SqliteConnection _connection; protected TestDatabaseWebAppDbContext DbContext; protected SqliteTestBase() { + // Save absolute path one time so during re-creation + // path won't change + _absoluteTestSolutionFile = Path.GetFullPath(_relativeTestSolutionFile); + _inMemoryConnectionString = string.Format(_inMemoryConnectionStringTemplate, DateTime.UtcNow.Ticks); _connection = new SqliteConnection(_inMemoryConnectionString); _connection.Open(); @@ -29,7 +33,7 @@ private static TestDatabaseWebAppDbContext CreateDbContext(SqliteConnection conn { var databaseConfigurator = new SqliteDatabaseProvider(); var solution = new NoxSolutionBuilder() - .UseYamlFile(_testSolutionFile) + .UseYamlFile(_absoluteTestSolutionFile) .Build(); var options = new DbContextOptionsBuilder() .UseSqlite(connection) diff --git a/tests/Nox.Tests/Nox.Tests.csproj b/tests/Nox.Tests/Nox.Tests.csproj index b9f23000d1..f8c8eb46c9 100644 --- a/tests/Nox.Tests/Nox.Tests.csproj +++ b/tests/Nox.Tests/Nox.Tests.csproj @@ -1,4 +1,4 @@ - + net7.0 @@ -9,11 +9,33 @@ true + + True + + + + True + + + + + + + + + Always + + + + + + + @@ -26,4 +48,11 @@ + + + + + + + diff --git a/tests/Nox.Tests/ProjectDependencies/CodeAnalysisSolutionFixture.cs b/tests/Nox.Tests/ProjectDependencies/CodeAnalysisSolutionFixture.cs index 3fa00a61fc..4e6d556e50 100644 --- a/tests/Nox.Tests/ProjectDependencies/CodeAnalysisSolutionFixture.cs +++ b/tests/Nox.Tests/ProjectDependencies/CodeAnalysisSolutionFixture.cs @@ -1,7 +1,7 @@ -using System.Reflection; using Microsoft.Build.Locator; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.MSBuild; +using System.Reflection; namespace Nox.Tests.ProjectDependencies; @@ -9,7 +9,7 @@ public class CodeAnalysisSolutionFixture : IAsyncLifetime { private const string SolutionPath = "src/Nox.Generator.sln"; - public Solution Solution { get; private set; } = null!; + public Microsoft.CodeAnalysis.Solution Solution { get; private set; } = null!; public Project NoxTypesProject { get; private set; } = null!; public Project NoxSolutionNet7 { get; private set; } = null!; public Project NoxSolutionNetStd20 { get; private set; } = null!; diff --git a/tests/Nox.Types.Tests/Nox.Types.Tests.csproj b/tests/Nox.Types.Tests/Nox.Types.Tests.csproj index 29af8fb62f..53fb4e1b5f 100644 --- a/tests/Nox.Types.Tests/Nox.Types.Tests.csproj +++ b/tests/Nox.Types.Tests/Nox.Types.Tests.csproj @@ -9,6 +9,14 @@ true + + True + + + + True + +