@@ -0,0 +1,82 @@
using Marten ;
using Marten . Events . Projections ;
using Microsoft . Extensions . Configuration ;
using Microsoft . Extensions . DependencyInjection ;
using Microsoft . Extensions . Hosting ;
var builder = Host . CreateApplicationBuilder ( ) ;
builder . Services . AddMarten ( opt => {
opt . Connection ( builder . Configuration . GetConnectionString ( "Marten" ) ?? "Host=localhost; Port=5433; User Id=postgres; Password=pgsql" ) ;
opt . Projections . Add < WorkByDayProjection > ( ProjectionLifecycle . Inline ) ;
} ) . UseLightweightSessions ( ) ;
builder . Services . AddHostedService < Runner > ( ) ;
var app = builder . Build ( ) ;
await app . RunAsync ( ) ;
public class Runner : BackgroundService
{
private readonly IDocumentSession _session ;
private readonly IHostApplicationLifetime _lifetime ;
public Runner ( IDocumentSession session , IHostApplicationLifetime lifetime )
{
_session = session ;
_lifetime = lifetime ;
}
protected override Task ExecuteAsync ( CancellationToken stoppingToken )
=> Task . Run ( async ( ) =>
{
var assignmentId = Guid . NewGuid ( ) ;
var workerId = Guid . NewGuid ( ) ;
var today = DateOnly . FromDateTime ( DateTime . Today ) ;
var tomorrow = today . AddDays ( 1 ) ;
var oneWeekFromToday = today . AddDays ( 7 ) ;
Console . Write ( $ "{ today } { oneWeekFromToday } ") ;
_session . Events . Append ( assignmentId , new WorkerAssigned ( assignmentId , workerId , today , oneWeekFromToday ) ) ;
_session . Events . Append ( assignmentId , new WorkCompleted ( assignmentId , today , "Work completed today" ) ) ;
_session . Events . Append ( assignmentId , new WorkCompleted ( assignmentId , today , "More work completed today" ) ) ;
_session . Events . Append ( assignmentId , new WorkCompleted ( assignmentId , tomorrow , "Work completed tomorrow" ) ) ;
await _session . SaveChangesAsync ( stoppingToken ) ;
_lifetime . StopApplication ( ) ;
} , stoppingToken ) ;
}
public record WorkerAssigned ( Guid AssignmentId , Guid WorkerId , DateOnly Start , DateOnly End ) ;
public record WorkCompleted ( Guid AssignmentId , DateOnly Date , string DescriptionOfWork ) ;
public record WorkByDay ( string Id , Guid AssignmentId , Guid WorkerId , DateOnly Date , string [ ] WorkCompleted ) ;
public record WorkerAssignedForDay ( Guid AssignmentId , Guid WorkerId , DateOnly Date ) ;
public class WorkByDayProjection : MultiStreamProjection < WorkByDay , string >
{
public WorkByDayProjection ( )
{
FanOut < WorkerAssigned , WorkerAssignedForDay > ( e => Enumerable . Range ( 0 , e . End . DayNumber - e . Start . DayNumber + 1 )
. Select ( d => new WorkerAssignedForDay ( e . AssignmentId , e . WorkerId , e . Start . AddDays ( d ) ) ) , FanoutMode . BeforeGrouping ) ;
Identity < WorkerAssignedForDay > ( e => IdForEvent ( e . AssignmentId , e . Date ) ) ;
Identity < WorkCompleted > ( e => IdForEvent ( e . AssignmentId , e . Date ) ) ;
IncludeType < WorkerAssigned > ( ) ;
}
private static string IdForEvent ( Guid assignmentId , DateOnly date ) => $ "{ assignmentId : N} :{ date : yyyyMMdd} ";
public static WorkByDay Create ( WorkerAssignedForDay evt ) => new ( IdForEvent ( evt . AssignmentId , evt . Date ) ,
evt . AssignmentId , evt . WorkerId , evt . Date , Array . Empty < string > ( ) ) ;
public static WorkByDay Apply ( WorkCompleted evt , WorkByDay view ) =>
view with { WorkCompleted = view . WorkCompleted . Append ( evt . DescriptionOfWork ) . ToArray ( ) } ;
}