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.Collections.Generic;
using System.Linq; using System.Linq;
@ -8,24 +9,6 @@ using MfGames.Nitride.Generators;
namespace MfGames.Nitride.Temporal.Schedules; 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> /// <summary>
/// Applies schedules against the list of entities. /// Applies schedules against the list of entities.
/// </summary> /// </summary>
@ -40,13 +23,15 @@ public partial class ApplySchedules : OperationBase
{ {
this.Timekeeper = timekeeper; this.Timekeeper = timekeeper;
this.validator = validator; this.validator = validator;
this.Schedules = new List<ISchedule>();
} }
/// <summary> /// <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> /// </summary>
public IList<ISchedule> Schedules { get; set; } public Func<Entity, IList<ISchedule>?>? GetSchedules { get; set; }
/// <summary> /// <summary>
/// Gets or sets the timekeeper associated with this operation. /// Gets or sets the timekeeper associated with this operation.
@ -61,16 +46,30 @@ public partial class ApplySchedules : OperationBase
return input.Select(this.Apply); return input.Select(this.Apply);
} }
public ApplySchedules WithSchedules<TItem>(IEnumerable<TItem> items) public ApplySchedules WithGetSchedules<TType>(
where TItem : ISchedule 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; return this;
} }
private Entity Apply(Entity entity) 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)) if (!schedule.CanApply(entity))
{ {

View file

@ -20,7 +20,7 @@ public partial class NumericalPathSchedule : ISchedule
public NumericalPathSchedule() public NumericalPathSchedule()
{ {
this.PathRegex = new Regex(@"^.*(\d+)"); this.PathRegex = new Regex(@"^.*(\d+)");
this.GetPath = (entity) => entity.Get<UPath>().ToString(); this.GetPath = entity => entity.Get<UPath>().ToString();
this.CaptureGroup = 1; this.CaptureGroup = 1;
this.CaptureOffset = -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() public ApplySchedulesValidator()
{ {
this.RuleFor(x => x.Schedules) this.RuleFor(x => x.GetSchedules)
.NotEmpty(); .NotNull();
this.RuleFor(x => x.Timekeeper) this.RuleFor(x => x.Timekeeper)
.NotNull(); .NotNull();

View file

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