From be83c4a88ff67bc08198889b946e3b8768b76058 Mon Sep 17 00:00:00 2001 From: halgari Date: Wed, 17 Jan 2024 16:34:52 -0700 Subject: [PATCH] Adapted most of the framework to the new index style --- .../EntityIdDefinition.cs | 12 ++--- .../IIndexableAttribute.cs | 2 +- src/NexusMods.EventSourcing/EntityContext.cs | 24 +++++++++- .../IndexerIngester.cs | 47 +++++++++++++++++++ 4 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 src/NexusMods.EventSourcing/IndexerIngester.cs diff --git a/src/NexusMods.EventSourcing.Abstractions/EntityIdDefinition.cs b/src/NexusMods.EventSourcing.Abstractions/EntityIdDefinition.cs index 940c5861..d5bb44fc 100644 --- a/src/NexusMods.EventSourcing.Abstractions/EntityIdDefinition.cs +++ b/src/NexusMods.EventSourcing.Abstractions/EntityIdDefinition.cs @@ -6,7 +6,7 @@ namespace NexusMods.EventSourcing.Abstractions; -public class EntityIdDefinition : IAttribute, IIndexableAttribute +public class EntityIdDefinition : IAttribute, IIndexableAttribute { /// public Type Owner => typeof(IEntity); @@ -15,14 +15,14 @@ public class EntityIdDefinition : IAttribute, IInde public string Name => "Id"; /// - public EntityDefinitionAccumulator CreateAccumulator() + public EntityIdDefinitionAccumulator CreateAccumulator() { - return new EntityDefinitionAccumulator(); + return new EntityIdDefinitionAccumulator(); } IAccumulator IAttribute.CreateAccumulator() { - return new EntityDefinitionAccumulator(); + return new EntityIdDefinitionAccumulator(); } /// @@ -49,14 +49,14 @@ public int SpanSize() /// public void WriteTo(Span span, IAccumulator accumulator) { - if (accumulator is not EntityDefinitionAccumulator entityDefinitionAccumulator) + if (accumulator is not EntityIdDefinitionAccumulator entityDefinitionAccumulator) throw new InvalidOperationException("Invalid accumulator type."); BinaryPrimitives.WriteUInt128BigEndian(span, entityDefinitionAccumulator.Id.Value); } } -public class EntityDefinitionAccumulator : IAccumulator +public class EntityIdDefinitionAccumulator : IAccumulator { public EntityId Id; diff --git a/src/NexusMods.EventSourcing.Abstractions/IIndexableAttribute.cs b/src/NexusMods.EventSourcing.Abstractions/IIndexableAttribute.cs index e3edcad1..ff6c3259 100644 --- a/src/NexusMods.EventSourcing.Abstractions/IIndexableAttribute.cs +++ b/src/NexusMods.EventSourcing.Abstractions/IIndexableAttribute.cs @@ -12,7 +12,7 @@ namespace NexusMods.EventSourcing.Abstractions; /// length values, hashing them and using the hash as the index is recommended. Once the entity is loaded with the help /// of the index, the actual value can be compared to ensure the values are correct. /// -public interface IIndexableAttribute +public interface IIndexableAttribute : IAttribute { /// /// The Id of the attribute definition index. diff --git a/src/NexusMods.EventSourcing/EntityContext.cs b/src/NexusMods.EventSourcing/EntityContext.cs index 213c8a6f..d473f60f 100644 --- a/src/NexusMods.EventSourcing/EntityContext.cs +++ b/src/NexusMods.EventSourcing/EntityContext.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using DynamicData; using NexusMods.EventSourcing.Abstractions; namespace NexusMods.EventSourcing; @@ -71,7 +72,7 @@ private Dictionary LoadAccumulators(EntityId id) } var ingester = new EntityContextIngester(values, id); - store.EventsForEntity(id, ingester, snapshotTxId, asOf); + store.EventsForIndex(IEntity.EntityIdAttribute, id, ingester, snapshotTxId, asOf); if (ingester.ProcessedEvents > MaxEventsBeforeSnapshotting) { @@ -109,7 +110,26 @@ public TransactionId Add(TEvent newEvent) where TEvent : IEvent lock (_lock) { - var newId = store.Add(newEvent); + var indexerIngester = new IndexerIngester(); + indexerIngester.Ingest(TransactionId.Min, newEvent); + + var lst = new List<(IIndexableAttribute, IAccumulator)>(); + + foreach (var entityId in indexerIngester.Ids) + { + lst.Add((IEntity.EntityIdAttribute, new EntityIdDefinitionAccumulator { Id = entityId })); + } + + foreach (var (attribute, accumulators) in indexerIngester.IndexedAttributes) + { + foreach (var accumulator in accumulators) + { + lst.Add((attribute, accumulator)); + } + } + + + var newId = store.Add(newEvent, lst.ToArray()); asOf = newId; var updatedAttributes = new HashSet<(EntityId, string)>(); diff --git a/src/NexusMods.EventSourcing/IndexerIngester.cs b/src/NexusMods.EventSourcing/IndexerIngester.cs new file mode 100644 index 00000000..b3e2f621 --- /dev/null +++ b/src/NexusMods.EventSourcing/IndexerIngester.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using DynamicData; +using NexusMods.EventSourcing.Abstractions; + +namespace NexusMods.EventSourcing; + +public class IndexerIngester : IEventIngester, IEventContext +{ + public Dictionary> IndexedAttributes = new(); + + public HashSet Ids = new(); + + + public bool Ingest(TransactionId id, IEvent @event) + { + @event.Apply(this); + return true; + } + + public bool GetAccumulator(EntityId entityId, TAttribute attributeDefinition, + out TAccumulator accumulator) where TOwner : IEntity where TAttribute : IAttribute where TAccumulator : IAccumulator + { + Ids.Add(entityId.Value); + + if (attributeDefinition is IIndexableAttribute indexableAttribute) + { + var indexedAccumulator = indexableAttribute.CreateAccumulator(); + + if (IndexedAttributes.TryGetValue(indexableAttribute, out var found)) + { + found.Add(indexedAccumulator); + } + else + { + var lst = new List(); + lst.Add(indexedAccumulator); + IndexedAttributes[indexableAttribute] = lst; + } + + accumulator = (TAccumulator)indexedAccumulator; + return true; + } + + accumulator = default!; + return false; + } +}