Browse Source

Immutable for rules.

pull/169/head
Sebastian Stehle 8 years ago
parent
commit
dbe6f11849
  1. 31
      src/Squidex.Domain.Apps.Core.Model/Rules/Actions/WebhookAction.cs
  2. 30
      src/Squidex.Domain.Apps.Core.Model/Rules/Rule.cs
  3. 4
      src/Squidex.Domain.Apps.Core.Model/Rules/RuleAction.cs
  4. 4
      src/Squidex.Domain.Apps.Core.Model/Rules/RuleTrigger.cs
  5. 18
      src/Squidex.Domain.Apps.Core.Model/Rules/Triggers/ContentChangedTrigger.cs
  6. 16
      src/Squidex.Domain.Apps.Events/Rules/Utils/RuleEventDispatcher.cs
  7. 74
      src/Squidex.Domain.Apps.Events/Schemas/Utils/SchemaEventDispatcher.cs
  8. 2
      src/Squidex.Domain.Apps.Read/Assets/IAssetEntity.cs
  9. 2
      src/Squidex.Domain.Apps.Read/Contents/IContentEntity.cs
  10. 8
      src/Squidex.Domain.Apps.Read/EntityMapper.cs
  11. 17
      src/Squidex.Domain.Apps.Read/IEntityWithAppRef.cs
  12. 2
      src/Squidex.Domain.Apps.Read/IEntityWithCreatedBy.cs
  13. 2
      src/Squidex.Domain.Apps.Read/IEntityWithVersion.cs
  14. 6
      src/Squidex.Domain.Apps.Read/IUpdateableEntityWithAppRef.cs
  15. 17
      src/Squidex.Domain.Apps.Read/IUpdateableEntityWithCreatedBy.cs
  16. 17
      src/Squidex.Domain.Apps.Read/IUpdateableEntityWithLastModifiedBy.cs
  17. 10
      src/Squidex.Domain.Apps.Read/IUpdateableEntityWithVersion.cs
  18. 4
      src/Squidex.Domain.Apps.Read/Rules/IRuleEntity.cs
  19. 2
      src/Squidex.Domain.Apps.Read/Rules/RuleEnqueuer.cs
  20. 2
      src/Squidex.Domain.Apps.Read/Schemas/ISchemaEntity.cs
  21. 3
      src/Squidex.Domain.Apps.Read/State/Orleans/AppStateEventConsumer.cs
  22. 16
      src/Squidex.Domain.Apps.Read/State/Orleans/Grains/IAppStateGrain.cs
  23. 30
      src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppStateGrain.cs
  24. 34
      src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppStateGrainState.cs
  25. 4
      src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/JsonAppEntity.cs
  26. 10
      src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/JsonEntity.cs
  27. 11
      src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/JsonRuleEntity.cs
  28. 9
      src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/JsonSchemaEntity.cs
  29. 57
      src/Squidex.Infrastructure/Json/Orleans/J.cs
  30. 21
      src/Squidex.Infrastructure/Json/Orleans/JsonExternalSerializer.cs

31
src/Squidex.Domain.Apps.Core.Model/Rules/Actions/WebhookAction.cs

