feat(schedules): changed ApplySchedules.Schedules to a getter GetSchedules

This commit is contained in:
D. Moonfire 2023-01-17 18:42:31 -06:00
parent fc1ab22a0e
commit 08aafb144c
6 changed files with 100 additions and 31 deletions

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
@ -8,24 +9,6 @@ using MfGames.Nitride.Generators;
namespace MfGames.Nitride.Temporal.Schedules;
public enum SchedulePeriod
{
/// <summary>
/// Indicates that all the matching schedule periods are instant (zero time).
/// </summary>
Instant,
/// <summary>
/// Indicates that the entities will be scheduled a day apart.
/// </summary>
Day,
/// <summary>
/// Indicates that the entities will be scheduled seven days apart.
/// </summary>
Week,
}
/// <summary>
/// Applies schedules against the list of entities.
/// </summary>
@ -40,13 +23,15 @@ public partial class ApplySchedules : OperationBase
{
this.Timekeeper = timekeeper;
this.validator = validator;
this.Schedules = new List<ISchedule>();
}
/// <summary>
/// Gets or sets the ordered list of schedules to apply to the entities.
/// Gets or sets the callback to get the schedules for the entity. This is
/// used to allow for per-entity schedules or generic schedules across
/// the entire system. If this returns null, then no schedule will be
/// applied.
/// </summary>
public IList<ISchedule> Schedules { get; set; }
public Func<Entity, IList<ISchedule>?>? GetSchedules { get; set; }
/// <summary>
/// Gets or sets the timekeeper associated with this operation.
@ -61,16 +46,30 @@ public partial class ApplySchedules : OperationBase
return input.Select(this.Apply);
}
public ApplySchedules WithSchedules<TItem>(IEnumerable<TItem> items)
where TItem : ISchedule
public ApplySchedules WithGetSchedules<TType>(
Func<Entity, IEnumerable<TType>?> value)
where TType : ISchedule
{
this.Schedules = items.OfType<ISchedule>().ToList();
this.GetSchedules = entity => value?
.Invoke(entity)
?.Cast<ISchedule>()
.ToList();
return this;
}
private Entity Apply(Entity entity)
{
foreach (ISchedule schedule in this.Schedules)
// Get the schedule for this entity.
IList<ISchedule>? schedules = this.GetSchedules?.Invoke(entity);
if (schedules == null || schedules.Count == 0)
{
return entity;
}
// Otherwise, apply the schedules to this entity.
foreach (ISchedule schedule in schedules)
{
if (!schedule.CanApply(entity))
{

View File

@ -20,7 +20,7 @@ public partial class NumericalPathSchedule : ISchedule
public NumericalPathSchedule()
{
this.PathRegex = new Regex(@"^.*(\d+)");
this.GetPath = (entity) => entity.Get<UPath>().ToString();
this.GetPath = entity => entity.Get<UPath>().ToString();
this.CaptureGroup = 1;
this.CaptureOffset = -1;
}

View File

@ -0,0 +1,19 @@
namespace MfGames.Nitride.Temporal.Schedules;
public enum SchedulePeriod
{
/// <summary>
/// Indicates that all the matching schedule periods are instant (zero time).
/// </summary>
Instant,
/// <summary>
/// Indicates that the entities will be scheduled a day apart.
/// </summary>
Day,
/// <summary>
/// Indicates that the entities will be scheduled seven days apart.
/// </summary>
Week,
}

View File

@ -0,0 +1,51 @@
using System;
using MfGames.Gallium;
using MfGames.Nitride.Generators;
using NodaTime;
namespace MfGames.Nitride.Temporal.Schedules;
/// <summary>
/// A schedule that goes against all entities it is applied to.
/// </summary>
[WithProperties]
public partial class SimplePathSchedule : ISchedule
{
/// <summary>
/// Gets or sets when the first item is scheduled.
/// </summary>
public DateTime? ScheduleStart { get; set; }
/// <inheritdoc />
public virtual Entity Apply(
Entity entity,
Timekeeper timekeeper)
{
DateTime start = this.ScheduleStart
?? throw new NullReferenceException(
"Cannot use a schedule without a start date.");
Instant instant = timekeeper.CreateInstant(start);
// If the time hasn't past, then we don't apply it.
Instant now = timekeeper.Clock.GetCurrentInstant();
return instant > now
? entity
: this.Apply(entity, instant);
}
/// <inheritdoc />
public virtual bool CanApply(Entity entity)
{
return true;
}
protected virtual Entity Apply(
Entity entity,
Instant instant)
{
return entity.Set(instant);
}
}

View File

@ -6,8 +6,8 @@ public class ApplySchedulesValidator : AbstractValidator<ApplySchedules>
{
public ApplySchedulesValidator()
{
this.RuleFor(x => x.Schedules)
.NotEmpty();
this.RuleFor(x => x.GetSchedules)
.NotNull();
this.RuleFor(x => x.Timekeeper)
.NotNull();

View File

@ -56,7 +56,7 @@ public class NumericalPathScheduleTests : TemporalSchedulesTestBase
// second but before the third item.
Timekeeper time = context.Resolve<Timekeeper>();
ApplySchedules op = context.Resolve<ApplySchedules>()
.WithSchedules(schedules);
.WithGetSchedules(_ => schedules);
var now = Instant.FromUtc(2023, 1, 9, 0, 0);
time.Clock = new FakeClock(now);
@ -111,7 +111,7 @@ public class NumericalPathScheduleTests : TemporalSchedulesTestBase
// second but before the third item.
Timekeeper time = context.Resolve<Timekeeper>();
ApplySchedules op = context.Resolve<ApplySchedules>()
.WithSchedules(schedules);
.WithGetSchedules(_ => schedules);
var now = Instant.FromUtc(2023, 1, 9, 0, 0);
time.Clock = new FakeClock(now);
@ -171,7 +171,7 @@ public class NumericalPathScheduleTests : TemporalSchedulesTestBase
// second but before the third item.
Timekeeper time = context.Resolve<Timekeeper>();
ApplySchedules op = context.Resolve<ApplySchedules>()
.WithSchedules(schedules);
.WithGetSchedules(_ => schedules);
var now = Instant.FromUtc(2023, 1, 9, 0, 0);
time.Clock = new FakeClock(now);