Skip to content

Commit 8f1c550

Browse files
author
MPCoreDeveloper
committed
event sourcing
1 parent ae4adfa commit 8f1c550

80 files changed

Lines changed: 13221 additions & 665 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/copilot-instructions.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,6 @@
2020
- Custom requirement A.
2121
- Custom requirement B.
2222
- Require full SQLite compatibility: SharpCoreDB sync and provider must support all SQLite syntax/features users could use, never less; extra capabilities are fine.
23+
- SharpCoreDB Server must support multiple databases and system databases, and must enforce HTTPS/TLS (minimum TLS 1.2) with no plain HTTP endpoints.
24+
- New SharpCoreDB features must remain optional; event sourcing must be delivered as a separate NuGet package, and issue-driven user features should be prioritized ahead of server mode work.
25+
- Event sourcing must support both persistent storage and the existing in-memory option; provide an additional demo example specifically for persistent storage.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
<LangVersion>14.0</LangVersion>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<Nullable>enable</Nullable>
9+
<Version>1.5.0</Version>
10+
<IsPackable>false</IsPackable>
11+
</PropertyGroup>
12+
13+
<ItemGroup>
14+
<ProjectReference Include="..\..\..\src\SharpCoreDB.EventSourcing\SharpCoreDB.EventSourcing.csproj" />
15+
<ProjectReference Include="..\..\..\src\SharpCoreDB\SharpCoreDB.csproj" />
16+
</ItemGroup>
17+
18+
<ItemGroup>
19+
<Compile Include="..\OrderManagement\OrderEvents.cs" Link="OrderEvents.cs" />
20+
<Compile Include="..\OrderManagement\OrderAggregate.cs" Link="OrderAggregate.cs" />
21+
</ItemGroup>
22+
23+
</Project>
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// <copyright file="Program.cs" company="MPCoreDeveloper">
2+
// Copyright (c) 2026 MPCoreDeveloper and GitHub Copilot. All rights reserved.
3+
// Licensed under the MIT License.
4+
// </copyright>
5+
6+
using Microsoft.Extensions.DependencyInjection;
7+
using OrderManagement;
8+
using SharpCoreDB;
9+
using SharpCoreDB.EventSourcing;
10+
11+
Console.WriteLine("========================================");
12+
Console.WriteLine(" SharpCoreDB Persistent Event Sourcing Demo");
13+
Console.WriteLine(" Order Management with Database-Backed Store");
14+
Console.WriteLine("========================================");
15+
Console.WriteLine();
16+
17+
var dbPath = Path.Combine(Path.GetTempPath(), "SharpCoreDB", "orders-persistent-demo");
18+
Console.WriteLine($"Database path: {dbPath}");
19+
Console.WriteLine();
20+
21+
var orderId = "ORDER-PERSIST-001";
22+
var customerId = "CUST-PERSIST-123";
23+
24+
Console.WriteLine("=== Session 1: Write Events to SharpCoreDB ===");
25+
Console.WriteLine();
26+
27+
var writeStore = CreatePersistentStore(dbPath);
28+
29+
var order = OrderAggregate.CreateOrder(orderId, customerId, [
30+
new OrderItem { ProductId = "PROD-1", ProductName = "Laptop", Quantity = 1, Price = 999.99m },
31+
new OrderItem { ProductId = "PROD-2", ProductName = "Mouse", Quantity = 1, Price = 29.99m },
32+
]);
33+
34+
await PersistEvents(writeStore, orderId, order);
35+
order.ConfirmOrder();
36+
await PersistEvents(writeStore, orderId, order);
37+
order.MarkAsPaid(order.TotalAmount, "CreditCard", "TXN-PERSIST-001");
38+
await PersistEvents(writeStore, orderId, order);
39+
40+
var beforeRestart = await writeStore.ReadStreamAsync(new EventStreamId(orderId), new EventReadRange(1, long.MaxValue));
41+
Console.WriteLine($"Events written before restart: {beforeRestart.Events.Count}");
42+
Console.WriteLine();
43+
44+
Console.WriteLine("=== Session 2: Reopen Store and Replay ===");
45+
Console.WriteLine();
46+
47+
var readStore = CreatePersistentStore(dbPath);
48+
var afterRestart = await readStore.ReadStreamAsync(new EventStreamId(orderId), new EventReadRange(1, long.MaxValue));
49+
50+
Console.WriteLine($"Events loaded after restart: {afterRestart.Events.Count}");
51+
foreach (var evt in afterRestart.Events)
52+
{
53+
Console.WriteLine($" [{evt.Sequence}] {evt.EventType} (global:{evt.GlobalSequence})");
54+
}
55+
56+
var rebuiltOrder = OrderAggregate.FromEventStream(afterRestart.Events);
57+
Console.WriteLine();
58+
Console.WriteLine("Rebuilt aggregate state:");
59+
Console.WriteLine($" Order ID: {rebuiltOrder.OrderId}");
60+
Console.WriteLine($" Customer: {rebuiltOrder.CustomerId}");
61+
Console.WriteLine($" Status: {rebuiltOrder.Status}");
62+
Console.WriteLine($" Total: ${rebuiltOrder.TotalAmount:F2}");
63+
Console.WriteLine($" Version: {rebuiltOrder.Version}");
64+
Console.WriteLine();
65+
66+
Console.WriteLine("✅ Persistent event sourcing works: events survived process restart.");
67+
68+
static IEventStore CreatePersistentStore(string dbPath)
69+
{
70+
var services = new ServiceCollection();
71+
services.AddSharpCoreDB();
72+
73+
var serviceProvider = services.BuildServiceProvider();
74+
var factory = serviceProvider.GetRequiredService<DatabaseFactory>();
75+
var database = factory.Create(dbPath, "demo-password");
76+
77+
return new SharpCoreDbEventStore(database);
78+
}
79+
80+
static async Task PersistEvents(IEventStore store, string orderId, OrderAggregate order)
81+
{
82+
var streamId = new EventStreamId(orderId);
83+
84+
foreach (var orderEvent in order.PendingEvents)
85+
{
86+
var entry = new EventAppendEntry(
87+
EventType: orderEvent.GetType().Name,
88+
Payload: orderEvent.Serialize(),
89+
Metadata: Array.Empty<byte>(),
90+
TimestampUtc: orderEvent.Timestamp);
91+
92+
await store.AppendEventAsync(streamId, entry);
93+
}
94+
95+
order.ClearPendingEvents();
96+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Order Management Persistent Demo
2+
3+
This example demonstrates `SharpCoreDbEventStore` persistence with SharpCoreDB as the backing database.
4+
5+
## What this demo proves
6+
7+
- Events are appended to a persistent SharpCoreDB table.
8+
- Events survive process restart.
9+
- Aggregate state can be rebuilt after reopening the store.
10+
11+
## Run
12+
13+
```bash
14+
cd examples/EventSourcing/OrderManagement.PersistentDemo
15+
dotnet run
16+
```
17+
18+
## Expected behavior
19+
20+
1. Session 1 writes lifecycle events for one order.
21+
2. Session 2 creates a new store instance with the same database path.
22+
3. The second session reads the same events and rebuilds the aggregate.
23+
24+
If both sessions show the same event count, persistence is working.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<LangVersion>14.0</LangVersion>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<IsPackable>false</IsPackable>
9+
<IsTestProject>true</IsTestProject>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
14+
<PackageReference Include="xunit" Version="2.9.2" />
15+
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
16+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
17+
<PrivateAssets>all</PrivateAssets>
18+
</PackageReference>
19+
</ItemGroup>
20+
21+
<ItemGroup>
22+
<ProjectReference Include="..\..\..\src\SharpCoreDB.EventSourcing\SharpCoreDB.EventSourcing.csproj" />
23+
</ItemGroup>
24+
25+
<!-- Include OrderManagement source files as links -->
26+
<ItemGroup>
27+
<Compile Include="..\OrderManagement\OrderEvents.cs" Link="OrderEvents.cs" />
28+
<Compile Include="..\OrderManagement\OrderAggregate.cs" Link="OrderAggregate.cs" />
29+
</ItemGroup>
30+
31+
</Project>

0 commit comments

Comments
 (0)