mirror of https://github.com/Squidex/squidex.git
48 changed files with 568 additions and 97 deletions
@ -0,0 +1,21 @@ |
|||||
|
// ==========================================================================
|
||||
|
// MongoAppEntity.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using MongoDB.Bson.Serialization.Attributes; |
||||
|
using PinkParrot.Read.Apps; |
||||
|
using PinkParrot.Store.MongoDb.Utils; |
||||
|
|
||||
|
namespace PinkParrot.Store.MongoDb.Apps |
||||
|
{ |
||||
|
public sealed class MongoAppEntity : MongoEntity, IAppEntity |
||||
|
{ |
||||
|
[BsonRequired] |
||||
|
[BsonElement] |
||||
|
public string Name { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,57 @@ |
|||||
|
// ==========================================================================
|
||||
|
// MongoAppRepository.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using MongoDB.Bson; |
||||
|
using MongoDB.Driver; |
||||
|
using PinkParrot.Events.Apps; |
||||
|
using PinkParrot.Infrastructure.CQRS; |
||||
|
using PinkParrot.Infrastructure.CQRS.Events; |
||||
|
using PinkParrot.Infrastructure.Dispatching; |
||||
|
using PinkParrot.Infrastructure.Reflection; |
||||
|
using PinkParrot.Read.Apps; |
||||
|
using PinkParrot.Read.Apps.Repositories; |
||||
|
using PinkParrot.Store.MongoDb.Utils; |
||||
|
|
||||
|
namespace PinkParrot.Store.MongoDb.Apps |
||||
|
{ |
||||
|
public sealed class MongoAppRepository : MongoRepositoryBase<MongoAppEntity>, IAppRepository, ICatchEventConsumer |
||||
|
{ |
||||
|
public MongoAppRepository(IMongoDatabase database) |
||||
|
: base(database) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public async Task<IReadOnlyList<IAppEntity>> QueryAllAsync() |
||||
|
{ |
||||
|
var entities = |
||||
|
await Collection.Find(new BsonDocument()).ToListAsync(); |
||||
|
|
||||
|
return entities; |
||||
|
} |
||||
|
|
||||
|
public async Task<IAppEntity> FindAppByNameAsync(string name) |
||||
|
{ |
||||
|
var entity = |
||||
|
await Collection.Find(s => s.Name == name).FirstOrDefaultAsync(); |
||||
|
|
||||
|
return entity; |
||||
|
} |
||||
|
|
||||
|
public Task On(AppCreated @event, EnvelopeHeaders headers) |
||||
|
{ |
||||
|
return Collection.CreateAsync(headers, a => SimpleMapper.Map(a, @event)); |
||||
|
} |
||||
|
|
||||
|
public Task On(Envelope<IEvent> @event) |
||||
|
{ |
||||
|
return this.DispatchActionAsync(@event.Payload, @event.Headers); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
// ==========================================================================
|
||||
|
// MongoEntity.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using MongoDB.Bson; |
||||
|
using MongoDB.Bson.Serialization.Attributes; |
||||
|
using PinkParrot.Read; |
||||
|
|
||||
|
namespace PinkParrot.Store.MongoDb.Utils |
||||
|
{ |
||||
|
public abstract class MongoEntity : IEntity |
||||
|
{ |
||||
|
[BsonId] |
||||
|
[BsonElement] |
||||
|
[BsonRepresentation(BsonType.String)] |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
[BsonRequired] |
||||
|
[BsonElement] |
||||
|
public DateTime Created { get; set; } |
||||
|
|
||||
|
[BsonRequired] |
||||
|
[BsonElement] |
||||
|
public DateTime LastModified { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AppCommandHandler.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Threading.Tasks; |
||||
|
using PinkParrot.Infrastructure.CQRS.Commands; |
||||
|
using PinkParrot.Infrastructure.Dispatching; |
||||
|
using PinkParrot.Write.Apps.Commands; |
||||
|
|
||||
|
namespace PinkParrot.Write.Apps |
||||
|
{ |
||||
|
public class AppCommandHandler : CommandHandler<AppDomainObject> |
||||
|
{ |
||||
|
public AppCommandHandler( |
||||
|
IDomainObjectFactory domainObjectFactory, |
||||
|
IDomainObjectRepository domainObjectRepository) |
||||
|
: base(domainObjectFactory, domainObjectRepository) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public Task On(CreateApp command) |
||||
|
{ |
||||
|
return CreateAsync(command, x => x.Create(command)); |
||||
|
} |
||||
|
|
||||
|
public override Task<bool> HandleAsync(CommandContext context) |
||||
|
{ |
||||
|
return context.IsHandled ? Task.FromResult(false) : this.DispatchActionAsync(context.Command); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using PinkParrot.Infrastructure.Reflection; |
||||
|
using PinkParrot.Modules.Api.Apps.Models; |
||||
|
using PinkParrot.Modules.Api.Schemas.Models; |
||||
|
using PinkParrot.Read.Apps.Repositories; |
||||
|
|
||||
|
namespace PinkParrot.Modules.Api.Apps |
||||
|
{ |
||||
|
public class AppController |
||||
|
{ |
||||
|
private readonly IAppRepository appRepository; |
||||
|
|
||||
|
public AppController(IAppRepository appRepository) |
||||
|
{ |
||||
|
this.appRepository = appRepository; |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("api/schemas/")] |
||||
|
public async Task<List<ListAppDto>> Query() |
||||
|
{ |
||||
|
var schemas = await appRepository.QueryAllAsync(); |
||||
|
|
||||
|
return schemas.Select(s => SimpleMapper.Map(s, new ListAppDto())).ToList(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ListAppDto.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace PinkParrot.Modules.Api.Apps.Models |
||||
|
{ |
||||
|
public sealed class ListAppDto |
||||
|
{ |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
public DateTime Created { get; set; } |
||||
|
|
||||
|
public DateTime LastModified { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Autofac; |
||||
|
using PinkParrot.Infrastructure.CQRS.Events; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace PinkParrot.Infrastructure.CQRS.Autofac |
||||
|
{ |
||||
|
public class AutofacDomainObjectFactoryTests |
||||
|
{ |
||||
|
private sealed class DO : DomainObject |
||||
|
{ |
||||
|
public DO(Guid id, int version) : base(id, version) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override void DispatchEvent(Envelope<IEvent> @event) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_domain_object_with_autofac() |
||||
|
{ |
||||
|
var containerBuilder = new ContainerBuilder(); |
||||
|
|
||||
|
containerBuilder.RegisterType<DO>() |
||||
|
.AsSelf(); |
||||
|
|
||||
|
var factory = new AutofacDomainObjectFactory(containerBuilder.Build()); |
||||
|
|
||||
|
var id = Guid.NewGuid(); |
||||
|
|
||||
|
var domainObject = factory.CreateNew(typeof(DO), id); |
||||
|
|
||||
|
Assert.Equal(id, domainObject.Id); |
||||
|
Assert.Equal(0, domainObject.Version); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,106 @@ |
|||||
|
// ==========================================================================
|
||||
|
// SchemaDomainObjectTest.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using FluentAssertions; |
||||
|
using PinkParrot.Core.Schemas; |
||||
|
using PinkParrot.Events.Schemas; |
||||
|
using PinkParrot.Infrastructure; |
||||
|
using PinkParrot.Write.Schemas; |
||||
|
using PinkParrot.Write.Schemas.Commands; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace PinkParrot.Write.Tests.Schemas |
||||
|
{ |
||||
|
[Collection("Schema")] |
||||
|
public class SchemaDomainObjectTest |
||||
|
{ |
||||
|
private const string TestName = "schema"; |
||||
|
private readonly Guid appId = Guid.NewGuid(); |
||||
|
private readonly FieldRegistry registry = new FieldRegistry(); |
||||
|
private readonly SchemaDomainObject sut; |
||||
|
|
||||
|
public SchemaDomainObjectTest() |
||||
|
{ |
||||
|
sut = new SchemaDomainObject(Guid.NewGuid(), 0, registry); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_throw_if_created() |
||||
|
{ |
||||
|
sut.Create(new CreateSchema { Name = TestName }); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => sut.Create(new CreateSchema { Name = TestName })); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_throw_if_command_is_invalid() |
||||
|
{ |
||||
|
Assert.Throws<ValidationException>(() => sut.Create(new CreateSchema())); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_create_schema() |
||||
|
{ |
||||
|
var props = new SchemaProperties(null, null); |
||||
|
|
||||
|
sut.Create(new CreateSchema { Name = TestName, AppId = appId, Properties = props }); |
||||
|
|
||||
|
Assert.Equal("schema", sut.Schema.Name); |
||||
|
Assert.Equal(props, sut.Schema.Properties); |
||||
|
Assert.Equal(appId, sut.AppId); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.Select(x => x.Payload as SchemaCreated) |
||||
|
.Single() |
||||
|
.ShouldBeEquivalentTo( |
||||
|
new SchemaCreated { Name = TestName, AppId = appId, Properties = props }); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_throw_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => sut.Update(new UpdateSchema { Properties = new SchemaProperties(null, null) })); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_throw_if_command_is_deleted() |
||||
|
{ |
||||
|
sut.Create(new CreateSchema { Name = TestName }); |
||||
|
sut.Delete(); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => sut.Update(new UpdateSchema())); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_throw_if_command_is_invalid() |
||||
|
{ |
||||
|
sut.Create(new CreateSchema { Name = TestName }); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => sut.Update(new UpdateSchema())); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_refresh_properties() |
||||
|
{ |
||||
|
var props = new SchemaProperties(null, null); |
||||
|
|
||||
|
sut.Create(new CreateSchema { Name = TestName, AppId = appId }); |
||||
|
sut.Update(new UpdateSchema { Properties = props }); |
||||
|
|
||||
|
Assert.Equal(props, sut.Schema.Properties); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.Select(x => x.Payload as SchemaUpdated) |
||||
|
.Last() |
||||
|
.ShouldBeEquivalentTo( |
||||
|
new SchemaUpdated { Properties = props }); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
// ==========================================================================
|
||||
|
// SchemaFixture.cs
|
||||
|
// PinkParrot Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) PinkParrot Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using PinkParrot.Core.Schemas; |
||||
|
using PinkParrot.Infrastructure; |
||||
|
using System.Reflection; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace PinkParrot.Write.Tests.Utils |
||||
|
{ |
||||
|
public class SchemaFixture |
||||
|
{ |
||||
|
public SchemaFixture() |
||||
|
{ |
||||
|
TypeNameRegistry.Map(typeof(Schema).GetTypeInfo().Assembly); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[CollectionDefinition("Schema")] |
||||
|
public class DatabaseCollection : ICollectionFixture<SchemaFixture> |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue