Fisher 0.6.0
See the version list below for details.
dotnet add package Fisher --version 0.6.0
NuGet\Install-Package Fisher -Version 0.6.0
<PackageReference Include="Fisher" Version="0.6.0" />
<PackageVersion Include="Fisher" Version="0.6.0" />
<PackageReference Include="Fisher" />
paket add Fisher --version 0.6.0
#r "nuget: Fisher, 0.6.0"
#:package Fisher@0.6.0
#addin nuget:?package=Fisher&version=0.6.0
#tool nuget:?package=Fisher&version=0.6.0
Fisher
SQLite-backed Event Store and Document Database inside the Critter Stack.
<div align="center"> <img src="./logo.png" alt="Fisher logo" width="40%"> </div>
Sorry, we don't have the documentation published yet, but we'll get there soon!
Documentation: fisher.jasperfx.net
Fisher is Marten and Polecat for SQLite —
event sourcing and document storage with the same API, in a database that is a file inside your own
process. There is no server to install, nothing to provision, and nothing to keep running. Backup is
cp. Tests need no fixture.
Status: early, but no longer a skeleton. The event store, document storage over all four identity types plus strong-typed wrappers, hierarchies, numeric revisions, soft delete, duplicated fields, user-declared indexes, document metadata mapping, LINQ — including joins, grouping and both paging styles — patching, bulk insert, DCB tags, natural keys, all five projection shapes across all three lifecycles (composite projections included), the async projection daemon, subscriptions, event rewriting — including data masking and stream compacting — both tenancy styles (conjoined and database-per-tenant, with tenants that appear at runtime),
AddFisher(...)DI registration, and theFisher.AspNetCoreandFisher.EntityFrameworkCorecompanion packages all work and are tested.Fisher passes all 32 suites and 272 tests of
JasperFx.Events.ComplianceTests, the shared cross-store suite Marten and Polecat also enroll in.The one thing that is not there is deliberate and permanent: no message bus. The projection side-effect seam exists and the default outbox drops every message, because delivery is a bus integration's job here as it is on both siblings.
Getting started
dotnet add package Fisher
builder.Services.AddFisher(opts =>
{
opts.Connection("Data Source=app.db");
})
.ApplyAllDatabaseChangesOnStartup();
// Documents
session.Store(new User { FirstName = "Jane", LastName = "Doe" });
await session.SaveChangesAsync();
var users = await session.Query<User>().Where(x => x.LastName == "Doe").ToListAsync();
// Events
var stream = session.Events.StartStream<Order>(new OrderPlaced("Acme", 199.95m));
await session.SaveChangesAsync();
var order = await session.Events.AggregateStreamAsync<Order>(stream.Id);
See Getting Started for the full walkthrough, and Why Fisher? for where it fits and where it does not.
What SQLite changes
The API is Marten's. The storage decisions are not, and the honest summary is that SQLite makes some things cheaper and one thing harder:
Cheaper. Duplicated fields are VIRTUAL generated columns — no backfill, no drift, and a patch
has nothing to refresh. Declared indexes are expression indexes and add no column at all. Patching
needs no server-side function installed. JSON-returning reads are byte-exact and skip the whole
round trip rather than a fraction of it, because the database is your process. Joins are plain SQL.
Database-per-tenant is a file per tenant, so it buys concurrency as well as isolation.
Harder. One writer per database file. That is why the unit of work is sequential, why a busy retry
is a real policy, why ITransactionParticipant and QueueSqlCommand matter more here than on either
sibling, and why the exclusive append methods fail where Marten's and Polecat's wait.
All of it is documented rather than left to be discovered — see the migration guide for the behaviours that differ.
Companion packages
dotnet add package Fisher.AspNetCore # streaming IResult types, ETags, a daemon health check
dotnet add package Fisher.EntityFrameworkCore # a DbContext inside Fisher's transaction
Support Plans
<div align="center"> <img src="https://www.jasperfx.net/logo.png" alt="JasperFx logo" width="70%"> </div>
While Fisher is open source, JasperFx Software offers paid support and consulting contracts for the Critter Stack.
Help us keep working on this project 💚
Become a Sponsor on GitHub by sponsoring monthly or one time.
Working with the Code
You need the .NET 10 SDK (available here) and the .NET 9 runtime to run that target framework's suites.
There is no database server to run. No docker-compose up, no connection string to configure, no
container to wait for — the tests create throwaway SQLite files under the temp directory. This is the
whole point of the library, and it applies to its own build as much as to yours.
dotnet build fisher.slnx
dotnet test fisher.slnx # both TFMs; they run serially on purpose
dotnet test fisher.slnx -f net10.0 # one TFM
# One test class or method (Microsoft Testing Platform — note the bare `--`)
dotnet test src/Fisher.Tests/Fisher.Tests.csproj -f net10.0 -- --filter-method "*appending_events*"
Documentation
The docs are written in Markdown under docs/ and published as a static
VitePress site, as the other JasperFx projects are.
npm install
npm run docs # dev server at http://localhost:5173
npm run docs-build # a dead internal link fails the build
Contributing
Fisher is developed in the open. Read CLAUDE.md first — it is the architectural account of the library, including every SQLite divergence and the reason behind it, and it will save you rediscovering a trap that has already bitten. ROADMAP.md is what comes next and in what order; HANDOFF.md is the compliance scoreboard and the deliberate gaps.
License
Copyright © Jeremy D. Miller and contributors.
Fisher is provided as-is under the MIT license. For more information see LICENSE.
Code of Conduct
This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- JasperFx (>= 2.47.0)
- JasperFx.Events (>= 2.47.0)
- Microsoft.Data.Sqlite (>= 10.0.9)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.0)
- Polly.Core (>= 8.6.5)
- SQLitePCLRaw.bundle_e_sqlite3 (>= 3.0.3)
- Weasel.Sqlite (>= 9.24.0)
- Weasel.Storage (>= 9.24.0)
-
net9.0
- JasperFx (>= 2.47.0)
- JasperFx.Events (>= 2.47.0)
- Microsoft.Data.Sqlite (>= 10.0.9)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.0)
- Polly.Core (>= 8.6.5)
- SQLitePCLRaw.bundle_e_sqlite3 (>= 3.0.3)
- Weasel.Sqlite (>= 9.24.0)
- Weasel.Storage (>= 9.24.0)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Fisher:
| Package | Downloads |
|---|---|
|
Fisher.EntityFrameworkCore
Entity Framework Core integration for Fisher |
|
|
Fisher.AspNetCore
ASP.NET Core helpers for Fisher-backed applications |
|
|
WolverineFx.Fisher
Fisher-backed Persistence for Wolverine Applications |
GitHub repositories
This package is not used by any popular GitHub repositories.