Browse Source

State updates fixed.

pull/206/head
Sebastian Stehle 8 years ago
parent
commit
322980d9c9
  1. 2
      src/Squidex.Domain.Apps.Entities.MongoDb/MongoCollectionExtensions.cs
  2. 63
      src/Squidex.Domain.Apps.Entities/Apps/AppDomainObject.cs
  3. 18
      src/Squidex.Domain.Apps.Entities/Apps/AppHistoryEventsCreator.cs
  4. 74
      src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs
  5. 24
      src/Squidex.Domain.Apps.Entities/Assets/AssetDomainObject.cs
  6. 38
      src/Squidex.Domain.Apps.Entities/Assets/State/AssetState.cs
  7. 55
      src/Squidex.Domain.Apps.Entities/EntityMapper.cs
  8. 2
      src/Squidex.Domain.Apps.Entities/Rules/RuleDequeuer.cs
  9. 22
      src/Squidex.Domain.Apps.Entities/Rules/RuleDomainObject.cs
  10. 36
      src/Squidex.Domain.Apps.Entities/Rules/State/RuleState.cs
  11. 54
      src/Squidex.Domain.Apps.Entities/Schemas/SchemaDomainObject.cs
  12. 143
      src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs
  13. 2
      src/Squidex.Domain.Users.MongoDb/MongoXmlRepository.cs
  14. 14
      src/Squidex.Infrastructure/Commands/DomainObjectBase.cs
  15. 1
      tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/Triggers/ContentChangedTriggerTests.cs
  16. 10
      tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs

2
src/Squidex.Domain.Apps.Entities.MongoDb/MongoCollectionExtensions.cs

@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb
{
public static Task CreateAsync<T>(this IMongoCollection<T> collection, SquidexEvent @event, EnvelopeHeaders headers, Action<T> updater) where T : class, IEntity, new()
{
var entity = EntityMapper.Create(@event, headers, updater);
var entity = new T().Update(@event, headers, updater);
return collection.InsertOneIfNotExistsAsync(entity);
}

63
src/Squidex.Domain.Apps.Entities/Apps/AppDomainObject.cs

@ -7,7 +7,6 @@
// ==========================================================================
using System;
using System.Linq;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.Apps.State;
@ -28,10 +27,6 @@ namespace Squidex.Domain.Apps.Entities.Apps
var appId = new NamedId<Guid>(command.AppId, command.Name);
UpdateState(command, s => { s.Id = appId.Id; s.Name = command.Name; });
UpdateContributors(command, c => c.Assign(command.Actor.Identifier, AppContributorPermission.Owner));
RaiseEvent(SimpleMapper.Map(command, CreateInitalEvent(appId)));
RaiseEvent(SimpleMapper.Map(command, CreateInitialOwner(appId, command)));
RaiseEvent(SimpleMapper.Map(command, CreateInitialLanguage(appId)));
@ -43,27 +38,6 @@ namespace Squidex.Domain.Apps.Entities.Apps
{
ThrowIfNotCreated();
UpdateLanguages(command, l =>
{
var fallback = command.Fallback;
if (fallback != null && fallback.Count > 0)
{
var existingLangauges = l.OfType<LanguageConfig>().Select(x => x.Language);
fallback = fallback.Intersect(existingLangauges).ToList();
}
l = l.Set(new LanguageConfig(command.Language, command.IsOptional, fallback));
if (command.IsMaster)
{
l = l.MakeMaster(command.Language);
}
return l;
});
RaiseEvent(SimpleMapper.Map(command, new AppLanguageUpdated()));
return this;
@ -75,15 +49,11 @@ namespace Squidex.Domain.Apps.Entities.Apps
if (!string.IsNullOrWhiteSpace(command.Name))
{
UpdateClients(command, c => c.Rename(command.Id, command.Name));
RaiseEvent(SimpleMapper.Map(command, new AppClientRenamed()));
}
if (command.Permission.HasValue)
{
UpdateClients(command, c => c.Update(command.Id, command.Permission.Value));
RaiseEvent(SimpleMapper.Map(command, new AppClientUpdated { Permission = command.Permission.Value }));
}
@ -94,8 +64,6 @@ namespace Squidex.Domain.Apps.Entities.Apps
{
ThrowIfNotCreated();
UpdateContributors(command, c => c.Assign(command.ContributorId, command.Permission));
RaiseEvent(SimpleMapper.Map(command, new AppContributorAssigned()));
return this;
@ -105,8 +73,6 @@ namespace Squidex.Domain.Apps.Entities.Apps
{
ThrowIfNotCreated();
UpdateContributors(command, c => c.Remove(command.ContributorId));
RaiseEvent(SimpleMapper.Map(command, new AppContributorRemoved()));
return this;
@ -116,8 +82,6 @@ namespace Squidex.Domain.Apps.Entities.Apps
{
ThrowIfNotCreated();
UpdateClients(command, c => c.Add(command.Id, command.Secret));
RaiseEvent(SimpleMapper.Map(command, new AppClientAttached()));
return this;
@ -127,8 +91,6 @@ namespace Squidex.Domain.Apps.Entities.Apps
{
ThrowIfNotCreated();
UpdateClients(command, c => c.Revoke(command.Id));
RaiseEvent(SimpleMapper.Map(command, new AppClientRevoked()));
return this;
@ -138,8 +100,6 @@ namespace Squidex.Domain.Apps.Entities.Apps
{
ThrowIfNotCreated();
UpdateLanguages(command, l => l.Set(new LanguageConfig(command.Language)));
RaiseEvent(SimpleMapper.Map(command, new AppLanguageAdded()));
return this;
@ -149,8 +109,6 @@ namespace Squidex.Domain.Apps.Entities.Apps
{
ThrowIfNotCreated();
UpdateLanguages(command, l => l.Remove(command.Language));
RaiseEvent(SimpleMapper.Map(command, new AppLanguageRemoved()));
return this;
@ -160,8 +118,6 @@ namespace Squidex.Domain.Apps.Entities.Apps
{
ThrowIfNotCreated();
UpdateState(command, s => s.Plan = command.PlanId != null ? new AppPlan(command.Actor, command.PlanId) : null);
RaiseEvent(SimpleMapper.Map(command, new AppPlanChanged()));
return this;
@ -208,24 +164,9 @@ namespace Squidex.Domain.Apps.Entities.Apps
}
}
private void UpdateClients(ICommand command, Func<AppClients, AppClients> updater)
{
UpdateState(command, s => s.Clients = updater(s.Clients));
}
private void UpdateContributors(ICommand command, Func<AppContributors, AppContributors> updater)
{
UpdateState(command, s => s.Contributors = updater(s.Contributors));
}
private void UpdateLanguages(ICommand command, Func<LanguagesConfig, LanguagesConfig> updater)
{
UpdateState(command, s => s.LanguagesConfig = updater(s.LanguagesConfig));
}
protected override AppState CloneState(ICommand command, Action<AppState> updater)
protected override void OnRaised(Envelope<IEvent> @event)
{
return State.Clone().Update((SquidexCommand)command, updater);
UpdateState(State.Apply(@event));
}
}
}

18
src/Squidex.Domain.Apps.Entities/Apps/AppHistoryEventsCreator.cs

@ -51,7 +51,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
"changed master language to {[Language]}");
}
protected Task<HistoryEventToStore> On(AppContributorRemoved @event, EnvelopeHeaders headers)
protected Task<HistoryEventToStore> On(AppContributorRemoved @event)
{
const string channel = "settings.contributors";
@ -60,7 +60,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
.AddParameter("Contributor", @event.ContributorId));
}
protected Task<HistoryEventToStore> On(AppContributorAssigned @event, EnvelopeHeaders headers)
protected Task<HistoryEventToStore> On(AppContributorAssigned @event)
{
const string channel = "settings.contributors";
@ -69,7 +69,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
.AddParameter("Contributor", @event.ContributorId).AddParameter("Permission", @event.Permission));
}
protected Task<HistoryEventToStore> On(AppClientAttached @event, EnvelopeHeaders headers)
protected Task<HistoryEventToStore> On(AppClientAttached @event)
{
const string channel = "settings.clients";
@ -78,7 +78,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
.AddParameter("Id", @event.Id));
}
protected Task<HistoryEventToStore> On(AppClientRevoked @event, EnvelopeHeaders headers)
protected Task<HistoryEventToStore> On(AppClientRevoked @event)
{
const string channel = "settings.clients";
@ -87,7 +87,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
.AddParameter("Id", @event.Id));
}
protected Task<HistoryEventToStore> On(AppClientRenamed @event, EnvelopeHeaders headers)
protected Task<HistoryEventToStore> On(AppClientRenamed @event)
{
const string channel = "settings.clients";
@ -96,7 +96,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
.AddParameter("Id", @event.Id).AddParameter("Name", ClientName(@event)));
}
protected Task<HistoryEventToStore> On(AppLanguageAdded @event, EnvelopeHeaders headers)
protected Task<HistoryEventToStore> On(AppLanguageAdded @event)
{
const string channel = "settings.languages";
@ -105,7 +105,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
.AddParameter("Language", @event.Language));
}
protected Task<HistoryEventToStore> On(AppLanguageRemoved @event, EnvelopeHeaders headers)
protected Task<HistoryEventToStore> On(AppLanguageRemoved @event)
{
const string channel = "settings.languages";
@ -114,7 +114,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
.AddParameter("Language", @event.Language));
}
protected Task<HistoryEventToStore> On(AppLanguageUpdated @event, EnvelopeHeaders headers)
protected Task<HistoryEventToStore> On(AppLanguageUpdated @event)
{
const string channel = "settings.languages";
@ -123,7 +123,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
.AddParameter("Language", @event.Language));
}
protected Task<HistoryEventToStore> On(AppMasterLanguageSet @event, EnvelopeHeaders headers)
protected Task<HistoryEventToStore> On(AppMasterLanguageSet @event)
{
const string channel = "settings.languages";

74
src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs

@ -8,11 +8,16 @@
using Newtonsoft.Json;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Events;
using Squidex.Domain.Apps.Events.Apps;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Dispatching;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Domain.Apps.Entities.Apps.State
{
public sealed class AppState : DomainObjectState<AppState>, IAppEntity
public class AppState : DomainObjectState<AppState>, IAppEntity
{
private static readonly LanguagesConfig English = LanguagesConfig.Build(Language.EN);
@ -30,5 +35,72 @@ namespace Squidex.Domain.Apps.Entities.Apps.State
[JsonProperty]
public LanguagesConfig LanguagesConfig { get; set; } = English;
protected void On(AppCreated @event)
{
SimpleMapper.Map(@event, this);
}
protected void On(AppPlanChanged @event)
{
Plan = @event.PlanId == null ? null : new AppPlan(@event.Actor, @event.PlanId);
}
protected void On(AppContributorAssigned @event)
{
Contributors = Contributors.Assign(@event.ContributorId, @event.Permission);
}
protected void On(AppContributorRemoved @event)
{
Contributors = Contributors.Remove(@event.ContributorId);
}
protected void On(AppClientAttached @event)
{
Clients = Clients.Add(@event.Id, @event.Secret);
}
protected void On(AppClientUpdated @event)
{
Clients = Clients.Update(@event.Id, @event.Permission);
}
protected void On(AppClientRenamed @event)
{
Clients = Clients.Rename(@event.Id, @event.Name);
}
protected void On(AppClientRevoked @event)
{
Clients = Clients.Revoke(@event.Id);
}
protected void On(AppLanguageAdded @event)
{
LanguagesConfig = LanguagesConfig.Set(new LanguageConfig(@event.Language));
}
protected void On(AppLanguageRemoved @event)
{
LanguagesConfig = LanguagesConfig.Remove(@event.Language);
}
protected void On(AppLanguageUpdated @event)
{
LanguagesConfig = LanguagesConfig.Set(new LanguageConfig(@event.Language, @event.IsOptional, @event.Fallback));
if (@event.IsMaster)
{
LanguagesConfig = LanguagesConfig.MakeMaster(@event.Language);
}
}
public AppState Apply(Envelope<IEvent> @event)
{
var payload = (SquidexEvent)@event.Payload;
return Clone().Update(payload, @event.Headers, r => r.DispatchAction(payload));
}
}
}

24
src/Squidex.Domain.Apps.Entities/Assets/AssetDomainObject.cs

@ -6,12 +6,12 @@
// All rights reserved.
// ==========================================================================
using System;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Assets.State;
using Squidex.Domain.Apps.Events.Assets;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Domain.Apps.Entities.Assets
@ -33,13 +33,6 @@ namespace Squidex.Domain.Apps.Entities.Assets
IsImage = command.ImageInfo != null
});
UpdateState(command, s =>
{
s.TotalSize = @event.FileSize;
SimpleMapper.Map(@event, s);
});
RaiseEvent(@event);
return this;
@ -59,13 +52,6 @@ namespace Squidex.Domain.Apps.Entities.Assets
IsImage = command.ImageInfo != null
});
UpdateState(command, s =>
{
s.TotalSize += @event.FileSize;
SimpleMapper.Map(@event, s);
});
RaiseEvent(@event);
return this;
@ -75,8 +61,6 @@ namespace Squidex.Domain.Apps.Entities.Assets
{
VerifyCreatedAndNotDeleted();
UpdateState(command, s => s.IsDeleted = true);
RaiseEvent(SimpleMapper.Map(command, new AssetDeleted { DeletedSize = State.TotalSize }));
return this;
@ -86,8 +70,6 @@ namespace Squidex.Domain.Apps.Entities.Assets
{
VerifyCreatedAndNotDeleted();
UpdateState(command, s => s.FileName = command.FileName);
RaiseEvent(SimpleMapper.Map(command, new AssetRenamed()));
return this;
@ -109,9 +91,9 @@ namespace Squidex.Domain.Apps.Entities.Assets
}
}
protected override AssetState CloneState(ICommand command, Action<AssetState> updater)
protected override void OnRaised(Envelope<IEvent> @event)
{
return State.Clone().Update((SquidexCommand)command, updater);
UpdateState(State.Apply(@event));
}
}
}

