Projections are an important yet pretty simple concept when working with event-centric or event sourcing systems. The concept is to build a state from a stream of events. In my previous post, Event Sourcing with SQL Stream Store, I made a pretty basic projection to keep the current account balance. In this post, I’ll use Liquid Projections to accomplish the same task.
I recommend checking out my post on SQL Stream Store as I’m using the same example/demo application in this post.
Liquid Projections
Liquid Projection is a library for building projections. The concept and API are pretty simple, and I’ll cover the basics in this post.
First I’ll update my Demo Application to use the Liquid Projections NuGet package.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The first building block is creating an event map. The idea is to map an event to an action that we want to be invoked when the event occurs. We can use the EventMapBuild<TContext> to create all of our event mappings. The TContext can be anything but I’ll be using it to mutate the state that represents the current balance.
As a refresher from my previous post, here is the Balance
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Now using the EventMapBuilder<Balance> to handle the Deposited and Withdrawn events.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
You’ll notice call Build() on the EventMapBuilder<Balance> which will return us the EventMap<Balance>. At this point, you can call Handle() to pass in the events incoming from our subscription with our current Balance.
Conditions
There are also some nice additions such as providing conditions for when to execute a map. For example, if you wanted to handle only deposited events where the amount was greater than 100.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
There is also support for inheritance, which means since my Deposited and Withdrawn events inherit from the AccountEvent base class, I could also have done
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters