Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tweak database implementation and retrieval of project list #72

Merged
merged 1 commit into from
Mar 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ var netFrameworkUnitTestAssemblies = new []
@"./src/Evelyn.Storage.EventStore.Tests/bin/"+compileConfig+"/net461/Evelyn.Storage.EventStore.Tests.dll",
};
var openCoverSettings = new OpenCoverSettings();
var minCodeCoverage = 93d;
var minCodeCoverage = 92d;
var coverallsRepoToken = "coveralls-repo-token-evelyn";

// integration testing
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Evelyn.Core.Tests.ReadModel.AccountProjects
{
using AutoFixture;
using Core.ReadModel.AccountProjects;
using Xunit;

public class AccountProjectsDtoSpecs : DtoSpecs<AccountProjectsDto>
{
[Fact]
public void Serialization()
{
var accountProjects = DataFixture.Create<AccountProjectsDto>();

AssertSerializationOf(accountProjects);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
namespace Evelyn.Core.Tests.ReadModel.ProjectList
namespace Evelyn.Core.Tests.ReadModel.AccountProjects
{
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoFixture;
using Core.ReadModel.AccountProjects;
using Core.ReadModel.Events;
using Core.ReadModel.ProjectList;
using CQRSlite.Events;
using CQRSlite.Routing;
using Evelyn.Core.ReadModel.Events;
using FluentAssertions;
using TestStack.BDDfy;
using Xunit;

public class ProjectListHandlerSpecs : HandlerSpecs
public class AccountProjectsHandlerSpecs : HandlerSpecs
{
private List<IEvent> _eventsProject1;
private List<IEvent> _eventsProject2;
private readonly List<IEvent> _eventsProject1;
private readonly List<IEvent> _eventsProject2;
private readonly string _accountId;

private ProjectCreated _event1;
private ProjectCreated _event2;

private List<ProjectListDto> _retrievedProjectList;
private AccountProjectsDto _retrievedAccountProjects;

public ProjectListHandlerSpecs()
public AccountProjectsHandlerSpecs()
{
_eventsProject1 = new List<IEvent>();
_eventsProject2 = new List<IEvent>();
_accountId = DataFixture.Create<string>();
}

[Fact]
Expand All @@ -49,52 +51,56 @@ public void MultipleProjectsCreated()

protected override void RegisterHandlers(Router router)
{
var handler = new ProjectListHandler(ProjectsStore);
var handler = new AccountProjectsHandler(AccountProjectsStore);
router.RegisterHandler<ProjectCreated>(handler.Handle);
}

private void GivenAnProjectIsCreated()
{
_event1 = DataFixture.Create<ProjectCreated>();
_event1.Version = _eventsProject1.Count + 1;
_event1 = DataFixture.Build<ProjectCreated>()
.With(pc => pc.AccountId, _accountId)
.With(pc => pc.Version, _eventsProject1.Count + 1)
.Create();

_eventsProject1.Add(_event1);
GivenWePublish(_event1);
}

private void GivenAnotherProjectIsCreated()
{
_event2 = DataFixture.Create<ProjectCreated>();
_event2.Version = _eventsProject2.Count + 1;
_event2 = DataFixture.Build<ProjectCreated>()
.With(pc => pc.AccountId, _accountId)
.With(pc => pc.Version, _eventsProject2.Count + 1)
.Create();

_eventsProject2.Add(_event2);
GivenWePublish(_event2);
}

private async Task WhenWeGetTheProjectList()
{
_retrievedProjectList = (await ReadModelFacade.GetProjects()).ToList();
_retrievedAccountProjects = await ReadModelFacade.GetProjects(_accountId);
}

private void ThenTheProjectIsAddedToTheProjectList()
{
_retrievedProjectList.Count.Should().Be(1);
_retrievedAccountProjects.Projects.Count.Should().Be(1);
ThenThereIsAnProjectInTheListFor(_event1);
}

private void ThenBothProjectsAreInTheProjectList()
{
_retrievedProjectList.Count().Should().Be(2);
_retrievedAccountProjects.Projects.Count.Should().Be(2);

ThenThereIsAnProjectInTheListFor(_event1);
ThenThereIsAnProjectInTheListFor(_event2);
}

private void ThenThereIsAnProjectInTheListFor(ProjectCreated ev)
{
ProjectsStore.Get().GetAwaiter().GetResult().Should().Contain(project =>
project.Id == ev.Id &&
project.Name == ev.Name);
AccountProjectsStore.Get(_accountId)
.GetAwaiter().GetResult()
.Projects[ev.Id].Name.Should().Be(ev.Name);
}
}
}
19 changes: 10 additions & 9 deletions src/Evelyn.Core.Tests/ReadModel/HandlerSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{
using System;
using AutoFixture;
using Core.ReadModel.AccountProjects;
using Core.ReadModel.ProjectDetails;
using Core.ReadModel.ProjectList;
using Core.ReadModel.ToggleDetails;
Expand All @@ -19,13 +20,13 @@ protected HandlerSpecs()
{
DataFixture = new Fixture();

ProjectsStore = new InMemoryDatabase<ProjectListDto>();
ProjectDetailsStore = new InMemoryDatabase<ProjectDetailsDto>();
EnvironmentDetailsStore = new InMemoryDatabase<EnvironmentDetailsDto>();
ToggleDetailsStore = new InMemoryDatabase<ToggleDetailsDto>();
AccountProjectsStore = new InMemoryDatabase<string, AccountProjectsDto>();
ProjectDetailsStore = new InMemoryDatabase<Guid, ProjectDetailsDto>();
EnvironmentDetailsStore = new InMemoryDatabase<Guid, EnvironmentDetailsDto>();
ToggleDetailsStore = new InMemoryDatabase<Guid, ToggleDetailsDto>();

ReadModelFacade = new DatabaseReadModelFacade(
ProjectsStore,
AccountProjectsStore,
ProjectDetailsStore,
EnvironmentDetailsStore,
ToggleDetailsStore);
Expand All @@ -39,13 +40,13 @@ protected HandlerSpecs()

protected IReadModelFacade ReadModelFacade { get; }

protected IDatabase<ProjectListDto> ProjectsStore { get; }
protected IDatabase<string, AccountProjectsDto> AccountProjectsStore { get; }

protected IDatabase<ProjectDetailsDto> ProjectDetailsStore { get; }
protected IDatabase<Guid, ProjectDetailsDto> ProjectDetailsStore { get; }

protected IDatabase<EnvironmentDetailsDto> EnvironmentDetailsStore { get; set; }
protected IDatabase<Guid, EnvironmentDetailsDto> EnvironmentDetailsStore { get; set; }

protected IDatabase<ToggleDetailsDto> ToggleDetailsStore { get; set; }
protected IDatabase<Guid, ToggleDetailsDto> ToggleDetailsStore { get; set; }

protected Exception ThrownException { get; set; }

Expand Down
17 changes: 0 additions & 17 deletions src/Evelyn.Core.Tests/ReadModel/ProjectList/ProjectListDtoSpecs.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public void Configure(HandlerOptions options)
{
typeof(ProjectCommandHandler),
typeof(ProjectDetailsHandler),
typeof(ProjectListHandler),
typeof(AccountProjectsHandler),
typeof(EnvironmentDetailsHandler),
typeof(ToggleDetailsHandler)
});
Expand Down
2 changes: 1 addition & 1 deletion src/Evelyn.Core/DependencyInjection/InMemoryReadCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public static class InMemoryReadCache
public static void InMemoryCache(this ReadModelCacheOptions parentOptions)
#pragma warning restore SA1614 // Element parameter documentation must have text
{
parentOptions.Services.TryAddSingleton(typeof(IDatabase<>), typeof(InMemoryDatabase<>));
parentOptions.Services.TryAddSingleton(typeof(IDatabase<,>), typeof(InMemoryDatabase<,>));
}
}
}
2 changes: 1 addition & 1 deletion src/Evelyn.Core/DependencyInjection/InProcessHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static void SynchronouslyInProcess(this EventPublisherOptions parentOptio
#pragma warning restore SA1614 // Element parameter documentation must have text
{
parentOptions.Services.TryAddSingleton<ProjectDetailsHandler>();
parentOptions.Services.TryAddSingleton<ProjectListHandler>();
parentOptions.Services.TryAddSingleton<AccountProjectsHandler>();
parentOptions.Services.TryAddSingleton<EnvironmentDetailsHandler>();
parentOptions.Services.TryAddSingleton<ToggleDetailsHandler>();

Expand Down
19 changes: 19 additions & 0 deletions src/Evelyn.Core/ReadModel/AccountProjects/AccountProjectsDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace Evelyn.Core.ReadModel.AccountProjects
{
using System;
using System.Collections.Generic;
using ProjectList;

public class AccountProjectsDto
{
public AccountProjectsDto(string accountId)
{
AccountId = accountId;
Projects = new Dictionary<Guid, ProjectListDto>();
}

public string AccountId { get; private set; }

public Dictionary<Guid, ProjectListDto> Projects { get; private set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
namespace Evelyn.Core.ReadModel.ProjectList
{
using System.Threading;
using System.Threading.Tasks;
using CQRSlite.Events;
using Evelyn.Core.ReadModel.AccountProjects;
using Events;
using Infrastructure;

public class AccountProjectsHandler
: ICancellableEventHandler<ProjectCreated>
{
private readonly IDatabase<string, AccountProjectsDto> _db;

public AccountProjectsHandler(IDatabase<string, AccountProjectsDto> db)
{
_db = db;
}

public async Task Handle(ProjectCreated message, CancellationToken token)
{
AccountProjectsDto accountProjects;
try
{
accountProjects = await _db.Get(message.AccountId);
}
catch (NotFoundException)
{
accountProjects = new AccountProjectsDto(message.AccountId);
}

accountProjects.Projects.Add(message.Id, new ProjectListDto(message.Id, message.Name));
await _db.AddOrUpdate(accountProjects.AccountId, accountProjects);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ public ProjectListDto(Guid id, string name)
Name = name;
}

public Guid Id { get; }
public Guid Id { get; private set; }

public string Name { get; }
public string Name { get; private set; }
}
}
33 changes: 20 additions & 13 deletions src/Evelyn.Core/ReadModel/DatabaseReadModelFacade.cs
Original file line number Diff line number Diff line change
@@ -1,39 +1,46 @@
namespace Evelyn.Core.ReadModel
{
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AccountProjects;
using Evelyn.Core.ReadModel.EnvironmentDetails;
using Evelyn.Core.ReadModel.Infrastructure;
using Evelyn.Core.ReadModel.ToggleDetails;
using ProjectDetails;
using ProjectList;

public class DatabaseReadModelFacade : IReadModelFacade
{
private readonly IDatabase<ProjectListDto> _projects;
private readonly IDatabase<string, AccountProjectsDto> _accountProjects;

private readonly IDatabase<ProjectDetailsDto> _projectDetails;
private readonly IDatabase<Guid, ProjectDetailsDto> _projectDetails;

private readonly IDatabase<EnvironmentDetailsDto> _environmentDetails;
private readonly IDatabase<Guid, EnvironmentDetailsDto> _environmentDetails;

private readonly IDatabase<ToggleDetailsDto> _toggleDetails;
private readonly IDatabase<Guid, ToggleDetailsDto> _toggleDetails;

public DatabaseReadModelFacade(
IDatabase<ProjectListDto> projects,
IDatabase<ProjectDetailsDto> projectDetails,
IDatabase<EnvironmentDetailsDto> environmentDetails,
IDatabase<ToggleDetailsDto> toggleDetails)
IDatabase<string, AccountProjectsDto> accountProjects,
IDatabase<Guid, ProjectDetailsDto> projectDetails,
IDatabase<Guid, EnvironmentDetailsDto> environmentDetails,
IDatabase<Guid, ToggleDetailsDto> toggleDetails)
{
_projects = projects;
_accountProjects = accountProjects;
_projectDetails = projectDetails;
_environmentDetails = environmentDetails;
_toggleDetails = toggleDetails;
}

public async Task<IEnumerable<ProjectListDto>> GetProjects()
public async Task<AccountProjectsDto> GetProjects(string accountId)
{
return await _projects.Get();
try
{
return await _accountProjects.Get(accountId);
}
catch (NotFoundException)
{
// hack! Remove this
return new AccountProjectsDto(accountId);
}
}

public async Task<ProjectDetailsDto> GetProjectDetails(Guid projectId)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace Evelyn.Core.ReadModel.EnvironmentDetails
{
using System;
using System.Threading;
using System.Threading.Tasks;
using CQRSlite.Events;
Expand All @@ -9,16 +10,16 @@
public class EnvironmentDetailsHandler
: ICancellableEventHandler<EnvironmentAdded>
{
private readonly IDatabase<EnvironmentDetailsDto> _environments;
private readonly IDatabase<Guid, EnvironmentDetailsDto> _db;

public EnvironmentDetailsHandler(IDatabase<EnvironmentDetailsDto> environments)
public EnvironmentDetailsHandler(IDatabase<Guid, EnvironmentDetailsDto> db)
{
_environments = environments;
_db = db;
}

public Task Handle(EnvironmentAdded message, CancellationToken token)
{
_environments.Add(message.EnvironmentId, new EnvironmentDetailsDto(message.Id, message.EnvironmentId, message.Name, message.TimeStamp));
_db.AddOrUpdate(message.EnvironmentId, new EnvironmentDetailsDto(message.Id, message.EnvironmentId, message.Name, message.TimeStamp));
return Task.CompletedTask;
}
}
Expand Down
Loading