38
src/Squidex.Domain.Apps.Entities/Assets/State/AssetState.cs

@ -9,10 +9,15 @@
using System;
using Newtonsoft.Json;
using Squidex.Domain.Apps.Core.ValidateContent;
using Squidex.Domain.Apps.Events;
using Squidex.Domain.Apps.Events.Assets;
using Squidex.Infrastructure.Dispatching;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Domain.Apps.Entities.Assets.State
{
public sealed class AssetState : DomainObjectState<AssetState>,
public class AssetState : DomainObjectState<AssetState>,
IAssetEntity,
IAssetInfo,
IUpdateableEntityWithAppRef
@ -51,5 +56,36 @@ namespace Squidex.Domain.Apps.Entities.Assets.State
{
get { return Id; }
}
protected void On(AssetCreated @event)
{
SimpleMapper.Map(@event, this);
TotalSize += @event.FileSize;
}
protected void On(AssetUpdated @event)
{
SimpleMapper.Map(@event, this);
TotalSize += @event.FileSize;
}
protected void On(AssetRenamed @event)
{
FileName = @event.FileName;
}
protected void On(AssetDeleted @event)
{
IsDeleted = true;
}
public AssetState Apply(Envelope<IEvent> @event)
{
var payload = (SquidexEvent)@event.Payload;
return Clone().Update(payload, @event.Headers, r => r.DispatchAction(payload));
}
}
}