@ -14,9 +14,36 @@ namespace Squidex.Domain.Apps.Core.Rules.Actions
[TypeName(nameof(WebhookAction))]
public sealed class WebhookAction : RuleAction
{
public Uri Url { get; set; }
private Uri url;
private string sharedSecret;
public string SharedSecret { get; set; }
public Uri Url
{
get
{
return url;
}
set
{
ThrowIfFrozen();
url = value;
}
}
public string SharedSecret
{
get
{
return sharedSecret;
}
set
{
ThrowIfFrozen();
sharedSecret = value;
}
}
public override T Accept<T>(IRuleActionVisitor<T> visitor)
{

30
src/Squidex.Domain.Apps.Core.Model/Rules/Rule.cs

@ -11,7 +11,7 @@ using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.Rules
{
public sealed class Rule
public sealed class Rule : Cloneable<Rule>
{
private RuleTrigger trigger;
private RuleAction action;
@ -41,17 +41,23 @@ namespace Squidex.Domain.Apps.Core.Rules
this.action = action;
}
public void Enable()
public Rule Enable()
{
this.isEnabled = true;
return Clone(clone =>
{
clone.isEnabled = true;
});
}
public void Disable()
public Rule Disable()
{
this.isEnabled = false;
return Clone(clone =>
{
clone.isEnabled = false;
});
}
public void Update(RuleTrigger newTrigger)
public Rule Update(RuleTrigger newTrigger)
{
Guard.NotNull(newTrigger, nameof(newTrigger));
@ -60,10 +66,13 @@ namespace Squidex.Domain.Apps.Core.Rules
throw new ArgumentException("New trigger has another type.", nameof(newTrigger));
}
trigger = newTrigger;
return Clone(clone =>
{
clone.trigger = newTrigger;
});
}
public void Update(RuleAction newAction)
public Rule Update(RuleAction newAction)
{
Guard.NotNull(newAction, nameof(newAction));
@ -72,7 +81,10 @@ namespace Squidex.Domain.Apps.Core.Rules
throw new ArgumentException("New action has another type.", nameof(newAction));
}
action = newAction;
return Clone(clone =>
{
clone.action = newAction;
});
}
}
}

4
src/Squidex.Domain.Apps.Core.Model/Rules/RuleAction.cs

