Skip to content

Commit

Permalink
add database configuration for ReferenceNumber (#1179)
Browse files Browse the repository at this point in the history
* add database configuration for ReferenceNumber

Sqlite does not support this type
SQL Server Support

* remove unused code

* override sequence creation on sqlite

* add postgres tests
  • Loading branch information
rochar authored Nov 28, 2023
1 parent 65f34c4 commit 44ef9a5
Show file tree
Hide file tree
Showing 839 changed files with 1,111 additions and 54,850 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public AppDbContext(
IUserProvider userProvider,
ISystemProvider systemProvider,
NoxCodeGenConventions codeGeneratorState
) : base(publisher, userProvider, systemProvider, options)
) : base(publisher, userProvider, systemProvider, databaseProvider, options)
{
_noxSolution = noxSolution;
_dbProvider = databaseProvider;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ attributes:
maxLength: 63
isRequired: true

- name: ReferenceNumber
description: Workplace Code
type: referenceNumber
referenceNumberTypeOptions:
startsAt: 10
incrementsBy: 5
prefix: "WP-"
suffixCheckSumDigit: true
isRequired: false

- name: Description
description: Workplace Description
type: text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public virtual IReadOnlyDictionary<string, IEnumerable<string>> Validate()
else
result.Add("Name", new [] { "Name is Required." });

if (this.ReferenceNumber is not null)
ExecuteActionAndCollectValidationExceptions("ReferenceNumber", () => DomainNamespace.WorkplaceMetadata.CreateReferenceNumber(this.ReferenceNumber.NonNullValue<System.String>()), result);
if (this.Description is not null)
ExecuteActionAndCollectValidationExceptions("Description", () => DomainNamespace.WorkplaceMetadata.CreateDescription(this.Description.NonNullValue<System.String>()), result);

Expand All @@ -61,6 +63,12 @@ public virtual IReadOnlyDictionary<string, IEnumerable<string>> Validate()
/// <remarks>Required.</remarks>
public System.String Name { get; set; } = default!;

/// <summary>
/// Workplace Code
/// </summary>
/// <remarks>Optional.</remarks>
public System.String? ReferenceNumber { get; set; }

/// <summary>
/// Workplace Description
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public static WorkplaceDto ToDto(this ClientApi.Domain.Workplace entity)
var dto = new WorkplaceDto();
dto.SetIfNotNull(entity?.Id, (dto) => dto.Id = entity!.Id.Value);
dto.SetIfNotNull(entity?.Name, (dto) => dto.Name =entity!.Name!.Value);
dto.SetIfNotNull(entity?.ReferenceNumber, (dto) => dto.ReferenceNumber =entity!.ReferenceNumber!.Value);
dto.SetIfNotNull(entity?.Description, (dto) => dto.Description =entity!.Description!.Value);
dto.SetIfNotNull(entity?.Greeting, (dto) => dto.Greeting =entity!.Greeting!.ToString());
dto.SetIfNotNull(entity?.CountryId, (dto) => dto.CountryId = entity!.CountryId!.Value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ from itemLocalized in joinedData.Where(l => item.Id == l.Id).DefaultIfEmpty()
{
Id = item.Id,
Name = item.Name,
ReferenceNumber = item.ReferenceNumber,
Description = itemLocalized.Description ?? "[" + item.Description + "]",
Greeting = item.Greeting,
CountryId = item.CountryId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ from itemLocalized in joinedData.Where(l => item.Id == l.Id).DefaultIfEmpty()
{
Id = item.Id,
Name = item.Name,
ReferenceNumber = item.ReferenceNumber,
Description = itemLocalized.Description ?? "[" + item.Description + "]",
Greeting = item.Greeting,
CountryId = item.CountryId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ internal abstract partial class WorkplaceBase : EntityBase, IEntityConcurrent
/// <remarks>Required.</remarks>
public Nox.Types.Text Name { get; set; } = null!;

/// <summary>
/// Workplace Code
/// </summary>
/// <remarks>Optional.</remarks>
public Nox.Types.ReferenceNumber? ReferenceNumber { get; set; } = null!;

/// <summary>
/// Workplace Description
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public AppDbContext(
IUserProvider userProvider,
ISystemProvider systemProvider,
NoxCodeGenConventions codeGeneratorState
) : base(publisher, userProvider, systemProvider, options)
) : base(publisher, userProvider, systemProvider, databaseProvider, options)
{
_noxSolution = noxSolution;
_dbProvider = databaseProvider;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,25 @@ public static Nox.Types.Text CreateName(System.String value)
=> Nox.Types.Text.From(value, NameTypeOptions);


/// <summary>
/// Type options for property 'ReferenceNumber'
/// </summary>
public static Nox.Types.ReferenceNumberTypeOptions ReferenceNumberTypeOptions {get; private set;} = new ()
{
StartsAt = 10,
IncrementsBy = 5,
Prefix = "WP-",
SuffixCheckSumDigit = true,
};


/// <summary>
/// Factory for property 'ReferenceNumber'
/// </summary>
public static Nox.Types.ReferenceNumber CreateReferenceNumber(System.String value)
=> Nox.Types.ReferenceNumber.From(value, ReferenceNumberTypeOptions);


/// <summary>
/// Type options for property 'Description'
/// </summary>
Expand Down Expand Up @@ -116,6 +135,15 @@ public static Nox.Types.Nuid CreateTenantId(System.UInt32 value)
.GetAttributeByName("Name")?
.UserInterface;

/// <summary>
/// User Interface for property 'ReferenceNumber'
/// </summary>
public static TypeUserInterface? ReferenceNumberUiOptions(NoxSolution solution)
=> solution.Domain!
.GetEntityByName("Workplace")
.GetAttributeByName("ReferenceNumber")?
.UserInterface;

/// <summary>
/// User Interface for property 'Description'
/// </summary>
Expand Down
6 changes: 3 additions & 3 deletions src/Nox.ClientApi.Tests/Tests/TestDatabaseInstanceService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace ClientApi.Tests;
public class TestDatabaseInstanceService : IAsyncLifetime, ITestDatabaseService
{
#if DEBUG
public static readonly DatabaseServerProvider DbProviderKind = DatabaseServerProvider.SqlServer;
public static readonly DatabaseServerProvider DbProviderKind = DatabaseServerProvider.Postgres;
#else
public static readonly DatabaseServerProvider DbProviderKind = DatabaseServerProvider.SqlServer;
#endif
Expand All @@ -38,8 +38,8 @@ public INoxDatabaseProvider GetDatabaseProvider(
{
return DbProviderKind switch
{
DatabaseServerProvider.Postgres => new PostgreSqlTestProvider("TODO", configurations, noxSolutionCodeGeneratorState, noxClientAssemblyProvider),
DatabaseServerProvider.SqlServer => new MsSqlTestProvider("Data Source=localhost;TrustServerCertificate=true;Initial Catalog=cleintapitests;User ID=sa;password=Developer*123;", configurations, noxSolutionCodeGeneratorState, noxClientAssemblyProvider),
DatabaseServerProvider.Postgres => new PostgreSqlTestProvider("Host=localhost; Database=clientapitests; Username=dev; Password=12345", configurations, noxSolutionCodeGeneratorState, noxClientAssemblyProvider),
DatabaseServerProvider.SqlServer => new MsSqlTestProvider("Data Source=localhost;TrustServerCertificate=true;Initial Catalog=clientapitests;User ID=sa;password=Developer*123;", configurations, noxSolutionCodeGeneratorState, noxClientAssemblyProvider),
_ => throw new NotImplementedException($"{DbProviderKind} is not suported"),
};
}
Expand Down
5 changes: 5 additions & 0 deletions src/Nox.EntityFramework.Postgres/PostgresDatabaseProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,9 @@ public void UnSetStoreTypeFlag(NoxDataStoreTypeFlags storeTypeFlag)
{
StoreTypes &= storeTypeFlag;
}

public string GetSqlStatementForSequenceNextValue(string sequenceName)
{
return $"SELECT nextval('{sequenceName}')";
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

using Nox.Infrastructure;
using Nox.Solution;
using Nox.Types;
Expand Down Expand Up @@ -72,4 +73,9 @@ public void UnSetStoreTypeFlag(NoxDataStoreTypeFlags storeTypeFlag)
{
StoreTypes &= storeTypeFlag;
}

public string GetSqlStatementForSequenceNextValue(string sequenceName)
{
return $"SELECT NEXT VALUE FOR {sequenceName}";
}
}
5 changes: 5 additions & 0 deletions src/Nox.EntityFramework.Sqlite/SqliteDatabaseProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,9 @@ public void UnSetStoreTypeFlag(NoxDataStoreTypeFlags storeTypeFlag)
{
StoreTypes &= storeTypeFlag;
}

public string GetSqlStatementForSequenceNextValue(string sequenceName)
{
throw new NotSupportedException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Microsoft.EntityFrameworkCore;
using Nox.Solution;
using Nox.Types;
using Nox.Types.EntityFramework.Types;

namespace Nox.EntityFramework.Sqlite.Type;

public class SqliteReferenceNumberDatabaseConfigurator : ReferenceNumberDatabaseConfigurator, ISqliteNoxTypeDatabaseConfigurator
{
public override bool IsDefault => false;

protected override void CreateSequence(NoxCodeGenConventions noxSolutionCodeGeneratorState, NoxSimpleTypeDefinition property, Entity entity, ModelBuilder modelBuilder, ReferenceNumberTypeOptions typeOptions)
{
//SQL Lite does not support sequences
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public AppDbContext(
IUserProvider userProvider,
ISystemProvider systemProvider,
NoxCodeGenConventions codeGeneratorState
) : base(publisher, userProvider, systemProvider, options)
) : base(publisher, userProvider, systemProvider, databaseProvider, options)
{
_noxSolution = noxSolution;
_dbProvider = databaseProvider;
Expand Down
31 changes: 25 additions & 6 deletions src/Nox.Lib/Infrastructure/Persistence/EntityDbContextBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System.Reflection.Emit;
using Nox.Types.EntityFramework.Types;
using Nox.Types.EntityFramework.Abstractions;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database;

namespace Nox.Infrastructure.Persistence
{
Expand All @@ -18,18 +20,20 @@ public abstract class EntityDbContextBase : DbContext
protected readonly IPublisher _publisher;
protected readonly IUserProvider _userProvider;
protected readonly ISystemProvider _systemProvider;

protected readonly INoxDatabaseProvider _databaseProvider;

protected EntityDbContextBase(
IPublisher publisher,
IUserProvider userProvider,
ISystemProvider systemProvider,
INoxDatabaseProvider databaseProvider,
DbContextOptions options
) : base(options)
{
_publisher = publisher;
_userProvider = userProvider;
_systemProvider = systemProvider;
_databaseProvider = databaseProvider;
}

public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
Expand All @@ -45,6 +49,23 @@ DbContextOptions options
throw new Nox.Exceptions.ConcurrencyException($"Latest value of {nameof(IEntityConcurrent.Etag)} must be provided", HttpStatusCode.Conflict);
}
}

public virtual async Task<long> GetSequenceNextValueAsync(string sequenceName)
{
var connection = base.Database.GetDbConnection();
try
{
await connection.OpenAsync();
using var cmd = connection.CreateCommand();
cmd.CommandText = _databaseProvider.GetSqlStatementForSequenceNextValue(sequenceName);
var result = await cmd.ExecuteScalarAsync();
return (long)result!;
}
finally
{
await connection.CloseAsync();
}
}
protected virtual async Task HandleDomainEvents()
{
var entriesWithDomainEvents = GetEntriesWithDomainEvents();
Expand All @@ -67,7 +88,6 @@ protected virtual void HandleSystemFields()
TrackConcurrency(entry);
}
}

protected virtual void AuditEntity(EntityEntry<AuditableEntityBase> entry)
{
var user = _userProvider.GetUser();
Expand All @@ -91,7 +111,6 @@ protected virtual void AuditEntity(EntityEntry<AuditableEntityBase> entry)
break;
}
}

private void ReattachOwnedEntries<T>(EntityEntry<AuditableEntityBase> parentEntry)
where T : class
{
Expand Down Expand Up @@ -172,15 +191,15 @@ protected virtual void ClearDomainEvents(List<EntityEntry<IEntityHaveDomainEvent
protected virtual void ConfigureEnumeration(EntityTypeBuilder enumModelBuilder, EnumerationTypeOptions enumTypeOptions)
{
enumModelBuilder.HasKey(nameof(EnumerationBase.Id));

enumModelBuilder
.Property(nameof(EnumerationBase.Id))
.HasConversion<EnumerationConverter>();

enumModelBuilder
.Property(nameof(EnumerationBase.Name))
.IsRequired(true);

foreach (var enumValue in enumTypeOptions.Values)
{
enumModelBuilder.HasData(new { Id = Enumeration.From(enumValue.Id, enumTypeOptions), Name = enumValue.Name });
Expand All @@ -205,7 +224,7 @@ protected virtual void ConfigureEnumerationLocalized(EntityTypeBuilder enumModel
.IsFixedLength(false)
.HasMaxLength(10)
.HasConversion<CultureCodeConverter>();

enumModelBuilder
.HasOne(enumType)
.WithMany()
Expand Down
6 changes: 6 additions & 0 deletions src/Nox.Solution/NoxCodeGenConventions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,10 @@ public NoxCodeGenConventions(NoxSolution noxSolution)
public string GetEntityDtoTypeFullName(string dtoName) => $"{DtoNameSpace}.{dtoName}";

public static string GetForeignKeyPropertyName(Entity entity, EntityRelationship relationship) => $"{entity.GetNavigationPropertyName(relationship)}Id";

/// <summary>
/// Computes the Database Sequence Name to be used by an Entity Attribute
/// </summary>
/// <remarks>lower case so its fully compatible with postgres</remarks>
public string GetDatabaseSequenceName(string entityName, string attributeName) => $"Seq{entityName}{attributeName}".ToLowerInvariant();
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@ public interface INoxDatabaseProvider
string ToTableNameForSqlRaw(string table, string schema);
void SetStoreTypeFlag(NoxDataStoreTypeFlags storeType);
void UnSetStoreTypeFlag(NoxDataStoreTypeFlags storeTypeFlag);

/// <summary>
/// Raw SQL to Select Sequence Next Value
/// </summary>
string GetSqlStatementForSequenceNextValue(string sequenceName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;

namespace Nox.Types.EntityFramework.Types;

public class ReferenceNumberConverter : ValueConverter<ReferenceNumber, string>
{
public ReferenceNumberConverter() : base(referenceNumber => referenceNumber.Value, currentNumber => ReferenceNumber.FromDatabase(currentNumber)) { }
}
Loading

0 comments on commit 44ef9a5

Please sign in to comment.