diff --git a/.gitignore b/.gitignore
index 439187c3..9c61e998 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,3 +38,6 @@ release
#dotCover
*.dotCover
+
+#TestResults
+/TestResults/*
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/App.config b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/App.config
new file mode 100644
index 00000000..5705bd4e
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/App.config
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/ChangeNoteCommand.cs b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/ChangeNoteCommand.cs
new file mode 100644
index 00000000..d86f8411
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/ChangeNoteCommand.cs
@@ -0,0 +1,14 @@
+using System;
+using Ncqrs.Commanding.CommandExecution.Mapping.Attributes;
+using Ncqrs.Commanding;
+
+namespace Ncqrs.Eventing.Storage.AWS.Tests.Env
+{
+ [MapsToAggregateRootMethod(typeof(Note), "ChangeNoteText")]
+ public class ChangeNoteCommand : CommandBase
+ {
+ [AggregateRootId]
+ public Guid NoteId { get; set; }
+ public string NewNoteText { get; set; }
+ }
+}
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/CreateNoteCommand.cs b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/CreateNoteCommand.cs
new file mode 100644
index 00000000..ed2bdb57
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/CreateNoteCommand.cs
@@ -0,0 +1,13 @@
+using System;
+using Ncqrs.Commanding;
+using Ncqrs.Commanding.CommandExecution.Mapping.Attributes;
+
+namespace Ncqrs.Eventing.Storage.AWS.Tests.Env
+{
+ [MapsToAggregateRootConstructor(typeof(Note))]
+ public class CreateNoteCommand : CommandBase
+ {
+ public Guid NoteId { get; set; }
+ public string NoteText { get; set; }
+ }
+}
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/Note.cs b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/Note.cs
new file mode 100644
index 00000000..04aad113
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/Note.cs
@@ -0,0 +1,48 @@
+using System;
+using Ncqrs.Domain;
+
+namespace Ncqrs.Eventing.Storage.AWS.Tests.Env
+{
+ public class Note : AggregateRootMappedByConvention
+ {
+ public string NoteText { get; private set; }
+
+
+ public Note(Guid noteId, string noteText)
+ : base(noteId)
+ {
+ if (noteText != null)
+ {
+ ApplyEvent(new NoteCreated
+ {
+ NoteText = noteText
+ });
+ }
+ }
+
+ public Note()
+ {
+ }
+
+ public void ChangeNoteText(string NewNoteText)
+ {
+ ApplyEvent(new NoteChanged
+ {
+ NewNoteText = NewNoteText
+ });
+
+ }
+
+ protected void OnNoteCreated(NoteCreated e)
+ {
+ NoteText = e.NoteText;
+ }
+
+ protected void OnNoteChange(NoteChanged e)
+ {
+ NoteText = e.NewNoteText;
+ }
+
+
+ }
+}
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/NoteChanged.cs b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/NoteChanged.cs
new file mode 100644
index 00000000..8381d45f
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/NoteChanged.cs
@@ -0,0 +1,12 @@
+using System;
+using Ncqrs.Eventing.Sourcing;
+
+namespace Ncqrs.Eventing.Storage.AWS.Tests.Env
+{
+ [Serializable]
+ public class NoteChanged : SourcedEvent
+ {
+ public Guid NoteId { get; set; }
+ public string NewNoteText { get; set; }
+ }
+}
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/NoteCreated.cs b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/NoteCreated.cs
new file mode 100644
index 00000000..f685580e
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/NoteCreated.cs
@@ -0,0 +1,12 @@
+using System;
+using Ncqrs.Eventing.Sourcing;
+
+namespace Ncqrs.Eventing.Storage.AWS.Tests.Env
+{
+ [Serializable]
+ public class NoteCreated : SourcedEvent
+ {
+ Guid NoteId { get; set; }
+ public string NoteText { get; set; }
+ }
+}
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/Startup.cs b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/Startup.cs
new file mode 100644
index 00000000..e874b621
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Env/Startup.cs
@@ -0,0 +1,18 @@
+using Ncqrs.Commanding.ServiceModel;
+using Ncqrs.Commanding.CommandExecution.Mapping.Attributes;
+
+namespace Ncqrs.Eventing.Storage.AWS.Tests.Env
+{
+ public static class Startup
+ {
+ public static void Start()
+ {
+ NcqrsEnvironment.SetDefault(new SimpleDBStore("MainTest"));
+ CommandService c = new CommandService();
+
+ c.RegisterExecutorsInAssembly(typeof(CreateNoteCommand).Assembly);
+
+ NcqrsEnvironment.SetDefault(c);
+ }
+ }
+}
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/MainTests.cs b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/MainTests.cs
new file mode 100644
index 00000000..97afa6a8
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/MainTests.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Ncqrs.Commanding.ServiceModel;
+using Ncqrs.Eventing.Storage.AWS.Tests.Env;
+
+namespace Ncqrs.Eventing.Storage.AWS.Tests
+{
+ [TestClass]
+ public class MainTests
+ {
+ public MainTests()
+ {
+ Startup.Start();
+ }
+
+ [TestMethod]
+ public void SniffForSmoke()
+ {
+ Guid smokeID = Guid.NewGuid();
+ NcqrsEnvironment.Get().Execute(new CreateNoteCommand
+ {
+ NoteId = smokeID,
+ NoteText = "Hello world"
+ });
+
+ NcqrsEnvironment.Get().Execute(new ChangeNoteCommand
+ {
+ NoteId = smokeID,
+ NewNoteText = "Hello universe"
+ });
+ }
+
+ [TestMethod]
+ public void LoadItUp()
+ {
+ IList ids = new List();
+
+ for (int i = 0; i < 5; i++)
+ {
+ Guid id = Guid.NewGuid();
+ ids.Add(id);
+
+ NcqrsEnvironment.Get().Execute(new CreateNoteCommand
+ {
+ NoteId = id,
+ NoteText = "Hello world " + i
+ });
+ }
+
+
+ foreach (Guid id in ids)
+ {
+ NcqrsEnvironment.Get().Execute(new ChangeNoteCommand
+ {
+ NoteId = id,
+ NewNoteText = "Hello solar system"
+ });
+ }
+
+ foreach (Guid id in ids)
+ {
+ NcqrsEnvironment.Get().Execute(new ChangeNoteCommand
+ {
+ NoteId = id,
+ NewNoteText = "Hello galaxy"
+ });
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Ncqrs.Eventing.Storage.AWS.Tests.csproj b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Ncqrs.Eventing.Storage.AWS.Tests.csproj
new file mode 100644
index 00000000..9c606714
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Ncqrs.Eventing.Storage.AWS.Tests.csproj
@@ -0,0 +1,81 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {04D30F12-E5F0-4805-AEA7-F3AB3C3BED8C}
+ Library
+ Properties
+ Ncqrs.Eventing.Storage.AWS.Tests
+ Ncqrs.Eventing.Storage.AWS.Tests
+ v4.0
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\..\..\lib\Release\Ncqrs.Eventing.Storage.AWS.Tests\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ ..\..\..\lib\ThirdParty\json.net\Newtonsoft.Json.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {01F84441-80D3-49B4-AB18-96894ACB2F90}
+ Ncqrs
+
+
+ {B43AEA6E-59C2-4731-91EA-40C36CEE8360}
+ ApplicationService
+
+
+ {D8D8A477-8018-432B-8E85-795E425D4862}
+ Ncqrs.Eventing.Storage.AWS
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Properties/AssemblyInfo.cs b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..c4ff90af
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Ncqrs.Eventing.Storage.AWS.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Ncqrs.Eventing.Storage.AWS.Tests")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("84e3fbf7-66d2-4dfe-986a-42909624936e")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS/Ncqrs.Eventing.Storage.AWS.csproj b/Extensions/src/Ncqrs.Eventing.Storage.AWS/Ncqrs.Eventing.Storage.AWS.csproj
new file mode 100644
index 00000000..fc87f26f
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS/Ncqrs.Eventing.Storage.AWS.csproj
@@ -0,0 +1,70 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {D8D8A477-8018-432B-8E85-795E425D4862}
+ Library
+ Properties
+ Ncqrs.Eventing.Storage.AWS
+ Ncqrs.Eventing.Storage.AWS
+ v4.0
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\..\..\lib\Release\Ncqrs.Eventing.Storage.AWS\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\lib\ThirdParty\AWSSDK\AWSSDK.dll
+
+
+ ..\..\..\lib\ThirdParty\json.net\Newtonsoft.Json.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {01F84441-80D3-49B4-AB18-96894ACB2F90}
+ Ncqrs
+
+
+
+
+
\ No newline at end of file
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS/Properties/AssemblyInfo.cs b/Extensions/src/Ncqrs.Eventing.Storage.AWS/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..31b30e68
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Ncqrs.Eventing.Storage.AWS")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Ncqrs.Eventing.Storage.AWS")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("4dacacd1-0fbf-46d9-8bd7-a56367086429")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS/Table/NcqrsEvent.cs b/Extensions/src/Ncqrs.Eventing.Storage.AWS/Table/NcqrsEvent.cs
new file mode 100644
index 00000000..5aff584f
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS/Table/NcqrsEvent.cs
@@ -0,0 +1,35 @@
+using System;
+using Ncqrs.Eventing.ServiceModel.Bus;
+
+namespace Ncqrs.Eventing.Storage.AWS
+{
+ internal class NcqrsEvent
+ {
+ public Guid EventSourceId { get; set; }
+ public Guid EventIdentifier { get; set; }
+ public Guid CommitId { get; set; }
+ public string Name { get; set; }
+ public string Version { get; set; }
+ public long Sequence { get; set; }
+ public string Data { get; set; }
+ public DateTime Timestamp { get; set; }
+
+ public NcqrsEvent()
+ { }
+
+ public NcqrsEvent(IPublishableEvent @event)
+ {
+ Timestamp = DateTime.UtcNow;
+ EventSourceId = @event.EventSourceId;
+ EventIdentifier = @event.EventIdentifier;
+ Name = @event.Payload.GetType().AssemblyQualifiedName;
+ Sequence = @event.EventSequence;
+ Version = @event.EventVersion.ToString();
+
+ if (@event.Payload != null)
+ {
+ Data = Utility.Jsonize(@event.Payload, Name);
+ }
+ }
+ }
+}
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS/Table/NcqrsEventSource.cs b/Extensions/src/Ncqrs.Eventing.Storage.AWS/Table/NcqrsEventSource.cs
new file mode 100644
index 00000000..6acab50f
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS/Table/NcqrsEventSource.cs
@@ -0,0 +1,34 @@
+using System;
+using Ncqrs.Eventing.Sourcing;
+
+namespace Ncqrs.Eventing.Storage.AWS
+{
+ public class NcqrsEventSource
+ {
+ public long Version { get; set; }
+ public string Name { get; set; }
+ public Guid EventSourceId { get; set; }
+ public DateTime Timestamp { get; set; }
+
+ public NcqrsEventSource()
+ { }
+
+ public NcqrsEventSource(IEventSource source)
+ {
+ EventSourceId = source.EventSourceId;
+ Timestamp = DateTime.UtcNow;
+ Version = source.Version;
+ Name = source.GetType().ToString();
+ }
+
+ public NcqrsEventSource(Guid eventSourceId,
+ long version,
+ string name)
+ {
+ EventSourceId = eventSourceId;
+ Timestamp = DateTime.UtcNow;
+ Version = version;
+ Name = name;
+ }
+ }
+}
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS/Table/NcqrsEventStoreContext.cs b/Extensions/src/Ncqrs.Eventing.Storage.AWS/Table/NcqrsEventStoreContext.cs
new file mode 100644
index 00000000..6a413d97
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS/Table/NcqrsEventStoreContext.cs
@@ -0,0 +1,184 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Amazon.SimpleDB;
+using Amazon.SimpleDB.Model;
+using Attribute = Amazon.SimpleDB.Model.Attribute;
+
+namespace Ncqrs.Eventing.Storage.AWS
+{
+ internal class NcqrsEventStoreContext
+ {
+ private readonly Guid _eventSourceID;
+ private const string _domainName = "NcqrsEventStore";
+ private readonly AmazonSimpleDB _account;
+
+ private string EVENTSOURCETABLENAME
+ {
+ get
+ {
+ return _tablePrefix + _domainName + "Source";
+ }
+ }
+ private string EVENTTABLENAME
+ {
+ get
+ {
+ return _tablePrefix + _domainName;
+ }
+ }
+
+ private readonly string _tablePrefix;
+
+ public NcqrsEventStoreContext(Guid eventSourceId,
+ AmazonSimpleDB account)
+ : this(eventSourceId, account, null)
+ {
+ _eventSourceID = eventSourceId;
+ }
+
+ public NcqrsEventStoreContext(Guid eventSourceId,
+ AmazonSimpleDB account,
+ string tablePrefix)
+ {
+ _account = account;
+ _eventSourceID = eventSourceId;
+ _tablePrefix = tablePrefix;
+
+ CreateIfNotExist(EVENTTABLENAME);
+ CreateIfNotExist(EVENTSOURCETABLENAME);
+ }
+
+ private void CreateIfNotExist(string domainName)
+ {
+ ListDomainsResponse response = _account.ListDomains(new ListDomainsRequest());
+
+ if (response.ListDomainsResult.DomainName.Any(domain => domain == domainName)) return;
+ _account.CreateDomain(new CreateDomainRequest { DomainName = domainName });
+ }
+
+ public IQueryable Events
+ {
+ get
+ {
+ string selectStmt = string.Format("select * from {0} where EventSourceId='{1}'", EVENTTABLENAME, _eventSourceID);
+ SelectRequest selectRequestAction = new SelectRequest().WithSelectExpression(selectStmt);
+ SelectResponse result = _account.Select(selectRequestAction);
+ if (result.SelectResult.Item.Count > 0 &&
+ result.SelectResult.Item[0].Attribute.Count > 0)
+ {
+ return result.SelectResult.Item.Select(
+ item => new NcqrsEvent
+ {
+ CommitId = new Guid(item.Attribute.First(a => a.Name == "CommitId").Value),
+ Data = item.Attribute.First(a => a.Name == "Data").Value,
+ EventIdentifier =
+ new Guid(item.Attribute.First(a => a.Name == "EventIdentifier").Value),
+ EventSourceId =
+ new Guid(item.Attribute.First(a => a.Name == "EventSourceId").Value),
+ Name = item.Attribute.First(a => a.Name == "Name").Value,
+ Sequence =
+ Convert.ToInt64(item.Attribute.First(a => a.Name == "Sequence").Value),
+ Timestamp =
+ Convert.ToDateTime(
+ item.Attribute.First(a => a.Name == "Timestamp").Value),
+ Version = item.Attribute.First(a => a.Name == "Version").Value
+ }).AsQueryable();
+ }
+ return null;
+ }
+ }
+
+ public NcqrsEventSource LatestEventSource
+ {
+ get
+ {
+ string selectStmt = string.Format("select * from {0} where EventSourceId='{1}'", EVENTSOURCETABLENAME, _eventSourceID);
+ SelectRequest selectRequestAction = new SelectRequest().WithSelectExpression(selectStmt);
+ SelectResponse result = _account.Select(selectRequestAction);
+ if (result.SelectResult.Item.Count > 0 &&
+ result.SelectResult.Item[0].Attribute.Count > 0)
+ {
+ List attributeCollection = result.SelectResult.Item[0].Attribute;
+ return new NcqrsEventSource
+ {
+ EventSourceId = new Guid(attributeCollection.First(a => a.Name == "EventSourceId").Value),
+ Name = attributeCollection.First(a => a.Name == "Name").Value,
+ Timestamp = Convert.ToDateTime(attributeCollection.First(a => a.Name == "Timestamp").Value),
+ Version = Convert.ToInt64(attributeCollection.First(a => a.Name == "Version").Value)
+ };
+ }
+ return null;
+ }
+ }
+
+ private Guid _commitId = Guid.Empty;
+
+ public Guid BeginCommit()
+ {
+ if (_commitId != Guid.Empty)
+ {
+ throw new InvalidOperationException("Cannot BeginCommit while CommitId [" + _commitId + "] is still pending");
+ }
+ _commitId = Guid.NewGuid();
+ return _commitId;
+ }
+
+ public void Add(NcqrsEvent @event)
+ {
+ if (_commitId == Guid.Empty)
+ {
+ throw new InvalidOperationException("Cannot Add events without beginning a commit. Call the BeginCommit method");
+ }
+ @event.CommitId = _commitId;
+
+ List list =
+ new List();
+ list.Add(new ReplaceableAttribute { Name = "Name", Replace = true, Value = @event.Name });
+ list.Add(new ReplaceableAttribute { Name = "CommitId", Replace = true, Value = @event.CommitId.ToString() });
+ list.Add(new ReplaceableAttribute { Name = "Data", Replace = true, Value = @event.Data });
+ list.Add(new ReplaceableAttribute { Name = "EventIdentifier", Replace = true, Value = @event.EventIdentifier.ToString() });
+ list.Add(new ReplaceableAttribute { Name = "EventSourceId", Replace = true, Value = @event.EventSourceId.ToString() });
+ list.Add(new ReplaceableAttribute { Name = "Sequence", Replace = true, Value = @event.Sequence.ToString(CultureInfo.InvariantCulture) });
+ list.Add(new ReplaceableAttribute { Name = "Timestamp", Replace = true, Value = @event.Timestamp.ToString(CultureInfo.InvariantCulture) });
+ list.Add(new ReplaceableAttribute { Name = "Version", Replace = true, Value = @event.Version });
+
+ _account.PutAttributes(
+ new PutAttributesRequest
+ {
+ Attribute = list,
+ DomainName = EVENTTABLENAME,
+ ItemName = @event.EventIdentifier.ToString()
+ });
+ }
+
+ public void SaveSource(NcqrsEventSource source)
+ {
+ if (_commitId == Guid.Empty)
+ {
+ throw new InvalidOperationException("Cannot Add event sources without beginning a commit. Call the BeginCommit method");
+ }
+
+ List list =
+ new List();
+ list.Add(new ReplaceableAttribute { Name = "EventSourceId", Replace = true, Value = source.EventSourceId.ToString() });
+ list.Add(new ReplaceableAttribute { Name = "Name", Replace = true, Value = source.Name });
+ list.Add(new ReplaceableAttribute { Name = "Timestamp", Replace = true, Value = source.Timestamp.ToString(CultureInfo.InvariantCulture) });
+ list.Add(new ReplaceableAttribute { Name = "Version", Replace = true, Value = source.Version.ToString(CultureInfo.InvariantCulture) });
+
+ _account.PutAttributes(
+ new PutAttributesRequest
+ {
+ Attribute = list,
+ DomainName = EVENTSOURCETABLENAME,
+ ItemName = source.EventSourceId.ToString()
+ });
+ }
+
+ public void EndCommit()
+ {
+ // No trx - can't commit
+ }
+ }
+}
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS/Table/SimpleDBStore.cs b/Extensions/src/Ncqrs.Eventing.Storage.AWS/Table/SimpleDBStore.cs
new file mode 100644
index 00000000..15d1bbec
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS/Table/SimpleDBStore.cs
@@ -0,0 +1,110 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Amazon;
+using Amazon.SimpleDB;
+
+namespace Ncqrs.Eventing.Storage.AWS
+{
+ ///
+ /// Initialises a new event store that uses Table Storage only.
+ ///
+ /// May not be appropriate for events with large payloads
+ public class SimpleDBStore : IEventStore
+ {
+ readonly AmazonSimpleDB account = AWSClientFactory.CreateAmazonSimpleDBClient();
+ private string prefix = null;
+
+ public SimpleDBStore()
+ { }
+
+ ///
+ /// Creates a new SimpleDBStore, and names the table including the supplied Prefix
+ ///
+ /// The prefix for the table name
+ /// Useful for testing and partitioning, e.g., new TableStorage("TestRun1")
+ public SimpleDBStore(string prefix)
+ {
+ this.prefix = prefix;
+ }
+
+ private void SaveEvents(Guid eventSourceId,
+ IEnumerable events)
+ {
+ string eventSourceName = events.First().GetType().ToString();
+ long initialVersion = events.First().InitialVersionOfEventSource;
+ long lastVersion = initialVersion + events.Count();
+
+ NcqrsEventStoreContext storeContext = new NcqrsEventStoreContext(eventSourceId, account, prefix);
+ Guid commitId = storeContext.BeginCommit();
+
+ NcqrsEventSource lastSource = storeContext.LatestEventSource;
+ if (lastSource == null)
+ {
+ lastSource = new NcqrsEventSource(eventSourceId,
+ initialVersion,
+ eventSourceName);
+
+ }
+ else if (lastSource.Version != initialVersion)
+ {
+ throw new ConcurrencyException(eventSourceId, initialVersion);
+ }
+
+ foreach (UncommittedEvent @event in events)
+ {
+ storeContext.Add(new NcqrsEvent(@event));
+ }
+
+ lastSource.Version = lastVersion;
+ storeContext.SaveSource(lastSource);
+
+ storeContext.EndCommit();
+ }
+
+ public CommittedEventStream ReadFrom(Guid id, long minVersion, long maxVersion)
+ {
+ NcqrsEventStoreContext eventContext = new NcqrsEventStoreContext(id, account, prefix);
+
+ IQueryable storeEvents = eventContext.Events;
+
+ if (minVersion != long.MinValue)
+ {
+ storeEvents = storeEvents.Where(e => e.Sequence >= minVersion);
+ }
+ if (maxVersion != long.MaxValue)
+ {
+ storeEvents = storeEvents.Where(e => e.Sequence <= maxVersion);
+ }
+
+ storeEvents = storeEvents.ToList().OrderBy(e => e.Sequence).AsQueryable();
+
+ IEnumerable committedEvents = storeEvents.Select(
+ e => new CommittedEvent(
+ e.CommitId,
+ e.EventIdentifier,
+ e.EventSourceId,
+ e.Sequence,
+ e.Timestamp,
+ Utility.DeJsonize(e.Data, e.Name),
+ Version.Parse(e.Version)
+ )
+ );
+
+ return new CommittedEventStream(id, committedEvents);
+ }
+
+ #region IEventStore Members
+
+ public void Store(UncommittedEventStream eventStream)
+ {
+ Parallel.ForEach(
+ eventStream.Select(es => es.EventSourceId).Distinct(),
+ eventSourceId => SaveEvents(eventSourceId, eventStream.Where(es => es.EventSourceId == eventSourceId))
+ );
+ }
+
+ #endregion
+ }
+}
diff --git a/Extensions/src/Ncqrs.Eventing.Storage.AWS/Utility.cs b/Extensions/src/Ncqrs.Eventing.Storage.AWS/Utility.cs
new file mode 100644
index 00000000..18bd6295
--- /dev/null
+++ b/Extensions/src/Ncqrs.Eventing.Storage.AWS/Utility.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Text;
+using System.IO;
+using Newtonsoft.Json;
+
+namespace Ncqrs.Eventing.Storage.AWS
+{
+ public static class Utility
+ {
+ public static string Jsonize(object data, Type type)
+ {
+ StringBuilder result = new StringBuilder();
+ new JsonSerializer().Serialize(new StringWriter(result), data);
+ return result.ToString();
+ }
+
+ public static string Jsonize(object data, string assemblyQualifiedTypeName)
+ {
+ Type parsedType = Type.GetType(assemblyQualifiedTypeName, true, true);
+ return Jsonize(data, parsedType);
+ }
+
+ public static object DeJsonize(string data, Type type)
+ {
+ return new JsonSerializer().Deserialize(new StringReader(data), type);
+ }
+
+ public static object DeJsonize(string data, string assemblyQualifiedTypeName)
+ {
+ Type parsedType = Type.GetType(assemblyQualifiedTypeName, true, true);
+ return DeJsonize(data, parsedType);
+ }
+
+ }
+}
diff --git a/Framework/AssemblyInfo.cs b/Framework/AssemblyInfo.cs
index c5fc3d5a..6d06b9e7 100644
--- a/Framework/AssemblyInfo.cs
+++ b/Framework/AssemblyInfo.cs
@@ -6,7 +6,7 @@
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
-// Runtime Version:4.0.30319.225
+// Runtime Version:4.0.30319.269
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
diff --git a/Framework/src/Ncqrs.Spec/AggregateRootTestFixture.cs b/Framework/src/Ncqrs.Spec/AggregateRootTestFixture.cs
index df2e8efe..ba72c6d6 100644
--- a/Framework/src/Ncqrs.Spec/AggregateRootTestFixture.cs
+++ b/Framework/src/Ncqrs.Spec/AggregateRootTestFixture.cs
@@ -1,34 +1,17 @@
using System;
using System.Collections.Generic;
-using System.Linq;
+using NUnit.Framework;
using Ncqrs.Domain;
using Ncqrs.Domain.Storage;
using Ncqrs.Eventing;
-using Ncqrs.Eventing.Sourcing;
-using NUnit.Framework;
namespace Ncqrs.Spec
{
[Specification]
- [TestFixture] // TODO: Testdriven.net debug runner doesn't recognize inhiret attributes. Use native for now.
+ [TestFixture] // TODO: Testdriven.net debug runner doesn't recognize inherit attributes. Use native for now.
public abstract class AggregateRootTestFixture where TAggregateRoot : AggregateRoot
{
- protected IAggregateRootCreationStrategy CreationStrategy { get; set; }
-
- protected TAggregateRoot AggregateRoot { get; set; }
-
- protected Exception CaughtException { get; private set; }
-
- protected List PublishedEvents { get; private set; }
-
- protected virtual IEnumerable