Skip to content

Commit 55c5b0b

Browse files
committed
Feat: add Redis governance document loading
1 parent 2c62fde commit 55c5b0b

4 files changed

Lines changed: 136 additions & 0 deletions

File tree

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using ModularityKit.Mutator.Governance.Redis.Keys;
2+
using StackExchange.Redis;
3+
4+
namespace ModularityKit.Mutator.Governance.Redis.Storage.Documents.Keys;
5+
6+
/// <summary>
7+
/// Creates Redis document keys for governed mutation requests.
8+
/// </summary>
9+
internal sealed class RedisMutationRequestDocumentKeyFactory(RedisMutationRequestKeyspace keyspace)
10+
{
11+
private readonly RedisMutationRequestKeyspace _keyspace = keyspace ?? throw new ArgumentNullException(nameof(keyspace));
12+
13+
/// <summary>
14+
/// Creates document keys for the supplied request identifiers.
15+
/// </summary>
16+
/// <param name="requestIds">The request identifiers to map.</param>
17+
/// <returns>The Redis document keys.</returns>
18+
public IReadOnlyList<RedisKey> CreateKeys(IEnumerable<string> requestIds) =>
19+
requestIds.Where(requestId => !string.IsNullOrWhiteSpace(requestId))
20+
.Distinct(StringComparer.Ordinal)
21+
.Select(_keyspace.RequestData)
22+
.ToArray();
23+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Model;
2+
using ModularityKit.Mutator.Governance.Redis.Serialization;
3+
using StackExchange.Redis;
4+
5+
namespace ModularityKit.Mutator.Governance.Redis.Storage.Documents.Materialization;
6+
7+
/// <summary>
8+
/// Materializes governed mutation requests from Redis payload values.
9+
/// </summary>
10+
internal static class RedisMutationRequestDocumentMaterializer
11+
{
12+
/// <summary>
13+
/// Deserializes request payloads and optionally orders the resulting requests by creation time.
14+
/// </summary>
15+
/// <param name="values">The raw Redis payload values.</param>
16+
/// <param name="cancellationToken">The cancellation token.</param>
17+
/// <param name="orderByCreated">Whether to order results by creation timestamp.</param>
18+
/// <returns>The materialized mutation requests.</returns>
19+
public static IReadOnlyList<MutationRequest> Materialize(IReadOnlyList<RedisValue> values, CancellationToken cancellationToken, bool orderByCreated)
20+
{
21+
var requests = new List<MutationRequest>(values.Count);
22+
23+
foreach (var value in values)
24+
{
25+
cancellationToken.ThrowIfCancellationRequested();
26+
27+
if (value.HasValue)
28+
requests.Add(RedisMutationRequestSerializer.Deserialize(value!));
29+
}
30+
31+
if (!orderByCreated)
32+
return requests;
33+
34+
return requests.OrderBy(request => request.CreatedAt)
35+
.ThenBy(request => request.RequestId)
36+
.ToList();
37+
}
38+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using StackExchange.Redis;
2+
3+
namespace ModularityKit.Mutator.Governance.Redis.Storage.Documents.Payloads;
4+
5+
/// <summary>
6+
/// Loads raw request document payloads from Redis.
7+
/// </summary>
8+
internal sealed class RedisMutationRequestPayloadReader(IDatabase database)
9+
{
10+
private readonly IDatabase _database = database ?? throw new ArgumentNullException(nameof(database));
11+
12+
/// <summary>
13+
/// Loads raw payload values for the supplied document keys.
14+
/// </summary>
15+
/// <param name="keys">The Redis document keys to read.</param>
16+
/// <param name="cancellationToken">The cancellation token.</param>
17+
/// <returns>The raw Redis payload values.</returns>
18+
public async Task<IReadOnlyList<RedisValue>> LoadAsync(IReadOnlyList<RedisKey> keys, CancellationToken cancellationToken)
19+
{
20+
cancellationToken.ThrowIfCancellationRequested();
21+
22+
if (keys.Count == 0)
23+
return [];
24+
25+
var values = await _database.StringGetAsync(keys.ToArray()).ConfigureAwait(false);
26+
return values;
27+
}
28+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Model;
2+
using ModularityKit.Mutator.Governance.Redis.Storage.Documents.Keys;
3+
using ModularityKit.Mutator.Governance.Redis.Storage.Documents.Materialization;
4+
using ModularityKit.Mutator.Governance.Redis.Storage.Documents.Payloads;
5+
6+
namespace ModularityKit.Mutator.Governance.Redis.Storage.Documents.Reading;
7+
8+
/// <summary>
9+
/// Coordinates Redis document key creation, payload reads, and request materialization.
10+
/// </summary>
11+
internal sealed class RedisMutationRequestDocumentReader(
12+
RedisMutationRequestDocumentKeyFactory keyFactory,
13+
RedisMutationRequestPayloadReader payloadReader)
14+
{
15+
private readonly RedisMutationRequestDocumentKeyFactory _keyFactory =
16+
keyFactory ?? throw new ArgumentNullException(nameof(keyFactory));
17+
private readonly RedisMutationRequestPayloadReader _payloadReader =
18+
payloadReader ?? throw new ArgumentNullException(nameof(payloadReader));
19+
20+
/// <summary>
21+
/// Loads request documents ordered by request creation time.
22+
/// </summary>
23+
/// <param name="requestIds">The request identifiers to load.</param>
24+
/// <param name="cancellationToken">The cancellation token.</param>
25+
/// <returns>The materialized and ordered mutation requests.</returns>
26+
public Task<IReadOnlyList<MutationRequest>> LoadOrderedByCreatedAsync(IEnumerable<string> requestIds, CancellationToken cancellationToken) =>
27+
LoadAsync(requestIds, cancellationToken, orderByCreated: true);
28+
29+
/// <summary>
30+
/// Loads request documents for the supplied identifiers.
31+
/// </summary>
32+
/// <param name="requestIds">The request identifiers to load.</param>
33+
/// <param name="cancellationToken">The cancellation token.</param>
34+
/// <param name="orderByCreated">Whether to order results by request creation time.</param>
35+
/// <returns>The materialized mutation requests.</returns>
36+
public async Task<IReadOnlyList<MutationRequest>> LoadAsync(IEnumerable<string> requestIds, CancellationToken cancellationToken, bool orderByCreated)
37+
{
38+
cancellationToken.ThrowIfCancellationRequested();
39+
40+
var keys = _keyFactory.CreateKeys(requestIds);
41+
if (keys.Count == 0)
42+
return [];
43+
44+
var values = await _payloadReader.LoadAsync(keys, cancellationToken).ConfigureAwait(false);
45+
return RedisMutationRequestDocumentMaterializer.Materialize(values, cancellationToken, orderByCreated);
46+
}
47+
}

0 commit comments

Comments
 (0)