@ -6,9 +6,11 @@
// All rights reserved.
// ==========================================================================
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.Rules
{
public abstract class RuleAction
public abstract class RuleAction : Freezable
{
public abstract T Accept<T>(IRuleActionVisitor<T> visitor);
}

4
src/Squidex.Domain.Apps.Core.Model/Rules/RuleTrigger.cs

@ -6,9 +6,11 @@
// All rights reserved.
// ==========================================================================
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.Rules
{
public abstract class RuleTrigger
public abstract class RuleTrigger : Freezable
{
public abstract T Accept<T>(IRuleTriggerVisitor<T> visitor);
}

18
src/Squidex.Domain.Apps.Core.Model/Rules/Triggers/ContentChangedTrigger.cs

@ -6,7 +6,7 @@
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Collections.Immutable;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.Rules.Triggers
@ -14,7 +14,21 @@ namespace Squidex.Domain.Apps.Core.Rules.Triggers
[TypeName(nameof(ContentChangedTrigger))]
public sealed class ContentChangedTrigger : RuleTrigger
{
public List<ContentChangedTriggerSchema> Schemas { get; set; }
private ImmutableList<ContentChangedTriggerSchema> schemas;
public ImmutableList<ContentChangedTriggerSchema> Schemas
{
get
{
return schemas;
}
set
{
ThrowIfFrozen();
schemas = value;
}
}
public override T Accept<T>(IRuleTriggerVisitor<T> visitor)
{

16
src/Squidex.Domain.Apps.Events/Rules/Utils/RuleEventDispatcher.cs

@ -17,27 +17,29 @@ namespace Squidex.Domain.Apps.Events.Rules.Utils
return new Rule(@event.Trigger, @event.Action);
}
public static void Apply(this Rule rule, RuleUpdated @event)
public static Rule Apply(this Rule rule, RuleUpdated @event)
{
if (@event.Trigger != null)
{
rule.Update(@event.Trigger);
return rule.Update(@event.Trigger);
}
if (@event.Action != null)
{
rule.Update(@event.Action);
return rule.Update(@event.Action);
}
return rule;
}
public static void Apply(this Rule rule, RuleEnabled @event)
public static Rule Apply(this Rule rule, RuleEnabled @event)
{
rule.Enable();
return rule.Enable();
}
public static void Apply(this Rule rule, RuleDisabled @event)
public static Rule Apply(this Rule rule, RuleDisabled @event)
{
rule.Disable();
return rule.Disable();
}
}
}

74
src/Squidex.Domain.Apps.Events/Schemas/Utils/SchemaEventDispatcher.cs

@ -9,7 +9,6 @@
using System;
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Domain.Apps.Events.Schemas.Utils
{
@ -61,7 +60,7 @@ namespace Squidex.Domain.Apps.Events.Schemas.Utils
return schema;
}
public static void Apply(this Schema schema, FieldAdded @event, FieldRegistry registry)
public static Schema Apply(this Schema schema, FieldAdded @event, FieldRegistry registry)
{
var partitioning =
string.Equals(@event.Partitioning, Partitioning.Language.Key, StringComparison.OrdinalIgnoreCase) ?
@ -71,86 +70,65 @@ namespace Squidex.Domain.Apps.Events.Schemas.Utils
var fieldId = @event.FieldId.Id;
var field = registry.CreateField(fieldId, @event.Name, partitioning, @event.Properties);
schema.DeleteField(fieldId);
schema.AddField(field);
}
schema = schema.DeleteField(fieldId);
schema = schema.AddField(field);
public static void Apply(this Schema schema, FieldUpdated @event)
{
if (schema.FieldsById.TryGetValue(@event.FieldId.Id, out var field))
{
field.Update(@event.Properties);
}
return schema;
}
public static void Apply(this Schema schema, FieldLocked @event)
public static Schema Apply(this Schema schema, FieldUpdated @event)
{
if (schema.FieldsById.TryGetValue(@event.FieldId.Id, out var field))
{
field.Lock();
}
return schema.UpdateField(@event.FieldId.Id, @event.Properties);
}
public static void Apply(this Schema schema, FieldHidden @event)
public static Schema Apply(this Schema schema, FieldLocked @event)
{
if (schema.FieldsById.TryGetValue(@event.FieldId.Id, out var field))
{
field.Hide();
}
return schema.LockField(@event.FieldId.Id);
}
public static void Apply(this Schema schema, FieldShown @event)
public static Schema Apply(this Schema schema, FieldHidden @event)
{
if (schema.FieldsById.TryGetValue(@event.FieldId.Id, out var field))
{
field.Show();
}
return schema.HideField(@event.FieldId.Id);
}
public static void Apply(this Schema schema, FieldDisabled @event)
public static Schema Apply(this Schema schema, FieldShown @event)
{
if (schema.FieldsById.TryGetValue(@event.FieldId.Id, out var field))
{
field.Disable();
}
return schema.ShowField(@event.FieldId.Id);
}
public static void Apply(this Schema schema, FieldEnabled @event)
public static Schema Apply(this Schema schema, FieldDisabled @event)
{
if (schema.FieldsById.TryGetValue(@event.FieldId.Id, out var field))
{
field.Enable();
}
return schema.DisableField(@event.FieldId.Id);
}
public static void Apply(this Schema schema, SchemaUpdated @event)
public static Schema Apply(this Schema schema, FieldEnabled @event)
{
schema.Update(@event.Properties);
return schema.EnableField(@event.FieldId.Id);
}
public static void Apply(this Schema schema, SchemaFieldsReordered @event)
public static Schema Apply(this Schema schema, SchemaUpdated @event)
{
schema.ReorderFields(@event.FieldIds);
return schema.Update(@event.Properties);
}
public static void Apply(this Schema schema, FieldDeleted @event)
public static Schema Apply(this Schema schema, SchemaFieldsReordered @event)
{
schema.DeleteField(@event.FieldId.Id);
return schema.ReorderFields(@event.FieldIds);
}
public static void Apply(this Schema schema, SchemaPublished @event)
public static Schema Apply(this Schema schema, FieldDeleted @event)
{
schema.Publish();
return schema.DeleteField(@event.FieldId.Id);
}
public static void Apply(this Schema schema, SchemaUnpublished @event)
public static Schema Apply(this Schema schema, SchemaPublished @event)
{
schema.Unpublish();
return schema.Publish();
}
public static void Apply(this Schema schema, ScriptsConfigured @event)
public static Schema Apply(this Schema schema, SchemaUnpublished @event)
{
SimpleMapper.Map(@event, schema);
return schema.Unpublish();
}
}
}

2
src/Squidex.Domain.Apps.Read/Assets/IAssetEntity.cs

