feat: refactored entity sequences and added tests

This commit is contained in:
Dylan R. E. Moonfire 2022-06-25 21:43:05 -05:00
parent 86403060e7
commit 74caa6eefd
7 changed files with 166 additions and 68 deletions

View file

@ -0,0 +1,33 @@
using System.Collections.Generic;
using Gallium;
namespace Nitride.Entities;
/// <summary>
/// Defines a relationship between a given entity and the others in a sequence.
/// </summary>
public class EntitySequence
{
public EntitySequence(IReadOnlyList<Entity> 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<Entity> Sequence { get; }
}

View file

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FluentValidation;
using Gallium;
namespace Nitride.Entities;
/// <summary>
/// Links a series of entities together in some manner. This assumes that
/// the entities coming into the operation are already ordered.
/// </summary>
[WithProperties]
public partial class LinkEntitySequence : OperationBase, IResolvingOperation
{
private readonly IValidator<LinkEntitySequence> validator;
public LinkEntitySequence(IValidator<LinkEntitySequence> validator)
{
this.validator = validator;
this.CreateSequenceIndex = (list, index) => new EntitySequence(list, index);
this.AddSequenceIndex = (entity, sequence) => entity.Add(sequence);
}
/// <summary>
/// Gets or sets a callback to add a sequence into a given entity.
/// </summary>
public Func<Entity, EntitySequence, Entity> AddSequenceIndex { get; set; }
/// <summary>
/// Gets or sets the function used to create the sequence index.
/// </summary>
public Func<IReadOnlyList<Entity>, int, EntitySequence> CreateSequenceIndex { get; set; }
/// <inheritdoc />
public override IEnumerable<Entity> Run(IEnumerable<Entity> 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);
}
}
}

View file

@ -0,0 +1,12 @@
using FluentValidation;
namespace Nitride.Entities;
public class LinkEntitySequenceValidator : AbstractValidator<LinkEntitySequence>
{
public LinkEntitySequenceValidator()
{
this.RuleFor(x => x.CreateSequenceIndex).NotNull();
this.RuleFor(x => x.AddSequenceIndex).NotNull();
}
}

View file

@ -1,5 +0,0 @@
using Gallium;
namespace Nitride.Entities;
public delegate Entity LinkPreviousNextHandler(Entity entity, Entity? previous, Entity? next);

View file

@ -1,52 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using FluentValidation;
using Gallium;
namespace Nitride.Entities;
/// <summary>
/// Links a series of entities together in some manner. This assumes that
/// the entities coming into the operation are already ordered.
/// </summary>
[WithProperties]
public partial class LinkSerialEntities : OperationBase
{
private readonly IValidator<LinkSerialEntities> validator;
public LinkSerialEntities(IValidator<LinkSerialEntities> validator)
{
this.validator = validator;
}
/// <summary>
/// The callback function that sets the previous and next
/// </summary>
public LinkPreviousNextHandler? UpdatePreviousNext { get; set; }
/// <inheritdoc />
public override IEnumerable<Entity> Run(IEnumerable<Entity> 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;
}
}

View file

@ -1,11 +0,0 @@
using FluentValidation;
namespace Nitride.Entities;
public class LinkSerialEntitiesValidator : AbstractValidator<LinkSerialEntities>
{
public LinkSerialEntitiesValidator()
{
this.RuleFor(x => x.UpdatePreviousNext).NotNull();
}
}

View file

@ -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<LinkEntitySequence>();
var input = new List<Entity>
{
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>();
EntitySequence seq2 = results[1].Get<EntitySequence>();
EntitySequence seq3 = results[2].Get<EntitySequence>();
Assert.True(seq1.IsFirst);
Assert.False(seq1.IsLast);
Assert.False(seq1.HasPrevious);
Assert.True(seq1.HasNext);
Assert.Null(seq1.Previous?.Get<string>());
Assert.Equal("page2", seq1.Next!.Get<string>());
Assert.False(seq2.IsFirst);
Assert.False(seq2.IsLast);
Assert.True(seq2.HasPrevious);
Assert.True(seq2.HasNext);
Assert.Equal("page1", seq2.Previous!.Get<string>());
Assert.Equal("page3", seq2.Next!.Get<string>());
Assert.False(seq3.IsFirst);
Assert.True(seq3.IsLast);
Assert.True(seq3.HasPrevious);
Assert.False(seq3.HasNext);
Assert.Equal("page2", seq3.Previous!.Get<string>());
Assert.Null(seq3.Next?.Get<string>());
}
}