mirror of
https://github.com/collinbarrett/FilterLists.git
synced 2026-03-11 09:04:27 +00:00
refactor(dir): ♻ Change model
This commit is contained in:
parent
c90f1d8d94
commit
83b81a668b
16 changed files with 70 additions and 84 deletions
|
|
@ -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<Response> 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
namespace FilterLists.Directory.Domain.Aggregates;
|
||||
|
||||
public interface IAggregate
|
||||
public abstract class AggregateRoot
|
||||
{
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
namespace FilterLists.Directory.Domain.Aggregates.Changes;
|
||||
|
||||
public enum ChangeType
|
||||
{
|
||||
Create,
|
||||
Update,
|
||||
Delete
|
||||
}
|
||||
|
|
@ -2,34 +2,28 @@
|
|||
|
||||
namespace FilterLists.Directory.Domain.Aggregates.Changes;
|
||||
|
||||
public sealed class FilterListChange : Change, IChangeAggregate<FilterList>
|
||||
public sealed class FilterListChange : Change, IChange<FilterList>
|
||||
{
|
||||
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 };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
namespace FilterLists.Directory.Domain.Aggregates.Changes;
|
||||
|
||||
public interface IChangeAggregate<TAggregate> where TAggregate : IAggregate
|
||||
public interface IChange<TAggregate> where TAggregate : AggregateRoot
|
||||
{
|
||||
TAggregate? Current { get; init; }
|
||||
TAggregate? Before { get; init; }
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
namespace FilterLists.Directory.Domain.Aggregates.Changes;
|
||||
|
||||
public interface IRequireChangeApproval<out TChange> where TChange : Change
|
||||
{
|
||||
public IReadOnlyCollection<TChange> Changes { get; }
|
||||
public IReadOnlyCollection<TChange> PendingChanges => (IReadOnlyCollection<TChange>)Changes.Where(c => c.ApprovedAt == null && c.RejectedAt == null);
|
||||
public IReadOnlyCollection<TChange> ApprovedChanges => (IReadOnlyCollection<TChange>)Changes.Where(c => c.ApprovedAt != null);
|
||||
public IReadOnlyCollection<TChange> RejectedChanges => (IReadOnlyCollection<TChange>)Changes.Where(c => c.RejectedAt != null);
|
||||
public bool IsLegacyApproved => Changes.Count == 0;
|
||||
public bool IsApproved => IsLegacyApproved || ApprovedChanges.Count > 0;
|
||||
}
|
||||
|
|
@ -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<FilterListChange>
|
||||
{
|
||||
private readonly ICollection<FilterListChange> _changes = new HashSet<FilterListChange>();
|
||||
|
||||
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<FilterListViewUrl> ViewUrls { get; init; } = new HashSet<FilterListViewUrl>();
|
||||
public IReadOnlyCollection<FilterListViewUrl> ViewUrls { get; private init; } = new HashSet<FilterListViewUrl>();
|
||||
|
||||
public IReadOnlyCollection<FilterListChange> Changes
|
||||
{
|
||||
get => (IReadOnlyCollection<FilterListChange>)_changes;
|
||||
init => _changes = (ICollection<FilterListChange>)value;
|
||||
}
|
||||
|
||||
public static FilterList Create(
|
||||
string name,
|
||||
|
|
@ -35,11 +44,11 @@ public static FilterList Create(
|
|||
Uri? chatUrl,
|
||||
string? emailAddress,
|
||||
Uri? donateUrl,
|
||||
ICollection<FilterListViewUrl> viewUrls)
|
||||
ICollection<FilterListViewUrl> 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<FilterListViewUrl>)viewUrls,
|
||||
Changes = new HashSet<FilterListChange>(new[] { FilterListChange.Create(createReason) })
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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!;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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<CommandDbContext> options) : base(optio
|
|||
{
|
||||
}
|
||||
|
||||
public DbSet<FilterListChange> FilterListChanges => Set<FilterListChange>();
|
||||
public DbSet<FilterList> FilterLists => Set<FilterList>();
|
||||
public DbSet<License> Licenses => Set<License>();
|
||||
|
||||
|
|
|
|||
|
|
@ -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<FilterListChange> FilterListChanges { get; }
|
||||
DbSet<FilterList> FilterLists { get; }
|
||||
DbSet<License> Licenses { get; }
|
||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
|
||||
|
|
|
|||
|
|
@ -9,5 +9,7 @@ internal class FilterListTypeConfiguration : IEntityTypeConfiguration<FilterList
|
|||
public virtual void Configure(EntityTypeBuilder<FilterList> builder)
|
||||
{
|
||||
builder.Property<int>(nameof(Queries.Entities.FilterList.Id));
|
||||
builder.Navigation(f => f.Changes).AutoInclude();
|
||||
builder.Navigation(f => f.ViewUrls).AutoInclude();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ChangeType>();
|
||||
}
|
||||
|
||||
public QueryDbContext(DbContextOptions<QueryDbContext> 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<ChangeType>();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<QueryDbContext>();
|
||||
await db.Database.MigrateAsync();
|
||||
|
||||
await using var conn = (NpgsqlConnection)db.Database.GetDbConnection();
|
||||
await conn.OpenAsync();
|
||||
conn.ReloadTypes();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue