This repository has been archived on 2023-02-02. You can view files and clone it, but cannot push or open issues or pull requests.
mfgames-nitride-cil/src/MfGames.Nitride.Temporal/SetInstantFromComponent.cs

106 lines
3.0 KiB
C#

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;
/// <summary>
/// Sets the instant from another component. This has methods for handling
/// nullable properties inside the component.
/// </summary>
public class SetInstantFromComponent<TComponent> : OperationBase
{
private readonly TimeService clock;
private readonly IValidator<SetInstantFromComponent<TComponent>> validator;
public SetInstantFromComponent(TimeService clock)
{
// TODO: Figure out why Autofac won't let us register IValidator of generic classes.
this.validator = new SetInstantFromComponentValidator<TComponent>();
this.clock = clock;
}
/// <summary>
/// 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.
/// </summary>
public Func<Entity, TComponent, object?>? GetDateTimeObject
{
get;
set;
}
/// <inheritdoc />
public override IEnumerable<Entity> Run(
IEnumerable<Entity> input,
CancellationToken cancellationToken = default)
{
this.validator.ValidateAndThrow(this);
return input.SelectEntity<TComponent>(this.Set);
}
/// <summary>
/// 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.
/// </summary>
public SetInstantFromComponent<TComponent> WithGetDateTimeObject(
Func<Entity, TComponent, object?>? 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);
}
}