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 }