mirror of https://github.com/Squidex/squidex.git
21 changed files with 1042 additions and 733 deletions
@ -0,0 +1,15 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Squidex.Infrastructure.Commands; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Assets |
|||
{ |
|||
public interface IAssetGrain : IDomainObjectGrain |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Squidex.Infrastructure.Commands; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Rules |
|||
{ |
|||
public interface IRuleGrain : IDomainObjectGrain |
|||
{ |
|||
} |
|||
} |
|||
@ -1,89 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Domain.Apps.Entities.Rules.Commands; |
|||
using Squidex.Domain.Apps.Entities.Rules.Guards; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.Commands; |
|||
using Squidex.Infrastructure.Dispatching; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Rules |
|||
{ |
|||
public class RuleCommandMiddleware : ICommandMiddleware |
|||
{ |
|||
private readonly IAggregateHandler handler; |
|||
private readonly IAppProvider appProvider; |
|||
|
|||
public RuleCommandMiddleware(IAggregateHandler handler, IAppProvider appProvider) |
|||
{ |
|||
Guard.NotNull(handler, nameof(handler)); |
|||
Guard.NotNull(appProvider, nameof(appProvider)); |
|||
|
|||
this.handler = handler; |
|||
|
|||
this.appProvider = appProvider; |
|||
} |
|||
|
|||
protected Task On(CreateRule command, CommandContext context) |
|||
{ |
|||
return handler.CreateSyncedAsync<RuleDomainObject>(context, async r => |
|||
{ |
|||
await GuardRule.CanCreate(command, appProvider); |
|||
|
|||
r.Create(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(UpdateRule command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<RuleDomainObject>(context, async r => |
|||
{ |
|||
await GuardRule.CanUpdate(command, r.Snapshot.AppId.Id, appProvider); |
|||
|
|||
r.Update(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(EnableRule command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<RuleDomainObject>(context, r => |
|||
{ |
|||
GuardRule.CanEnable(command, r.Snapshot.RuleDef); |
|||
|
|||
r.Enable(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(DisableRule command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<RuleDomainObject>(context, r => |
|||
{ |
|||
GuardRule.CanDisable(command, r.Snapshot.RuleDef); |
|||
|
|||
r.Disable(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(DeleteRule command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<RuleDomainObject>(context, r => |
|||
{ |
|||
GuardRule.CanDelete(command); |
|||
|
|||
r.Delete(command); |
|||
}); |
|||
} |
|||
|
|||
public async Task HandleAsync(CommandContext context, Func<Task> next) |
|||
{ |
|||
await this.DispatchActionAsync(context.Command, context); |
|||
await next(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,86 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Squidex.Domain.Apps.Entities.Rules.Commands; |
|||
using Squidex.Domain.Apps.Entities.Rules.State; |
|||
using Squidex.Domain.Apps.Events; |
|||
using Squidex.Domain.Apps.Events.Rules; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.EventSourcing; |
|||
using Squidex.Infrastructure.Reflection; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Rules |
|||
{ |
|||
public sealed class RuleDomainObject : SquidexDomainObjectBase<RuleState> |
|||
{ |
|||
public void Create(CreateRule command) |
|||
{ |
|||
VerifyNotCreated(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new RuleCreated())); |
|||
} |
|||
|
|||
public void Update(UpdateRule command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new RuleUpdated())); |
|||
} |
|||
|
|||
public void Enable(EnableRule command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new RuleEnabled())); |
|||
} |
|||
|
|||
public void Disable(DisableRule command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new RuleDisabled())); |
|||
} |
|||
|
|||
public void Delete(DeleteRule command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new RuleDeleted())); |
|||
} |
|||
|
|||
private void RaiseEvent(AppEvent @event) |
|||
{ |
|||
if (@event.AppId == null) |
|||
{ |
|||
@event.AppId = Snapshot.AppId; |
|||
} |
|||
|
|||
RaiseEvent(Envelope.Create(@event)); |
|||
} |
|||
|
|||
private void VerifyNotCreated() |
|||
{ |
|||
if (Snapshot.RuleDef != null) |
|||
{ |
|||
throw new DomainException("Webhook has already been created."); |
|||
} |
|||
} |
|||
|
|||
private void VerifyCreatedAndNotDeleted() |
|||
{ |
|||
if (Snapshot.IsDeleted || Snapshot.RuleDef == null) |
|||
{ |
|||
throw new DomainException("Webhook has already been deleted or not created yet."); |
|||
} |
|||
} |
|||
|
|||
public override void ApplyEvent(Envelope<IEvent> @event) |
|||
{ |
|||
ApplySnapshot(Snapshot.Apply(@event)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,135 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Domain.Apps.Entities.Rules.Commands; |
|||
using Squidex.Domain.Apps.Entities.Rules.Guards; |
|||
using Squidex.Domain.Apps.Entities.Rules.State; |
|||
using Squidex.Domain.Apps.Events; |
|||
using Squidex.Domain.Apps.Events.Rules; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.Commands; |
|||
using Squidex.Infrastructure.EventSourcing; |
|||
using Squidex.Infrastructure.Reflection; |
|||
using Squidex.Infrastructure.States; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Rules |
|||
{ |
|||
public sealed class RuleGrain : DomainObjectGrain<RuleState>, IRuleGrain |
|||
{ |
|||
private readonly IAppProvider appProvider; |
|||
|
|||
public RuleGrain(IStore<Guid> store, IAppProvider appProvider) |
|||
: base(store) |
|||
{ |
|||
Guard.NotNull(appProvider, nameof(appProvider)); |
|||
|
|||
this.appProvider = appProvider; |
|||
} |
|||
|
|||
public override Task<object> ExecuteAsync(IAggregateCommand command) |
|||
{ |
|||
switch (command) |
|||
{ |
|||
case CreateRule createRule: |
|||
return CreateAsync(createRule, c => |
|||
{ |
|||
GuardRule.CanCreate(c, appProvider); |
|||
|
|||
Create(c); |
|||
}); |
|||
case UpdateRule updateRule: |
|||
return UpdateAsync(updateRule, c => |
|||
{ |
|||
GuardRule.CanUpdate(c, Snapshot.AppId.Id, appProvider); |
|||
|
|||
Update(c); |
|||
}); |
|||
case EnableRule enableRule: |
|||
return UpdateAsync(enableRule, c => |
|||
{ |
|||
GuardRule.CanEnable(c, Snapshot.RuleDef); |
|||
|
|||
Enable(c); |
|||
}); |
|||
case DisableRule disableRule: |
|||
return UpdateAsync(disableRule, c => |
|||
{ |
|||
GuardRule.CanDisable(c, Snapshot.RuleDef); |
|||
|
|||
Disable(c); |
|||
}); |
|||
case DeleteRule deleteRule: |
|||
return UpdateAsync(deleteRule, c => |
|||
{ |
|||
GuardRule.CanDelete(deleteRule); |
|||
|
|||
Delete(c); |
|||
}); |
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
public void Create(CreateRule command) |
|||
{ |
|||
RaiseEvent(SimpleMapper.Map(command, new RuleCreated())); |
|||
} |
|||
|
|||
public void Update(UpdateRule command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new RuleUpdated())); |
|||
} |
|||
|
|||
public void Enable(EnableRule command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new RuleEnabled())); |
|||
} |
|||
|
|||
public void Disable(DisableRule command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new RuleDisabled())); |
|||
} |
|||
|
|||
public void Delete(DeleteRule command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new RuleDeleted())); |
|||
} |
|||
|
|||
private void RaiseEvent(AppEvent @event) |
|||
{ |
|||
if (@event.AppId == null) |
|||
{ |
|||
@event.AppId = Snapshot.AppId; |
|||
} |
|||
|
|||
RaiseEvent(Envelope.Create(@event)); |
|||
} |
|||
|
|||
private void VerifyNotDeleted() |
|||
{ |
|||
if (Snapshot.IsDeleted || Snapshot.RuleDef == null) |
|||
{ |
|||
throw new DomainException("Webhook has already been deleted."); |
|||
} |
|||
} |
|||
|
|||
public override void ApplyEvent(Envelope<IEvent> @event) |
|||
{ |
|||
ApplySnapshot(Snapshot.Apply(@event)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Squidex.Infrastructure.Commands; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Schemas |
|||
{ |
|||
public interface ISchemaGrain : IDomainObjectGrain |
|||
{ |
|||
} |
|||
} |
|||
@ -1,194 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Domain.Apps.Entities.Schemas.Commands; |
|||
using Squidex.Domain.Apps.Entities.Schemas.Guards; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.Commands; |
|||
using Squidex.Infrastructure.Dispatching; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Schemas |
|||
{ |
|||
public class SchemaCommandMiddleware : ICommandMiddleware |
|||
{ |
|||
private readonly IAppProvider appProvider; |
|||
private readonly IAggregateHandler handler; |
|||
|
|||
public SchemaCommandMiddleware(IAggregateHandler handler, IAppProvider appProvider) |
|||
{ |
|||
Guard.NotNull(handler, nameof(handler)); |
|||
Guard.NotNull(appProvider, nameof(appProvider)); |
|||
|
|||
this.handler = handler; |
|||
|
|||
this.appProvider = appProvider; |
|||
} |
|||
|
|||
protected Task On(CreateSchema command, CommandContext context) |
|||
{ |
|||
return handler.CreateSyncedAsync<SchemaDomainObject>(context, async s => |
|||
{ |
|||
await GuardSchema.CanCreate(command, appProvider); |
|||
|
|||
s.Create(command); |
|||
|
|||
context.Complete(EntityCreatedResult.Create(command.SchemaId, s.Version)); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(AddField command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<SchemaDomainObject>(context, s => |
|||
{ |
|||
GuardSchemaField.CanAdd(s.Snapshot.SchemaDef, command); |
|||
|
|||
s.Add(command); |
|||
|
|||
context.Complete(EntityCreatedResult.Create(s.Snapshot.SchemaDef.FieldsById.Values.First(x => x.Name == command.Name).Id, s.Version)); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(DeleteField command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<SchemaDomainObject>(context, s => |
|||
{ |
|||
GuardSchemaField.CanDelete(s.Snapshot.SchemaDef, command); |
|||
|
|||
s.DeleteField(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(LockField command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<SchemaDomainObject>(context, s => |
|||
{ |
|||
GuardSchemaField.CanLock(s.Snapshot.SchemaDef, command); |
|||
|
|||
s.LockField(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(HideField command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<SchemaDomainObject>(context, s => |
|||
{ |
|||
GuardSchemaField.CanHide(s.Snapshot.SchemaDef, command); |
|||
|
|||
s.HideField(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(ShowField command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<SchemaDomainObject>(context, s => |
|||
{ |
|||
GuardSchemaField.CanShow(s.Snapshot.SchemaDef, command); |
|||
|
|||
s.ShowField(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(DisableField command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<SchemaDomainObject>(context, s => |
|||
{ |
|||
GuardSchemaField.CanDisable(s.Snapshot.SchemaDef, command); |
|||
|
|||
s.DisableField(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(EnableField command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<SchemaDomainObject>(context, s => |
|||
{ |
|||
GuardSchemaField.CanEnable(s.Snapshot.SchemaDef, command); |
|||
|
|||
s.EnableField(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(UpdateField command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<SchemaDomainObject>(context, s => |
|||
{ |
|||
GuardSchemaField.CanUpdate(s.Snapshot.SchemaDef, command); |
|||
|
|||
s.UpdateField(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(ReorderFields command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<SchemaDomainObject>(context, s => |
|||
{ |
|||
GuardSchema.CanReorder(s.Snapshot.SchemaDef, command); |
|||
|
|||
s.Reorder(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(UpdateSchema command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<SchemaDomainObject>(context, s => |
|||
{ |
|||
GuardSchema.CanUpdate(s.Snapshot.SchemaDef, command); |
|||
|
|||
s.Update(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(PublishSchema command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<SchemaDomainObject>(context, s => |
|||
{ |
|||
GuardSchema.CanPublish(s.Snapshot.SchemaDef, command); |
|||
|
|||
s.Publish(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(UnpublishSchema command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<SchemaDomainObject>(context, s => |
|||
{ |
|||
GuardSchema.CanUnpublish(s.Snapshot.SchemaDef, command); |
|||
|
|||
s.Unpublish(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(ConfigureScripts command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<SchemaDomainObject>(context, s => |
|||
{ |
|||
GuardSchema.CanConfigureScripts(s.Snapshot.SchemaDef, command); |
|||
|
|||
s.ConfigureScripts(command); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(DeleteSchema command, CommandContext context) |
|||
{ |
|||
return handler.UpdateSyncedAsync<SchemaDomainObject>(context, s => |
|||
{ |
|||
GuardSchema.CanDelete(s.Snapshot.SchemaDef, command); |
|||
|
|||
s.Delete(command); |
|||
}); |
|||
} |
|||
|
|||
public async Task HandleAsync(CommandContext context, Func<Task> next) |
|||
{ |
|||
await this.DispatchActionAsync(context.Command, context); |
|||
await next(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,229 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
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; |
|||
using Squidex.Domain.Apps.Events.Schemas; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.EventSourcing; |
|||
using Squidex.Infrastructure.Reflection; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Schemas |
|||
{ |
|||
public sealed class SchemaDomainObject : SquidexDomainObjectBase<SchemaState> |
|||
{ |
|||
private readonly FieldRegistry registry; |
|||
|
|||
public SchemaDomainObject(FieldRegistry registry) |
|||
{ |
|||
Guard.NotNull(registry, nameof(registry)); |
|||
|
|||
this.registry = registry; |
|||
} |
|||
|
|||
public SchemaDomainObject Create(CreateSchema command) |
|||
{ |
|||
VerifyNotCreated(); |
|||
|
|||
var @event = SimpleMapper.Map(command, new SchemaCreated { SchemaId = new NamedId<Guid>(command.SchemaId, command.Name) }); |
|||
|
|||
if (command.Fields != null) |
|||
{ |
|||
@event.Fields = new List<SchemaCreatedField>(); |
|||
|
|||
foreach (var commandField in command.Fields) |
|||
{ |
|||
var eventField = SimpleMapper.Map(commandField, new SchemaCreatedField()); |
|||
|
|||
@event.Fields.Add(eventField); |
|||
} |
|||
} |
|||
|
|||
RaiseEvent(@event); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public SchemaDomainObject Add(AddField command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new FieldAdded { FieldId = new NamedId<long>(Snapshot.TotalFields + 1, command.Name) })); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public SchemaDomainObject UpdateField(UpdateField command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(command, SimpleMapper.Map(command, new FieldUpdated())); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public SchemaDomainObject LockField(LockField command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(command, new FieldLocked()); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public SchemaDomainObject HideField(HideField command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(command, new FieldHidden()); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public SchemaDomainObject ShowField(ShowField command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(command, new FieldShown()); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public SchemaDomainObject DisableField(DisableField command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(command, new FieldDisabled()); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public SchemaDomainObject EnableField(EnableField command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(command, new FieldEnabled()); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public SchemaDomainObject DeleteField(DeleteField command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(command, new FieldDeleted()); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public SchemaDomainObject Reorder(ReorderFields command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new SchemaFieldsReordered())); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public SchemaDomainObject Publish(PublishSchema command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new SchemaPublished())); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public SchemaDomainObject Unpublish(UnpublishSchema command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new SchemaUnpublished())); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public SchemaDomainObject ConfigureScripts(ConfigureScripts command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new ScriptsConfigured())); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public SchemaDomainObject Delete(DeleteSchema command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new SchemaDeleted())); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public SchemaDomainObject Update(UpdateSchema command) |
|||
{ |
|||
VerifyCreatedAndNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new SchemaUpdated())); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
private void RaiseEvent(FieldCommand fieldCommand, FieldEvent @event) |
|||
{ |
|||
SimpleMapper.Map(fieldCommand, @event); |
|||
|
|||
if (Snapshot.SchemaDef.FieldsById.TryGetValue(fieldCommand.FieldId, out var field)) |
|||
{ |
|||
@event.FieldId = new NamedId<long>(field.Id, field.Name); |
|||
} |
|||
|
|||
RaiseEvent(@event); |
|||
} |
|||
|
|||
private void RaiseEvent(SchemaEvent @event) |
|||
{ |
|||
if (@event.SchemaId == null) |
|||
{ |
|||
@event.SchemaId = new NamedId<Guid>(Snapshot.Id, Snapshot.Name); |
|||
} |
|||
|
|||
if (@event.AppId == null) |
|||
{ |
|||
@event.AppId = Snapshot.AppId; |
|||
} |
|||
|
|||
RaiseEvent(Envelope.Create(@event)); |
|||
} |
|||
|
|||
private void VerifyNotCreated() |
|||
{ |
|||
if (Snapshot.SchemaDef != null) |
|||
{ |
|||
throw new DomainException("Schema has already been created."); |
|||
} |
|||
} |
|||
|
|||
private void VerifyCreatedAndNotDeleted() |
|||
{ |
|||
if (Snapshot.IsDeleted || Snapshot.SchemaDef == null) |
|||
{ |
|||
throw new DomainException("Schema has already been deleted or not created yet."); |
|||
} |
|||
} |
|||
|
|||
public override void ApplyEvent(Envelope<IEvent> @event) |
|||
{ |
|||
ApplySnapshot(Snapshot.Apply(@event, registry)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,330 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Domain.Apps.Core.Schemas; |
|||
using Squidex.Domain.Apps.Entities.Schemas.Commands; |
|||
using Squidex.Domain.Apps.Entities.Schemas.Guards; |
|||
using Squidex.Domain.Apps.Entities.Schemas.State; |
|||
using Squidex.Domain.Apps.Events; |
|||
using Squidex.Domain.Apps.Events.Schemas; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.Commands; |
|||
using Squidex.Infrastructure.EventSourcing; |
|||
using Squidex.Infrastructure.Reflection; |
|||
using Squidex.Infrastructure.States; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Schemas |
|||
{ |
|||
public sealed class SchemaGrain : DomainObjectGrain<SchemaState>, ISchemaGrain |
|||
{ |
|||
private readonly IAppProvider appProvider; |
|||
private readonly FieldRegistry registry; |
|||
|
|||
public SchemaGrain(IStore<Guid> store, IAppProvider appProvider, FieldRegistry registry) |
|||
: base(store) |
|||
{ |
|||
Guard.NotNull(appProvider, nameof(appProvider)); |
|||
Guard.NotNull(registry, nameof(registry)); |
|||
|
|||
this.appProvider = appProvider; |
|||
|
|||
this.registry = registry; |
|||
} |
|||
|
|||
public override Task<object> ExecuteAsync(IAggregateCommand command) |
|||
{ |
|||
switch (command) |
|||
{ |
|||
case CreateSchema createSchema: |
|||
return CreateAsync(createSchema, async c => |
|||
{ |
|||
await GuardSchema.CanCreate(c, appProvider); |
|||
|
|||
Create(c); |
|||
}); |
|||
|
|||
case AddField addField: |
|||
return UpdateReturnAsync(addField, c => |
|||
{ |
|||
GuardSchemaField.CanAdd(Snapshot.SchemaDef, c); |
|||
|
|||
Add(c); |
|||
|
|||
return EntityCreatedResult.Create(Snapshot.SchemaDef.FieldsById.Values.First(x => x.Name == addField.Name).Id, Version); |
|||
}); |
|||
|
|||
case DeleteField deleteField: |
|||
return UpdateAsync(deleteField, c => |
|||
{ |
|||
GuardSchemaField.CanDelete(Snapshot.SchemaDef, deleteField); |
|||
|
|||
DeleteField(c); |
|||
}); |
|||
|
|||
case LockField lockField: |
|||
return UpdateAsync(lockField, c => |
|||
{ |
|||
GuardSchemaField.CanLock(Snapshot.SchemaDef, lockField); |
|||
|
|||
LockField(c); |
|||
}); |
|||
|
|||
case HideField hideField: |
|||
return UpdateAsync(hideField, c => |
|||
{ |
|||
GuardSchemaField.CanHide(Snapshot.SchemaDef, c); |
|||
|
|||
HideField(c); |
|||
}); |
|||
|
|||
case ShowField showField: |
|||
return UpdateAsync(showField, c => |
|||
{ |
|||
GuardSchemaField.CanShow(Snapshot.SchemaDef, c); |
|||
|
|||
ShowField(c); |
|||
}); |
|||
|
|||
case DisableField disableField: |
|||
return UpdateAsync(disableField, c => |
|||
{ |
|||
GuardSchemaField.CanDisable(Snapshot.SchemaDef, c); |
|||
|
|||
DisableField(c); |
|||
}); |
|||
|
|||
case EnableField enableField: |
|||
return UpdateAsync(enableField, c => |
|||
{ |
|||
GuardSchemaField.CanEnable(Snapshot.SchemaDef, c); |
|||
|
|||
EnableField(c); |
|||
}); |
|||
|
|||
case UpdateField updateField: |
|||
return UpdateAsync(updateField, c => |
|||
{ |
|||
GuardSchemaField.CanUpdate(Snapshot.SchemaDef, c); |
|||
|
|||
UpdateField(c); |
|||
}); |
|||
|
|||
case ReorderFields reorderFields: |
|||
return UpdateAsync(reorderFields, c => |
|||
{ |
|||
GuardSchema.CanReorder(Snapshot.SchemaDef, c); |
|||
|
|||
Reorder(c); |
|||
}); |
|||
|
|||
case UpdateSchema updateSchema: |
|||
return UpdateAsync(updateSchema, c => |
|||
{ |
|||
GuardSchema.CanUpdate(Snapshot.SchemaDef, c); |
|||
|
|||
Update(c); |
|||
}); |
|||
|
|||
case PublishSchema publishSchema: |
|||
return UpdateAsync(publishSchema, c => |
|||
{ |
|||
GuardSchema.CanPublish(Snapshot.SchemaDef, c); |
|||
|
|||
Publish(c); |
|||
}); |
|||
|
|||
case UnpublishSchema unpublishSchema: |
|||
return UpdateAsync(unpublishSchema, c => |
|||
{ |
|||
GuardSchema.CanUnpublish(Snapshot.SchemaDef, c); |
|||
|
|||
Unpublish(c); |
|||
}); |
|||
|
|||
case ConfigureScripts configureScripts: |
|||
return UpdateAsync(configureScripts, c => |
|||
{ |
|||
GuardSchema.CanConfigureScripts(Snapshot.SchemaDef, c); |
|||
|
|||
ConfigureScripts(c); |
|||
}); |
|||
|
|||
case DeleteSchema deleteSchema: |
|||
return UpdateAsync(deleteSchema, c => |
|||
{ |
|||
GuardSchema.CanDelete(Snapshot.SchemaDef, c); |
|||
|
|||
Delete(c); |
|||
}); |
|||
|
|||
default: |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
|
|||
public void Create(CreateSchema command) |
|||
{ |
|||
var @event = SimpleMapper.Map(command, new SchemaCreated { SchemaId = new NamedId<Guid>(command.SchemaId, command.Name) }); |
|||
|
|||
if (command.Fields != null) |
|||
{ |
|||
@event.Fields = new List<SchemaCreatedField>(); |
|||
|
|||
foreach (var commandField in command.Fields) |
|||
{ |
|||
var eventField = SimpleMapper.Map(commandField, new SchemaCreatedField()); |
|||
|
|||
@event.Fields.Add(eventField); |
|||
} |
|||
} |
|||
|
|||
RaiseEvent(@event); |
|||
} |
|||
|
|||
public void Add(AddField command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new FieldAdded { FieldId = new NamedId<long>(Snapshot.TotalFields + 1, command.Name) })); |
|||
} |
|||
|
|||
public void UpdateField(UpdateField command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(command, SimpleMapper.Map(command, new FieldUpdated())); |
|||
} |
|||
|
|||
public void LockField(LockField command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(command, new FieldLocked()); |
|||
} |
|||
|
|||
public void HideField(HideField command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(command, new FieldHidden()); |
|||
} |
|||
|
|||
public void ShowField(ShowField command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(command, new FieldShown()); |
|||
} |
|||
|
|||
public void DisableField(DisableField command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(command, new FieldDisabled()); |
|||
} |
|||
|
|||
public void EnableField(EnableField command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(command, new FieldEnabled()); |
|||
} |
|||
|
|||
public void DeleteField(DeleteField command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(command, new FieldDeleted()); |
|||
} |
|||
|
|||
public void Reorder(ReorderFields command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new SchemaFieldsReordered())); |
|||
} |
|||
|
|||
public void Publish(PublishSchema command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new SchemaPublished())); |
|||
} |
|||
|
|||
public void Unpublish(UnpublishSchema command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new SchemaUnpublished())); |
|||
} |
|||
|
|||
public void ConfigureScripts(ConfigureScripts command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new ScriptsConfigured())); |
|||
} |
|||
|
|||
public void Delete(DeleteSchema command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new SchemaDeleted())); |
|||
} |
|||
|
|||
public void Update(UpdateSchema command) |
|||
{ |
|||
VerifyNotDeleted(); |
|||
|
|||
RaiseEvent(SimpleMapper.Map(command, new SchemaUpdated())); |
|||
} |
|||
|
|||
private void RaiseEvent(FieldCommand fieldCommand, FieldEvent @event) |
|||
{ |
|||
SimpleMapper.Map(fieldCommand, @event); |
|||
|
|||
if (Snapshot.SchemaDef.FieldsById.TryGetValue(fieldCommand.FieldId, out var field)) |
|||
{ |
|||
@event.FieldId = new NamedId<long>(field.Id, field.Name); |
|||
} |
|||
|
|||
RaiseEvent(@event); |
|||
} |
|||
|
|||
private void RaiseEvent(SchemaEvent @event) |
|||
{ |
|||
if (@event.SchemaId == null) |
|||
{ |
|||
@event.SchemaId = new NamedId<Guid>(Snapshot.Id, Snapshot.Name); |
|||
} |
|||
|
|||
if (@event.AppId == null) |
|||
{ |
|||
@event.AppId = Snapshot.AppId; |
|||
} |
|||
|
|||
RaiseEvent(Envelope.Create(@event)); |
|||
} |
|||
|
|||
private void VerifyNotDeleted() |
|||
{ |
|||
if (Snapshot.IsDeleted) |
|||
{ |
|||
throw new DomainException("Schema has already been deleted."); |
|||
} |
|||
} |
|||
|
|||
public override void ApplyEvent(Envelope<IEvent> @event) |
|||
{ |
|||
ApplySnapshot(Snapshot.Apply(@event, registry)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,204 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Orleans; |
|||
using Squidex.Infrastructure.EventSourcing; |
|||
using Squidex.Infrastructure.Orleans; |
|||
using Squidex.Infrastructure.States; |
|||
|
|||
namespace Squidex.Infrastructure.Commands |
|||
{ |
|||
public abstract class DomainObjectGrain<T> : Grain, IDomainObjectGrain where T : IDomainState, new() |
|||
{ |
|||
private readonly List<Envelope<IEvent>> uncomittedEvents = new List<Envelope<IEvent>>(); |
|||
private readonly IStore<Guid> store; |
|||
private T snapshot = new T { Version = EtagVersion.Empty }; |
|||
private IPersistence<T> persistence; |
|||
|
|||
public long Version |
|||
{ |
|||
get { return snapshot.Version; } |
|||
} |
|||
|
|||
public long NewVersion |
|||
{ |
|||
get { return snapshot.Version + uncomittedEvents.Count; } |
|||
} |
|||
|
|||
protected T Snapshot |
|||
{ |
|||
get { return snapshot; } |
|||
} |
|||
|
|||
protected DomainObjectGrain(IStore<Guid> store) |
|||
{ |
|||
Guard.NotNull(store, nameof(store)); |
|||
|
|||
this.store = store; |
|||
} |
|||
|
|||
public override Task OnActivateAsync() |
|||
{ |
|||
persistence = store.WithSnapshotsAndEventSourcing<T, Guid>(GetType(), this.GetPrimaryKey(), ApplySnapshot, ApplyEvent); |
|||
|
|||
return persistence.ReadAsync(); |
|||
} |
|||
|
|||
public void RaiseEvent(IEvent @event) |
|||
{ |
|||
RaiseEvent(Envelope.Create(@event)); |
|||
} |
|||
|
|||
public virtual void RaiseEvent(Envelope<IEvent> @event) |
|||
{ |
|||
Guard.NotNull(@event, nameof(@event)); |
|||
|
|||
@event.SetAggregateId(this.GetPrimaryKey()); |
|||
|
|||
ApplyEvent(@event); |
|||
|
|||
uncomittedEvents.Add(@event); |
|||
} |
|||
|
|||
public IReadOnlyList<Envelope<IEvent>> GetUncomittedEvents() |
|||
{ |
|||
return uncomittedEvents; |
|||
} |
|||
|
|||
public void ClearUncommittedEvents() |
|||
{ |
|||
uncomittedEvents.Clear(); |
|||
} |
|||
|
|||
public virtual void ApplySnapshot(T newSnapshot) |
|||
{ |
|||
snapshot = newSnapshot; |
|||
} |
|||
|
|||
public virtual void ApplyEvent(Envelope<IEvent> @event) |
|||
{ |
|||
} |
|||
|
|||
public Task WriteSnapshotAsync() |
|||
{ |
|||
snapshot.Version = persistence.Version; |
|||
|
|||
return persistence.WriteSnapshotAsync(snapshot); |
|||
} |
|||
|
|||
protected Task<object> CreateReturnAsync<TCommand>(TCommand command, Func<TCommand, Task<object>> handler) where TCommand : class, IAggregateCommand |
|||
{ |
|||
return InvokeAsync(command, handler, false); |
|||
} |
|||
|
|||
protected Task<object> CreateReturnAsync<TCommand>(TCommand command, Func<TCommand, object> handler) where TCommand : class, IAggregateCommand |
|||
{ |
|||
return InvokeAsync(command, x => Task.FromResult(handler(x)), false); |
|||
} |
|||
|
|||
protected Task<object> CreateAsync<TCommand>(TCommand command, Func<TCommand, Task> handler) where TCommand : class, IAggregateCommand |
|||
{ |
|||
return InvokeAsync(command, x => handler(x).ContinueWith<object>(t => null), false); |
|||
} |
|||
|
|||
protected Task<object> CreateAsync<TCommand>(TCommand command, Action<TCommand> handler) where TCommand : class, IAggregateCommand |
|||
{ |
|||
return InvokeAsync(command, x => { handler(x); return Task.FromResult<object>(null); }, false); |
|||
} |
|||
|
|||
protected Task<object> UpdateReturnAsync<TCommand>(TCommand command, Func<TCommand, Task<object>> handler) where TCommand : class, IAggregateCommand |
|||
{ |
|||
return InvokeAsync(command, handler, true); |
|||
} |
|||
|
|||
protected Task<object> UpdateReturnAsync<TCommand>(TCommand command, Func<TCommand, object> handler) where TCommand : class, IAggregateCommand |
|||
{ |
|||
return InvokeAsync(command, x => Task.FromResult(handler(x)), true); |
|||
} |
|||
|
|||
protected Task<object> UpdateAsync<TCommand>(TCommand command, Func<TCommand, Task> handler) where TCommand : class, IAggregateCommand |
|||
{ |
|||
return InvokeAsync(command, x => handler(x).ContinueWith<object>(t => null), true); |
|||
} |
|||
|
|||
protected Task<object> UpdateAsync<TCommand>(TCommand command, Action<TCommand> handler) where TCommand : class, IAggregateCommand |
|||
{ |
|||
return InvokeAsync(command, x => { handler(x); return Task.FromResult<object>(null); }, true); |
|||
} |
|||
|
|||
private async Task<object> InvokeAsync<TCommand>(TCommand command, Func<TCommand, Task<object>> handler, bool isUpdate) where TCommand : class, IAggregateCommand |
|||
{ |
|||
Guard.NotNull(command, nameof(command)); |
|||
|
|||
if (command.ExpectedVersion != EtagVersion.Any && command.ExpectedVersion != Version) |
|||
{ |
|||
throw new DomainObjectVersionException(this.GetPrimaryKey().ToString(), GetType(), Version, command.ExpectedVersion); |
|||
} |
|||
|
|||
if (isUpdate && Version < 0) |
|||
{ |
|||
DeactivateOnIdle(); |
|||
|
|||
throw new DomainObjectNotFoundException(this.GetPrimaryKey().ToString(), GetType()); |
|||
} |
|||
else if (!isUpdate && Version >= 0) |
|||
{ |
|||
throw new DomainException("Object has already been created."); |
|||
} |
|||
|
|||
var previousSnapshot = snapshot; |
|||
try |
|||
{ |
|||
var result = await handler(command); |
|||
|
|||
var events = uncomittedEvents.ToArray(); |
|||
|
|||
if (events.Length > 0) |
|||
{ |
|||
snapshot.Version = NewVersion; |
|||
|
|||
await persistence.WriteEventsAsync(events); |
|||
await persistence.WriteSnapshotAsync(snapshot); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
if (isUpdate) |
|||
{ |
|||
result = new EntitySavedResult(Version); |
|||
} |
|||
else |
|||
{ |
|||
result = EntityCreatedResult.Create(this.GetPrimaryKey(), Version); |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
catch |
|||
{ |
|||
snapshot = previousSnapshot; |
|||
|
|||
throw; |
|||
} |
|||
finally |
|||
{ |
|||
uncomittedEvents.Clear(); |
|||
} |
|||
} |
|||
|
|||
public Task<J<object>> ExecuteAsync(J<IAggregateCommand> command) |
|||
{ |
|||
return ExecuteAsync(command.Value).ContinueWith(x => x.Result.AsJ()); |
|||
} |
|||
|
|||
public abstract Task<object> ExecuteAsync(IAggregateCommand command); |
|||
} |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Orleans; |
|||
|
|||
namespace Squidex.Infrastructure.Commands |
|||
{ |
|||
public class GrainCommandMiddleware<TCommand, TGrain> : ICommandMiddleware where TCommand : IAggregateCommand where TGrain : IDomainObjectGrain |
|||
{ |
|||
private readonly IGrainFactory grainFactory; |
|||
|
|||
public GrainCommandMiddleware(IGrainFactory grainFactory) |
|||
{ |
|||
Guard.NotNull(grainFactory, nameof(grainFactory)); |
|||
|
|||
this.grainFactory = grainFactory; |
|||
} |
|||
|
|||
public async virtual Task HandleAsync(CommandContext context, Func<Task> next) |
|||
{ |
|||
if (context.Command is TCommand typedCommand) |
|||
{ |
|||
var result = await ExecuteCommandAsync(typedCommand); |
|||
|
|||
context.Complete(result); |
|||
} |
|||
|
|||
await next(); |
|||
} |
|||
|
|||
protected async Task<object> ExecuteCommandAsync(TCommand typedCommand) |
|||
{ |
|||
var grain = grainFactory.GetGrain<TGrain>(typedCommand.AggregateId); |
|||
|
|||
var result = await grain.ExecuteAsync(typedCommand); |
|||
|
|||
return result.Value; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading.Tasks; |
|||
using Orleans; |
|||
using Squidex.Infrastructure.Orleans; |
|||
|
|||
namespace Squidex.Infrastructure.Commands |
|||
{ |
|||
public interface IDomainObjectGrain : IGrainWithGuidKey |
|||
{ |
|||
Task WriteSnapshotAsync(); |
|||
|
|||
Task<J<object>> ExecuteAsync(J<IAggregateCommand> command); |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Newtonsoft.Json; |
|||
|
|||
#pragma warning disable SA1401 // Fields must be private
|
|||
|
|||
namespace Squidex.Infrastructure.Orleans |
|||
{ |
|||
public static class J |
|||
{ |
|||
public static JsonSerializer Serializer = new JsonSerializer(); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
namespace Squidex.Infrastructure.Orleans |
|||
{ |
|||
public static class JExtensions |
|||
{ |
|||
public static J<T> AsJ<T>(this T value) |
|||
{ |
|||
return new J<T>(value); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,85 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using Newtonsoft.Json; |
|||
using Orleans.CodeGeneration; |
|||
using Orleans.Serialization; |
|||
|
|||
namespace Squidex.Infrastructure.Orleans |
|||
{ |
|||
public struct J<T> |
|||
{ |
|||
private readonly T value; |
|||
|
|||
public T Value |
|||
{ |
|||
get { return value; } |
|||
} |
|||
|
|||
[JsonConstructor] |
|||
public J(T value) |
|||
{ |
|||
this.value = value; |
|||
} |
|||
|
|||
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); |
|||
} |
|||
|
|||
[CopierMethod] |
|||
private static object Copy(object input, ICopyContext context) |
|||
{ |
|||
return input; |
|||
} |
|||
|
|||
[SerializerMethod] |
|||
private static void Serialize(object input, ISerializationContext context, Type expected) |
|||
{ |
|||
var stream = new MemoryStream(); |
|||
|
|||
using (var writer = new JsonTextWriter(new StreamWriter(stream))) |
|||
{ |
|||
J.Serializer.Serialize(writer, input); |
|||
|
|||
writer.Flush(); |
|||
} |
|||
|
|||
var outBytes = stream.ToArray(); |
|||
|
|||
context.StreamWriter.Write(outBytes.Length); |
|||
context.StreamWriter.Write(outBytes); |
|||
} |
|||
|
|||
[DeserializerMethod] |
|||
private static object Deserialize(Type expected, IDeserializationContext context) |
|||
{ |
|||
var outLength = context.StreamReader.ReadInt(); |
|||
var outBytes = context.StreamReader.ReadBytes(outLength); |
|||
|
|||
var stream = new MemoryStream(outBytes); |
|||
|
|||
using (var reader = new JsonTextReader(new StreamReader(stream))) |
|||
{ |
|||
return J.Serializer.Deserialize(reader, expected); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue