Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
rasmus committed Oct 22, 2015
2 parents 6c757db + 7d413a1 commit 96e7f90
Show file tree
Hide file tree
Showing 46 changed files with 1,011 additions and 57 deletions.
31 changes: 31 additions & 0 deletions Documentation/ReadStores-Elasticsearch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Elasticsearch read model store

Configuring EventFlow to use Elasticsearch as a store for read models is done
in steps.

1. Configure Elasticsearch connection in EventFlow
1. Configure your Elasticsearch read models in EventFlow

Given you have defined a read model class named `MyElasticsearchReadModel`, the
above will look like this.

```csharp
var resolver = EventFlowOptions.New
.ConfigureElasticsearch(new Uri("http://localhost:9200"))
.UseElasticsearchReadModel<MyElasticsearchReadModel>()
...
.CreateResolver();
```

Overloads of `ConfigureElasticsearch(...)` is available for alternative
Elasticsearch configuration.

EventFlow makes assumptions regarding how you use Elasticsearch to store read
models.

* The host application of EventFlow is responsible for creating correct
Elasticsearch type mapping for any indexes by creating index templates

If you want to control the index a specific read model is stored in, create
create an implementation of `IReadModelDescriptionProvider` and register it
in the [EventFlow IoC](./Customize.md).
16 changes: 16 additions & 0 deletions EventFlow.sln
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventFlow.Hangfire", "Sourc
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventFlow.Hangfire.Tests", "Source\EventFlow.Hangfire.Tests\EventFlow.Hangfire.Tests.csproj", "{35180FC7-9135-4E79-8643-0FB825B40871}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Elasticsearch", "Elasticsearch", "{D6F5FF86-C3F3-443D-BEC4-11BDEC5E34FB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventFlow.ReadStores.Elasticsearch", "Source\EventFlow.ReadStores.Elasticsearch\EventFlow.ReadStores.Elasticsearch.csproj", "{404C6099-E82F-4433-8505-5479D76660CD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventFlow.ReadStores.Elasticsearch.Tests", "Source\EventFlow.ReadStores.Elasticsearch.Tests\EventFlow.ReadStores.Elasticsearch.Tests.csproj", "{D4D7E41C-1473-4449-A128-CA4383783E6C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -123,6 +129,14 @@ Global
{35180FC7-9135-4E79-8643-0FB825B40871}.Debug|Any CPU.Build.0 = Debug|Any CPU
{35180FC7-9135-4E79-8643-0FB825B40871}.Release|Any CPU.ActiveCfg = Release|Any CPU
{35180FC7-9135-4E79-8643-0FB825B40871}.Release|Any CPU.Build.0 = Release|Any CPU
{404C6099-E82F-4433-8505-5479D76660CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{404C6099-E82F-4433-8505-5479D76660CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{404C6099-E82F-4433-8505-5479D76660CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{404C6099-E82F-4433-8505-5479D76660CD}.Release|Any CPU.Build.0 = Release|Any CPU
{D4D7E41C-1473-4449-A128-CA4383783E6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4D7E41C-1473-4449-A128-CA4383783E6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4D7E41C-1473-4449-A128-CA4383783E6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4D7E41C-1473-4449-A128-CA4383783E6C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -142,5 +156,7 @@ Global
{EDCD8854-6224-4329-87C2-9ADD7D153070} = {980EEDAA-1FEF-4D7C-8811-5EF1D9729773}
{FB079985-722A-43C9-9F14-C7D2AFBE8826} = {4741A405-DA64-40CC-A726-A2C48CA49DA3}
{35180FC7-9135-4E79-8643-0FB825B40871} = {4741A405-DA64-40CC-A726-A2C48CA49DA3}
{404C6099-E82F-4433-8505-5479D76660CD} = {D6F5FF86-C3F3-443D-BEC4-11BDEC5E34FB}
{D4D7E41C-1473-4449-A128-CA4383783E6C} = {D6F5FF86-C3F3-443D-BEC4-11BDEC5E34FB}
EndGlobalSection
EndGlobal
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

[![NuGet Status](http://img.shields.io/nuget/v/EventFlow.svg?style=flat)](https://www.nuget.org/packages/EventFlow/)
[![Build status](https://ci.appveyor.com/api/projects/status/51yvhvbd909e4o82/branch/develop?svg=true)](https://ci.appveyor.com/project/rasmusnu/eventflow)
[![License](https://img.shields.io/github/license/rasmus/eventflow.svg)](./LICENSE)

EventFlow is a basic CQRS+ES framework designed to be easy to use.

Expand Down Expand Up @@ -41,6 +40,7 @@ to the documentation.
* **Read models:** Denormalized representation of aggregate events
optimized for reading fast. Currently there is support for these
read model storage types.
* [Elasticsearch](./Documentation/ReadStores-Elasticsearch.md)
* In-memory - only for test
* Microsoft SQL Server
* [**Queries:**](./Documentation/Queries.md) Value objects that represent
Expand Down
15 changes: 14 additions & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
### New in 0.19 (not released yet)
### New in 0.20 (not released yet)

* Breaking: `Entity<T>` now inherits from `ValueObject` but uses only the `Id`
field as equality component. Override `GetEqualityComponents()` if you have
a different notion of equality for a specific entity
* Breaking: `Entity<T>` will now throw an `ArgumentNullException` if the `id`
passed to its constructor is `null`
* Breaking: Fixed method spelling. Renamed
`ISpecification<T>.WhyIsNotStatisfiedBy` to `WhyIsNotSatisfiedBy` and
`Specification<T>.IsNotStatisfiedBecause` to `IsNotSatisfiedBecause`
* New: Read model support for Elasticsearch via the new NuGet package
`EventFlow.ReadStores.Elasticsearch`

### New in 0.19.1225 (released 2015-10-19)

* Breaking: `AddDefaults` now also adds the job type definition to the
`IJobsDefinitonService`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// The MIT License (MIT)
//
// Copyright (c) 2015 Rasmus Mikkelsen
// https://github.com/rasmus/EventFlow
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using EventFlow.Aggregates;
using EventFlow.TestHelpers.Aggregates.Test;
using EventFlow.TestHelpers.Aggregates.Test.Events;
using EventFlow.TestHelpers.Aggregates.Test.ReadModels;
using Nest;

namespace EventFlow.ReadStores.Elasticsearch.Tests
{
[ElasticType(IdProperty = "Id", Name = "test")]
public class ElasticsearchTestAggregateReadModel : ITestAggregateReadModel
{
[ElasticProperty(
Name = "DomainErrorAfterFirstReceived",
Index = FieldIndexOption.NotAnalyzed)]
public bool DomainErrorAfterFirstReceived { get; set; }

[ElasticProperty(
Name = "PingsReceived",
Index = FieldIndexOption.NotAnalyzed)]
public int PingsReceived { get; set; }

public void Apply(IReadModelContext context, IDomainEvent<TestAggregate, TestId, DomainErrorAfterFirstEvent> e)
{
DomainErrorAfterFirstReceived = true;
}

public void Apply(IReadModelContext context, IDomainEvent<TestAggregate, TestId, PingEvent> e)
{
PingsReceived++;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D4D7E41C-1473-4449-A128-CA4383783E6C}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>EventFlow.ReadStores.Elasticsearch.Tests</RootNamespace>
<AssemblyName>EventFlow.ReadStores.Elasticsearch.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Reference Include="Elasticsearch.Net, Version=1.0.0.0, Culture=neutral, PublicKeyToken=96c599bbe3e70f5d, processorArchitecture=MSIL">
<HintPath>..\..\packages\Elasticsearch.Net.1.7.1\lib\net45\Elasticsearch.Net.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="FluentAssertions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\..\packages\FluentAssertions.3.5.0\lib\net45\FluentAssertions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="FluentAssertions.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\..\packages\FluentAssertions.3.5.0\lib\net45\FluentAssertions.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Nest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=96c599bbe3e70f5d, processorArchitecture=MSIL">
<HintPath>..\..\packages\NEST.1.7.1\lib\net45\Nest.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="nunit.framework, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
<HintPath>..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ElasticsearchTestAggregateReadModel.cs" />
<Compile Include="Integration\ElasticsearchIntegrationTestConfiguration.cs" />
<Compile Include="Integration\ElasticsearchReadModelStoreTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EventFlow.ReadStores.Elasticsearch\EventFlow.ReadStores.Elasticsearch.csproj">
<Project>{404c6099-e82f-4433-8505-5479d76660cd}</Project>
<Name>EventFlow.ReadStores.Elasticsearch</Name>
</ProjectReference>
<ProjectReference Include="..\EventFlow.TestHelpers\EventFlow.TestHelpers.csproj">
<Project>{571d291c-5e4c-43af-855f-7c4e2f318f4c}</Project>
<Name>EventFlow.TestHelpers</Name>
</ProjectReference>
<ProjectReference Include="..\EventFlow\EventFlow.csproj">
<Project>{11131251-778d-4d2e-bdd1-4844a789bca9}</Project>
<Name>EventFlow</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// The MIT License (MIT)
//
// Copyright (c) 2015 Rasmus Mikkelsen
// https://github.com/rasmus/EventFlow
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using EventFlow.Configuration;
using EventFlow.Core;
using EventFlow.ReadStores.Elasticsearch.Extensions;
using EventFlow.TestHelpers;
using EventFlow.TestHelpers.Aggregates.Test.ReadModels;
using Nest;
using NUnit.Framework;

namespace EventFlow.ReadStores.Elasticsearch.Tests.Integration
{
public class ElasticsearchIntegrationTestConfiguration : IntegrationTestConfiguration
{
private IReadModelPopulator _readModelPopulator;
private IRootResolver _resolver;
private IElasticClient _elasticClient;
private IReadModelDescriptionProvider _readModelDescriptionProvider;
private IElasticsearchReadModelStore<ElasticsearchTestAggregateReadModel> _readModelStore;

public override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions)
{
// Disable SSL certificate validation
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

var url = Environment.GetEnvironmentVariable("ELASTICSEARCH_URL");
if (string.IsNullOrEmpty(url))
{
Assert.Inconclusive("The environment variabel named 'ELASTICSEARCH_URL' isn't set. Set it to e.g. 'http://localhost:9200'");
}

_resolver = eventFlowOptions
.ConfigureElasticsearch(new Uri(url))
.UseElasticsearchReadModel<ElasticsearchTestAggregateReadModel>()
.CreateResolver();
_elasticClient = _resolver.Resolve<IElasticClient>();
_readModelPopulator = _resolver.Resolve<IReadModelPopulator>();
_readModelDescriptionProvider = _resolver.Resolve<IReadModelDescriptionProvider>();
_readModelStore = _resolver.Resolve<IElasticsearchReadModelStore<ElasticsearchTestAggregateReadModel>>();

return _resolver;
}

public override async Task<ITestAggregateReadModel> GetTestAggregateReadModelAsync(IIdentity id)
{
var readModelEnvelope = await _readModelStore.GetAsync(id.Value, CancellationToken.None).ConfigureAwait(false);
return readModelEnvelope.ReadModel;
}

public override Task PurgeTestAggregateReadModelAsync()
{
return _readModelPopulator.PurgeAsync<ElasticsearchTestAggregateReadModel>(CancellationToken.None);
}

public override Task PopulateTestAggregateReadModelAsync()
{
return _readModelPopulator.PopulateAsync<ElasticsearchTestAggregateReadModel>(CancellationToken.None);
}

public override void TearDown()
{
try
{
var readModelDescription = _readModelDescriptionProvider.GetReadModelDescription<ElasticsearchTestAggregateReadModel>();
_elasticClient.DeleteIndex(readModelDescription.IndexName.Value);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// The MIT License (MIT)
//
// Copyright (c) 2015 Rasmus Mikkelsen
// https://github.com/rasmus/EventFlow
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using EventFlow.TestHelpers.Suites;

namespace EventFlow.ReadStores.Elasticsearch.Tests.Integration
{
public class ElasticsearchReadModelStoreTests : ReadModelStoreSuite<ElasticsearchIntegrationTestConfiguration>
{
}
}
Loading

0 comments on commit 96e7f90

Please sign in to comment.