106 lines
3.0 KiB
C#
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);
|
|
}
|
|
}
|