diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/EventSourcing.Demo.csproj b/EventSourcing.Demo.csproj new file mode 100644 index 0000000..1b30db0 --- /dev/null +++ b/EventSourcing.Demo.csproj @@ -0,0 +1,14 @@ + + + + net5.0 + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/EventSourcing.Demo.csproj b/EventSourcing.Demo.csproj new file mode 100644 index 0000000..1b30db0 --- /dev/null +++ b/EventSourcing.Demo.csproj @@ -0,0 +1,14 @@ + + + + net5.0 + + + + + + + + + + diff --git a/Events.cs b/Events.cs new file mode 100644 index 0000000..018c062 --- /dev/null +++ b/Events.cs @@ -0,0 +1,24 @@ +using System; + +namespace EventSourcing.Demo +{ + public interface IEvent + { + string EventType { get; } + } + + public record ProductShipped(string Sku, int Quantity, DateTime DateTime) : IEvent + { + public string EventType { get; } = "ProductShipped"; + } + + public record ProductReceived(string Sku, int Quantity, DateTime DateTime) : IEvent + { + public string EventType { get; } = "ProductReceived"; + } + + public record InventoryAdjusted(string Sku, int Quantity, string Reason, DateTime DateTime) : IEvent + { + public string EventType { get; } = "InventoryAdjusted"; + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/EventSourcing.Demo.csproj b/EventSourcing.Demo.csproj new file mode 100644 index 0000000..1b30db0 --- /dev/null +++ b/EventSourcing.Demo.csproj @@ -0,0 +1,14 @@ + + + + net5.0 + + + + + + + + + + diff --git a/Events.cs b/Events.cs new file mode 100644 index 0000000..018c062 --- /dev/null +++ b/Events.cs @@ -0,0 +1,24 @@ +using System; + +namespace EventSourcing.Demo +{ + public interface IEvent + { + string EventType { get; } + } + + public record ProductShipped(string Sku, int Quantity, DateTime DateTime) : IEvent + { + public string EventType { get; } = "ProductShipped"; + } + + public record ProductReceived(string Sku, int Quantity, DateTime DateTime) : IEvent + { + public string EventType { get; } = "ProductReceived"; + } + + public record InventoryAdjusted(string Sku, int Quantity, string Reason, DateTime DateTime) : IEvent + { + public string EventType { get; } = "InventoryAdjusted"; + } +} \ No newline at end of file diff --git a/Folder.DotSettings b/Folder.DotSettings new file mode 100644 index 0000000..408a942 --- /dev/null +++ b/Folder.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/EventSourcing.Demo.csproj b/EventSourcing.Demo.csproj new file mode 100644 index 0000000..1b30db0 --- /dev/null +++ b/EventSourcing.Demo.csproj @@ -0,0 +1,14 @@ + + + + net5.0 + + + + + + + + + + diff --git a/Events.cs b/Events.cs new file mode 100644 index 0000000..018c062 --- /dev/null +++ b/Events.cs @@ -0,0 +1,24 @@ +using System; + +namespace EventSourcing.Demo +{ + public interface IEvent + { + string EventType { get; } + } + + public record ProductShipped(string Sku, int Quantity, DateTime DateTime) : IEvent + { + public string EventType { get; } = "ProductShipped"; + } + + public record ProductReceived(string Sku, int Quantity, DateTime DateTime) : IEvent + { + public string EventType { get; } = "ProductReceived"; + } + + public record InventoryAdjusted(string Sku, int Quantity, string Reason, DateTime DateTime) : IEvent + { + public string EventType { get; } = "InventoryAdjusted"; + } +} \ No newline at end of file diff --git a/Folder.DotSettings b/Folder.DotSettings new file mode 100644 index 0000000..408a942 --- /dev/null +++ b/Folder.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/Test.cs b/Test.cs new file mode 100644 index 0000000..f34c04f --- /dev/null +++ b/Test.cs @@ -0,0 +1,128 @@ +using System; +using System.Linq; +using AutoFixture; +using Shouldly; +using Xunit; + +namespace EventSourcing.Demo +{ + public class ProductTests + { + private readonly string _sku; + private readonly int _initialQuantity; + private readonly WarehouseProduct _sut; + private readonly Fixture _fixture; + + public ProductTests() + { + _fixture = new Fixture(); + _fixture.Customizations.Add(new Int32SequenceGenerator()); + _sku = _fixture.Create(); + _initialQuantity = (int)_fixture.Create(); + + _sut = WarehouseProduct.Load(_sku, new [] { + new ProductReceived(_sku, _initialQuantity, DateTime.UtcNow) + }); + } + + [Fact] + public void ShipProductShouldRaiseProductShipped() + { + var quantityToShip = _fixture.Create(); + _sut.ShipProduct(quantityToShip); + + var outEvents = _sut.GetUncommittedEvents(); + outEvents.Count.ShouldBe(1); + var outEvent = outEvents.Single(); + outEvent.ShouldBeOfType(); + + var productShipped = (ProductShipped)outEvent; + productShipped.ShouldSatisfyAllConditions( + x => x.Quantity.ShouldBe(quantityToShip), + x => x.Sku.ShouldBe(_sku), + x => x.EventType.ShouldBe("ProductShipped") + ); + } + + [Fact] + public void ShipProductShouldUpdateState() + { + var quantityToShip = _fixture.Create(); + _sut.ShipProduct(quantityToShip); + + _sut.GetQuantityOnHand().ShouldBe(_initialQuantity - quantityToShip); + } + + [Fact] + public void ShipProductShouldThrowIfNoQuantityOnHand() + { + var ex = Should.Throw(() => _sut.ShipProduct(_initialQuantity + 1)); + ex.Message.ShouldBe("Cannot Ship to a negative Quantity on Hand."); + } + + [Fact] + public void ReceiveProductShouldRaiseProductReceived() + { + var quantityToReceive = _fixture.Create(); + _sut.ReceiveProduct(quantityToReceive); + + var outEvents = _sut.GetUncommittedEvents(); + outEvents.Count.ShouldBe(1); + var outEvent = outEvents.Single(); + outEvent.ShouldBeOfType(); + + var productReceived = (ProductReceived)outEvent; + productReceived.ShouldSatisfyAllConditions( + x => x.Quantity.ShouldBe(quantityToReceive), + x => x.Sku.ShouldBe(_sku), + x => x.EventType.ShouldBe("ProductReceived") + ); + } + + [Fact] + public void ReceiveProductShouldUpdateState() + { + var quantityToReceive = _fixture.Create(); + _sut.ReceiveProduct(quantityToReceive); + + _sut.GetQuantityOnHand().ShouldBe(_initialQuantity + quantityToReceive); + } + + [Fact] + public void AdjustInventoryShouldRaiseProductAdjusted() + { + var quantityToAdjust = _fixture.Create(); + var reason = _fixture.Create(); + _sut.AdjustInventory(quantityToAdjust, reason); + + var outEvents = _sut.GetUncommittedEvents(); + outEvents.Count.ShouldBe(1); + var outEvent = outEvents.Single(); + outEvent.ShouldBeOfType(); + + var productShipped = (InventoryAdjusted)outEvent; + productShipped.ShouldSatisfyAllConditions( + x => x.Quantity.ShouldBe(quantityToAdjust), + x => x.Sku.ShouldBe(_sku), + x => x.Reason.ShouldBe(reason), + x => x.EventType.ShouldBe("InventoryAdjusted") + ); + } + + [Fact] + public void AdjustInventoryShouldUpdateState() + { + var quantityToAdjust = _fixture.Create(); + _sut.AdjustInventory(quantityToAdjust, string.Empty); + + _sut.GetQuantityOnHand().ShouldBe(_initialQuantity + quantityToAdjust); + } + + [Fact] + public void AdjustInventoryShouldThrowIfNoQuantityOnHand() + { + var ex = Should.Throw(() => _sut.AdjustInventory((_initialQuantity + 1) * -1, string.Empty)); + ex.Message.ShouldBe("Cannot adjust to a negative Quantity on Hand."); + } + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/EventSourcing.Demo.csproj b/EventSourcing.Demo.csproj new file mode 100644 index 0000000..1b30db0 --- /dev/null +++ b/EventSourcing.Demo.csproj @@ -0,0 +1,14 @@ + + + + net5.0 + + + + + + + + + + diff --git a/Events.cs b/Events.cs new file mode 100644 index 0000000..018c062 --- /dev/null +++ b/Events.cs @@ -0,0 +1,24 @@ +using System; + +namespace EventSourcing.Demo +{ + public interface IEvent + { + string EventType { get; } + } + + public record ProductShipped(string Sku, int Quantity, DateTime DateTime) : IEvent + { + public string EventType { get; } = "ProductShipped"; + } + + public record ProductReceived(string Sku, int Quantity, DateTime DateTime) : IEvent + { + public string EventType { get; } = "ProductReceived"; + } + + public record InventoryAdjusted(string Sku, int Quantity, string Reason, DateTime DateTime) : IEvent + { + public string EventType { get; } = "InventoryAdjusted"; + } +} \ No newline at end of file diff --git a/Folder.DotSettings b/Folder.DotSettings new file mode 100644 index 0000000..408a942 --- /dev/null +++ b/Folder.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/Test.cs b/Test.cs new file mode 100644 index 0000000..f34c04f --- /dev/null +++ b/Test.cs @@ -0,0 +1,128 @@ +using System; +using System.Linq; +using AutoFixture; +using Shouldly; +using Xunit; + +namespace EventSourcing.Demo +{ + public class ProductTests + { + private readonly string _sku; + private readonly int _initialQuantity; + private readonly WarehouseProduct _sut; + private readonly Fixture _fixture; + + public ProductTests() + { + _fixture = new Fixture(); + _fixture.Customizations.Add(new Int32SequenceGenerator()); + _sku = _fixture.Create(); + _initialQuantity = (int)_fixture.Create(); + + _sut = WarehouseProduct.Load(_sku, new [] { + new ProductReceived(_sku, _initialQuantity, DateTime.UtcNow) + }); + } + + [Fact] + public void ShipProductShouldRaiseProductShipped() + { + var quantityToShip = _fixture.Create(); + _sut.ShipProduct(quantityToShip); + + var outEvents = _sut.GetUncommittedEvents(); + outEvents.Count.ShouldBe(1); + var outEvent = outEvents.Single(); + outEvent.ShouldBeOfType(); + + var productShipped = (ProductShipped)outEvent; + productShipped.ShouldSatisfyAllConditions( + x => x.Quantity.ShouldBe(quantityToShip), + x => x.Sku.ShouldBe(_sku), + x => x.EventType.ShouldBe("ProductShipped") + ); + } + + [Fact] + public void ShipProductShouldUpdateState() + { + var quantityToShip = _fixture.Create(); + _sut.ShipProduct(quantityToShip); + + _sut.GetQuantityOnHand().ShouldBe(_initialQuantity - quantityToShip); + } + + [Fact] + public void ShipProductShouldThrowIfNoQuantityOnHand() + { + var ex = Should.Throw(() => _sut.ShipProduct(_initialQuantity + 1)); + ex.Message.ShouldBe("Cannot Ship to a negative Quantity on Hand."); + } + + [Fact] + public void ReceiveProductShouldRaiseProductReceived() + { + var quantityToReceive = _fixture.Create(); + _sut.ReceiveProduct(quantityToReceive); + + var outEvents = _sut.GetUncommittedEvents(); + outEvents.Count.ShouldBe(1); + var outEvent = outEvents.Single(); + outEvent.ShouldBeOfType(); + + var productReceived = (ProductReceived)outEvent; + productReceived.ShouldSatisfyAllConditions( + x => x.Quantity.ShouldBe(quantityToReceive), + x => x.Sku.ShouldBe(_sku), + x => x.EventType.ShouldBe("ProductReceived") + ); + } + + [Fact] + public void ReceiveProductShouldUpdateState() + { + var quantityToReceive = _fixture.Create(); + _sut.ReceiveProduct(quantityToReceive); + + _sut.GetQuantityOnHand().ShouldBe(_initialQuantity + quantityToReceive); + } + + [Fact] + public void AdjustInventoryShouldRaiseProductAdjusted() + { + var quantityToAdjust = _fixture.Create(); + var reason = _fixture.Create(); + _sut.AdjustInventory(quantityToAdjust, reason); + + var outEvents = _sut.GetUncommittedEvents(); + outEvents.Count.ShouldBe(1); + var outEvent = outEvents.Single(); + outEvent.ShouldBeOfType(); + + var productShipped = (InventoryAdjusted)outEvent; + productShipped.ShouldSatisfyAllConditions( + x => x.Quantity.ShouldBe(quantityToAdjust), + x => x.Sku.ShouldBe(_sku), + x => x.Reason.ShouldBe(reason), + x => x.EventType.ShouldBe("InventoryAdjusted") + ); + } + + [Fact] + public void AdjustInventoryShouldUpdateState() + { + var quantityToAdjust = _fixture.Create(); + _sut.AdjustInventory(quantityToAdjust, string.Empty); + + _sut.GetQuantityOnHand().ShouldBe(_initialQuantity + quantityToAdjust); + } + + [Fact] + public void AdjustInventoryShouldThrowIfNoQuantityOnHand() + { + var ex = Should.Throw(() => _sut.AdjustInventory((_initialQuantity + 1) * -1, string.Empty)); + ex.Message.ShouldBe("Cannot adjust to a negative Quantity on Hand."); + } + } +} \ No newline at end of file diff --git a/WarehouseProduct.cs b/WarehouseProduct.cs new file mode 100644 index 0000000..29de5a4 --- /dev/null +++ b/WarehouseProduct.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; + +namespace EventSourcing.Demo +{ + public class WarehouseProductState + { + public int QuantityOnHand { get; set; } + } + + public abstract class AggregateRoot + { + private readonly IList _uncommittedEvents = new List(); + + public IList GetUncommittedEvents() + { + return _uncommittedEvents; + } + + public void ClearUncommittedEvents() + { + _uncommittedEvents.Clear(); + } + + protected void Add(IEvent evnt) + { + _uncommittedEvents.Add(evnt); + } + } + + public class WarehouseProduct : AggregateRoot + { + public string Sku { get; } + + private readonly WarehouseProductState _warehouseProductState = new(); + + public WarehouseProduct(string sku) + { + Sku = sku; + } + + public static WarehouseProduct Load(string sku, IEnumerable events) + { + var warehouseProduct = new WarehouseProduct(sku); + foreach (var evnt in events) + { + warehouseProduct.Apply(evnt as dynamic); + } + return warehouseProduct; + } + + public WarehouseProductState GetState() + { + return _warehouseProductState; + } + + public void ShipProduct(int quantity) + { + if (quantity > _warehouseProductState.QuantityOnHand) + { + throw new InvalidDomainException("Cannot Ship to a negative Quantity on Hand."); + } + + var productShipped = new ProductShipped(Sku, quantity, DateTime.UtcNow); + + Apply(productShipped); + Add(productShipped); + } + + private void Apply(ProductShipped evnt) + { + _warehouseProductState.QuantityOnHand -= evnt.Quantity; + } + + public void ReceiveProduct(int quantity) + { + var productReceived = new ProductReceived(Sku, quantity, DateTime.UtcNow); + + Apply(productReceived); + Add(productReceived); + } + + private void Apply(ProductReceived evnt) + { + _warehouseProductState.QuantityOnHand += evnt.Quantity; + } + + public void AdjustInventory(int quantity, string reason) + { + if (_warehouseProductState.QuantityOnHand + quantity < 0) + { + throw new InvalidDomainException("Cannot adjust to a negative Quantity on Hand."); + } + + var inventoryAdjusted = new InventoryAdjusted(Sku, quantity, reason, DateTime.UtcNow); + + Apply(inventoryAdjusted); + Add(inventoryAdjusted); + } + + private void Apply(InventoryAdjusted evnt) + { + _warehouseProductState.QuantityOnHand += evnt.Quantity; + } + + public int GetQuantityOnHand() + { + return _warehouseProductState.QuantityOnHand; + } + } + + public class InvalidDomainException : Exception + { + public InvalidDomainException(string message) : base(message) + { + + } + } +} \ No newline at end of file