Skip to content

Commit 2c70b6c

Browse files
feat/refactor: move the boxing up a level for annotated commands
this allows pattern matching on IEntityAnnotation<> where the actual command type can be used as the generic parameter. before you would have to check IEntityAnnotation<...>.Data is <CommandType>; now you can check IEntityAnnotation<CommandType>
1 parent 12cc8da commit 2c70b6c

File tree

5 files changed

+45
-38
lines changed

5 files changed

+45
-38
lines changed

src/EntityDb.Common/Annotations/EntityAnnotation.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using EntityDb.Abstractions.Transactions;
33
using EntityDb.Abstractions.Transactions.Steps;
44
using EntityDb.Abstractions.ValueObjects;
5+
using System;
56

67
namespace EntityDb.Common.Annotations;
78

@@ -14,16 +15,25 @@ internal record EntityAnnotation<TData>
1415
TData Data
1516
) : IEntityAnnotation<TData>
1617
{
17-
public static EntityAnnotation<TData> CreateFrom(ITransaction transaction, ITransactionStep transactionStep,
18-
TData data)
18+
public static IEntityAnnotation<TData> CreateFromBoxedData
19+
(
20+
Id transactionId,
21+
TimeStamp transactionTimeStamp,
22+
Id entityId,
23+
VersionNumber entityVersionNumber,
24+
object boxedData
25+
)
1926
{
20-
return new
27+
var dataAnnotationType = typeof(EntityAnnotation<>).MakeGenericType(boxedData.GetType());
28+
29+
return (IEntityAnnotation<TData>)Activator.CreateInstance
2130
(
22-
transaction.Id,
23-
transaction.TimeStamp,
24-
transactionStep.EntityId,
25-
transactionStep.EntityVersionNumber,
26-
data
27-
);
31+
dataAnnotationType,
32+
transactionId,
33+
transactionTimeStamp,
34+
entityId,
35+
entityVersionNumber,
36+
boxedData
37+
)!;
2838
}
2939
}

src/EntityDb.Common/Transactions/ProjectionSnapshotTransactionSubscriber.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,14 @@ protected override async Task NotifyAsync(ITransaction transaction)
6262

6363
var projection = previousProjection;
6464

65-
var annotatedCommand = EntityAnnotation<object>.CreateFrom(transaction, appendCommandTransactionStep, appendCommandTransactionStep.Command);
65+
var annotatedCommand = EntityAnnotation<object>.CreateFromBoxedData
66+
(
67+
transaction.Id,
68+
transaction.TimeStamp,
69+
appendCommandTransactionStep.EntityId,
70+
appendCommandTransactionStep.EntityVersionNumber,
71+
appendCommandTransactionStep.Command
72+
);
6673

6774
projection = projection.Reduce(annotatedCommand);
6875

src/EntityDb.MongoDb/Extensions/DocumentQueryExtensions.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System;
1111
using System.Collections.Generic;
1212
using System.Linq;
13+
using System.Reflection;
1314
using System.Threading;
1415
using System.Threading.Tasks;
1516

@@ -104,19 +105,20 @@ public static async Task<IEntityAnnotation<TData>[]> GetEntityAnnotation<TDocume
104105
CancellationToken cancellationToken
105106
)
106107
where TDocument : IEntityDocument
108+
where TData : notnull
107109
{
108110
var documents = await documentQuery.Execute(mongoSession, NoDocumentIdProjection, cancellationToken);
109111

110112
return documents
111-
.Select(document => new EntityAnnotation<TData>
113+
.Select(document => EntityAnnotation<TData>.CreateFromBoxedData
112114
(
113115
document.TransactionId,
114116
document.TransactionTimeStamp,
115117
document.EntityId,
116118
document.EntityVersionNumber,
117119
envelopeService.Reconstruct<TData>(document.Data)
118120
))
119-
.ToArray<IEntityAnnotation<TData>>();
121+
.ToArray();
120122
}
121123

122124
public static async Task<TData[]> GetData<TDocument, TData>

test/EntityDb.Common.Tests/Implementations/Entities/TestEntity.cs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
using EntityDb.Common.Entities;
22
using System;
3+
using System.Linq;
34
using System.Threading;
45
using EntityDb.Abstractions.Reducers;
56
using EntityDb.Abstractions.ValueObjects;
67
using EntityDb.Common.Snapshots;
8+
using EntityDb.Common.Tests.Implementations.Commands;
79
using EntityDb.Common.Tests.Implementations.Snapshots;
810

911
namespace EntityDb.Common.Tests.Implementations.Entities;
@@ -40,19 +42,12 @@ public VersionNumber GetVersionNumber()
4042

4143
public TestEntity Reduce(object[] commands)
4244
{
43-
var newEntity = this;
44-
45-
foreach (var command in commands)
45+
return commands.Aggregate(this, (previousEntity, nextCommand) => nextCommand switch
4646
{
47-
if (command is not IReducer<TestEntity> reducer)
48-
{
49-
throw new NotImplementedException();
50-
}
51-
52-
newEntity = reducer.Reduce(newEntity);
53-
}
54-
55-
return newEntity;
47+
DoNothing doNothing => doNothing.Reduce(previousEntity),
48+
Count count => count.Reduce(previousEntity),
49+
_ => throw new NotSupportedException()
50+
});
5651
}
5752

5853
public static AsyncLocal<Func<TestEntity, TestEntity?, bool>?> ShouldReplaceLogic { get; } = new();

test/EntityDb.Common.Tests/Implementations/Projections/OneToOneProjection.cs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
using System;
2+
using System.Linq;
23
using System.Threading;
34
using EntityDb.Abstractions.Annotations;
45
using EntityDb.Abstractions.Reducers;
56
using EntityDb.Abstractions.ValueObjects;
67
using EntityDb.Common.Projections;
78
using EntityDb.Common.Snapshots;
9+
using EntityDb.Common.Tests.Implementations.Commands;
810
using EntityDb.Common.Tests.Implementations.Snapshots;
911

1012
namespace EntityDb.Common.Tests.Implementations.Projections;
@@ -34,21 +36,12 @@ public VersionNumber GetEntityVersionNumber(Id entityId)
3436

3537
public OneToOneProjection Reduce(params IEntityAnnotation<object>[] annotatedCommands)
3638
{
37-
var newProjection = this;
38-
39-
foreach (var annotatedCommand in annotatedCommands)
39+
return annotatedCommands.Aggregate(this, (previousProjection, nextAnnotatedCommand) => nextAnnotatedCommand switch
4040
{
41-
var command = annotatedCommand.Data;
42-
43-
if (command is not IReducer<OneToOneProjection> reducer)
44-
{
45-
throw new NotImplementedException();
46-
}
47-
48-
newProjection = reducer.Reduce(newProjection);
49-
}
50-
51-
return newProjection;
41+
IEntityAnnotation<DoNothing> doNothing => doNothing.Data.Reduce(previousProjection),
42+
IEntityAnnotation<Count> count => count.Data.Reduce(previousProjection),
43+
_ => throw new NotSupportedException()
44+
});
5245
}
5346

5447
public static AsyncLocal<Func<OneToOneProjection, OneToOneProjection?, bool>?> ShouldReplaceLogic { get; } = new();

0 commit comments

Comments
 (0)