55
src/Squidex.Domain.Apps.Entities/EntityMapper.cs

@ -1,5 +1,5 @@
// ==========================================================================
// EntityMapper.cs
// EntityMapper2.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
@ -8,82 +8,81 @@
using System;
using NodaTime;
using Squidex.Infrastructure.Commands;
using Squidex.Domain.Apps.Events;
using Squidex.Infrastructure.EventSourcing;
namespace Squidex.Domain.Apps.Entities
{
public static class EntityMapper
{
public static T Update<T>(this T entity, SquidexCommand command, Action<T> updater = null) where T : IEntity
public static T Update<T>(this T entity, SquidexEvent @event, EnvelopeHeaders headers, Action<T> updater = null) where T : IEntity
{
var timestamp = SystemClock.Instance.GetCurrentInstant();
SetId(entity, command);
SetAppId(entity, command);
SetCreated(entity, timestamp);
SetCreatedBy(entity, command);
SetLastModified(entity, timestamp);
SetLastModifiedBy(entity, command);
SetVersion(entity);
SetId(entity, headers);
SetAppId(entity, @event);
SetCreated(entity, headers);
SetCreatedBy(entity, @event);
SetLastModified(entity, headers);
SetLastModifiedBy(entity, @event);
SetVersion(entity, headers);
updater?.Invoke(entity);
return entity;
}
private static void SetId(IEntity entity, SquidexCommand command)
private static void SetId(IEntity entity, EnvelopeHeaders headers)
{
if (entity is IUpdateableEntity updateable && command is IAggregateCommand aggregateCommand)
if (entity is IUpdateableEntity updateable)
{
updateable.Id = aggregateCommand.AggregateId;
updateable.Id = headers.AggregateId();
}
}
private static void SetVersion(IEntity entity)
private static void SetVersion(IEntity entity, EnvelopeHeaders headers)
{
if (entity is IUpdateableEntityWithVersion withVersion)
{
withVersion.Version++;
withVersion.Version = headers.EventStreamNumber();
}
}
private static void SetCreated(IEntity entity, Instant timestamp)
private static void SetCreated(IEntity entity, EnvelopeHeaders headers)
{
if (entity is IUpdateableEntity updateable && updateable.Created == default(Instant))
{
updateable.Created = timestamp;
updateable.Created = headers.Timestamp();
}
}
private static void SetCreatedBy(IEntity entity, SquidexCommand command)
private static void SetCreatedBy(IEntity entity, SquidexEvent @event)
{
if (entity is IUpdateableEntityWithCreatedBy withCreatedBy && withCreatedBy.CreatedBy == null)
{
withCreatedBy.CreatedBy = command.Actor;
withCreatedBy.CreatedBy = @event.Actor;
}
}
private static void SetLastModified(IEntity entity, Instant timestamp)
private static void SetLastModified(IEntity entity, EnvelopeHeaders headers)
{
if (entity is IUpdateableEntity updateable)
{
updateable.LastModified = timestamp;
updateable.LastModified = headers.Timestamp();
}
}
private static void SetLastModifiedBy(IEntity entity, SquidexCommand command)
private static void SetLastModifiedBy(IEntity entity, SquidexEvent @event)
{
if (entity is IUpdateableEntityWithLastModifiedBy withModifiedBy)
{
withModifiedBy.LastModifiedBy = command.Actor;
withModifiedBy.LastModifiedBy = @event.Actor;
}
}
private static void SetAppId(IEntity entity, SquidexCommand command)
private static void SetAppId(IEntity entity, SquidexEvent @event)
{
if (entity is IUpdateableEntityWithAppRef appEntity && command is AppCommand appCommand)
if (entity is IUpdateableEntityWithAppRef appEntity && @event is AppEvent appEvent)
{
appEntity.AppId = appCommand.AppId.Id;
appEntity.AppId = appEvent.AppId.Id;
}
}
}

2
src/Squidex.Domain.Apps.Entities/Rules/RuleDequeuer.cs

@ -21,7 +21,7 @@ using Squidex.Infrastructure.Timers;
namespace Squidex.Domain.Apps.Entities.Rules
{
public sealed class RuleDequeuer : DisposableObjectBase, IExternalSystem
public class RuleDequeuer : DisposableObjectBase, IExternalSystem
{
private readonly ActionBlock<IRuleEventEntity> requestBlock;
private readonly IRuleEventRepository ruleEventRepository;

22
src/Squidex.Domain.Apps.Entities/Rules/RuleDomainObject.cs

@ -6,13 +6,12 @@
// All rights reserved.
// ==========================================================================
using System;
using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Entities.Rules.Commands;
using Squidex.Domain.Apps.Entities.Rules.State;
using Squidex.Domain.Apps.Events.Rules;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Domain.Apps.Entities.Rules
@ -23,8 +22,6 @@ namespace Squidex.Domain.Apps.Entities.Rules
{
VerifyNotCreated();
UpdateRule(command, r => new Rule(command.Trigger, command.Action));
RaiseEvent(SimpleMapper.Map(command, new RuleCreated()));
}
@ -32,8 +29,6 @@ namespace Squidex.Domain.Apps.Entities.Rules
{
VerifyCreatedAndNotDeleted();
UpdateRule(command, r => r.Update(command.Trigger).Update(command.Action));
RaiseEvent(SimpleMapper.Map(command, new RuleUpdated()));
}
@ -41,8 +36,6 @@ namespace Squidex.Domain.Apps.Entities.Rules
{
VerifyCreatedAndNotDeleted();
UpdateRule(command, r => r.Enable());
RaiseEvent(SimpleMapper.Map(command, new RuleEnabled()));
}
@ -50,8 +43,6 @@ namespace Squidex.Domain.Apps.Entities.Rules
{
VerifyCreatedAndNotDeleted();
UpdateRule(command, r => r.Disable());
RaiseEvent(SimpleMapper.Map(command, new RuleDisabled()));
}
@ -59,8 +50,6 @@ namespace Squidex.Domain.Apps.Entities.Rules
{
VerifyCreatedAndNotDeleted();
UpdateState(command, s => s.IsDeleted = true);
RaiseEvent(SimpleMapper.Map(command, new RuleDeleted()));
}
@ -80,14 +69,9 @@ namespace Squidex.Domain.Apps.Entities.Rules
}
}
private void UpdateRule(ICommand command, Func<Rule, Rule> updater)
{
UpdateState(command, s => s.RuleDef = updater(s.RuleDef));
}
protected override RuleState CloneState(ICommand command, Action<RuleState> updater)
protected override void OnRaised(Envelope<IEvent> @event)
{
return State.Clone().Update((SquidexCommand)command, updater);
UpdateState(State.Apply(@event));
}
}
}

