Skip to content

Commit

Permalink
Implemented field type replacement & update. (#33)
Browse files Browse the repository at this point in the history
* Implemented field type replacement.

* Controller.

* Implemented field type update.

* Replace with delta.
  • Loading branch information
Utar94 authored Jul 22, 2024
1 parent 223f091 commit 6370449
Show file tree
Hide file tree
Showing 30 changed files with 910 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Logitar.Cms.Contracts.FieldTypes.Properties;

namespace Logitar.Cms.Contracts.FieldTypes;

public record ReplaceFieldTypePayload
{
public string UniqueName { get; set; }
public string? DisplayName { get; set; }
public string? Description { get; set; }

public BooleanProperties? BooleanProperties { get; set; }
public DateTimeProperties? DateTimeProperties { get; set; }
public NumberProperties? NumberProperties { get; set; }
public StringProperties? StringProperties { get; set; }
public TextProperties? TextProperties { get; set; }

public ReplaceFieldTypePayload() : this(string.Empty)
{
}

public ReplaceFieldTypePayload(string uniqueName)
{
UniqueName = uniqueName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Logitar.Cms.Contracts.FieldTypes.Properties;

namespace Logitar.Cms.Contracts.FieldTypes;

public record UpdateFieldTypePayload
{
public string? UniqueName { get; set; }
public Change<string>? DisplayName { get; set; }
public Change<string>? Description { get; set; }

public BooleanProperties? BooleanProperties { get; set; }
public DateTimeProperties? DateTimeProperties { get; set; }
public NumberProperties? NumberProperties { get; set; }
public StringProperties? StringProperties { get; set; }
public TextProperties? TextProperties { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using Logitar.Cms.Contracts.FieldTypes;
using MediatR;

namespace Logitar.Cms.Core.FieldTypes.Commands;

public record ReplaceFieldTypeCommand(Guid Id, ReplaceFieldTypePayload Payload, long? Version) : Activity, IRequest<FieldType?>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using FluentValidation;
using Logitar.Cms.Contracts.FieldTypes;
using Logitar.Cms.Core.FieldTypes.Properties;
using Logitar.Cms.Core.FieldTypes.Validators;
using Logitar.Identity.Contracts.Settings;
using Logitar.Identity.Domain.Shared;
using MediatR;

namespace Logitar.Cms.Core.FieldTypes.Commands;

internal class ReplaceFieldTypeCommandHandler : IRequestHandler<ReplaceFieldTypeCommand, FieldType?>
{
private readonly IFieldTypeQuerier _fieldTypeQuerier;
private readonly IFieldTypeRepository _fieldTypeRepository;
private readonly ISender _sender;

public ReplaceFieldTypeCommandHandler(IFieldTypeQuerier fieldTypeQuerier, IFieldTypeRepository fieldTypeRepository, ISender sender)
{
_fieldTypeQuerier = fieldTypeQuerier;
_fieldTypeRepository = fieldTypeRepository;
_sender = sender;
}

public async Task<FieldType?> Handle(ReplaceFieldTypeCommand command, CancellationToken cancellationToken)
{
FieldTypeId id = new(command.Id);
FieldTypeAggregate? fieldType = await _fieldTypeRepository.LoadAsync(id, cancellationToken);
if (fieldType == null)
{
return null;
}

IUniqueNameSettings uniqueNameSettings = FieldTypeAggregate.UniqueNameSettings;

ReplaceFieldTypePayload payload = command.Payload;
new ReplaceFieldTypeValidator(uniqueNameSettings, fieldType.DataType).ValidateAndThrow(payload);

FieldTypeAggregate? reference = null;
if (command.Version.HasValue)
{
reference = await _fieldTypeRepository.LoadAsync(id, command.Version.Value, cancellationToken);
}

UniqueNameUnit uniqueName = new(uniqueNameSettings, payload.UniqueName);
DisplayNameUnit? displayName = DisplayNameUnit.TryCreate(payload.DisplayName);
DescriptionUnit? description = DescriptionUnit.TryCreate(payload.Description);
if (reference == null || uniqueName != reference.UniqueName)
{
fieldType.UniqueName = uniqueName;
}
if (reference == null || displayName != reference.DisplayName)
{
fieldType.DisplayName = displayName;
}
if (reference == null || description != reference.Description)
{
fieldType.Description = description;
}
fieldType.Update(command.ActorId);

if (payload.BooleanProperties != null)
{
ReadOnlyBooleanProperties properties = new(payload.BooleanProperties);
if (reference == null || properties != reference.Properties)
{
fieldType.SetProperties(properties, command.ActorId);
}
}
if (payload.DateTimeProperties != null)
{
ReadOnlyDateTimeProperties properties = new(payload.DateTimeProperties);
if (reference == null || properties != reference.Properties)
{
fieldType.SetProperties(properties, command.ActorId);
}
}
if (payload.NumberProperties != null)
{
ReadOnlyNumberProperties properties = new(payload.NumberProperties);
if (reference == null || properties != reference.Properties)
{
fieldType.SetProperties(properties, command.ActorId);
}
}
if (payload.StringProperties != null)
{
ReadOnlyStringProperties properties = new(payload.StringProperties);
if (reference == null || properties != reference.Properties)
{
fieldType.SetProperties(properties, command.ActorId);
}
}
if (payload.TextProperties != null)
{
ReadOnlyTextProperties properties = new(payload.TextProperties);
if (reference == null || properties != reference.Properties)
{
fieldType.SetProperties(properties, command.ActorId);
}
}

await _sender.Send(new SaveFieldTypeCommand(fieldType), cancellationToken);

return await _fieldTypeQuerier.ReadAsync(fieldType, cancellationToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using Logitar.Cms.Contracts.FieldTypes;
using MediatR;

namespace Logitar.Cms.Core.FieldTypes.Commands;

public record UpdateFieldTypeCommand(Guid Id, UpdateFieldTypePayload Payload) : Activity, IRequest<FieldType?>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using FluentValidation;
using Logitar.Cms.Contracts.FieldTypes;
using Logitar.Cms.Core.FieldTypes.Properties;
using Logitar.Cms.Core.FieldTypes.Validators;
using Logitar.Identity.Contracts.Settings;
using Logitar.Identity.Domain.Shared;
using MediatR;

namespace Logitar.Cms.Core.FieldTypes.Commands;

internal class UpdateFieldTypeCommandHandler : IRequestHandler<UpdateFieldTypeCommand, FieldType?>
{
private readonly IFieldTypeQuerier _fieldTypeQuerier;
private readonly IFieldTypeRepository _fieldTypeRepository;
private readonly ISender _sender;

public UpdateFieldTypeCommandHandler(IFieldTypeQuerier fieldTypeQuerier, IFieldTypeRepository fieldTypeRepository, ISender sender)
{
_fieldTypeQuerier = fieldTypeQuerier;
_fieldTypeRepository = fieldTypeRepository;
_sender = sender;
}

public async Task<FieldType?> Handle(UpdateFieldTypeCommand command, CancellationToken cancellationToken)
{
FieldTypeId id = new(command.Id);
FieldTypeAggregate? fieldType = await _fieldTypeRepository.LoadAsync(id, cancellationToken);
if (fieldType == null)
{
return null;
}

IUniqueNameSettings uniqueNameSettings = FieldTypeAggregate.UniqueNameSettings;

UpdateFieldTypePayload payload = command.Payload;
new UpdateFieldTypeValidator(uniqueNameSettings, fieldType.DataType).ValidateAndThrow(payload);

if (!string.IsNullOrWhiteSpace(payload.UniqueName))
{
fieldType.UniqueName = new UniqueNameUnit(uniqueNameSettings, payload.UniqueName);
}
if (payload.DisplayName != null)
{
fieldType.DisplayName = DisplayNameUnit.TryCreate(payload.DisplayName.Value);
}
if (payload.Description != null)
{
fieldType.Description = DescriptionUnit.TryCreate(payload.Description.Value);
}
fieldType.Update(command.ActorId);

if (payload.BooleanProperties != null)
{
fieldType.SetProperties(new ReadOnlyBooleanProperties(payload.BooleanProperties), command.ActorId);
}
if (payload.DateTimeProperties != null)
{
fieldType.SetProperties(new ReadOnlyDateTimeProperties(payload.DateTimeProperties), command.ActorId);
}
if (payload.NumberProperties != null)
{
fieldType.SetProperties(new ReadOnlyNumberProperties(payload.NumberProperties), command.ActorId);
}
if (payload.StringProperties != null)
{
fieldType.SetProperties(new ReadOnlyStringProperties(payload.StringProperties), command.ActorId);
}
if (payload.TextProperties != null)
{
fieldType.SetProperties(new ReadOnlyTextProperties(payload.TextProperties), command.ActorId);
}

await _sender.Send(new SaveFieldTypeCommand(fieldType), cancellationToken);

return await _fieldTypeQuerier.ReadAsync(fieldType, cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ namespace Logitar.Cms.Core.FieldTypes.Events;

public class FieldTypeUpdatedEvent : DomainEvent, INotification
{
public UniqueNameUnit? UniqueName { get; set; }
public Change<DisplayNameUnit>? DisplayName { get; set; }
public Change<DescriptionUnit>? Description { get; set; }

public bool HasChanges => DisplayName != null || Description != null;
public bool HasChanges => UniqueName != null || DisplayName != null || Description != null;
}
17 changes: 16 additions & 1 deletion backend/src/Logitar.Cms.Core/FieldTypes/FieldTypeAggregate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,18 @@ public class FieldTypeAggregate : AggregateRoot
public new FieldTypeId Id => new(base.Id);

private UniqueNameUnit? _uniqueName = null;
public UniqueNameUnit UniqueName => _uniqueName ?? throw new InvalidOperationException($"The {nameof(UniqueName)} has not been initialized yet.");
public UniqueNameUnit UniqueName
{
get => _uniqueName ?? throw new InvalidOperationException($"The {nameof(UniqueName)} has not been initialized yet.");
set
{
if (_uniqueName != value)
{
_uniqueName = value;
_updatedEvent.UniqueName = value;
}
}
}
private DisplayNameUnit? _displayName = null;
public DisplayNameUnit? DisplayName
{
Expand Down Expand Up @@ -199,6 +210,10 @@ public void Update(ActorId actorId = default)
}
protected virtual void Apply(FieldTypeUpdatedEvent @event)
{
if (@event.UniqueName != null)
{
_uniqueName = @event.UniqueName;
}
if (@event.DisplayName != null)
{
_displayName = @event.DisplayName.Value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public interface IFieldTypeRepository
{
Task<IReadOnlyCollection<FieldTypeAggregate>> LoadAsync(CancellationToken cancellationToken = default);
Task<FieldTypeAggregate?> LoadAsync(FieldTypeId id, CancellationToken cancellationToken = default);
Task<FieldTypeAggregate?> LoadAsync(FieldTypeId id, long? version, CancellationToken cancellationToken = default);
Task<IReadOnlyCollection<FieldTypeAggregate>> LoadAsync(IEnumerable<FieldTypeId> ids, CancellationToken cancellationToken = default);
Task<FieldTypeAggregate?> LoadAsync(UniqueNameUnit uniqueName, CancellationToken cancellationToken = default);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public CreateFieldTypeValidator(IUniqueNameSettings uniqueNameSettings)
.Otherwise(() =>
{
When(x => x.BooleanProperties != null, () => RuleFor(x => x.BooleanProperties!).SetValidator(new BooleanPropertiesValidator()));
When(x => x.DateTimeProperties != null, () => RuleFor(x => x.DateTimeProperties!).SetValidator(new DateTimePropertiesValidator()));
When(x => x.NumberProperties != null, () => RuleFor(x => x.NumberProperties!).SetValidator(new NumberPropertiesValidator()));
When(x => x.StringProperties != null, () => RuleFor(x => x.StringProperties!).SetValidator(new StringPropertiesValidator()));
When(x => x.TextProperties != null, () => RuleFor(x => x.TextProperties!).SetValidator(new TextPropertiesValidator()));
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using FluentValidation;
using Logitar.Cms.Contracts.FieldTypes;
using Logitar.Identity.Contracts.Settings;
using Logitar.Identity.Domain.Shared;

namespace Logitar.Cms.Core.FieldTypes.Validators;

public class ReplaceFieldTypeValidator : AbstractValidator<ReplaceFieldTypePayload>
{
public ReplaceFieldTypeValidator(IUniqueNameSettings uniqueNameSettings, DataType dataType)
{
RuleFor(x => x.UniqueName).SetValidator(new UniqueNameValidator(uniqueNameSettings));
When(x => !string.IsNullOrWhiteSpace(x.DisplayName), () => RuleFor(x => x.DisplayName!).SetValidator(new DisplayNameValidator()));
When(x => !string.IsNullOrWhiteSpace(x.Description), () => RuleFor(x => x.Description!).SetValidator(new DescriptionValidator()));

switch (dataType)
{
case DataType.Boolean:
When(x => x.BooleanProperties != null, () => RuleFor(x => x.BooleanProperties!).SetValidator(new BooleanPropertiesValidator()))
.Otherwise(() => RuleFor(x => x.BooleanProperties).NotNull());
RuleFor(x => x.DateTimeProperties).Null();
RuleFor(x => x.NumberProperties).Null();
RuleFor(x => x.StringProperties).Null();
RuleFor(x => x.TextProperties).Null();
break;
case DataType.DateTime:
RuleFor(x => x.BooleanProperties).Null();
When(x => x.DateTimeProperties != null, () => RuleFor(x => x.DateTimeProperties!).SetValidator(new DateTimePropertiesValidator()))
.Otherwise(() => RuleFor(x => x.DateTimeProperties).NotNull());
RuleFor(x => x.NumberProperties).Null();
RuleFor(x => x.StringProperties).Null();
RuleFor(x => x.TextProperties).Null();
break;
case DataType.Number:
RuleFor(x => x.BooleanProperties).Null();
RuleFor(x => x.DateTimeProperties).Null();
When(x => x.NumberProperties != null, () => RuleFor(x => x.NumberProperties!).SetValidator(new NumberPropertiesValidator()))
.Otherwise(() => RuleFor(x => x.NumberProperties).NotNull());
RuleFor(x => x.StringProperties).Null();
RuleFor(x => x.TextProperties).Null();
break;
case DataType.String:
RuleFor(x => x.BooleanProperties).Null();
RuleFor(x => x.DateTimeProperties).Null();
RuleFor(x => x.NumberProperties).Null();
When(x => x.StringProperties != null, () => RuleFor(x => x.StringProperties!).SetValidator(new StringPropertiesValidator()))
.Otherwise(() => RuleFor(x => x.StringProperties).NotNull());
RuleFor(x => x.TextProperties).Null();
break;
case DataType.Text:
RuleFor(x => x.BooleanProperties).Null();
RuleFor(x => x.DateTimeProperties).Null();
RuleFor(x => x.NumberProperties).Null();
RuleFor(x => x.StringProperties).Null();
When(x => x.TextProperties != null, () => RuleFor(x => x.TextProperties!).SetValidator(new TextPropertiesValidator()))
.Otherwise(() => RuleFor(x => x.TextProperties).NotNull());
break;
default:
throw new DataTypeNotSupportedException(dataType);
}
}
}
Loading

0 comments on commit 6370449

Please sign in to comment.