generated from Nexus-Mods/NexusMods.App.Template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Start of the standard entity context
- Loading branch information
Showing
12 changed files
with
235 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,94 @@ | ||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using NexusMods.EventSourcing.Abstractions; | ||
|
||
namespace NexusMods.EventSourcing; | ||
|
||
public class EntityContext : IEntityContext | ||
public class EntityContext(IEventStore store) : IEntityContext | ||
{ | ||
private TransactionId asOf = TransactionId.From(0); | ||
private object _lock = new object(); | ||
|
||
private ConcurrentDictionary<EntityId, IEntity> _entities = new(); | ||
private ConcurrentDictionary<EntityId, Dictionary<IAttribute, IAccumulator>> _values = new(); | ||
|
||
|
||
public TEntity Get<TEntity>(EntityId<TEntity> id) where TEntity : IEntity | ||
{ | ||
throw new System.NotImplementedException(); | ||
if (_entities.TryGetValue(id.Value, out var entity)) | ||
{ | ||
return (TEntity) entity; | ||
} | ||
|
||
var values = GetValues(id.Value); | ||
var type = (Type)values[IEntity.TypeAttribute].Get(); | ||
|
||
var newEntity = (TEntity)Activator.CreateInstance(type, this, id)!; | ||
if (_entities.TryAdd(id.Value, newEntity)) | ||
{ | ||
return newEntity; | ||
} | ||
|
||
return (TEntity)_entities[id.Value]; | ||
} | ||
|
||
public TEntity Get<TEntity>() where TEntity : ISingletonEntity | ||
private Dictionary<IAttribute, IAccumulator> GetValues(EntityId id) | ||
{ | ||
throw new System.NotImplementedException(); | ||
if (_values.TryGetValue(id, out var values)) | ||
{ | ||
return values; | ||
} | ||
var newValues = LoadValues(id); | ||
return _values.TryAdd(id, newValues) ? newValues : _values[id]; | ||
} | ||
|
||
public ValueTask Add<TEvent>(TEvent entity) where TEvent : IEvent | ||
|
||
private Dictionary<IAttribute, IAccumulator> LoadValues(EntityId id) | ||
{ | ||
throw new System.NotImplementedException(); | ||
var values = new Dictionary<IAttribute, IAccumulator>(); | ||
var ingester = new EntityContextIngester(values, id); | ||
store.EventsForEntity(id, ingester); | ||
return values; | ||
} | ||
|
||
public IAccumulator GetAccumulator<TOwner, TAttribute>(EntityId ownerId, TAttribute attributeDefinition) where TOwner : IEntity where TAttribute : IAttribute | ||
public TEntity Get<TEntity>() where TEntity : ISingletonEntity | ||
{ | ||
throw new System.NotImplementedException(); | ||
var id = TEntity.SingletonId; | ||
if (_entities.TryGetValue(id, out var entity)) | ||
{ | ||
return (TEntity) entity; | ||
} | ||
|
||
var newEntity = (TEntity)Activator.CreateInstance(typeof(TEntity), this, id)!; | ||
if (_entities.TryAdd(id, newEntity)) | ||
{ | ||
return newEntity; | ||
} | ||
|
||
return (TEntity)_entities[id]; | ||
} | ||
|
||
public TransactionId Add<TEvent>(TEvent newEvent) where TEvent : IEvent | ||
{ | ||
lock (_lock) | ||
{ | ||
var newId = store.Add(newEvent); | ||
asOf = newId; | ||
|
||
var ingester = new ForwardEventContext(_values); | ||
newEvent.Apply(ingester); | ||
|
||
return newId; | ||
} | ||
} | ||
public IAccumulator GetAccumulator<TOwner, TAttribute>(EntityId ownerId, TAttribute attributeDefinition) | ||
where TOwner : IEntity where TAttribute : IAttribute | ||
{ | ||
var values = GetValues(ownerId); | ||
return values[attributeDefinition]; | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Runtime.CompilerServices; | ||
using NexusMods.EventSourcing.Abstractions; | ||
|
||
namespace NexusMods.EventSourcing; | ||
|
||
public struct EntityContextIngester(Dictionary<IAttribute, IAccumulator> values, EntityId id) : IEventContext, IEventIngester | ||
{ | ||
public void Ingest(IEvent @event) | ||
{ | ||
@event.Apply(this); | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
private IAccumulator GetAccumulator<TAttribute>(TAttribute attributeDefinition) | ||
where TAttribute : IAttribute | ||
{ | ||
if (values.TryGetValue(attributeDefinition, out var accumulator)) | ||
{ | ||
return accumulator; | ||
} | ||
|
||
accumulator = attributeDefinition.CreateAccumulator(); | ||
values.Add(attributeDefinition, accumulator); | ||
return accumulator; | ||
} | ||
|
||
public void Emit<TOwner, TVal>(EntityId<TOwner> entity, AttributeDefinition<TOwner, TVal> attr, TVal value) where TOwner : IEntity | ||
{ | ||
if (entity.Value != id) return; | ||
|
||
var accumulator = GetAccumulator(attr); | ||
accumulator.Add(value!); | ||
} | ||
|
||
public void Emit<TOwner, TVal>(EntityId<TOwner> entity, MultiEntityAttributeDefinition<TOwner, TVal> attr, EntityId<TVal> value) where TOwner : IEntity where TVal : IEntity | ||
{ | ||
if (entity.Value != id) return; | ||
|
||
var accumulator = GetAccumulator(attr); | ||
accumulator.Add(value!); | ||
} | ||
|
||
public void Retract<TOwner, TVal>(EntityId<TOwner> entity, AttributeDefinition<TOwner, TVal> attr, TVal value) where TOwner : IEntity | ||
{ | ||
if (entity.Value != id) return; | ||
|
||
var accumulator = GetAccumulator(attr); | ||
accumulator.Retract(value!); | ||
} | ||
|
||
public void Retract<TOwner, TVal>(EntityId<TOwner> entity, MultiEntityAttributeDefinition<TOwner, TVal> attr, EntityId<TVal> value) where TOwner : IEntity where TVal : IEntity | ||
{ | ||
if (entity.Value != id) return; | ||
|
||
var accumulator = GetAccumulator(attr); | ||
accumulator.Retract(value!); | ||
} | ||
|
||
public void New<TType>(EntityId<TType> newId) where TType : IEntity | ||
{ | ||
if (newId.Value != id) return; | ||
|
||
var accumulator = GetAccumulator(IEntity.TypeAttribute); | ||
accumulator.Add(id); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using NexusMods.EventSourcing.Abstractions; | ||
|
||
namespace NexusMods.EventSourcing; | ||
|
||
public readonly struct ForwardEventContext(ConcurrentDictionary<EntityId, Dictionary<IAttribute, IAccumulator>> trackedValues) : IEventContext | ||
{ | ||
|
||
private IAccumulator? GetAccumulator<TAttribute>(EntityId id, TAttribute attributeDefinition) | ||
where TAttribute : IAttribute | ||
{ | ||
if (!trackedValues.TryGetValue(id, out var values)) return null; | ||
|
||
if (values.TryGetValue(attributeDefinition, out var accumulator)) | ||
{ | ||
return accumulator; | ||
} | ||
|
||
var newAccumulator = attributeDefinition.CreateAccumulator(); | ||
values.Add(attributeDefinition, newAccumulator); | ||
return newAccumulator; | ||
} | ||
|
||
public void Emit<TOwner, TVal>(EntityId<TOwner> entity, AttributeDefinition<TOwner, TVal> attr, TVal value) where TOwner : IEntity | ||
{ | ||
var accumulator = GetAccumulator(entity.Value, attr); | ||
accumulator?.Add(value!); | ||
} | ||
|
||
public void Emit<TOwner, TVal>(EntityId<TOwner> entity, MultiEntityAttributeDefinition<TOwner, TVal> attr, EntityId<TVal> value) where TOwner : IEntity where TVal : IEntity | ||
{ | ||
var accumulator = GetAccumulator(entity.Value, attr); | ||
accumulator?.Add(value!); | ||
} | ||
|
||
public void Retract<TOwner, TVal>(EntityId<TOwner> entity, AttributeDefinition<TOwner, TVal> attr, TVal value) where TOwner : IEntity | ||
{ | ||
var accumulator = GetAccumulator(entity.Value, attr); | ||
accumulator?.Retract(value!); | ||
} | ||
|
||
public void Retract<TOwner, TVal>(EntityId<TOwner> entity, MultiEntityAttributeDefinition<TOwner, TVal> attr, EntityId<TVal> value) where TOwner : IEntity where TVal : IEntity | ||
{ | ||
var accumulator = GetAccumulator(entity.Value, attr); | ||
accumulator?.Retract(value!); | ||
} | ||
|
||
public void New<TType>(EntityId<TType> id) where TType : IEntity | ||
{ | ||
// Do nothing, as this entity should be pulled fresh from the store when needed | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.