36
src/Squidex.Domain.Apps.Entities/Rules/State/RuleState.cs

@ -9,10 +9,17 @@
using System;
using Newtonsoft.Json;
using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Events;
using Squidex.Domain.Apps.Events.Rules;
using Squidex.Infrastructure.Dispatching;
using Squidex.Infrastructure.EventSourcing;
namespace Squidex.Domain.Apps.Entities.Rules.State
{
public sealed class RuleState : DomainObjectState<RuleState>, IRuleEntity
public class RuleState : DomainObjectState<RuleState>,
IRuleEntity,
IEntityWithAppRef,
IUpdateableEntityWithAppRef
{
[JsonProperty]
public Guid AppId { get; set; }
@ -22,5 +29,32 @@ namespace Squidex.Domain.Apps.Entities.Rules.State
[JsonProperty]
public bool IsDeleted { get; set; }
protected void On(RuleCreated @event)
{
RuleDef = new Rule(@event.Trigger, @event.Action);
}
protected void On(RuleUpdated @event)
{
RuleDef = RuleDef.Update(@event.Trigger).Update(@event.Action);
}
protected void On(RuleEnabled @event)
{
RuleDef = RuleDef.Enable();
}
protected void On(RuleDisabled @event)
{
RuleDef = RuleDef.Disable();
}
public RuleState Apply(Envelope<IEvent> @event)
{
var payload = (SquidexEvent)@event.Payload;
return Clone().Update(payload, @event.Headers, r => r.DispatchAction(payload));
}
}
}

