using System; using System.Collections.Generic; using System.Threading; using FluentValidation; using MfGames.Gallium; using MfGames.Nitride.Temporal.Validators; using NodaTime; namespace MfGames.Nitride.Temporal; /// /// Sets the instant from another component. This has methods for handling /// nullable properties inside the component. /// public class SetInstantFromComponent : OperationBase { private readonly TimeService clock; private readonly IValidator> validator; public SetInstantFromComponent(TimeService clock) { // TODO: Figure out why Autofac won't let us register IValidator of generic classes. this.validator = new SetInstantFromComponentValidator(); this.clock = clock; } /// /// The callback used to get a date time object which is converted into /// an Instant automatically. This can handle DateTime, DateTimeOffset, /// LocalDate, and Instant. Nulls are skipped. /// public Func? GetDateTimeObject { get; set; } /// public override IEnumerable Run( IEnumerable input, CancellationToken cancellationToken = default) { this.validator.ValidateAndThrow(this); return input.SelectEntity(this.Set); } /// /// Sets the callback used to get a date time object which is converted /// into an Instant automatically. This can handle DateTime, /// DateTimeOffset, LocalDate, and Instant. Nulls are skipped. /// public SetInstantFromComponent WithGetDateTimeObject( Func? callback) { this.GetDateTimeObject = callback; return this; } private Entity Set( Entity entity, TComponent component) { object? temporal = this.GetDateTimeObject!(entity, component); Instant instant; switch (temporal) { case null: return entity; case Instant direct: instant = direct; break; case LocalDate other: instant = this.clock.CreateInstant(other); break; case DateTime other: instant = this.clock.CreateInstant(other); break; case DateTimeOffset other: instant = this.clock.CreateInstant(other); break; default: throw new InvalidOperationException( "Did not get a date time object from the callback. " + "Can only handle DateTime, DateTimeOffset, LocalDate, " + "and Instant. Got a " + temporal.GetType() .Name + " instead."); } return entity.Set(instant); } }