Newer
Older
PersistenceIgnorance / Four.cs
@Derek Comartin Derek Comartin on 23 Aug 4 KB Init
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace PersistenceIgnorance.Four;

public class Repository
{
    private readonly ShipmentDbContext _dbContext;

    public Repository(ShipmentDbContext dbContext)
    {
        _dbContext = dbContext;
    }
    public Shipment GetShipment(Guid shipmentId)
    {
        var stops = _dbContext.ShipmentStops.Where(x => x.ShipmentId == shipmentId);
        return new Shipment(stops);
    }
}

public class Shipment
{
    private readonly IEnumerable<StopData> _stops;

    public Shipment(IEnumerable<StopData> stops)
    {
        _stops = stops;
    }

    public bool IsComplete()
    {
        return _stops.All(x => x.Status == StopStatus.Departed);
    }

    public void Arrive(Guid stopId)
    {
        var currentStop = _stops.SingleOrDefault(x => x.StopId == stopId);
        if (currentStop == null)
        {
            throw new InvalidOperationException("Stop does not exist.");
        }

        var previousStopsAreNotDeparted = _stops.Any(x => x.Sequence < currentStop.Sequence && x.Status != StopStatus.Departed);
        if (previousStopsAreNotDeparted)
        {
            throw new InvalidOperationException("Previous stops have not departed.");
        }

        if (currentStop.Status != StopStatus.InTransit)
        {
            throw new InvalidOperationException("Stop has already arrived.");
        }

        currentStop.Status = StopStatus.Arrived;
    }
    
    public void Pickup(Guid stopId)
    {
        var currentStop = _stops.SingleOrDefault(x => x.StopId == stopId);
        if (currentStop == null)
        {
            throw new InvalidOperationException("Stop does not exist.");
        }

        if (currentStop.StopType == StopType.Pickup)
        {
            throw new InvalidOperationException("Stop is not a pickup.");
        }

        if (currentStop.Status == StopStatus.Departed)
        {
            throw new InvalidOperationException("Stop has already departed.");
        }

        if (currentStop.Status == StopStatus.InTransit)
        {
            throw new InvalidOperationException("Stop hasn't arrived yet.");
        }

        currentStop.Status = StopStatus.Departed;
    }

    public void Deliver(Guid stopId)
    {
        var currentStop = _stops.SingleOrDefault(x => x.StopId == stopId);
        if (currentStop == null)
        {
            throw new InvalidOperationException("Stop does not exist.");
        }

        if (currentStop.StopType == StopType.Delivery)
        {
            throw new InvalidOperationException("Stop is not a delivery.");
        }

        if (currentStop.Status == StopStatus.Departed)
        {
            throw new InvalidOperationException("Stop has already departed.");
        }

        if (currentStop.Status == StopStatus.InTransit)
        {
            throw new InvalidOperationException("Stop hasn't arrived yet.");
        }

        currentStop.Status = StopStatus.Departed;
    }
}

public class ShipmentDbContext
{
    public List<StopData> ShipmentStops { get; set; }
}

public class Shipper
{
    public Guid ShipperId { get; set; }
    public required string Name { get; set; }
}

public class StopData
{
    public Guid ShipmentId { get; private set; }
    public Guid StopId { get;  set; }
    public StopType StopType { get; set; }
    public Location Location { get; set; }
    public StopStatus Status { get; set; }
    public int Sequence { get; set; }

    protected StopData(Guid stopId, StopType stopType, Location location, StopStatus status, int sequence)
    {
        StopId = stopId;
        StopType = stopType;
        Location = location;
        Status = status;
        Sequence = sequence;
    }
}

public class Location
{
    public Location(string street, string city, string state, string postal)
    {
        Street = street;
        City = city;
        State = state;
        Postal = postal;
    }
    
    public string Street { get; private set; }
    public string City { get; private set; }
    public string State { get; private set; }
    public string Postal { get; private set; }
}

public enum StopType
{
    Pickup,
    Delivery
}

public enum StopStatus
{
    InTransit,
    Arrived,
    Departed
}