54
src/Squidex.Domain.Apps.Entities/Schemas/SchemaDomainObject.cs

@ -8,13 +8,13 @@
using System;
using System.Collections.Generic;
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Schemas.Commands;
using Squidex.Domain.Apps.Entities.Schemas.State;
using Squidex.Domain.Apps.Events.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Domain.Apps.Entities.Schemas
@ -57,22 +57,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas
{
VerifyCreatedAndNotDeleted();
var partitioning =
string.Equals(command.Partitioning, Partitioning.Language.Key, StringComparison.OrdinalIgnoreCase) ?
Partitioning.Language :
Partitioning.Invariant;
var fieldId = State.TotalFields;
var field = registry.CreateField(fieldId, command.Name, partitioning, command.Properties);
UpdateState(command, state =>
{
state.SchemaDef = state.SchemaDef.AddField(field);
state.TotalFields = fieldId + 1;
});
RaiseEvent(SimpleMapper.Map(command, new FieldAdded { FieldId = new NamedId<long>(fieldId + 1, command.Name) }));
RaiseEvent(SimpleMapper.Map(command, new FieldAdded { FieldId = new NamedId<long>(State.TotalFields + 1, command.Name) }));
return this;
}
@ -81,8 +66,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas
{
VerifyCreatedAndNotDeleted();
UpdateSchema(command, s => s.UpdateField(command.FieldId, command.Properties));
RaiseEvent(command, SimpleMapper.Map(command, new FieldUpdated()));
return this;
@ -92,8 +75,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas
{
VerifyCreatedAndNotDeleted();
UpdateSchema(command, s => s.LockField(command.FieldId));
RaiseEvent(command, new FieldLocked());
return this;
@ -103,8 +84,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas
{
VerifyCreatedAndNotDeleted();
UpdateSchema(command, s => s.HideField(command.FieldId));
RaiseEvent(command, new FieldHidden());
return this;
@ -114,8 +93,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas
{
VerifyCreatedAndNotDeleted();
UpdateSchema(command, s => s.ShowField(command.FieldId));
RaiseEvent(command, new FieldShown());
return this;
@ -125,8 +102,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas
{
VerifyCreatedAndNotDeleted();
UpdateSchema(command, s => s.DisableField(command.FieldId));
RaiseEvent(command, new FieldDisabled());
return this;
@ -136,8 +111,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas
{
VerifyCreatedAndNotDeleted();
UpdateSchema(command, s => s.EnableField(command.FieldId));
RaiseEvent(command, new FieldEnabled());
return this;
@ -147,8 +120,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas
{
VerifyCreatedAndNotDeleted();
UpdateSchema(command, s => s.DeleteField(command.FieldId));
RaiseEvent(command, new FieldDeleted());
return this;
@ -158,8 +129,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas
{
VerifyCreatedAndNotDeleted();
UpdateSchema(command, s => s.ReorderFields(command.FieldIds));
RaiseEvent(SimpleMapper.Map(command, new SchemaFieldsReordered()));
return this;
@ -169,8 +138,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas
{
VerifyCreatedAndNotDeleted();
UpdateSchema(command, s => s.Publish());
RaiseEvent(SimpleMapper.Map(command, new SchemaPublished()));
return this;
@ -180,8 +147,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas
{
VerifyCreatedAndNotDeleted();
UpdateSchema(command, s => s.Unpublish());
RaiseEvent(SimpleMapper.Map(command, new SchemaUnpublished()));
return this;
@ -191,8 +156,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas
{
VerifyCreatedAndNotDeleted();
UpdateState(command, s => SimpleMapper.Map(command, s));
RaiseEvent(SimpleMapper.Map(command, new ScriptsConfigured()));
return this;
@ -202,8 +165,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas
{
VerifyCreatedAndNotDeleted();
UpdateState(command, s => s.IsDeleted = true);
RaiseEvent(SimpleMapper.Map(command, new SchemaDeleted()));
return this;
@ -213,8 +174,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas
{
VerifyCreatedAndNotDeleted();
UpdateState(command, s => SimpleMapper.Map(command, s));
RaiseEvent(SimpleMapper.Map(command, new SchemaUpdated()));
return this;
@ -248,14 +207,9 @@ namespace Squidex.Domain.Apps.Entities.Schemas
}
}
private void UpdateSchema(ICommand command, Func<Schema, Schema> updater)
{
UpdateState(command, s => s.SchemaDef = updater(s.SchemaDef));
}
protected override SchemaState CloneState(ICommand command, Action<SchemaState> updater)
protected override void OnRaised(Envelope<IEvent> @event)
{
return State.Clone().Update((SquidexCommand)command, updater);
UpdateState(State.Apply(@event));
}
}
}

143
src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs

@ -1,5 +1,5 @@
// ==========================================================================
// JsonSchemaEntity.cs
// SchemaState.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
@ -8,11 +8,17 @@
using System;
using Newtonsoft.Json;
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Events;
using Squidex.Domain.Apps.Events.Schemas;
using Squidex.Infrastructure.Dispatching;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Domain.Apps.Entities.Schemas.State
{
public sealed class SchemaState : DomainObjectState<SchemaState>,
public class SchemaState : DomainObjectState<SchemaState>,
ISchemaEntity,
IUpdateableEntityWithAppRef,
IUpdateableEntityWithCreatedBy,
@ -25,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State
public Guid AppId { get; set; }
[JsonProperty]
public int TotalFields { get; set; }
public int TotalFields { get; set; } = 1;
[JsonProperty]
public bool IsDeleted { get; set; }
@ -53,5 +59,136 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State
{
get { return SchemaDef.IsPublished; }
}
protected void On(SchemaCreated @event, FieldRegistry registry)
{
var schema = new Schema(@event.Name);
if (@event.Properties != null)
{
schema = schema.Update(@event.Properties);
}
if (@event.Fields != null)
{
foreach (var eventField in @event.Fields)
{
var partitioning =
string.Equals(eventField.Partitioning, Partitioning.Language.Key, StringComparison.OrdinalIgnoreCase) ?
Partitioning.Language :
Partitioning.Invariant;
var field = registry.CreateField(TotalFields, eventField.Name, partitioning, eventField.Properties);
if (eventField.IsHidden)
{
field = field.Hide();
}
if (eventField.IsDisabled)
{
field = field.Disable();
}
if (eventField.IsLocked)
{
field = field.Lock();
}
schema = schema.AddField(field);
TotalFields++;
}
}
SchemaDef = schema;
}
protected void On(FieldAdded @event, FieldRegistry registry)
{
var partitioning =
string.Equals(@event.Partitioning, Partitioning.Language.Key, StringComparison.OrdinalIgnoreCase) ?
Partitioning.Language :
Partitioning.Invariant;
var field = registry.CreateField(@event.FieldId.Id, @event.Name, partitioning, @event.Properties);
SchemaDef = SchemaDef.DeleteField(@event.FieldId.Id);
SchemaDef = SchemaDef.AddField(field);
TotalFields++;
}
protected void On(SchemaPublished @event, FieldRegistry registry)
{
SchemaDef = SchemaDef.Publish();
}
protected void On(SchemaUnpublished @event, FieldRegistry registry)
{
SchemaDef = SchemaDef.Unpublish();
}
protected void On(SchemaUpdated @event, FieldRegistry registry)
{
SchemaDef = SchemaDef.Update(@event.Properties);
}
protected void On(SchemaFieldsReordered @event, FieldRegistry registry)
{
SchemaDef = SchemaDef.ReorderFields(@event.FieldIds);
}
protected void On(FieldUpdated @event, FieldRegistry registry)
{
SchemaDef = SchemaDef.UpdateField(@event.FieldId.Id, @event.Properties);
}
protected void On(FieldLocked @event, FieldRegistry registry)
{
SchemaDef = SchemaDef.LockField(@event.FieldId.Id);
}
protected void On(FieldDisabled @event, FieldRegistry registry)
{
SchemaDef = SchemaDef.DisableField(@event.FieldId.Id);
}
protected void On(FieldEnabled @event, FieldRegistry registry)
{
SchemaDef = SchemaDef.EnableField(@event.FieldId.Id);
}
protected void On(FieldHidden @event, FieldRegistry registry)
{
SchemaDef = SchemaDef.HideField(@event.FieldId.Id);
}
protected void On(FieldShown @event, FieldRegistry registry)
{
SchemaDef = SchemaDef.ShowField(@event.FieldId.Id);
}
protected void On(FieldDeleted @event, FieldRegistry registry)
{
SchemaDef = SchemaDef.DeleteField(@event.FieldId.Id);
}
protected void On(SchemaDeleted @event, FieldRegistry registry)
{
IsDeleted = true;
}
protected void On(ScriptsConfigured @event, FieldRegistry registry)
{
SimpleMapper.Map(@event, this);
}
public SchemaState Apply(Envelope<IEvent> @event)
{
var payload = (SquidexEvent)@event.Payload;
return Clone().Update(payload, @event.Headers, r => r.DispatchAction(payload));
}
}
}

2
src/Squidex.Domain.Users.MongoDb/MongoXmlRepository.cs

@ -18,8 +18,6 @@ namespace Squidex.Domain.Users.MongoDb
{
public sealed class MongoXmlRepository : MongoRepositoryBase<MongoXmlDocument>, IXmlRepository
{
private static readonly UpdateOptions Upsert = new UpdateOptions { IsUpsert = true };
public MongoXmlRepository(IMongoDatabase database)
: base(database)
{

14
src/Squidex.Infrastructure/Commands/DomainObjectBase.cs

@ -49,24 +49,28 @@ namespace Squidex.Infrastructure.Commands
return persistence.ReadAsync();
}
protected void RaiseEvent(IEvent @event)
public void RaiseEvent(IEvent @event)
{
RaiseEvent(Envelope.Create(@event));
}
protected void RaiseEvent<TEvent>(Envelope<TEvent> @event) where TEvent : class, IEvent
public void RaiseEvent<TEvent>(Envelope<TEvent> @event) where TEvent : class, IEvent
{
Guard.NotNull(@event, nameof(@event));
OnRaised(@event.To<IEvent>());
uncomittedEvents.Add(@event.To<IEvent>());
}
public void UpdateState(ICommand command, Action<TState> updater)
public void UpdateState(TState newState)
{
state = CloneState(command, updater);
state = newState;
}
protected abstract TState CloneState(ICommand command, Action<TState> updater);
protected virtual void OnRaised(Envelope<IEvent> @event)
{
}
public async Task WriteAsync(ISemanticLog log)
{

1
tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/Triggers/ContentChangedTriggerTests.cs

@ -11,7 +11,6 @@ using System.Collections.Immutable;
using System.Threading.Tasks;
using FakeItEasy;
using Squidex.Domain.Apps.Core.Rules.Triggers;
using Squidex.Domain.Apps.Entities;
using Squidex.Domain.Apps.Entities.Schemas;
using Xunit;

10
tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs

@ -33,6 +33,16 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers
IsUpdated = false;
}
public Task<V> CreateSyncedAsync<V>(CommandContext context, Func<V, Task> creator) where V : class, IDomainObject
{
return CreateAsync(context, creator);
}
public Task<V> UpdateSyncedAsync<V>(CommandContext context, Func<V, Task> creator) where V : class, IDomainObject
{
return UpdateAsync(context, creator);
}
public async Task<V> CreateAsync<V>(CommandContext context, Func<V, Task> creator) where V : class, IDomainObject
{
IsCreated = true;

Loading…
Cancel
Save