From 74caa6eefdfea14baaf9130636dce1273b688161 Mon Sep 17 00:00:00 2001 From: "Dylan R. E. Moonfire" Date: Sat, 25 Jun 2022 21:43:05 -0500 Subject: [PATCH] feat: refactored entity sequences and added tests --- src/Nitride/Entities/EntitySequence.cs | 33 ++++++++++ src/Nitride/Entities/LinkEntitySequence.cs | 58 +++++++++++++++++ .../Entities/LinkEntitySequenceValidator.cs | 12 ++++ .../Entities/LinkPreviousNextHandler.cs | 5 -- src/Nitride/Entities/LinkSerialEntities.cs | 52 --------------- .../Entities/LinkSerialEntitiesValidator.cs | 11 ---- .../Entities/LinkEntitySequenceTests.cs | 63 +++++++++++++++++++ 7 files changed, 166 insertions(+), 68 deletions(-) create mode 100644 src/Nitride/Entities/EntitySequence.cs create mode 100644 src/Nitride/Entities/LinkEntitySequence.cs create mode 100644 src/Nitride/Entities/LinkEntitySequenceValidator.cs delete mode 100644 src/Nitride/Entities/LinkPreviousNextHandler.cs delete mode 100644 src/Nitride/Entities/LinkSerialEntities.cs delete mode 100644 src/Nitride/Entities/LinkSerialEntitiesValidator.cs create mode 100644 tests/Nitride.Tests/Entities/LinkEntitySequenceTests.cs diff --git a/src/Nitride/Entities/EntitySequence.cs b/src/Nitride/Entities/EntitySequence.cs new file mode 100644 index 0000000..e90ac75 --- /dev/null +++ b/src/Nitride/Entities/EntitySequence.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; + +using Gallium; + +namespace Nitride.Entities; + +/// +/// Defines a relationship between a given entity and the others in a sequence. +/// +public class EntitySequence +{ + public EntitySequence(IReadOnlyList sequence, int index) + { + this.Sequence = sequence; + this.Index = index; + } + + public bool HasNext => !this.IsLast; + + public bool HasPrevious => !this.IsFirst; + + public int Index { get; } + + public bool IsFirst => this.Index == 0; + + public bool IsLast => this.Index == this.Sequence.Count - 1; + + public Entity? Next => this.HasNext ? this.Sequence[this.Index + 1] : null; + + public Entity? Previous => this.HasPrevious ? this.Sequence[this.Index - 1] : null; + + public IReadOnlyList Sequence { get; } +} diff --git a/src/Nitride/Entities/LinkEntitySequence.cs b/src/Nitride/Entities/LinkEntitySequence.cs new file mode 100644 index 0000000..e7ba83b --- /dev/null +++ b/src/Nitride/Entities/LinkEntitySequence.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using FluentValidation; + +using Gallium; + +namespace Nitride.Entities; + +/// +/// Links a series of entities together in some manner. This assumes that +/// the entities coming into the operation are already ordered. +/// +[WithProperties] +public partial class LinkEntitySequence : OperationBase, IResolvingOperation +{ + private readonly IValidator validator; + + public LinkEntitySequence(IValidator validator) + { + this.validator = validator; + this.CreateSequenceIndex = (list, index) => new EntitySequence(list, index); + this.AddSequenceIndex = (entity, sequence) => entity.Add(sequence); + } + + /// + /// Gets or sets a callback to add a sequence into a given entity. + /// + public Func AddSequenceIndex { get; set; } + + /// + /// Gets or sets the function used to create the sequence index. + /// + public Func, int, EntitySequence> CreateSequenceIndex { get; set; } + + /// + public override IEnumerable Run(IEnumerable input) + { + // Make sure everything is good. + this.validator.ValidateAndThrow(this); + + // We pull all the entities into a list so we can walk through them + // more than once along with index access. We also don't reorder the + // list since we assumed it has been ordered already. + var list = input.ToList(); + + // Go through the list and assign each entity in order with a unique + // copy of the sequence. + for (int i = 0; i < list.Count; i++) + { + Entity entity = list[i]; + EntitySequence index = this.CreateSequenceIndex(list.AsReadOnly(), i); + + yield return this.AddSequenceIndex(entity, index); + } + } +} diff --git a/src/Nitride/Entities/LinkEntitySequenceValidator.cs b/src/Nitride/Entities/LinkEntitySequenceValidator.cs new file mode 100644 index 0000000..92fb565 --- /dev/null +++ b/src/Nitride/Entities/LinkEntitySequenceValidator.cs @@ -0,0 +1,12 @@ +using FluentValidation; + +namespace Nitride.Entities; + +public class LinkEntitySequenceValidator : AbstractValidator +{ + public LinkEntitySequenceValidator() + { + this.RuleFor(x => x.CreateSequenceIndex).NotNull(); + this.RuleFor(x => x.AddSequenceIndex).NotNull(); + } +} diff --git a/src/Nitride/Entities/LinkPreviousNextHandler.cs b/src/Nitride/Entities/LinkPreviousNextHandler.cs deleted file mode 100644 index 553d3c8..0000000 --- a/src/Nitride/Entities/LinkPreviousNextHandler.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Gallium; - -namespace Nitride.Entities; - -public delegate Entity LinkPreviousNextHandler(Entity entity, Entity? previous, Entity? next); diff --git a/src/Nitride/Entities/LinkSerialEntities.cs b/src/Nitride/Entities/LinkSerialEntities.cs deleted file mode 100644 index 53d584c..0000000 --- a/src/Nitride/Entities/LinkSerialEntities.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -using FluentValidation; - -using Gallium; - -namespace Nitride.Entities; - -/// -/// Links a series of entities together in some manner. This assumes that -/// the entities coming into the operation are already ordered. -/// -[WithProperties] -public partial class LinkSerialEntities : OperationBase -{ - private readonly IValidator validator; - - public LinkSerialEntities(IValidator validator) - { - this.validator = validator; - } - - /// - /// The callback function that sets the previous and next - /// - public LinkPreviousNextHandler? UpdatePreviousNext { get; set; } - - /// - public override IEnumerable Run(IEnumerable input) - { - // Make sure everything is good. - this.validator.ValidateAndThrow(this); - - // We pull all the entities into a list so we can walk through them - // more than once along with index access. - var list = input.ToList(); - - // Go through the list and assign each entity in order. - for (int i = 0; i < list.Count; i++) - { - Entity entity = list[i]; - Entity? previous = i > 0 ? list[i - 1] : null; - Entity? next = i < list.Count - 1 ? list[i + 1] : null; - - list[i] = this.UpdatePreviousNext!(entity, previous, next); - } - - // Return the resulting list. - return list; - } -} diff --git a/src/Nitride/Entities/LinkSerialEntitiesValidator.cs b/src/Nitride/Entities/LinkSerialEntitiesValidator.cs deleted file mode 100644 index d505ced..0000000 --- a/src/Nitride/Entities/LinkSerialEntitiesValidator.cs +++ /dev/null @@ -1,11 +0,0 @@ -using FluentValidation; - -namespace Nitride.Entities; - -public class LinkSerialEntitiesValidator : AbstractValidator -{ - public LinkSerialEntitiesValidator() - { - this.RuleFor(x => x.UpdatePreviousNext).NotNull(); - } -} diff --git a/tests/Nitride.Tests/Entities/LinkEntitySequenceTests.cs b/tests/Nitride.Tests/Entities/LinkEntitySequenceTests.cs new file mode 100644 index 0000000..6bb2576 --- /dev/null +++ b/tests/Nitride.Tests/Entities/LinkEntitySequenceTests.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Gallium; + +using Nitride.Entities; + +using Xunit; +using Xunit.Abstractions; + +namespace Nitride.Tests.Entities; + +public class LinkEntitySequenceTests : NitrideTestBase +{ + public LinkEntitySequenceTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void LinkThree() + { + NitrideTestContext context = this.CreateContext(); + LinkEntitySequence op = context.Resolve(); + + var input = new List + { + new Entity().Add("page1"), + new Entity().Add("page2"), + new Entity().Add("page3"), + }; + + var results = op.Run(input).ToList(); + + Assert.Equal(3, results.Count); + + EntitySequence seq1 = results[0].Get(); + EntitySequence seq2 = results[1].Get(); + EntitySequence seq3 = results[2].Get(); + + Assert.True(seq1.IsFirst); + Assert.False(seq1.IsLast); + Assert.False(seq1.HasPrevious); + Assert.True(seq1.HasNext); + Assert.Null(seq1.Previous?.Get()); + Assert.Equal("page2", seq1.Next!.Get()); + + Assert.False(seq2.IsFirst); + Assert.False(seq2.IsLast); + Assert.True(seq2.HasPrevious); + Assert.True(seq2.HasNext); + Assert.Equal("page1", seq2.Previous!.Get()); + Assert.Equal("page3", seq2.Next!.Get()); + + Assert.False(seq3.IsFirst); + Assert.True(seq3.IsLast); + Assert.True(seq3.HasPrevious); + Assert.False(seq3.HasNext); + Assert.Equal("page2", seq3.Previous!.Get()); + Assert.Null(seq3.Next?.Get()); + } +}