Sharpino 1.4.4
See the version list below for details.
dotnet add package Sharpino --version 1.4.4
NuGet\Install-Package Sharpino -Version 1.4.4
<PackageReference Include="Sharpino" Version="1.4.4" />
paket add Sharpino --version 1.4.4
#r "nuget: Sharpino, 1.4.4"
// Install Sharpino as a Cake Addin #addin nuget:?package=Sharpino&version=1.4.4 // Install Sharpino as a Cake Tool #tool nuget:?package=Sharpino&version=1.4.4
Sharpino
<img src="ico/sharpino.png" alt="drawing" width="50"/>
A little F# event-sourcing library
What is it?
Support for Event-sourcing in F#. No sensible data (GDPR) support.
Features
- Support in memory and Postgres storage. Support Eventstoredb (only for the LightCommandHandler).
- Support publishing events to Kafka.
- Example application with tests including Kafka subscriber.
- Contexts represent sets of collections of entities (e.g. a collection of todos, a collection of tags, a collection of categories, etc.) associated with events
- A specific practice to refactor context and test context refactoring
- Send events to Apache Kafka
Projects
Sharpino.Lib:
Core.fs: Abstract definition of Events, Commands and Undoer (the reverse of a command to be used if storage lacks transaction between streams). Definition of EvolveUnForgivingErrors and "normal" Evolve. The former raises an error if there are some events that cannot be applied to the current state of the context. The latter just skip those events.
CommandHandler.fs: gets and stores snapshots, execute commands, and produces and store events using the storage.
LightCommandHandler.fs: gets and stores snapshots, execute commands, produces and store events using a storage that supports pub/sub model (only Eventstoredb at the moment).
DbStorage.fs and MemoryStorage.fs: Manages persistency in Postgres or in-memory.
Cache.fs. Cache current state.
Sharpino.Sample You need a user called 'safe' with password 'safe' in your Postgres (if you want to use Postgres as Eventstore).
It is an example of a library for managing todos with tags and categories. There are two versions in the sense of two different configurations concerning the distribution of the models (collection of entities) between the contexts. There is a strategy to test the migration between versions (contexts refactoring) that is described in the code (See: AppVersions.fs and MultiVersionsTests.fs .
contexts (e.g. TodosContext) own a partition of the models and provide members to handle them.
contexts members have corresponding events (e.g. TagsEvents) that are Discriminated Unions cases. Event types implement the Process interface.
contexts are related to Commands (e.g. TagCommand) that are Discriminated Unions cases that can return lists of events by implementing the Executable interface.
Commands defines also undoers are functions that can undo the commands to reverse action in a multiple-stream operation for storage that doesn't support multiple-stream transactions (see LightCommandHandler).
- A Storage stores and retrieves events and snapshots.
- The api layer functions provide business logic involving one or more clusters by accessing their state, and by building one or more commands and sending them to the CommandHandler.
- An example of how to handle multiple versions of the application to help refactoring and migration between different versions: application versions.
Sharpino.Sample.tests
- tests for the sample application
Sharpino.Sample.Kafka
- scripts to setup a Kafka topics corresponding to the contexts of the sample application
How to use it
- You can run the sample application as a rest service by running the following command from Sharpino.Sample folder:
dotnet run
- You can run the client Fable/Elmish sample application by running the following command from the Sharpino.Sample.Client folder:
npm install
npm start
- Just use ordinary dotnet command line tools for building the solution. Particularly you can run tests of the sample application by using the following command:
dotnet test
You can also run the tests by the following command from Sharpino.Sample.Tests folder:
dotnet run
In the latter case, you get the output from Expecto test runner (in this case the console shows eventual standard output/printf).
By default, the tests run only the in-memory implementation of the storage. You can set up the Postgres tables and db by using dbmate. In the Sharpino.Sample folder you can run the following command to set up the Postgres database:
dbmate -e up
(see the .env to set up the DATABASE_URL environment variable to connect to the Postgres database with a connection string). If you have Eventstore the standard configuration should work. (I have tested it with Eventstore 20.10.2-alpha on M2 Apple Silicon chip under Docker).
Tests on eventstoredb
If eventstore is running on docker you may want to run tests on it as follows: by making the eventstore tests not pending (search for "eventstore tests" and change ptestList to ftestList) or by uncommenting the following line on the file MultiversionsTests.fs:
// (AppVersions.evSApp, AppVersions.evSApp, fun () -> () |> Result.Ok)
Faq:
- Why "Sharpino"?
- It's a mix of Sharp and fino (Italian for "thin"). "sciarpino" (same pronunciation) in Italian means also "little scarf".
- Why another event-sourcing library?
- I wanted to study the subject and it ended up in a tiny little framework.
- Why F#?
- Any functional language from the ML family language in my opinion is a good fit for the following reasons:
- Events are immutable, building the state of the context is a function of those events.
- Discriminated Unions are suitable to represent events and commands.
- The use of the lambda expression is a nice trick for the undoers (the under is returned as a lambda that retrieves the context for applying the undo and returns another lambda that actually can "undo" the command).
- It is a .net language, so you can use everything in the .net ecosystem (including C# libraries).
- Any functional language from the ML family language in my opinion is a good fit for the following reasons:
- How to use it
- add the nuget package Sharpino to your project (current version 1.0.1)
- note: on my side, when I added Sharpino as a library into a web app, then I had to add the following line to the web app project file to avoid a false error (the error was "A function labeled with the 'EntryPointAttribute' attribute must be the last declaration")
<GenerateProgramFile>false</GenerateProgramFile>
News:
Version 1.4.0: runCommand instead of Result<unit, string> returns, under result, info about event-store created IDs (Postgres based) of new events and eventually Kafka Delivery result (if Kafka is configured).
Version 1.3.9: Repository interface changed (using Result type when it is needed). Note: the new Repository interface (and implementation) is not compatible with the one introduced in Version 1.3.8!
Version 1.3.8: can use a new Repository type instead of lists (even though they are still implemented as plain lists at the moment) to handle collections of entities.
Version 1.3.5: the library is split into two nuget packages: Sharpino.Core and Sharpino.Lib. the Sharpino.Core can be included in a Shared project in the Fable Remoting style. The collections of the entities used in the Sharpino.Sample are not lists anymore but use Repository data type (which at the moment uses plain lists anyway).
Version 1.3.4 there is the possibility to choose a pessimistic lock (or not) in command processing. Needed a configuration file named appSettings.json in the root of the project with the following content:
"SharpinoConfig": {
"PessimisticLock": false // or true
}
}
More documentation (Sharpino gitbook)
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET Framework | net is compatible. |
-
net7.0
- Confluent.Kafka (>= 2.3.0)
- EventStore.Client.Grpc.Streams (>= 23.1.0)
- Expecto (>= 10.1.0)
- Expecto.FsCheck (>= 10.1.0)
- Farmer (>= 1.8.2)
- FsCheck (>= 2.16.6)
- FSharp.Control.AsyncSeq (>= 3.2.1)
- FSharp.Data (>= 6.3.0)
- FSharpPlus (>= 1.5.0)
- FsToolkit.ErrorHandling (>= 4.12.0)
- Log4net (>= 2.0.15)
- Microsoft.Extensions.Configuration (>= 8.0.0)
- Microsoft.Extensions.Configuration.Binder (>= 8.0.0)
- Microsoft.Extensions.Configuration.Json (>= 8.0.0)
- Microsoft.NET.Test.Sdk (>= 17.0.0)
- Newtonsoft.Json (>= 13.0.3)
- Npgsql (>= 7.0.6)
- Npgsql.FSharp (>= 5.7.0)
- Sharpino.Core (>= 1.0.1)
- System.collections (>= 4.3.0)
- System.Data.Common (>= 4.3.0)
- YoloDev.Expecto.TestSdk (>= 0.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated | |
---|---|---|---|
3.0.2 | 30 | 11/17/2024 | |
3.0.1 | 36 | 11/14/2024 | |
3.0.0 | 46 | 11/14/2024 | |
2.7.7 | 78 | 11/4/2024 | |
2.7.6 | 73 | 11/3/2024 | |
2.7.5 | 85 | 10/29/2024 | |
2.7.4 | 79 | 10/25/2024 | |
2.7.3 | 65 | 10/21/2024 | |
2.7.2 | 72 | 10/21/2024 | |
2.7.1 | 94 | 10/20/2024 | |
2.7.0 | 82 | 10/20/2024 | |
2.6.9 | 79 | 10/16/2024 | |
2.6.8 | 87 | 10/16/2024 | |
2.6.7 | 78 | 10/14/2024 | |
2.6.6 | 69 | 10/14/2024 | |
2.6.5 | 82 | 10/10/2024 | |
2.6.4 | 76 | 10/8/2024 | |
2.6.3 | 88 | 9/30/2024 | |
2.6.2 | 87 | 9/28/2024 | |
2.6.1 | 81 | 9/28/2024 | |
2.6.0 | 86 | 9/24/2024 | |
2.5.9 | 83 | 9/24/2024 | |
2.5.8 | 91 | 9/18/2024 | |
2.5.7 | 105 | 9/16/2024 | |
2.5.6 | 118 | 9/14/2024 | |
2.5.5 | 124 | 8/22/2024 | |
2.5.4 | 127 | 8/15/2024 | |
2.5.3 | 120 | 8/13/2024 | |
2.5.2 | 113 | 8/9/2024 | |
2.5.1 | 64 | 7/29/2024 | |
2.5.0 | 107 | 7/19/2024 | |
2.4.2 | 103 | 7/14/2024 | |
2.4.1 | 105 | 7/13/2024 | |
2.4.0 | 132 | 7/6/2024 | |
2.3.0 | 116 | 6/28/2024 | |
2.2.9 | 118 | 6/27/2024 | |
2.2.8 | 102 | 6/26/2024 | |
2.2.7 | 105 | 6/23/2024 | |
2.2.6 | 96 | 6/18/2024 | |
2.2.5 | 96 | 6/17/2024 | |
2.2.4 | 103 | 5/29/2024 | |
2.2.3 | 112 | 5/25/2024 | |
2.2.2 | 107 | 5/19/2024 | |
2.2.1 | 102 | 5/14/2024 | |
2.2.0 | 97 | 5/14/2024 | |
2.1.3 | 91 | 5/12/2024 | |
2.1.2 | 104 | 5/10/2024 | |
2.1.1 | 116 | 5/9/2024 | |
2.1.0 | 106 | 5/8/2024 | |
2.0.7 | 117 | 5/6/2024 | |
2.0.6 | 111 | 5/4/2024 | |
2.0.5 | 74 | 5/3/2024 | |
2.0.4 | 66 | 5/3/2024 | |
2.0.3 | 65 | 5/3/2024 | |
2.0.2 | 69 | 5/3/2024 | |
2.0.1 | 60 | 5/2/2024 | |
2.0.0 | 72 | 5/2/2024 | |
1.6.6 | 103 | 4/29/2024 | |
1.6.5 | 115 | 4/28/2024 | |
1.6.4 | 96 | 4/28/2024 | |
1.6.3 | 113 | 4/25/2024 | |
1.6.2 | 119 | 4/23/2024 | |
1.6.1 | 109 | 4/21/2024 | |
1.6.0 | 126 | 4/6/2024 | |
1.5.9 | 173 | 3/17/2024 | |
1.5.8 | 182 | 3/11/2024 | |
1.5.7 | 167 | 3/10/2024 | |
1.5.6 | 207 | 3/4/2024 | |
1.5.5 | 211 | 3/3/2024 | |
1.5.4 | 211 | 2/26/2024 | |
1.5.3 | 256 | 2/25/2024 | |
1.5.2 | 221 | 2/18/2024 | |
1.5.1 | 273 | 2/7/2024 | |
1.5.0 | 247 | 2/1/2024 | |
1.4.9 | 286 | 1/26/2024 | |
1.4.8 | 285 | 1/25/2024 | |
1.4.7 | 356 | 1/2/2024 | |
1.4.6 | 375 | 12/19/2023 | |
1.4.5 | 377 | 12/19/2023 | |
1.4.4 | 409 | 12/14/2023 | |
1.4.3 | 382 | 12/13/2023 | |
1.4.1 | 437 | 12/9/2023 | |
1.4.0 | 412 | 12/8/2023 | |
1.3.9 | 453 | 12/1/2023 | |
1.3.8 | 479 | 11/29/2023 | |
1.3.6 | 437 | 11/29/2023 | |
1.3.4 | 437 | 11/27/2023 | |
1.3.3 | 448 | 11/27/2023 | |
1.3.2 | 449 | 11/16/2023 | |
1.3.1 | 419 | 11/15/2023 | |
1.3.0 | 432 | 11/9/2023 | |
1.3.0-beta | 392 | 11/9/2023 | |
1.2.8 | 421 | 11/6/2023 | |
1.2.7 | 433 | 11/5/2023 | |
1.2.6 | 462 | 11/3/2023 | |
1.2.5 | 456 | 11/2/2023 | |
1.2.4 | 478 | 10/21/2023 | |
1.2.3 | 499 | 10/14/2023 | |
1.2.2 | 444 | 10/13/2023 | |
1.2.0 | 467 | 10/13/2023 | |
1.1.0 | 479 | 10/7/2023 | |
1.0.2 | 464 | 9/20/2023 | |
1.0.1 | 497 | 9/12/2023 | |
1.0.0 | 1,665 | 9/12/2023 |