Skip to content

Instantly share code, notes, and snippets.

@flew2bits
Created April 12, 2024 11:27
Show Gist options
  • Save flew2bits/051c67e0c18ef513f3f915c177ed993d to your computer and use it in GitHub Desktop.
Save flew2bits/051c67e0c18ef513f3f915c177ed993d to your computer and use it in GitHub Desktop.
FanOut sample for Dates
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() };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment