From 83b81a668b96d954557d6036f1c11ea5401f27e8 Mon Sep 17 00:00:00 2001 From: "Collin M. Barrett" Date: Mon, 15 Nov 2021 20:19:04 -0600 Subject: [PATCH] =?UTF-8?q?refactor(dir):=20=E2=99=BB=20Change=20model?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Commands/CreateList.cs | 11 +++---- .../{IAggregate.cs => AggregateRoot.cs} | 2 +- .../Aggregates/Changes/Change.cs | 8 ++--- .../Aggregates/Changes/ChangeType.cs | 8 ----- .../Aggregates/Changes/FilterListChange.cs | 16 +++------- ...geAggregate.cs => IChangeAggregateRoot.cs} | 2 +- .../Changes/IRequireChangeApproval.cs | 11 +++++++ .../Aggregates/FilterLists/FilterList.cs | 22 +++++++++---- .../FilterLists/FilterListViewUrl.cs | 10 +++--- .../Aggregates/Licenses/License.cs | 6 ++-- .../Commands/Context/CommandDbContext.cs | 4 +-- .../Commands/Context/ICommandContext.cs | 4 +-- .../FilterListEntityTypeConfiguration.cs | 2 ++ .../Queries/Context/QueryDbContext.cs | 11 +------ .../Persistence/Queries/Entities/Change.cs | 32 +++++++++---------- .../Persistence/SeedExtensions.cs | 5 --- 16 files changed, 70 insertions(+), 84 deletions(-) rename services/Directory/FilterLists.Directory.Domain/Aggregates/{IAggregate.cs => AggregateRoot.cs} (62%) delete mode 100644 services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/ChangeType.cs rename services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/{IChangeAggregate.cs => IChangeAggregateRoot.cs} (70%) create mode 100644 services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/IRequireChangeApproval.cs diff --git a/services/Directory/FilterLists.Directory.Application/Commands/CreateList.cs b/services/Directory/FilterLists.Directory.Application/Commands/CreateList.cs index 66363c45e..5c1594f80 100644 --- a/services/Directory/FilterLists.Directory.Application/Commands/CreateList.cs +++ b/services/Directory/FilterLists.Directory.Application/Commands/CreateList.cs @@ -1,5 +1,4 @@ -using FilterLists.Directory.Domain.Aggregates.Changes; -using FilterLists.Directory.Domain.Aggregates.FilterLists; +using FilterLists.Directory.Domain.Aggregates.FilterLists; using FilterLists.Directory.Infrastructure.Persistence.Commands.Context; using FluentValidation; using MediatR; @@ -63,11 +62,9 @@ public async Task Handle(Command request, CancellationToken cancellati request.ChatUrl, request.EmailAddress, request.DonateUrl, - request.ViewUrls); - //_commandContext.FilterLists.Add(filterList); - - var change = FilterListChange.Create(filterList, request.ChangeReason); - _commandContext.FilterListChanges.Add(change); + request.ViewUrls, + request.ChangeReason); + _commandContext.FilterLists.Add(filterList); await _commandContext.SaveChangesAsync(cancellationToken); diff --git a/services/Directory/FilterLists.Directory.Domain/Aggregates/IAggregate.cs b/services/Directory/FilterLists.Directory.Domain/Aggregates/AggregateRoot.cs similarity index 62% rename from services/Directory/FilterLists.Directory.Domain/Aggregates/IAggregate.cs rename to services/Directory/FilterLists.Directory.Domain/Aggregates/AggregateRoot.cs index 4349329d2..054c0d074 100644 --- a/services/Directory/FilterLists.Directory.Domain/Aggregates/IAggregate.cs +++ b/services/Directory/FilterLists.Directory.Domain/Aggregates/AggregateRoot.cs @@ -1,5 +1,5 @@ namespace FilterLists.Directory.Domain.Aggregates; -public interface IAggregate +public abstract class AggregateRoot { } diff --git a/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/Change.cs b/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/Change.cs index 68a09bbc9..2a2efb1dd 100644 --- a/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/Change.cs +++ b/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/Change.cs @@ -2,15 +2,15 @@ public abstract class Change { - public string? Reason { get; init; } - public DateTime SubmittedAt { get; init; } = DateTime.UtcNow; - public DateTime? AppliedAt { get; private set; } + public string? Reason { get; protected init; } + public DateTime SubmittedAt { get; } = DateTime.UtcNow; + public DateTime? ApprovedAt { get; private set; } public DateTime? RejectedAt { get; private set; } public string? RejectedReason { get; private set; } public void Approve() { - AppliedAt = DateTime.UtcNow; + ApprovedAt = DateTime.UtcNow; } public void Reject(string? reason) diff --git a/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/ChangeType.cs b/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/ChangeType.cs deleted file mode 100644 index 043c5e4de..000000000 --- a/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/ChangeType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace FilterLists.Directory.Domain.Aggregates.Changes; - -public enum ChangeType -{ - Create, - Update, - Delete -} diff --git a/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/FilterListChange.cs b/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/FilterListChange.cs index 6f63d591b..e9f7b7f4c 100644 --- a/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/FilterListChange.cs +++ b/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/FilterListChange.cs @@ -2,34 +2,28 @@ namespace FilterLists.Directory.Domain.Aggregates.Changes; -public sealed class FilterListChange : Change, IChangeAggregate +public sealed class FilterListChange : Change, IChange { private FilterListChange() { } - private FilterListChange(FilterList current, string? reason) - { - Current = current; - Reason = reason; - } - public FilterList? Current { get; init; } public FilterList? Before { get; init; } public FilterList? After { get; init; } - public static FilterListChange Create(FilterList filterList, string? reason) + public static FilterListChange Create(string? reason) { - return new FilterListChange(filterList, reason) { After = filterList }; + return new FilterListChange { Reason = reason }; } public static FilterListChange Update(FilterList before, FilterList after, string? reason) { - return new FilterListChange(before, reason) { Before = before, After = after }; + return new FilterListChange { Before = before, After = after, Reason = reason }; } public static FilterListChange Delete(FilterList filterList, string? reason) { - return new FilterListChange(filterList, reason) { Before = filterList }; + return new FilterListChange { Before = filterList, Reason = reason }; } } diff --git a/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/IChangeAggregate.cs b/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/IChangeAggregateRoot.cs similarity index 70% rename from services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/IChangeAggregate.cs rename to services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/IChangeAggregateRoot.cs index 1f8d0ba2b..922c1d22f 100644 --- a/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/IChangeAggregate.cs +++ b/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/IChangeAggregateRoot.cs @@ -1,6 +1,6 @@ namespace FilterLists.Directory.Domain.Aggregates.Changes; -public interface IChangeAggregate where TAggregate : IAggregate +public interface IChange where TAggregate : AggregateRoot { TAggregate? Current { get; init; } TAggregate? Before { get; init; } diff --git a/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/IRequireChangeApproval.cs b/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/IRequireChangeApproval.cs new file mode 100644 index 000000000..72f553143 --- /dev/null +++ b/services/Directory/FilterLists.Directory.Domain/Aggregates/Changes/IRequireChangeApproval.cs @@ -0,0 +1,11 @@ +namespace FilterLists.Directory.Domain.Aggregates.Changes; + +public interface IRequireChangeApproval where TChange : Change +{ + public IReadOnlyCollection Changes { get; } + public IReadOnlyCollection PendingChanges => (IReadOnlyCollection)Changes.Where(c => c.ApprovedAt == null && c.RejectedAt == null); + public IReadOnlyCollection ApprovedChanges => (IReadOnlyCollection)Changes.Where(c => c.ApprovedAt != null); + public IReadOnlyCollection RejectedChanges => (IReadOnlyCollection)Changes.Where(c => c.RejectedAt != null); + public bool IsLegacyApproved => Changes.Count == 0; + public bool IsApproved => IsLegacyApproved || ApprovedChanges.Count > 0; +} diff --git a/services/Directory/FilterLists.Directory.Domain/Aggregates/FilterLists/FilterList.cs b/services/Directory/FilterLists.Directory.Domain/Aggregates/FilterLists/FilterList.cs index ec3d4d40a..2b4e6f8c5 100644 --- a/services/Directory/FilterLists.Directory.Domain/Aggregates/FilterLists/FilterList.cs +++ b/services/Directory/FilterLists.Directory.Domain/Aggregates/FilterLists/FilterList.cs @@ -1,9 +1,12 @@ -using FilterLists.Directory.Domain.Aggregates.Licenses; +using FilterLists.Directory.Domain.Aggregates.Changes; +using FilterLists.Directory.Domain.Aggregates.Licenses; namespace FilterLists.Directory.Domain.Aggregates.FilterLists; -public class FilterList : IAggregate +public sealed class FilterList : AggregateRoot, IRequireChangeApproval { + private readonly ICollection _changes = new HashSet(); + private FilterList() { } @@ -20,7 +23,13 @@ private FilterList() public Uri? ChatUrl { get; private init; } public string? EmailAddress { get; private init; } public Uri? DonateUrl { get; private init; } - public IEnumerable ViewUrls { get; init; } = new HashSet(); + public IReadOnlyCollection ViewUrls { get; private init; } = new HashSet(); + + public IReadOnlyCollection Changes + { + get => (IReadOnlyCollection)_changes; + init => _changes = (ICollection)value; + } public static FilterList Create( string name, @@ -35,11 +44,11 @@ public static FilterList Create( Uri? chatUrl, string? emailAddress, Uri? donateUrl, - ICollection viewUrls) + ICollection viewUrls, + string? createReason) { if (viewUrls.Count == 0) { - // TODO: create and handle DomainExceptions throw new ArgumentException("At lest one view URL is required.", nameof(viewUrls)); } @@ -57,7 +66,8 @@ public static FilterList Create( ChatUrl = chatUrl, EmailAddress = emailAddress, DonateUrl = donateUrl, - ViewUrls = viewUrls + ViewUrls = (IReadOnlyCollection)viewUrls, + Changes = new HashSet(new[] { FilterListChange.Create(createReason) }) }; } } diff --git a/services/Directory/FilterLists.Directory.Domain/Aggregates/FilterLists/FilterListViewUrl.cs b/services/Directory/FilterLists.Directory.Domain/Aggregates/FilterLists/FilterListViewUrl.cs index fa4a282d5..520a4b3c7 100644 --- a/services/Directory/FilterLists.Directory.Domain/Aggregates/FilterLists/FilterListViewUrl.cs +++ b/services/Directory/FilterLists.Directory.Domain/Aggregates/FilterLists/FilterListViewUrl.cs @@ -1,8 +1,10 @@ namespace FilterLists.Directory.Domain.Aggregates.FilterLists; -public class FilterListViewUrl +public sealed class FilterListViewUrl { - public short SegmentNumber { get; init; } - public short Primariness { get; init; } - public Uri Url { get; init; } = null!; + private FilterListViewUrl() { } + + public short SegmentNumber { get; private init; } + public short Primariness { get; private init; } + public Uri Url { get; private init; } = null!; } diff --git a/services/Directory/FilterLists.Directory.Domain/Aggregates/Licenses/License.cs b/services/Directory/FilterLists.Directory.Domain/Aggregates/Licenses/License.cs index dc138149e..39d60b40c 100644 --- a/services/Directory/FilterLists.Directory.Domain/Aggregates/Licenses/License.cs +++ b/services/Directory/FilterLists.Directory.Domain/Aggregates/Licenses/License.cs @@ -1,10 +1,8 @@ namespace FilterLists.Directory.Domain.Aggregates.Licenses; -public class License +public sealed class License { - private License() - { - } + private License() { } public string Name { get; private init; } = null!; public Uri? Url { get; private init; } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Commands/Context/CommandDbContext.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Commands/Context/CommandDbContext.cs index be4ac429d..391213a6f 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Commands/Context/CommandDbContext.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Commands/Context/CommandDbContext.cs @@ -1,5 +1,4 @@ -using FilterLists.Directory.Domain.Aggregates.Changes; -using FilterLists.Directory.Domain.Aggregates.FilterLists; +using FilterLists.Directory.Domain.Aggregates.FilterLists; using FilterLists.Directory.Domain.Aggregates.Licenses; using FilterLists.Directory.Infrastructure.Persistence.Commands.EntityTypeConfigurations; using Microsoft.EntityFrameworkCore; @@ -12,7 +11,6 @@ public CommandDbContext(DbContextOptions options) : base(optio { } - public DbSet FilterListChanges => Set(); public DbSet FilterLists => Set(); public DbSet Licenses => Set(); diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Commands/Context/ICommandContext.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Commands/Context/ICommandContext.cs index 8f747ba89..07c6cd5fd 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Commands/Context/ICommandContext.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Commands/Context/ICommandContext.cs @@ -1,5 +1,4 @@ -using FilterLists.Directory.Domain.Aggregates.Changes; -using FilterLists.Directory.Domain.Aggregates.FilterLists; +using FilterLists.Directory.Domain.Aggregates.FilterLists; using FilterLists.Directory.Domain.Aggregates.Licenses; using Microsoft.EntityFrameworkCore; @@ -7,7 +6,6 @@ namespace FilterLists.Directory.Infrastructure.Persistence.Commands.Context; public interface ICommandContext { - DbSet FilterListChanges { get; } DbSet FilterLists { get; } DbSet Licenses { get; } Task SaveChangesAsync(CancellationToken cancellationToken); diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Commands/EntityTypeConfigurations/FilterListEntityTypeConfiguration.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Commands/EntityTypeConfigurations/FilterListEntityTypeConfiguration.cs index 6eee05d52..bd4dff375 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Commands/EntityTypeConfigurations/FilterListEntityTypeConfiguration.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Commands/EntityTypeConfigurations/FilterListEntityTypeConfiguration.cs @@ -9,5 +9,7 @@ internal class FilterListTypeConfiguration : IEntityTypeConfiguration builder) { builder.Property(nameof(Queries.Entities.FilterList.Id)); + builder.Navigation(f => f.Changes).AutoInclude(); + builder.Navigation(f => f.ViewUrls).AutoInclude(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/QueryDbContext.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/QueryDbContext.cs index 153f34e81..34de1085f 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/QueryDbContext.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/QueryDbContext.cs @@ -1,18 +1,10 @@ -using FilterLists.Directory.Domain.Aggregates.Changes; -using FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; +using FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; using Microsoft.EntityFrameworkCore; -using Npgsql; -using Change = FilterLists.Directory.Infrastructure.Persistence.Queries.Entities.Change; namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Context; public class QueryDbContext : DbContext { - static QueryDbContext() - { - NpgsqlConnection.GlobalTypeMapper.MapEnum(); - } - public QueryDbContext(DbContextOptions options) : base(options) { } @@ -42,6 +34,5 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly, type => type.Namespace == typeof(FilterListTypeConfiguration).Namespace); - modelBuilder.HasPostgresEnum(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Change.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Change.cs index cb90975a6..05c682f61 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Change.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Change.cs @@ -1,5 +1,4 @@ using System.Text.Json; -using FilterLists.Directory.Domain.Aggregates.Changes; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -7,28 +6,27 @@ namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; public record Change { - public int Id { get; init; } - public ChangeType Type { get; init; } - public JsonDocument? AggregateBefore { get; init; } - public JsonDocument? AggregateAfter { get; init; } - public string? Reason { get; init; } - public DateTime SubmittedAt { get; init; } - public DateTime? AppliedAt { get; init; } - public DateTime? RejectedAt { get; init; } - public string? RejectedReason { get; init; } - public int? FilterListId { get; init; } + public int Id { get; private init; } + public string? Reason { get; private init; } + public DateTime SubmittedAt { get; private init; } + public DateTime? ApprovedAt { get; private init; } + public DateTime? RejectedAt { get; private init; } + public string? RejectedReason { get; private init; } + public JsonDocument? AggregateBefore { get; private init; } + public JsonDocument? AggregateAfter { get; private init; } + public int? FilterListId { get; private init; } public FilterList? FilterList { get; } - public string? LanguageIso6391 { get; init; } + public string? LanguageIso6391 { get; private init; } public Language? Language { get; } - public int? LicenseId { get; init; } + public int? LicenseId { get; private init; } public License? License { get; } - public int? MaintainerId { get; init; } + public int? MaintainerId { get; private init; } public Maintainer? Maintainer { get; } - public int? SoftwareId { get; init; } + public int? SoftwareId { get; private init; } public Software? Software { get; } - public int? SyntaxId { get; init; } + public int? SyntaxId { get; private init; } public Syntax? Syntax { get; } - public int? TagId { get; init; } + public int? TagId { get; private init; } public Tag? Tag { get; } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/SeedExtensions.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/SeedExtensions.cs index b109ad123..472dba893 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/SeedExtensions.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/SeedExtensions.cs @@ -5,7 +5,6 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Npgsql; namespace FilterLists.Directory.Infrastructure.Persistence; @@ -16,10 +15,6 @@ public static async Task MigrateAsync(this IHost host) using var scope = host.Services.CreateScope(); var db = scope.ServiceProvider.GetRequiredService(); await db.Database.MigrateAsync(); - - await using var conn = (NpgsqlConnection)db.Database.GetDbConnection(); - await conn.OpenAsync(); - conn.ReloadTypes(); } }