@ -8,7 +8,7 @@
namespace Squidex.Domain.Apps.Read.Assets
{
public interface IAssetEntity : IAppRefEntity, IEntityWithCreatedBy, IEntityWithLastModifiedBy, IEntityWithVersion
public interface IAssetEntity : IEntityWithAppRef, IEntityWithCreatedBy, IEntityWithLastModifiedBy, IEntityWithVersion
{
string MimeType { get; }

2
src/Squidex.Domain.Apps.Read/Contents/IContentEntity.cs

@ -11,7 +11,7 @@ using Squidex.Domain.Apps.Core.Contents;
namespace Squidex.Domain.Apps.Read.Contents
{
public interface IContentEntity : IAppRefEntity, IEntityWithCreatedBy, IEntityWithLastModifiedBy, IEntityWithVersion
public interface IContentEntity : IEntityWithAppRef, IEntityWithCreatedBy, IEntityWithLastModifiedBy, IEntityWithVersion
{
Status Status { get; }

8
src/Squidex.Domain.Apps.Read/EntityMapper.cs

@ -57,7 +57,7 @@ namespace Squidex.Domain.Apps.Read
private static void SetVersion(EnvelopeHeaders headers, IEntity entity)
{
if (entity is IEntityWithVersion withVersion)
if (entity is IUpdateableEntityWithVersion withVersion)
{
withVersion.Version = headers.EventStreamNumber();
}
@ -65,7 +65,7 @@ namespace Squidex.Domain.Apps.Read
private static void SetCreatedBy(SquidexEvent @event, IEntity entity)
{
if (entity is IEntityWithCreatedBy withCreatedBy)
if (entity is IUpdateableEntityWithCreatedBy withCreatedBy)
{
withCreatedBy.CreatedBy = @event.Actor;
}
@ -73,7 +73,7 @@ namespace Squidex.Domain.Apps.Read
private static void SetLastModifiedBy(SquidexEvent @event, IEntity entity)
{
if (entity is IEntityWithLastModifiedBy withModifiedBy)
if (entity is IUpdateableEntityWithLastModifiedBy withModifiedBy)
{
withModifiedBy.LastModifiedBy = @event.Actor;
}
@ -81,7 +81,7 @@ namespace Squidex.Domain.Apps.Read
private static void SetAppId(SquidexEvent @event, IEntity entity)
{
if (entity is IAppRefEntity app && @event is AppEvent appEvent)
if (entity is IUpdateableEntityWithAppRef app && @event is AppEvent appEvent)
{
app.AppId = appEvent.AppId.Id;
}

17
src/Squidex.Domain.Apps.Read/IEntityWithAppRef.cs

@ -0,0 +1,17 @@
// ==========================================================================
// IEntityWithAppRef.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
namespace Squidex.Domain.Apps.Read
{
public interface IEntityWithAppRef : IEntity
{
Guid AppId { get; }
}
}

2
src/Squidex.Domain.Apps.Read/IEntityWithCreatedBy.cs

@ -12,6 +12,6 @@ namespace Squidex.Domain.Apps.Read
{
public interface IEntityWithCreatedBy
{
RefToken CreatedBy { get; set; }
RefToken CreatedBy { get; }
}
}

2
src/Squidex.Domain.Apps.Read/IEntityWithVersion.cs

@ -10,6 +10,6 @@ namespace Squidex.Domain.Apps.Read
{
public interface IEntityWithVersion
{
long Version { get; set; }
long Version { get; }
}
}

6
src/Squidex.Domain.Apps.Read/IAppRefEntity.cs → src/Squidex.Domain.Apps.Read/IUpdateableEntityWithAppRef.cs

@ -1,5 +1,5 @@
// ==========================================================================
// IAppRefEntity.cs
// IUpdateableEntityWithAppRef.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
@ -10,8 +10,8 @@ using System;
namespace Squidex.Domain.Apps.Read
{
public interface IAppRefEntity : IEntity
public interface IUpdateableEntityWithAppRef
{
Guid AppId { get; set; }
}
}
}

17
src/Squidex.Domain.Apps.Read/IUpdateableEntityWithCreatedBy.cs

@ -0,0 +1,17 @@
// ==========================================================================
// IUpdateableEntityWithCreatedBy.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Read
{
public interface IUpdateableEntityWithCreatedBy
{
RefToken CreatedBy { get; set; }
}
}

17
src/Squidex.Domain.Apps.Read/IUpdateableEntityWithLastModifiedBy.cs

@ -0,0 +1,17 @@
// ==========================================================================
// IUpdateableEntityWithLastModifiedBy.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Read
{
public interface IUpdateableEntityWithLastModifiedBy
{
RefToken LastModifiedBy { get; set; }
}
}

10
src/Squidex.Infrastructure/Json/Orleans/IJsonValue.cs → src/Squidex.Domain.Apps.Read/IUpdateableEntityWithVersion.cs

@ -1,17 +1,15 @@
// ==========================================================================
// IJsonValue.cs
// IUpdateableEntityWithVersion.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
namespace Squidex.Infrastructure.Json.Orleans
namespace Squidex.Domain.Apps.Read
{
public interface IJsonValue
public interface IUpdateableEntityWithVersion
{
object Value { get; }
bool IsImmutable { get; }
long Version { get; set; }
}
}

4
src/Squidex.Domain.Apps.Read/Rules/IRuleEntity.cs

@ -10,8 +10,8 @@ using Squidex.Domain.Apps.Core.Rules;
namespace Squidex.Domain.Apps.Read.Rules
{
public interface IRuleEntity : IAppRefEntity, IEntityWithCreatedBy, IEntityWithLastModifiedBy, IEntityWithVersion
public interface IRuleEntity : IEntityWithAppRef, IEntityWithCreatedBy, IEntityWithLastModifiedBy, IEntityWithVersion
{
Rule Rule { get; }
Rule RuleDef { get; }
}
}

2
src/Squidex.Domain.Apps.Read/Rules/RuleEnqueuer.cs

@ -60,7 +60,7 @@ namespace Squidex.Domain.Apps.Read.Rules
foreach (var ruleEntity in rules)
{
var job = ruleService.CreateJob(ruleEntity.Rule, @event);
var job = ruleService.CreateJob(ruleEntity.RuleDef, @event);
if (job != null)
{

2
src/Squidex.Domain.Apps.Read/Schemas/ISchemaEntity.cs

@ -10,7 +10,7 @@ using Squidex.Domain.Apps.Core.Schemas;
namespace Squidex.Domain.Apps.Read.Schemas
{
public interface ISchemaEntity : IAppRefEntity, IEntityWithCreatedBy, IEntityWithLastModifiedBy, IEntityWithVersion
public interface ISchemaEntity : IEntityWithAppRef, IEntityWithCreatedBy, IEntityWithLastModifiedBy, IEntityWithVersion
{
string Name { get; }

3
src/Squidex.Domain.Apps.Read/State/Orleans/AppStateEventConsumer.cs

@ -8,6 +8,7 @@
using System.Threading.Tasks;
using Orleans;
using Orleans.Concurrency;
using Squidex.Domain.Apps.Events;
using Squidex.Domain.Apps.Events.Apps;
using Squidex.Domain.Apps.Read.State.Orleans.Grains;
@ -49,7 +50,7 @@ namespace Squidex.Domain.Apps.Read.State.Orleans
{
var appGrain = factory.GetGrain<IAppStateGrain>(appEvent.AppId.Name);
await appGrain.HandleAsync(@event);
await appGrain.HandleAsync(new Immutable<Envelope<IEvent>>(@event));
}
if (@event.Payload is AppContributorAssigned contributorAssigned)

16
src/Squidex.Domain.Apps.Read/State/Orleans/Grains/IAppStateGrain.cs

@ -10,28 +10,28 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Orleans;
using Orleans.Concurrency;
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Rules;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.Json.Orleans;
namespace Squidex.Domain.Apps.Read.State.Orleans.Grains
{
public interface IAppStateGrain : IGrainWithStringKey
{
Task<J<(IAppEntity, ISchemaEntity)>> GetAppWithSchemaAsync(Guid id);
Task<Immutable<(IAppEntity, ISchemaEntity)>> GetAppWithSchemaAsync(Guid id);
Task<J<IAppEntity>> GetAppAsync();
Task<Immutable<IAppEntity>> GetAppAsync();
Task<J<ISchemaEntity>> GetSchemaAsync(Guid id, bool provideDeleted = false);
Task<Immutable<ISchemaEntity>> GetSchemaAsync(Guid id, bool provideDeleted = false);
Task<J<ISchemaEntity>> GetSchemaAsync(string name, bool provideDeleted = false);
Task<Immutable<ISchemaEntity>> GetSchemaAsync(string name, bool provideDeleted = false);
Task<J<List<ISchemaEntity>>> GetSchemasAsync();
Task<Immutable<List<ISchemaEntity>>> GetSchemasAsync();
Task<J<List<IRuleEntity>>> GetRulesAsync();
Task<Immutable<List<IRuleEntity>>> GetRulesAsync();
Task HandleAsync(J<Envelope<IEvent>> message);
Task HandleAsync(Immutable<Envelope<IEvent>> message);
}
}

30
src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppStateGrain.cs

@ -10,13 +10,13 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Orleans;
using Orleans.Concurrency;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Rules;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.Json.Orleans;
namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations
{
@ -31,51 +31,51 @@ namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations
this.fieldRegistry = fieldRegistry;
}
public Task<J<(IAppEntity, ISchemaEntity)>> GetAppWithSchemaAsync(Guid id)
public Task<Immutable<(IAppEntity, ISchemaEntity)>> GetAppWithSchemaAsync(Guid id)
{
var schema = State.FindSchema(x => x.Id == id && !x.IsDeleted);
return J<(IAppEntity AppEntity, ISchemaEntity SchemaEntity)>.AsTask((State.GetApp(), schema));
return Task.FromResult((State.GetApp(), schema).AsImmutable());
}
public Task<J<IAppEntity>> GetAppAsync()
public Task<Immutable<IAppEntity>> GetAppAsync()
{
var value = State.GetApp();
return J<IAppEntity>.AsTask(value);
return Task.FromResult(value.AsImmutable());
}
public Task<J<List<IRuleEntity>>> GetRulesAsync()
public Task<Immutable<List<IRuleEntity>>> GetRulesAsync()
{
var value = State.FindRules();
return J<List<IRuleEntity>>.AsTask(value);
return Task.FromResult(value.AsImmutable());
}
public Task<J<List<ISchemaEntity>>> GetSchemasAsync()
public Task<Immutable<List<ISchemaEntity>>> GetSchemasAsync()
{
var value = State.FindSchemas(x => !x.IsDeleted);
return J<List<ISchemaEntity>>.AsTask(value);
return Task.FromResult(value.AsImmutable());
}
public Task<J<ISchemaEntity>> GetSchemaAsync(Guid id, bool provideDeleted = false)
public Task<Immutable<ISchemaEntity>> GetSchemaAsync(Guid id, bool provideDeleted = false)
{
var value = State.FindSchema(x => x.Id == id && (!x.IsDeleted || provideDeleted));
return J<ISchemaEntity>.AsTask(value);
return Task.FromResult(value.AsImmutable());
}
public Task<J<ISchemaEntity>> GetSchemaAsync(string name, bool provideDeleted = false)
public Task<Immutable<ISchemaEntity>> GetSchemaAsync(string name, bool provideDeleted = false)
{
var value = State.FindSchema(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) && (!x.IsDeleted || provideDeleted));
return J<ISchemaEntity>.AsTask(value);
return Task.FromResult(value.AsImmutable());
}
public Task HandleAsync(J<Envelope<IEvent>> message)
public Task HandleAsync(Immutable<Envelope<IEvent>> message)
{
State.Apply(message, fieldRegistry);
State.Apply(message.Value, fieldRegistry);
return WriteStateAsync();
}

34
src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppStateGrainState.cs

@ -163,21 +163,21 @@ namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations
case RuleCreated @event:
Rules[@event.RuleId] = EntityMapper.Create<JsonRuleEntity>(@event, envelope.Headers, r =>
{
r.Rule = RuleEventDispatcher.Create(@event);
r.RuleDef = RuleEventDispatcher.Create(@event);
});
break;
case RuleUpdated @event:
UpdateRule(envelope, r =>
{
r.Rule.Apply(@event);
r.RuleDef = r.RuleDef.Apply(@event);
});
break;
case RuleEnabled @event:
UpdateRule(envelope, r =>
{
r.Rule.Apply(@event);
r.RuleDef = r.RuleDef.Apply(@event);
});
break;
@ -197,84 +197,84 @@ namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations
case FieldAdded @event:
UpdateSchema(envelope, s =>
{
s.SchemaDef.Apply(@event, registry);
s.SchemaDef = s.SchemaDef.Apply(@event, registry);
});
break;
case FieldDeleted @event:
UpdateSchema(envelope, s =>
{
s.SchemaDef.Apply(@event);
s.SchemaDef = s.SchemaDef.Apply(@event);
});
break;
case FieldLocked @event:
UpdateSchema(envelope, s =>
{
s.SchemaDef.Apply(@event);
s.SchemaDef = s.SchemaDef.Apply(@event);
});
break;
case FieldHidden @event:
UpdateSchema(envelope, s =>
{
s.SchemaDef.Apply(@event);
s.SchemaDef = s.SchemaDef.Apply(@event);
});
break;
case FieldShown @event:
UpdateSchema(envelope, s =>
{
s.SchemaDef.Apply(@event);
s.SchemaDef = s.SchemaDef.Apply(@event);
});
break;
case FieldDisabled @event:
UpdateSchema(envelope, s =>
{
s.SchemaDef.Apply(@event);
s.SchemaDef = s.SchemaDef.Apply(@event);
});
break;
case FieldEnabled @event:
UpdateSchema(envelope, s =>
{
s.SchemaDef.Apply(@event);
s.SchemaDef = s.SchemaDef.Apply(@event);
});
break;
case FieldUpdated @event:
UpdateSchema(envelope, s =>
{
s.SchemaDef.Apply(@event);
s.SchemaDef = s.SchemaDef.Apply(@event);
});
break;
case SchemaFieldsReordered @event:
UpdateSchema(envelope, s =>
{
s.SchemaDef.Apply(@event);
s.SchemaDef = s.SchemaDef.Apply(@event);
});
break;
case SchemaUpdated @event:
UpdateSchema(envelope, s =>
{
s.SchemaDef.Apply(@event);
s.SchemaDef = s.SchemaDef.Apply(@event);
});
break;
case SchemaPublished @event:
UpdateSchema(envelope, s =>
{
s.SchemaDef.Apply(@event);
s.SchemaDef = s.SchemaDef.Apply(@event);
});
break;
case ScriptsConfigured @event:
UpdateSchema(envelope, s =>
{
s.SchemaDef.Apply(@event);
SimpleMapper.Map(s, @event);
});
break;
@ -308,14 +308,14 @@ namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations
{
var e = envelope.To<RuleEvent>();
Rules[e.Payload.RuleId].Update(e.Payload, e.Headers, updater);
Rules[e.Payload.RuleId].Clone().Update(e.Payload, e.Headers, updater);
}
private void UpdateSchema(Envelope<IEvent> envelope, Action<JsonSchemaEntity> updater = null)
{
var e = envelope.To<SchemaEvent>();
Schemas[e.Payload.SchemaId.Id].Copy().Update(e.Payload, e.Headers, updater);
Schemas[e.Payload.SchemaId.Id].Clone().Update(e.Payload, e.Headers, updater);
}
}
}

4
src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/JsonAppEntity.cs

@ -7,12 +7,14 @@
// ==========================================================================
using Newtonsoft.Json;
using Orleans.Concurrency;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Read.Apps;
namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations
{
public sealed class JsonAppEntity : JsonEntity, IAppEntity
[Immutable]
public sealed class JsonAppEntity : JsonEntity<JsonAppEntity>, IAppEntity
{
[JsonProperty]
public string Name { get; set; }

10
src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/JsonEntity.cs

@ -9,10 +9,13 @@
using System;
using Newtonsoft.Json;
using NodaTime;
using Orleans.Concurrency;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations
{
public abstract class JsonEntity
[Immutable]
public abstract class JsonEntity<T> : Cloneable<T>, IUpdateableEntityWithVersion where T : Cloneable
{
[JsonProperty]
public Guid Id { get; set; }
@ -25,5 +28,10 @@ namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations
[JsonProperty]
public long Version { get; set; }
public T Clone()
{
return Clone(x => { });
}
}
}

11
src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/JsonRuleEntity.cs

@ -8,13 +8,20 @@
using System;
using Newtonsoft.Json;
using Orleans.Concurrency;
using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Read.Rules;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations
{
public sealed class JsonRuleEntity : JsonEntity, IRuleEntity
[Immutable]
public sealed class JsonRuleEntity :
JsonEntity<JsonRuleEntity>,
IRuleEntity,
IUpdateableEntityWithAppRef,
IUpdateableEntityWithCreatedBy,
IUpdateableEntityWithLastModifiedBy
{
[JsonProperty]
public Guid AppId { get; set; }
@ -26,6 +33,6 @@ namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations
public RefToken LastModifiedBy { get; set; }
[JsonProperty]
public Rule Rule { get; set; }
public Rule RuleDef { get; set; }
}
}

9
src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/JsonSchemaEntity.cs

@ -8,13 +8,20 @@
using System;
using Newtonsoft.Json;
using Orleans.Concurrency;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations
{
public sealed class JsonSchemaEntity : JsonEntity, ISchemaEntity
[Immutable]
public sealed class JsonSchemaEntity :
JsonEntity<JsonSchemaEntity>,
ISchemaEntity,
IUpdateableEntityWithAppRef,
IUpdateableEntityWithCreatedBy,
IUpdateableEntityWithLastModifiedBy
{
[JsonProperty]
public string Name { get; set; }

57
src/Squidex.Infrastructure/Json/Orleans/J.cs

@ -1,57 +0,0 @@
// ==========================================================================
// J.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Squidex.Infrastructure.Json.Orleans
{
public struct J<T> : IJsonValue
{
private readonly T value;
private readonly bool isImmutable;
public T Value
{
get { return value; }
}
bool IJsonValue.IsImmutable
{
get { return isImmutable; }
}
object IJsonValue.Value
{
get { return Value; }
}
[JsonConstructor]
public J(T value, bool isImmutable = false)
{
this.value = value;
this.isImmutable = isImmutable;
}
public static implicit operator T(J<T> value)
{
return value.Value;
}
public static implicit operator J<T>(T d)
{
return new J<T>(d);
}
public static Task<J<T>> AsTask(T value)
{
return Task.FromResult<J<T>>(value);
}
}
}

21
src/Squidex.Infrastructure/Json/Orleans/JsonExternalSerializer.cs

@ -7,8 +7,8 @@
// ==========================================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Orleans.Runtime;
@ -19,12 +19,15 @@ namespace Squidex.Infrastructure.Json.Orleans
public class JsonExternalSerializer : IExternalSerializer
{
private readonly JsonSerializer serializer;
private readonly HashSet<Type> types;
public JsonExternalSerializer(JsonSerializer serializer)
public JsonExternalSerializer(JsonSerializer serializer, params Type[] types)
{
Guard.NotNull(serializer, nameof(serializer));
this.serializer = serializer;
this.types = new HashSet<Type>(types);
}
public void Initialize(Logger logger)
@ -33,25 +36,15 @@ namespace Squidex.Infrastructure.Json.Orleans
public bool IsSupportedType(Type itemType)
{
return itemType.GetInterfaces().Contains(typeof(IJsonValue));
return types.Contains(itemType);
}
public object DeepCopy(object source, ICopyContext context)
{
var jsonValue = source as IJsonValue;
if (jsonValue == null)
if (source == null)
{
return null;
}
else if (jsonValue.IsImmutable)
{
return jsonValue;
}
else if (jsonValue.Value == null)
{
return jsonValue;
}
else
{
return JObject.FromObject(source, serializer).ToObject(source.GetType(), serializer);

Loading…
Cancel
Save