mirror of https://github.com/Squidex/squidex.git
52 changed files with 1050 additions and 114 deletions
@ -0,0 +1,58 @@ |
|||
// ==========================================================================
|
|||
// InfrastructureDependencies.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Net; |
|||
using Autofac; |
|||
using EventStore.ClientAPI; |
|||
using EventStore.ClientAPI.SystemData; |
|||
using PinkParrot.Infrastructure.CQRS.Autofac; |
|||
using PinkParrot.Infrastructure.CQRS.Commands; |
|||
using PinkParrot.Infrastructure.CQRS.EventStore; |
|||
|
|||
namespace PinkParrot.Configurations |
|||
{ |
|||
public class InfrastructureDependencies : Module |
|||
{ |
|||
protected override void Load(ContainerBuilder builder) |
|||
{ |
|||
var eventStore = |
|||
EventStoreConnection.Create( |
|||
ConnectionSettings.Create() |
|||
.UseConsoleLogger() |
|||
.UseDebugLogger() |
|||
.KeepReconnecting() |
|||
.KeepRetrying(), |
|||
new IPEndPoint(IPAddress.Loopback, 1113)); |
|||
|
|||
eventStore.ConnectAsync().Wait(); |
|||
|
|||
builder.RegisterInstance(new UserCredentials("admin", "changeit")) |
|||
.SingleInstance(); |
|||
|
|||
builder.RegisterType<AutofacDomainObjectFactory>() |
|||
.As<IDomainObjectFactory>() |
|||
.SingleInstance(); |
|||
|
|||
builder.RegisterType<DefaultNameResolver>() |
|||
.As<IStreamNameResolver>() |
|||
.SingleInstance(); |
|||
|
|||
builder.RegisterInstance(eventStore) |
|||
.As<IEventStoreConnection>() |
|||
.SingleInstance(); |
|||
|
|||
builder.RegisterType<EventStoreDomainObjectRepository>() |
|||
.As<IDomainObjectRepository>() |
|||
.SingleInstance(); |
|||
|
|||
builder.RegisterType<InMemoryCommandBus>() |
|||
.As<ICommandBus>() |
|||
.SingleInstance(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
// ==========================================================================
|
|||
// ReadDependencies.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using Autofac; |
|||
using PinkParrot.Read.Services; |
|||
using PinkParrot.Read.Services.Implementations; |
|||
|
|||
namespace PinkParrot.Configurations |
|||
{ |
|||
public sealed class ReadDependencies : Module |
|||
{ |
|||
protected override void Load(ContainerBuilder builder) |
|||
{ |
|||
builder.RegisterType<SchemaProvider>() |
|||
.As<ISchemaProvider>() |
|||
.SingleInstance(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
// ==========================================================================
|
|||
// Serializers.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Reflection; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Newtonsoft.Json; |
|||
using Newtonsoft.Json.Serialization; |
|||
using PinkParrot.Core.Schema; |
|||
using PinkParrot.Infrastructure.CQRS.EventStore; |
|||
using PinkParrot.Infrastructure.Json; |
|||
|
|||
namespace PinkParrot.Configurations |
|||
{ |
|||
public static class Serializers |
|||
{ |
|||
private static JsonSerializerSettings ConfigureJson(JsonSerializerSettings settings) |
|||
{ |
|||
settings.Binder = new TypeNameSerializationBinder().Map(typeof(ModelSchema).GetTypeInfo().Assembly); |
|||
settings.ContractResolver = new CamelCasePropertyNamesContractResolver(); |
|||
settings.Converters.Add(new PropertiesBagConverter()); |
|||
settings.DateFormatHandling = DateFormatHandling.IsoDateFormat; |
|||
settings.DateParseHandling = DateParseHandling.DateTime; |
|||
settings.TypeNameHandling = TypeNameHandling.Auto; |
|||
|
|||
return settings; |
|||
} |
|||
|
|||
private static JsonSerializerSettings CreateSettings() |
|||
{ |
|||
return ConfigureJson(new JsonSerializerSettings()); |
|||
} |
|||
|
|||
public static void AddEventFormatter(this IServiceCollection services) |
|||
{ |
|||
var fieldFactory = |
|||
new ModelFieldFactory() |
|||
.AddFactory<NumberFieldProperties>(id => new NumberField(id)); |
|||
|
|||
services.AddSingleton(t => CreateSettings()); |
|||
services.AddSingleton(fieldFactory); |
|||
services.AddSingleton<EventStoreParser>(); |
|||
} |
|||
|
|||
public static void AddAppSerializers(this IMvcBuilder mvc) |
|||
{ |
|||
mvc.AddJsonOptions(options => |
|||
{ |
|||
ConfigureJson(options.SerializerSettings); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
// ==========================================================================
|
|||
// Swagger.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.IO; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.PlatformAbstractions; |
|||
using PinkParrot.Pipeline.Swagger; |
|||
using Swashbuckle.Swagger.Model; |
|||
|
|||
namespace PinkParrot.Configurations |
|||
{ |
|||
public static class Swagger |
|||
{ |
|||
public static void AddAppSwagger(this IServiceCollection services) |
|||
{ |
|||
services.AddSwaggerGen(options => |
|||
{ |
|||
options.SingleApiVersion(new Info { Title = "Pink Parrot", Version = "v1" }); |
|||
options.OperationFilter<HidePropertyFilter>(); |
|||
options.OperationFilter<CamelCaseParameterFilter>(); |
|||
options.SchemaFilter<HidePropertyFilter>(); |
|||
options.SchemaFilter<RemoveReadonlyFilter>(); |
|||
options.IncludeXmlComments(GetXmlCommentsPath(PlatformServices.Default.Application)); |
|||
}); |
|||
} |
|||
|
|||
public static void UseAppSwagger(this IApplicationBuilder app) |
|||
{ |
|||
app.UseSwagger(); |
|||
app.UseSwaggerUi(); |
|||
} |
|||
|
|||
private static string GetXmlCommentsPath(ApplicationEnvironment appEnvironment) |
|||
{ |
|||
return Path.Combine(appEnvironment.ApplicationBasePath, "PinkParrot.xml"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
// ==========================================================================
|
|||
// WriteDependencies.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using Autofac; |
|||
using PinkParrot.Infrastructure.CQRS.Commands; |
|||
using PinkParrot.Write.Schema; |
|||
|
|||
namespace PinkParrot.Configurations |
|||
{ |
|||
public class WriteDependencies : Module |
|||
{ |
|||
protected override void Load(ContainerBuilder builder) |
|||
{ |
|||
builder.RegisterType<ModelSchemaCommandHandler>() |
|||
.As<ICommandHandler>() |
|||
.SingleInstance(); |
|||
|
|||
builder.RegisterType<ModelSchemaDomainObject>() |
|||
.InstancePerDependency(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
// ==========================================================================
|
|||
// EntityCreated.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace PinkParrot.Modules.Api |
|||
{ |
|||
public class EntityCreated |
|||
{ |
|||
[Required] |
|||
public Guid Id { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
// ==========================================================================
|
|||
// CamelCaseParameterFilter.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using Swashbuckle.Swagger.Model; |
|||
using Swashbuckle.SwaggerGen.Generator; |
|||
|
|||
namespace PinkParrot.Pipeline.Swagger |
|||
{ |
|||
public sealed class CamelCaseParameterFilter : IOperationFilter |
|||
{ |
|||
public void Apply(Operation operation, OperationFilterContext context) |
|||
{ |
|||
if (operation.Parameters == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
foreach (var parameter in operation.Parameters) |
|||
{ |
|||
parameter.Name = char.ToLowerInvariant(parameter.Name[0]) + parameter.Name.Substring(1); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
// ==========================================================================
|
|||
// HidePropertyFilter.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; |
|||
using PinkParrot.Infrastructure; |
|||
using Swashbuckle.Swagger.Model; |
|||
using Swashbuckle.SwaggerGen.Generator; |
|||
|
|||
namespace PinkParrot.Pipeline.Swagger |
|||
{ |
|||
public class HidePropertyFilter : ISchemaFilter, IOperationFilter |
|||
{ |
|||
public void Apply(Schema model, SchemaFilterContext context) |
|||
{ |
|||
foreach (var property in context.JsonContract.UnderlyingType.GetProperties()) |
|||
{ |
|||
var attribute = property.GetCustomAttribute<HideAttribute>(); |
|||
|
|||
if (attribute != null) |
|||
{ |
|||
model.Properties.Remove(property.Name); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public void Apply(Operation operation, OperationFilterContext context) |
|||
{ |
|||
if (context?.ApiDescription.ParameterDescriptions == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (operation.Parameters == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
foreach (var parameterDescription in context.ApiDescription.ParameterDescriptions) |
|||
{ |
|||
var metadata = parameterDescription.ModelMetadata as DefaultModelMetadata; |
|||
|
|||
var hasAttribute = metadata?.Attributes?.Attributes.OfType<HideAttribute>().Any(); |
|||
|
|||
if (hasAttribute != true) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
var parameter = operation.Parameters.FirstOrDefault(p => p.Name == parameterDescription.Name); |
|||
|
|||
if (parameter != null) |
|||
{ |
|||
operation.Parameters.Remove(parameter); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
// ==========================================================================
|
|||
// RemoveReadonlyFilter.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using Swashbuckle.Swagger.Model; |
|||
using Swashbuckle.SwaggerGen.Generator; |
|||
|
|||
namespace PinkParrot.Pipeline.Swagger |
|||
{ |
|||
public class RemoveReadonlyFilter : ISchemaFilter |
|||
{ |
|||
public void Apply(Schema model, SchemaFilterContext context) |
|||
{ |
|||
Apply(model); |
|||
} |
|||
|
|||
private static void Apply(Schema model) |
|||
{ |
|||
model.ReadOnly = null; |
|||
|
|||
if (model.Properties == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
foreach (var property in model.Properties) |
|||
{ |
|||
Apply(property.Value); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,13 +1,17 @@ |
|||
// ==========================================================================
|
|||
// GetEventStoreDomainObjectRepository.cs
|
|||
// IAggregateCommand.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
namespace PinkParrot.Infrastructure.CQRS.GetEventStore |
|||
|
|||
using System; |
|||
|
|||
namespace PinkParrot.Infrastructure.CQRS.Commands |
|||
{ |
|||
public class GetEventStoreDomainObjectRepository |
|||
public interface IAggregateCommand : ICommand |
|||
{ |
|||
Guid AggregateId { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
// ==========================================================================
|
|||
// DefaultNameResolver.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Globalization; |
|||
|
|||
namespace PinkParrot.Infrastructure.CQRS.EventStore |
|||
{ |
|||
public sealed class DefaultNameResolver : IStreamNameResolver |
|||
{ |
|||
private readonly string prefix; |
|||
|
|||
public DefaultNameResolver() |
|||
: this(string.Empty) |
|||
{ |
|||
} |
|||
|
|||
public DefaultNameResolver(string prefix) |
|||
{ |
|||
this.prefix = prefix; |
|||
} |
|||
|
|||
public string GetStreamName(Type aggregateType, Guid id) |
|||
{ |
|||
return string.Format(CultureInfo.InvariantCulture, "{0}{1}-{2}", prefix, char.ToLower(aggregateType.Name[0]) + aggregateType.Name.Substring(1), id); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,153 @@ |
|||
// ==========================================================================
|
|||
// GetEventStoreDomainObjectRepository.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using EventStore.ClientAPI; |
|||
using EventStore.ClientAPI.SystemData; |
|||
using PinkParrot.Infrastructure.CQRS.Commands; |
|||
// ReSharper disable RedundantAssignment
|
|||
|
|||
// ReSharper disable ConvertIfStatementToSwitchStatement
|
|||
// ReSharper disable TooWideLocalVariableScope
|
|||
|
|||
namespace PinkParrot.Infrastructure.CQRS.EventStore |
|||
{ |
|||
public sealed class EventStoreDomainObjectRepository : IDomainObjectRepository |
|||
{ |
|||
private const int WritePageSize = 500; |
|||
private const int ReadPageSize = 500; |
|||
private readonly IEventStoreConnection connection; |
|||
private readonly IStreamNameResolver nameResolver; |
|||
private readonly IDomainObjectFactory factory; |
|||
private readonly UserCredentials credentials; |
|||
private readonly EventStoreParser formatter; |
|||
|
|||
public EventStoreDomainObjectRepository( |
|||
IDomainObjectFactory factory, |
|||
IStreamNameResolver nameResolver, |
|||
IEventStoreConnection connection, |
|||
UserCredentials credentials, |
|||
EventStoreParser formatter) |
|||
{ |
|||
Guard.NotNull(factory, nameof(factory)); |
|||
Guard.NotNull(formatter, nameof(formatter)); |
|||
Guard.NotNull(connection, nameof(connection)); |
|||
Guard.NotNull(credentials, nameof(credentials)); |
|||
Guard.NotNull(nameResolver, nameof(nameResolver)); |
|||
|
|||
this.factory = factory; |
|||
this.formatter = formatter; |
|||
this.connection = connection; |
|||
this.credentials = credentials; |
|||
this.nameResolver = nameResolver; |
|||
} |
|||
|
|||
public async Task<TDomainObject> GetByIdAsync<TDomainObject>(Guid id, int version = 0) where TDomainObject : class, IAggregate |
|||
{ |
|||
Guard.GreaterThan(version, 0, nameof(version)); |
|||
|
|||
var streamName = nameResolver.GetStreamName(typeof(TDomainObject), id); |
|||
|
|||
var domainObject = (TDomainObject)factory.CreateNew(typeof(TDomainObject), id); |
|||
|
|||
var sliceStart = 0; |
|||
var sliceCount = 0; |
|||
|
|||
StreamEventsSlice currentSlice; |
|||
do |
|||
{ |
|||
sliceCount = sliceStart + ReadPageSize <= version ? ReadPageSize : version - sliceStart + 1; |
|||
|
|||
currentSlice = await connection.ReadStreamEventsForwardAsync(streamName, sliceStart, sliceCount, false, credentials); |
|||
|
|||
if (currentSlice.Status == SliceReadStatus.StreamNotFound) |
|||
{ |
|||
throw new DomainObjectNotFoundException(id.ToString(), typeof(TDomainObject)); |
|||
} |
|||
|
|||
if (currentSlice.Status == SliceReadStatus.StreamDeleted) |
|||
{ |
|||
throw new DomainObjectDeletedException(id.ToString(), typeof(TDomainObject)); |
|||
} |
|||
|
|||
sliceStart = currentSlice.NextEventNumber; |
|||
|
|||
foreach (var resolved in currentSlice.Events) |
|||
{ |
|||
var envelope = formatter.Parse(resolved); |
|||
|
|||
domainObject.ApplyEvent(envelope); |
|||
} |
|||
} |
|||
while (version >= currentSlice.NextEventNumber && !currentSlice.IsEndOfStream); |
|||
|
|||
if (domainObject.Version != version && version < int.MaxValue) |
|||
{ |
|||
throw new DomainObjectVersionException(id.ToString(), typeof(TDomainObject), domainObject.Version, version); |
|||
} |
|||
|
|||
return domainObject; |
|||
} |
|||
|
|||
public async Task SaveAsync(IAggregate domainObject, Guid commitId) |
|||
{ |
|||
Guard.NotNull(domainObject, nameof(domainObject)); |
|||
|
|||
var streamName = nameResolver.GetStreamName(domainObject.GetType(), domainObject.Id); |
|||
|
|||
var newEvents = domainObject.GetUncomittedEvents(); |
|||
|
|||
var currVersion = domainObject.Version; |
|||
var prevVersion = currVersion - newEvents.Count; |
|||
var exptVersion = prevVersion == 0 ? ExpectedVersion.NoStream : prevVersion - 1; |
|||
|
|||
var eventsToSave = newEvents.Select(x => formatter.ToEventData(x, commitId)).ToList(); |
|||
|
|||
await InsertEventsAsync(streamName, exptVersion, eventsToSave); |
|||
|
|||
domainObject.ClearUncommittedEvents(); |
|||
} |
|||
|
|||
private async Task InsertEventsAsync(string streamName, int exptVersion, IReadOnlyCollection<EventData> eventsToSave) |
|||
{ |
|||
if (eventsToSave.Count > 0) |
|||
{ |
|||
if (eventsToSave.Count < WritePageSize) |
|||
{ |
|||
await connection.AppendToStreamAsync(streamName, exptVersion, eventsToSave, credentials); |
|||
} |
|||
else |
|||
{ |
|||
var transaction = await connection.StartTransactionAsync(streamName, exptVersion, credentials); |
|||
|
|||
try |
|||
{ |
|||
for (var p = 0; p < eventsToSave.Count; p += WritePageSize) |
|||
{ |
|||
await transaction.WriteAsync(eventsToSave.Skip(p).Take(WritePageSize)); |
|||
} |
|||
|
|||
await transaction.CommitAsync(); |
|||
} |
|||
finally |
|||
{ |
|||
transaction.Dispose(); |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
Debug.WriteLine(string.Format("No events to insert for: {0}", streamName), "GetEventStoreRepository"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
// ==========================================================================
|
|||
// EventStoreFormatter.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Text; |
|||
using EventStore.ClientAPI; |
|||
using Newtonsoft.Json; |
|||
using PinkParrot.Infrastructure.CQRS.Events; |
|||
|
|||
// ReSharper disable InconsistentNaming
|
|||
|
|||
namespace PinkParrot.Infrastructure.CQRS.EventStore |
|||
{ |
|||
public class EventStoreParser |
|||
{ |
|||
private readonly JsonSerializerSettings serializerSettings; |
|||
|
|||
public EventStoreParser(JsonSerializerSettings serializerSettings = null) |
|||
{ |
|||
this.serializerSettings = serializerSettings ?? new JsonSerializerSettings(); |
|||
} |
|||
|
|||
public Envelope<IEvent> Parse(ResolvedEvent @event) |
|||
{ |
|||
var headers = ReadJson<EnvelopeHeaders>(@event.Event.Metadata); |
|||
|
|||
var eventType = Type.GetType(headers.Properties[CommonHeaders.EventType].ToString()); |
|||
var eventData = ReadJson<IEvent>(@event.Event.Data, eventType); |
|||
|
|||
var envelope = new Envelope<IEvent>(eventData, headers); |
|||
|
|||
envelope.Headers.Set(CommonHeaders.Timestamp, DateTime.SpecifyKind(@event.Event.Created, DateTimeKind.Utc)); |
|||
envelope.Headers.Set(CommonHeaders.EventNumber, @event.OriginalEventNumber); |
|||
|
|||
return envelope; |
|||
} |
|||
|
|||
public EventData ToEventData(Envelope<IEvent> envelope, Guid commitId) |
|||
{ |
|||
var eventType = envelope.Payload.GetType(); |
|||
|
|||
envelope.Headers.Set(CommonHeaders.CommitId, commitId); |
|||
envelope.Headers.Set(CommonHeaders.EventType, eventType.AssemblyQualifiedName); |
|||
|
|||
var headers = WriteJson(envelope.Headers); |
|||
var content = WriteJson(envelope.Payload); |
|||
|
|||
return new EventData(envelope.Headers.EventId(), eventType.Name, true, content, headers); |
|||
} |
|||
|
|||
private T ReadJson<T>(byte[] data, Type type = null) |
|||
{ |
|||
return (T)JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data), type ?? typeof(T), serializerSettings); |
|||
} |
|||
|
|||
private byte[] WriteJson(object value) |
|||
{ |
|||
return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value, serializerSettings)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
// ==========================================================================
|
|||
// IStreamNameResolver.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
|
|||
namespace PinkParrot.Infrastructure.CQRS.EventStore |
|||
{ |
|||
public interface IStreamNameResolver |
|||
{ |
|||
string GetStreamName(Type aggregateType, Guid id); |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
// ==========================================================================
|
|||
// DomainObjectDeletedException.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
|
|||
namespace PinkParrot.Infrastructure |
|||
{ |
|||
public class DomainObjectDeletedException : DomainObjectException |
|||
{ |
|||
public DomainObjectDeletedException(string id, Type type) |
|||
: base(FormatMessage(id, type), id, type) |
|||
{ |
|||
} |
|||
|
|||
private static string FormatMessage(string id, Type type) |
|||
{ |
|||
return $"Domain object \'{id}\' (type {type}) not deleted."; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
// ==========================================================================
|
|||
// DomainObjectException.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
|
|||
namespace PinkParrot.Infrastructure |
|||
{ |
|||
public class DomainObjectException : Exception |
|||
{ |
|||
private readonly string id; |
|||
private readonly string typeName; |
|||
|
|||
public string TypeName |
|||
{ |
|||
get |
|||
{ |
|||
return typeName; |
|||
} |
|||
} |
|||
|
|||
public string Id |
|||
{ |
|||
get |
|||
{ |
|||
return id; |
|||
} |
|||
} |
|||
|
|||
protected DomainObjectException(string message, string id, Type type) |
|||
: this(message, id, type, null) |
|||
{ |
|||
} |
|||
|
|||
protected DomainObjectException(string message, string id, Type type, Exception inner) |
|||
: base(message, inner) |
|||
{ |
|||
this.id = id; |
|||
|
|||
if (type != null) |
|||
{ |
|||
typeName = type.Name; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
// ==========================================================================
|
|||
// DomainObjectNotFoundException.cs
|
|||
// Green Parrot Framework
|
|||
// ==========================================================================
|
|||
// Copyright (c) Sebastian Stehle
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
|
|||
namespace PinkParrot.Infrastructure |
|||
{ |
|||
public class DomainObjectNotFoundException : DomainObjectException |
|||
{ |
|||
public DomainObjectNotFoundException(string id, Type type) |
|||
: base(FormatMessage(id, type), id, type) |
|||
{ |
|||
} |
|||
|
|||
private static string FormatMessage(string id, Type type) |
|||
{ |
|||
return $"Domain object \'{id}\' (type {type}) not found."; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
// ==========================================================================
|
|||
// DomainObjectVersionException.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
|
|||
namespace PinkParrot.Infrastructure |
|||
{ |
|||
public class DomainObjectVersionException : DomainObjectException |
|||
{ |
|||
private readonly int currentVersion; |
|||
private readonly int expectedVersion; |
|||
|
|||
public int CurrentVersion |
|||
{ |
|||
get |
|||
{ |
|||
return currentVersion; |
|||
} |
|||
} |
|||
|
|||
public int ExpectedVersion |
|||
{ |
|||
get |
|||
{ |
|||
return expectedVersion; |
|||
} |
|||
} |
|||
|
|||
public DomainObjectVersionException(string id, Type type, int currentVersion, int expectedVersion) |
|||
: base(FormatMessage(id, type, currentVersion, expectedVersion), id, type) |
|||
{ |
|||
this.currentVersion = currentVersion; |
|||
|
|||
this.expectedVersion = expectedVersion; |
|||
} |
|||
|
|||
private static string FormatMessage(string id, Type type, int currentVersion, int expectedVersion) |
|||
{ |
|||
return $"Request version {expectedVersion} for object '{id}' (type {type}), but found {currentVersion}."; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
// ==========================================================================
|
|||
// HideAttribute.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
|
|||
namespace PinkParrot.Infrastructure |
|||
{ |
|||
[AttributeUsage(AttributeTargets.Property)] |
|||
public class HideAttribute : Attribute |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
// ==========================================================================
|
|||
// ISchemaProvider.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace PinkParrot.Read.Services |
|||
{ |
|||
public interface ISchemaProvider |
|||
{ |
|||
Task<Guid> FindSchemaIdByNameAsync(string name); |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
// ==========================================================================
|
|||
// SchemaProvider.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace PinkParrot.Read.Services.Implementations |
|||
{ |
|||
public class SchemaProvider : ISchemaProvider |
|||
{ |
|||
public Task<Guid> FindSchemaIdByNameAsync(string name) |
|||
{ |
|||
return Task.FromResult(Guid.Empty); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue