dotnet-cqrs/Svrnty.CQRS.Events/Projections/InMemoryProjectionCheckpointStore.cs

78 lines
2.4 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Svrnty.CQRS.Events.Abstractions.Projections;
namespace Svrnty.CQRS.Events.Projections;
/// <summary>
/// In-memory implementation of projection checkpoint storage for development/testing.
/// </summary>
/// <remarks>
/// <para>
/// <strong>Warning:</strong> This is an in-memory store. All checkpoints are lost on restart.
/// For production, use PostgresProjectionCheckpointStore or another persistent implementation.
/// </para>
/// <para>
/// Thread-safe implementation using ConcurrentDictionary.
/// </para>
/// </remarks>
public sealed class InMemoryProjectionCheckpointStore : IProjectionCheckpointStore
{
private readonly ConcurrentDictionary<string, ProjectionCheckpoint> _checkpoints = new();
/// <inheritdoc />
public Task<ProjectionCheckpoint?> GetCheckpointAsync(
string projectionName,
string streamName,
CancellationToken cancellationToken = default)
{
var key = GetKey(projectionName, streamName);
var checkpoint = _checkpoints.TryGetValue(key, out var value) ? value : null;
return Task.FromResult(checkpoint);
}
/// <inheritdoc />
public Task SaveCheckpointAsync(
ProjectionCheckpoint checkpoint,
CancellationToken cancellationToken = default)
{
if (checkpoint == null)
throw new ArgumentNullException(nameof(checkpoint));
var key = GetKey(checkpoint.ProjectionName, checkpoint.StreamName);
_checkpoints[key] = checkpoint;
return Task.CompletedTask;
}
/// <inheritdoc />
public Task ResetCheckpointAsync(
string projectionName,
string streamName,
CancellationToken cancellationToken = default)
{
var key = GetKey(projectionName, streamName);
_checkpoints.TryRemove(key, out _);
return Task.CompletedTask;
}
/// <inheritdoc />
public Task<ProjectionCheckpoint[]> GetAllCheckpointsAsync(
string projectionName,
CancellationToken cancellationToken = default)
{
var checkpoints = _checkpoints.Values
.Where(c => c.ProjectionName == projectionName)
.ToArray();
return Task.FromResult(checkpoints);
}
private static string GetKey(string projectionName, string streamName)
{
return $"{projectionName}::{streamName}";
}
}