Postgres backed event store written in F# perhaps best described as barebones, or beginner-friendly, but in no way intended to compete with options such as the battle-tested jet/equinox or the increasingly compatible Dzoukr/CosmoStore, the latter of which also works with PostgreSQL now. Definitely look into those for something more tried and true.
Package | Description | NuGet |
---|---|---|
Everstream.PostgreSQL | PostgreSQL-backed event store | |
Everstream | API definition (you don't need this) |
Here's the API, short, sweet, and to the point.
type EventStore =
{
/// Get a specific stream identified by a stream query
GetStream : IProgress -> StreamQuery -> Async<PersistedEvent list>
/// Get all streams of a specific type
GetStreams : IProgress -> EventDataType -> Async<Map<Stream, PersistedEvent list>>
/// Get all events identified by a history query
GetHistory : IProgress -> HistoryQuery -> Async<PersistedEvent list>
/// Append events, optionally as consequences of an existing event
Append : PersistedEvent option -> EventData list -> Stream -> Async<PersistedEvent list>
}
You may be thinking "hold on, that is pretty simple, but what are these query paramters hiding".
Fair enough, here they are:
type Stream =
{
Id: StreamId // string
Version: Version // int
}
module Query =
type HistoryQuery =
| SinceTheBeginning
| SinceTimestamp of Timestamp // long
type StreamQuery =
| SinceVersion of Stream
| Full of StreamId // string
To make things easier, there's an EventProxy
agent that you can use that implements the EventStore
API above. This proxy takes care of maintaining the history of events in memory, and only fetching new ones whenever an update is necessary. Its API mirrors the EventStore
API, adding a few more functions for convenience. This proxy is not particularly optimized, it'll get you up and running with no effort, but eventually you may want to replace it with something more optimized for your own particular needs.
Everstream was created with the very specific purpose of having an F# library with Event persistence as its single concern. While I myself use it with CQRS, there is no reference to commands or projections, the storing logic is completely distilled into its own independent package here. Think of Everstream as monkey sees Event, monkey writes Event, and monkey eventually fetches a previously written Event. But monkey does not even know (or care) what an Event is.
In line with the above mission statement, Everstream is incredibly feature-light and will always be that way. The idea is that most of what you'll do with events are projections (really, think about it), and thus should be defined elsewhere. In my solutions, the projects that define projections — no pun intended — don't even reference Everstream. It's easy to fall into the trap of mixing everything Event-related together in your code, when in fact, Event persistence is an infrastructure concern, it's unrelated to business logic which is what Events are.
Since this is my first project here, I'm looking for contributors with experience in Github repository management, Nuget package management or both. This package does have some rudimentary tests using Expecto, but this part could definitely use some love, so if you like writing tests for breakfast and F# |> U <3
, please wear some aluminum foil over your head so I can see you.
This is not meant to be used by Fortune 500 companies, the stability of the API is far less important than it being as concise and self-documenting as possible. Expect new versions to change the API using [<Obsolete>]
whenever possible so as to not break your code without a fair warning. That is unless you update your packages once a year, in which case, shame on you... and me, I do it too.
I will try to add some examples asap, feel free to tweet @luislikelewis and nag me out of my procrastination zone...