Skip to content

Commit 9220312

Browse files
committed
Add support for singleton entities
1 parent ddf0a12 commit 9220312

File tree

8 files changed

+39
-10
lines changed

8 files changed

+39
-10
lines changed

src/NexusMods.EventSourcing.Abstractions/IEntityContext.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ public interface IEntityContext
1717
public TEntity Get<TEntity>(EntityId<TEntity> id) where TEntity : IEntity;
1818

1919

20+
/// <summary>
21+
/// Gets the singleton entity of the specified type.
22+
/// </summary>
23+
/// <typeparam name="TEntity"></typeparam>
24+
/// <returns></returns>
25+
public TEntity Get<TEntity>() where TEntity : ISingletonEntity;
26+
27+
2028
/// <summary>
2129
/// Transacts a new event into the context.
2230
/// </summary>

src/NexusMods.EventSourcing.Abstractions/ISingletonEntity.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ namespace NexusMods.EventSourcing.Abstractions;
33
/// <summary>
44
/// Marks this entity as a singleton entity, the singleton id is used to retrieve the entity from the cache.
55
/// </summary>
6-
public interface ISingletonEntity
6+
public interface ISingletonEntity : IEntity
77
{
88
public static virtual EntityId SingletonId { get; }
99
}

src/NexusMods.EventSourcing/EntityContext.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ public TEntity Get<TEntity>(EntityId<TEntity> id) where TEntity : IEntity
1111
throw new System.NotImplementedException();
1212
}
1313

14+
public TEntity Get<TEntity>() where TEntity : ISingletonEntity
15+
{
16+
throw new System.NotImplementedException();
17+
}
18+
1419
public ValueTask Add<TEvent>(TEvent entity) where TEvent : IEvent
1520
{
1621
throw new System.NotImplementedException();

src/NexusMods.EventSourcing/EventFormatter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
namespace NexusMods.EventSourcing;
99

10-
public class EventFormatter : MemoryPackFormatter<IEvent>
10+
internal class EventFormatter : MemoryPackFormatter<IEvent>
1111
{
1212
private static Guid _zeroGuid = Guid.Empty;
1313
private readonly Dictionary<Guid,Type> _eventByGuid;

tests/NexusMods.EventSourcing.TestModel/Events/CreateLoadout.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public async ValueTask Apply<T>(T context) where T : IEventContext
1818
{
1919
context.New(Id);
2020
context.Emit(Id, Loadout._name, Name);
21+
context.Emit(LoadoutRegistry.SingletonId, LoadoutRegistry._loadouts, Id);
2122
}
2223

2324
public static CreateLoadout Create(string name) => new() { Name = name, Id = EntityId<Loadout>.NewId() };

tests/NexusMods.EventSourcing.TestModel/Model/LoadoutRegistry.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,9 @@
44

55
namespace NexusMods.EventSourcing.TestModel.Model;
66

7-
public class LoadoutRegistry(IEntityContext context, EntityId id) : AEntity(context, id)
7+
public class LoadoutRegistry(IEntityContext context) : AEntity(context, SingletonId.Value), ISingletonEntity
88
{
9-
/// <summary>
10-
/// Gets the instance of the loadout registry from the entity context.
11-
/// </summary>
12-
/// <param name="context"></param>
13-
/// <returns></returns>
14-
public static LoadoutRegistry GetInstance(IEntityContext context) =>
15-
context.Get(EntityId<LoadoutRegistry>.From("10BAE6BA-D5F9-40F4-AF7F-CCA1417C3BB0"));
9+
public static EntityId<LoadoutRegistry> SingletonId => EntityId<LoadoutRegistry>.From("10BAE6BA-D5F9-40F4-AF7F-CCA1417C3BB0");
1610

1711
/// <summary>
1812
/// The loadouts in the registry.

tests/NexusMods.EventSourcing.Tests/BasicFunctionalityTests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using NexusMods.EventSourcing.TestModel.Events;
2+
using NexusMods.EventSourcing.TestModel.Model;
23
using NexusMods.EventSourcing.Tests.Contexts;
34

45
namespace NexusMods.EventSourcing.Tests;
@@ -73,4 +74,11 @@ public async void CanDeleteEntities()
7374

7475
loadout.Mods.First().Name.Should().Be("Second Mod");
7576
}
77+
78+
[Fact]
79+
public async void CanGetSingletonEntities()
80+
{
81+
var entity = _ctx.Get<LoadoutRegistry>();
82+
entity.Should().NotBeNull();
83+
}
7684
}

tests/NexusMods.EventSourcing.Tests/Contexts/TestContext.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@ public TEntity Get<TEntity>(EntityId<TEntity> id) where TEntity : IEntity
2929
return createdEntity;
3030
}
3131

32+
public TEntity Get<TEntity>() where TEntity : ISingletonEntity
33+
{
34+
var id = TEntity.SingletonId;
35+
if (_entities.TryGetValue(id, out var entity))
36+
{
37+
return (TEntity)entity;
38+
}
39+
40+
var instance = (TEntity)Activator.CreateInstance(typeof(TEntity), this)!;
41+
_entities.Add(id, instance);
42+
return instance;
43+
}
44+
3245
private Dictionary<IAttribute, IAccumulator> LoadValues(EntityId id)
3346
{
3447
var ingester = new Ingester(id);

0 commit comments

Comments
 (0)