diff --git a/src/Services/Flight/src/Flight/Airports/Exceptions/InvalidAddressException.cs b/src/Services/Flight/src/Flight/Airports/Exceptions/InvalidAddressException.cs new file mode 100644 index 00000000..1036a8b3 --- /dev/null +++ b/src/Services/Flight/src/Flight/Airports/Exceptions/InvalidAddressException.cs @@ -0,0 +1,9 @@ +namespace Flight.Airports.Exceptions; +using BuildingBlocks.Exception; + +public class InvalidAddressException : BadRequestException +{ + public InvalidAddressException() : base("Address cannot be empty or whitespace.") + { + } +} diff --git a/src/Services/Flight/src/Flight/Airports/Exceptions/InvalidAirportIdExceptions.cs b/src/Services/Flight/src/Flight/Airports/Exceptions/InvalidAirportIdExceptions.cs new file mode 100644 index 00000000..504030a2 --- /dev/null +++ b/src/Services/Flight/src/Flight/Airports/Exceptions/InvalidAirportIdExceptions.cs @@ -0,0 +1,11 @@ +namespace Flight.Airports.Exceptions; +using System; +using BuildingBlocks.Exception; + +public class InvalidAirportIdExceptions : BadRequestException +{ + public InvalidAirportIdExceptions(Guid airportId) + : base($"airportId: '{airportId}' is invalid.") + { + } +} diff --git a/src/Services/Flight/src/Flight/Airports/Exceptions/InvalidCodeException.cs b/src/Services/Flight/src/Flight/Airports/Exceptions/InvalidCodeException.cs new file mode 100644 index 00000000..9b69b550 --- /dev/null +++ b/src/Services/Flight/src/Flight/Airports/Exceptions/InvalidCodeException.cs @@ -0,0 +1,10 @@ +namespace Flight.Airports.Exceptions; +using BuildingBlocks.Exception; + + +public class InvalidCodeException : BadRequestException +{ + public InvalidCodeException() : base("Code cannot be empty or whitespace.") + { + } +} diff --git a/src/Services/Flight/src/Flight/Airports/Exceptions/InvalidNameException.cs b/src/Services/Flight/src/Flight/Airports/Exceptions/InvalidNameException.cs new file mode 100644 index 00000000..310ffb88 --- /dev/null +++ b/src/Services/Flight/src/Flight/Airports/Exceptions/InvalidNameException.cs @@ -0,0 +1,10 @@ +namespace Flight.Airports.Exceptions; +using BuildingBlocks.Exception; + + +public class InvalidNameException : BadRequestException +{ + public InvalidNameException() : base("Name cannot be empty or whitespace.") + { + } +} diff --git a/src/Services/Flight/src/Flight/Airports/Features/AirportMappings.cs b/src/Services/Flight/src/Flight/Airports/Features/AirportMappings.cs index 805f1786..5c7b7cd3 100644 --- a/src/Services/Flight/src/Flight/Airports/Features/AirportMappings.cs +++ b/src/Services/Flight/src/Flight/Airports/Features/AirportMappings.cs @@ -1,9 +1,9 @@ -namespace Flight.Airports.Features; +namespace Flight.Airports.Features; using CreatingAirport.V1; -using Models; using Mapster; using MassTransit; +using Models; public class AirportMappings : IRegister { @@ -15,7 +15,7 @@ public void Register(TypeAdapterConfig config) config.NewConfig() .Map(d => d.Id, s => NewId.NextGuid()) - .Map(d => d.AirportId, s => s.Id); + .Map(d => d.AirportId, s => s.Id.Value); config.NewConfig() .ConstructUsing(x => new CreateAirport(x.Name, x.Address, x.Code)); diff --git a/src/Services/Flight/src/Flight/Airports/Features/CreatingAirport/V1/CreateAirport.cs b/src/Services/Flight/src/Flight/Airports/Features/CreatingAirport/V1/CreateAirport.cs index f1363741..bf050516 100644 --- a/src/Services/Flight/src/Flight/Airports/Features/CreatingAirport/V1/CreateAirport.cs +++ b/src/Services/Flight/src/Flight/Airports/Features/CreatingAirport/V1/CreateAirport.cs @@ -7,9 +7,9 @@ namespace Flight.Airports.Features.CreatingAirport.V1; using BuildingBlocks.Core.CQRS; using BuildingBlocks.Core.Event; using BuildingBlocks.Web; -using Exceptions; using Data; using Duende.IdentityServer.EntityFramework.Entities; +using Exceptions; using FluentValidation; using MapsterMapper; using MassTransit; @@ -18,6 +18,7 @@ namespace Flight.Airports.Features.CreatingAirport.V1; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.EntityFrameworkCore; +using ValueObjects; public record CreateAirport(string Name, string Address, string Code) : ICommand, IInternalCommand { @@ -87,17 +88,17 @@ public async Task Handle(CreateAirport request, Cancellatio Guard.Against.Null(request, nameof(request)); var airport = - await _flightDbContext.Airports.SingleOrDefaultAsync(x => x.Code == request.Code, cancellationToken); + await _flightDbContext.Airports.SingleOrDefaultAsync(x => x.Code.Value == request.Code, cancellationToken); if (airport is not null) { throw new AirportAlreadyExistException(); } - var airportEntity = Models.Airport.Create(request.Id, request.Name, request.Code, request.Address); + var airportEntity = Models.Airport.Create(AirportId.Of(request.Id), Name.Of(request.Name), Address.Of(request.Address), Code.Of(request.Code)); var newAirport = (await _flightDbContext.Airports.AddAsync(airportEntity, cancellationToken))?.Entity; - return new CreateAirportResult(newAirport.Id); + return new CreateAirportResult(newAirport.Id.Value); } } diff --git a/src/Services/Flight/src/Flight/Airports/Models/Airport.cs b/src/Services/Flight/src/Flight/Airports/Models/Airport.cs index fbdd71df..327e0b90 100644 --- a/src/Services/Flight/src/Flight/Airports/Models/Airport.cs +++ b/src/Services/Flight/src/Flight/Airports/Models/Airport.cs @@ -2,16 +2,16 @@ namespace Flight.Airports.Models; -using System; using Features.CreatingAirport.V1; +using Flight.Airports.ValueObjects; -public record Airport : Aggregate +public record Airport : Aggregate { - public string Name { get; private set; } - public string Address { get; private set; } - public string Code { get; private set; } + public Name Name { get; private set; } = default!; + public Address Address { get; private set; } = default!; + public Code Code { get; private set; } - public static Airport Create(Guid id, string name, string address, string code, bool isDeleted = false) + public static Airport Create(AirportId id, Name name, Address address, Code code, bool isDeleted = false) { var airport = new Airport { @@ -22,10 +22,10 @@ public static Airport Create(Guid id, string name, string address, string code, }; var @event = new AirportCreatedDomainEvent( - airport.Id, - airport.Name, - airport.Address, - airport.Code, + airport.Id.Value, + airport.Name.Value, + airport.Address.Value, + airport.Code.Value, isDeleted); airport.AddDomainEvent(@event); diff --git a/src/Services/Flight/src/Flight/Airports/ValueObjects/Address.cs b/src/Services/Flight/src/Flight/Airports/ValueObjects/Address.cs new file mode 100644 index 00000000..fe0d2c0b --- /dev/null +++ b/src/Services/Flight/src/Flight/Airports/ValueObjects/Address.cs @@ -0,0 +1,43 @@ +namespace Flight.Airports.ValueObjects; +using System.Linq; +using Exceptions; + +public class Address +{ + public string Street { get; } + public string City { get; } + public string State { get; } + public string ZipCode { get; } + public string Country { get; } + public string Value { get; } + + public Address(string value) + { + if (string.IsNullOrWhiteSpace(value)) + { + throw new InvalidAddressException(); + } + Value = value; + } + + public Address(string street, string city, string state, string zipCode, string country) + { + Street = street?.Trim(); + City = city?.Trim(); + State = state?.Trim(); + ZipCode = zipCode?.Trim(); + Country = country?.Trim(); + + Value = string.Join(", ", new[] { Street, City, State, ZipCode, Country }.Where(s => !string.IsNullOrWhiteSpace(s))); + } + + public static Address Of(string value) + { + return new Address(value); + } + + public static implicit operator string(Address address) + { + return address.Value; + } +} diff --git a/src/Services/Flight/src/Flight/Airports/ValueObjects/AirportId.cs b/src/Services/Flight/src/Flight/Airports/ValueObjects/AirportId.cs new file mode 100644 index 00000000..8f48019d --- /dev/null +++ b/src/Services/Flight/src/Flight/Airports/ValueObjects/AirportId.cs @@ -0,0 +1,28 @@ +namespace Flight.Airports.ValueObjects; +using System; +using Flight.Airports.Exceptions; + +public record AirportId +{ + public Guid Value { get; } + + private AirportId(Guid value) + { + if (value == Guid.Empty) + { + throw new InvalidAirportIdExceptions(value); + } + + Value = value; + } + + public static AirportId Of(Guid value) + { + return new AirportId(value); + } + + public static implicit operator Guid(AirportId airportId) + { + return airportId.Value; + } +} diff --git a/src/Services/Flight/src/Flight/Airports/ValueObjects/Code.cs b/src/Services/Flight/src/Flight/Airports/ValueObjects/Code.cs new file mode 100644 index 00000000..210a8d77 --- /dev/null +++ b/src/Services/Flight/src/Flight/Airports/ValueObjects/Code.cs @@ -0,0 +1,25 @@ +namespace Flight.Airports.ValueObjects; + +using Exceptions; + +public record Code +{ + public string Value { get; } + public Code(string value) + { + if (string.IsNullOrWhiteSpace(value)) + { + throw new InvalidCodeException(); + } + Value = value; + } + public static Code Of(string value) + { + return new Code(value); + } + + public static implicit operator string(Code code) + { + return code.Value; + } +} diff --git a/src/Services/Flight/src/Flight/Airports/ValueObjects/Name.cs b/src/Services/Flight/src/Flight/Airports/ValueObjects/Name.cs new file mode 100644 index 00000000..5529c564 --- /dev/null +++ b/src/Services/Flight/src/Flight/Airports/ValueObjects/Name.cs @@ -0,0 +1,25 @@ +namespace Flight.Airports.ValueObjects; + +using Flight.Airports.Exceptions; + +public record Name +{ + public string Value { get; } + public Name(string value) + { + if (string.IsNullOrWhiteSpace(value)) + { + throw new InvalidNameException(); + } + Value = value; + } + public static Name Of(string value) + { + return new Name(value); + } + + public static implicit operator string(Name name) + { + return name.Value; + } +} diff --git a/src/Services/Flight/src/Flight/Data/Configurations/AirportConfiguration.cs b/src/Services/Flight/src/Flight/Data/Configurations/AirportConfiguration.cs index b3f475be..6570a2dd 100644 --- a/src/Services/Flight/src/Flight/Data/Configurations/AirportConfiguration.cs +++ b/src/Services/Flight/src/Flight/Data/Configurations/AirportConfiguration.cs @@ -1,10 +1,13 @@ +using System; using Flight.Airports.Models; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Flight.Data.Configurations; -public class AirportConfiguration: IEntityTypeConfiguration +using Airports.ValueObjects; + +public class AirportConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { @@ -12,10 +15,43 @@ public void Configure(EntityTypeBuilder builder) builder.ToTable(nameof(Airport)); builder.HasKey(r => r.Id); - builder.Property(r => r.Id).ValueGeneratedNever(); - - + builder.Property(r => r.Id).ValueGeneratedNever() + .HasConversion(airportId => airportId.Value, dbId => AirportId.Of(dbId)); // // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api builder.Property(r => r.Version).IsConcurrencyToken(); + + + builder.OwnsOne( + x => x.Name, + a => + { + a.Property(p => p.Value) + .HasColumnName(nameof(Airport.Name)) + .HasMaxLength(50) + .IsRequired(); + } + ); + + builder.OwnsOne( + x => x.Address, + a => + { + a.Property(p => p.Value) + .HasColumnName(nameof(Airport.Address)) + .HasMaxLength(50) + .IsRequired(); + } + ); + + builder.OwnsOne( + x => x.Code, + a => + { + a.Property(p => p.Value) + .HasColumnName(nameof(Airport.Code)) + .HasMaxLength(50) + .IsRequired(); + } + ); } } diff --git a/src/Services/Flight/src/Flight/Data/Configurations/FlightConfiguration.cs b/src/Services/Flight/src/Flight/Data/Configurations/FlightConfiguration.cs index 42e549eb..ea0a176a 100644 --- a/src/Services/Flight/src/Flight/Data/Configurations/FlightConfiguration.cs +++ b/src/Services/Flight/src/Flight/Data/Configurations/FlightConfiguration.cs @@ -1,4 +1,3 @@ -using BuildingBlocks.EFCore; using Flight.Aircrafts.Models; using Flight.Airports.Models; using Microsoft.EntityFrameworkCore; @@ -7,6 +6,8 @@ namespace Flight.Data.Configurations; using System; +using Flights.Models; +using Flights.ValueObjects; public class FlightConfiguration : IEntityTypeConfiguration { @@ -15,12 +16,23 @@ public void Configure(EntityTypeBuilder builder) builder.ToTable(nameof(Flight)); builder.HasKey(r => r.Id); - builder.Property(r => r.Id).ValueGeneratedNever(); + builder.Property(r => r.Id).ValueGeneratedNever() + .HasConversion(flight => flight.Value, dbId => FlightId.Of(dbId)); - - // // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api builder.Property(r => r.Version).IsConcurrencyToken(); + + builder.OwnsOne( + x => x.FlightNumber, + a => + { + a.Property(p => p.Value) + .HasColumnName(nameof(Flight.FlightNumber)) + .HasMaxLength(50) + .IsRequired(); + } + ); + builder .HasOne() .WithMany() @@ -29,9 +41,30 @@ public void Configure(EntityTypeBuilder builder) builder .HasOne() .WithMany() - .HasForeignKey(d => d.DepartureAirportId) - .HasForeignKey(a => a.ArriveAirportId); + .HasForeignKey(d => d.DepartureAirportId); + + builder + .HasOne() + .WithMany() + .HasForeignKey(d => d.ArriveAirportId); + + //builder + // .HasOne() + // .WithMany() + // .HasForeignKey(d => d.DepartureAirportId.Value) + // .HasForeignKey(a => a.ArriveAirportId.Value); + + builder.OwnsOne( + x => x.DurationMinutes, + a => + { + a.Property(p => p.Value) + .HasColumnName(nameof(Flight.DurationMinutes)) + .HasMaxLength(50) + .IsRequired(); + } + ); builder.Property(x => x.Status) .HasDefaultValue(Flights.Enums.FlightStatus.Unknown) @@ -39,15 +72,45 @@ public void Configure(EntityTypeBuilder builder) x => x.ToString(), x => (Flights.Enums.FlightStatus)Enum.Parse(typeof(Flights.Enums.FlightStatus), x)); - // // https://docs.microsoft.com/en-us/ef/core/modeling/shadow-properties - // // https://docs.microsoft.com/en-us/ef/core/modeling/owned-entities - // builder.OwnsMany(p => p.Seats, a => - // { - // a.WithOwner().HasForeignKey("FlightId"); - // a.Property("Id"); - // a.HasKey("Id"); - // a.Property("FlightId"); - // a.ToTable("Seat"); - // }); + builder.OwnsOne( + x => x.Price, + a => + { + a.Property(p => p.Value) + .HasColumnName(nameof(Flight.Price)) + .HasMaxLength(10) + .IsRequired(); + } + ); + + builder.OwnsOne( + x => x.ArriveDate, + a => + { + a.Property(p => p.Value) + .HasColumnName(nameof(Flight.ArriveDate)) + .IsRequired(); + } + ); + + builder.OwnsOne( + x => x.DepartureDate, + a => + { + a.Property(p => p.Value) + .HasColumnName(nameof(Flight.DepartureDate)) + .IsRequired(); + } + ); + + builder.OwnsOne( + x => x.FlightDate, + a => + { + a.Property(p => p.Value) + .HasColumnName(nameof(Flight.FlightDate)) + .IsRequired(); + } + ); } } diff --git a/src/Services/Flight/src/Flight/Data/Configurations/SeatConfiguration.cs b/src/Services/Flight/src/Flight/Data/Configurations/SeatConfiguration.cs index e1e6e0f6..ff8b995d 100644 --- a/src/Services/Flight/src/Flight/Data/Configurations/SeatConfiguration.cs +++ b/src/Services/Flight/src/Flight/Data/Configurations/SeatConfiguration.cs @@ -1,4 +1,3 @@ -using BuildingBlocks.EFCore; using Flight.Seats.Models; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -6,6 +5,7 @@ namespace Flight.Data.Configurations; using System; +using Seats.ValueObjects; public class SeatConfiguration : IEntityTypeConfiguration { @@ -14,10 +14,21 @@ public void Configure(EntityTypeBuilder builder) builder.ToTable(nameof(Seat)); builder.HasKey(r => r.Id); - builder.Property(r => r.Id).ValueGeneratedNever(); - - // // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api - builder.Property(r => r.Version).IsConcurrencyToken(); + builder.Property(r => r.Id).ValueGeneratedNever() + .HasConversion(seatId => seatId.Value, dbId => SeatId.Of(dbId)); + + builder.Property(r => r.Version).IsConcurrencyToken(); + + builder.OwnsOne( + x => x.SeatNumber, + a => + { + a.Property(p => p.Value) + .HasColumnName(nameof(Seat.SeatNumber)) + .HasMaxLength(50) + .IsRequired(); + } + ); builder .HasOne() diff --git a/src/Services/Flight/src/Flight/Data/Migrations/20230609154649_AddValueObjectForSeat-Airport-Flight.Designer.cs b/src/Services/Flight/src/Flight/Data/Migrations/20230609154649_AddValueObjectForSeat-Airport-Flight.Designer.cs new file mode 100644 index 00000000..0578cf92 --- /dev/null +++ b/src/Services/Flight/src/Flight/Data/Migrations/20230609154649_AddValueObjectForSeat-Airport-Flight.Designer.cs @@ -0,0 +1,573 @@ +// +using System; +using Flight.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Flight.Data.Migrations +{ + [DbContext(typeof(FlightDbContext))] + [Migration("20230609154649_AddValueObjectForSeat-Airport-Flight")] + partial class AddValueObjectForSeatAirportFlight + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Flight.Aircrafts.Models.Aircraft", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("CreatedBy") + .HasColumnType("bigint") + .HasColumnName("created_by"); + + b.Property("IsDeleted") + .HasColumnType("boolean") + .HasColumnName("is_deleted"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified"); + + b.Property("LastModifiedBy") + .HasColumnType("bigint") + .HasColumnName("last_modified_by"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("bigint") + .HasColumnName("version"); + + b.HasKey("Id") + .HasName("pk_aircraft"); + + b.ToTable("aircraft", (string)null); + }); + + modelBuilder.Entity("Flight.Airports.Models.Airport", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("CreatedBy") + .HasColumnType("bigint") + .HasColumnName("created_by"); + + b.Property("IsDeleted") + .HasColumnType("boolean") + .HasColumnName("is_deleted"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified"); + + b.Property("LastModifiedBy") + .HasColumnType("bigint") + .HasColumnName("last_modified_by"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("bigint") + .HasColumnName("version"); + + b.HasKey("Id") + .HasName("pk_airport"); + + b.ToTable("airport", (string)null); + }); + + modelBuilder.Entity("Flight.Flights.Models.Flight", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AircraftId") + .HasColumnType("uuid") + .HasColumnName("aircraft_id"); + + b.Property("ArriveAirportId") + .HasColumnType("uuid") + .HasColumnName("arrive_airport_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("CreatedBy") + .HasColumnType("bigint") + .HasColumnName("created_by"); + + b.Property("DepartureAirportId") + .HasColumnType("uuid") + .HasColumnName("departure_airport_id"); + + b.Property("IsDeleted") + .HasColumnType("boolean") + .HasColumnName("is_deleted"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified"); + + b.Property("LastModifiedBy") + .HasColumnType("bigint") + .HasColumnName("last_modified_by"); + + b.Property("Status") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("text") + .HasDefaultValue("Unknown") + .HasColumnName("status"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("bigint") + .HasColumnName("version"); + + b.HasKey("Id") + .HasName("pk_flight"); + + b.HasIndex("AircraftId") + .HasDatabaseName("ix_flight_aircraft_id"); + + b.HasIndex("ArriveAirportId") + .HasDatabaseName("ix_flight_arrive_airport_id"); + + b.HasIndex("DepartureAirportId") + .HasDatabaseName("ix_flight_departure_airport_id"); + + b.ToTable("flight", (string)null); + }); + + modelBuilder.Entity("Flight.Seats.Models.Seat", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Class") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("text") + .HasDefaultValue("Unknown") + .HasColumnName("class"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("CreatedBy") + .HasColumnType("bigint") + .HasColumnName("created_by"); + + b.Property("FlightId") + .HasColumnType("uuid") + .HasColumnName("flight_id"); + + b.Property("IsDeleted") + .HasColumnType("boolean") + .HasColumnName("is_deleted"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified"); + + b.Property("LastModifiedBy") + .HasColumnType("bigint") + .HasColumnName("last_modified_by"); + + b.Property("Type") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("text") + .HasDefaultValue("Unknown") + .HasColumnName("type"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("bigint") + .HasColumnName("version"); + + b.HasKey("Id") + .HasName("pk_seat"); + + b.HasIndex("FlightId") + .HasDatabaseName("ix_seat_flight_id"); + + b.ToTable("seat", (string)null); + }); + + modelBuilder.Entity("Flight.Aircrafts.Models.Aircraft", b => + { + b.OwnsOne("Flight.Aircrafts.ValueObjects.ManufacturingYear", "ManufacturingYear", b1 => + { + b1.Property("AircraftId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .HasMaxLength(5) + .HasColumnType("integer") + .HasColumnName("manufacturing_year"); + + b1.HasKey("AircraftId") + .HasName("pk_aircraft"); + + b1.ToTable("aircraft"); + + b1.WithOwner() + .HasForeignKey("AircraftId") + .HasConstraintName("fk_aircraft_aircraft_id"); + }); + + b.OwnsOne("Flight.Aircrafts.ValueObjects.Model", "Model", b1 => + { + b1.Property("AircraftId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("model"); + + b1.HasKey("AircraftId") + .HasName("pk_aircraft"); + + b1.ToTable("aircraft"); + + b1.WithOwner() + .HasForeignKey("AircraftId") + .HasConstraintName("fk_aircraft_aircraft_id"); + }); + + b.OwnsOne("Flight.Aircrafts.ValueObjects.Name", "Name", b1 => + { + b1.Property("AircraftId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("name"); + + b1.HasKey("AircraftId") + .HasName("pk_aircraft"); + + b1.ToTable("aircraft"); + + b1.WithOwner() + .HasForeignKey("AircraftId") + .HasConstraintName("fk_aircraft_aircraft_id"); + }); + + b.Navigation("ManufacturingYear") + .IsRequired(); + + b.Navigation("Model") + .IsRequired(); + + b.Navigation("Name") + .IsRequired(); + }); + + modelBuilder.Entity("Flight.Airports.Models.Airport", b => + { + b.OwnsOne("Flight.Airports.ValueObjects.Address", "Address", b1 => + { + b1.Property("AirportId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("address"); + + b1.HasKey("AirportId") + .HasName("pk_airport"); + + b1.ToTable("airport"); + + b1.WithOwner() + .HasForeignKey("AirportId") + .HasConstraintName("fk_airport_airport_id"); + }); + + b.OwnsOne("Flight.Airports.ValueObjects.Code", "Code", b1 => + { + b1.Property("AirportId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("code"); + + b1.HasKey("AirportId") + .HasName("pk_airport"); + + b1.ToTable("airport"); + + b1.WithOwner() + .HasForeignKey("AirportId") + .HasConstraintName("fk_airport_airport_id"); + }); + + b.OwnsOne("Flight.Airports.ValueObjects.Name", "Name", b1 => + { + b1.Property("AirportId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("name"); + + b1.HasKey("AirportId") + .HasName("pk_airport"); + + b1.ToTable("airport"); + + b1.WithOwner() + .HasForeignKey("AirportId") + .HasConstraintName("fk_airport_airport_id"); + }); + + b.Navigation("Address") + .IsRequired(); + + b.Navigation("Code") + .IsRequired(); + + b.Navigation("Name") + .IsRequired(); + }); + + modelBuilder.Entity("Flight.Flights.Models.Flight", b => + { + b.HasOne("Flight.Aircrafts.Models.Aircraft", null) + .WithMany() + .HasForeignKey("AircraftId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_flight_aircraft_aircraft_id"); + + b.HasOne("Flight.Airports.Models.Airport", null) + .WithMany() + .HasForeignKey("ArriveAirportId") + .HasConstraintName("fk_flight_airport_arrive_airport_id"); + + b.HasOne("Flight.Airports.Models.Airport", null) + .WithMany() + .HasForeignKey("DepartureAirportId") + .HasConstraintName("fk_flight_airport_departure_airport_id"); + + b.OwnsOne("Flight.Flights.ValueObjects.ArriveDate", "ArriveDate", b1 => + { + b1.Property("FlightId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .HasColumnType("timestamp with time zone") + .HasColumnName("arrive_date"); + + b1.HasKey("FlightId") + .HasName("pk_flight"); + + b1.ToTable("flight"); + + b1.WithOwner() + .HasForeignKey("FlightId") + .HasConstraintName("fk_flight_flight_id"); + }); + + b.OwnsOne("Flight.Flights.ValueObjects.DepartureDate", "DepartureDate", b1 => + { + b1.Property("FlightId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .HasColumnType("timestamp with time zone") + .HasColumnName("departure_date"); + + b1.HasKey("FlightId") + .HasName("pk_flight"); + + b1.ToTable("flight"); + + b1.WithOwner() + .HasForeignKey("FlightId") + .HasConstraintName("fk_flight_flight_id"); + }); + + b.OwnsOne("Flight.Flights.ValueObjects.DurationMinutes", "DurationMinutes", b1 => + { + b1.Property("FlightId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .HasMaxLength(50) + .HasColumnType("numeric") + .HasColumnName("duration_minutes"); + + b1.HasKey("FlightId") + .HasName("pk_flight"); + + b1.ToTable("flight"); + + b1.WithOwner() + .HasForeignKey("FlightId") + .HasConstraintName("fk_flight_flight_id"); + }); + + b.OwnsOne("Flight.Flights.ValueObjects.FlightDate", "FlightDate", b1 => + { + b1.Property("FlightId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .HasColumnType("timestamp with time zone") + .HasColumnName("flight_date"); + + b1.HasKey("FlightId") + .HasName("pk_flight"); + + b1.ToTable("flight"); + + b1.WithOwner() + .HasForeignKey("FlightId") + .HasConstraintName("fk_flight_flight_id"); + }); + + b.OwnsOne("Flight.Flights.ValueObjects.FlightNumber", "FlightNumber", b1 => + { + b1.Property("FlightId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("flight_number"); + + b1.HasKey("FlightId") + .HasName("pk_flight"); + + b1.ToTable("flight"); + + b1.WithOwner() + .HasForeignKey("FlightId") + .HasConstraintName("fk_flight_flight_id"); + }); + + b.OwnsOne("Flight.Flights.ValueObjects.Price", "Price", b1 => + { + b1.Property("FlightId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .HasMaxLength(10) + .HasColumnType("numeric") + .HasColumnName("price"); + + b1.HasKey("FlightId") + .HasName("pk_flight"); + + b1.ToTable("flight"); + + b1.WithOwner() + .HasForeignKey("FlightId") + .HasConstraintName("fk_flight_flight_id"); + }); + + b.Navigation("ArriveDate"); + + b.Navigation("DepartureDate"); + + b.Navigation("DurationMinutes"); + + b.Navigation("FlightDate"); + + b.Navigation("FlightNumber"); + + b.Navigation("Price"); + }); + + modelBuilder.Entity("Flight.Seats.Models.Seat", b => + { + b.HasOne("Flight.Flights.Models.Flight", null) + .WithMany() + .HasForeignKey("FlightId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_seat_flight_flight_id"); + + b.OwnsOne("Flight.Seats.ValueObjects.SeatNumber", "SeatNumber", b1 => + { + b1.Property("SeatId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("seat_number"); + + b1.HasKey("SeatId") + .HasName("pk_seat"); + + b1.ToTable("seat"); + + b1.WithOwner() + .HasForeignKey("SeatId") + .HasConstraintName("fk_seat_seat_id"); + }); + + b.Navigation("SeatNumber") + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Services/Flight/src/Flight/Data/Migrations/20230609154649_AddValueObjectForSeat-Airport-Flight.cs b/src/Services/Flight/src/Flight/Data/Migrations/20230609154649_AddValueObjectForSeat-Airport-Flight.cs new file mode 100644 index 00000000..ea258845 --- /dev/null +++ b/src/Services/Flight/src/Flight/Data/Migrations/20230609154649_AddValueObjectForSeat-Airport-Flight.cs @@ -0,0 +1,391 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Flight.Data.Migrations +{ + /// + public partial class AddValueObjectForSeatAirportFlight : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "seat_number", + table: "seat", + type: "character varying(50)", + maxLength: 50, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "price", + table: "flight", + type: "numeric", + maxLength: 10, + nullable: true, + oldClrType: typeof(decimal), + oldType: "numeric"); + + migrationBuilder.AlterColumn( + name: "flight_number", + table: "flight", + type: "character varying(50)", + maxLength: 50, + nullable: true, + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "flight_date", + table: "flight", + type: "timestamp with time zone", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone"); + + migrationBuilder.AlterColumn( + name: "duration_minutes", + table: "flight", + type: "numeric", + maxLength: 50, + nullable: true, + oldClrType: typeof(decimal), + oldType: "numeric"); + + migrationBuilder.AlterColumn( + name: "departure_date", + table: "flight", + type: "timestamp with time zone", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone"); + + migrationBuilder.AlterColumn( + name: "departure_airport_id", + table: "flight", + type: "uuid", + nullable: true, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AlterColumn( + name: "arrive_date", + table: "flight", + type: "timestamp with time zone", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone"); + + migrationBuilder.AlterColumn( + name: "arrive_airport_id", + table: "flight", + type: "uuid", + nullable: true, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AlterColumn( + name: "aircraft_id", + table: "flight", + type: "uuid", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + oldClrType: typeof(Guid), + oldType: "uuid", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "name", + table: "airport", + type: "character varying(50)", + maxLength: 50, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "code", + table: "airport", + type: "character varying(50)", + maxLength: 50, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "address", + table: "airport", + type: "character varying(50)", + maxLength: 50, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "name", + table: "aircraft", + type: "character varying(50)", + maxLength: 50, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "character varying(50)", + oldMaxLength: 50, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "model", + table: "aircraft", + type: "character varying(50)", + maxLength: 50, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "character varying(50)", + oldMaxLength: 50, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "manufacturing_year", + table: "aircraft", + type: "integer", + maxLength: 5, + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "integer", + oldMaxLength: 5, + oldNullable: true); + + migrationBuilder.CreateIndex( + name: "ix_flight_departure_airport_id", + table: "flight", + column: "departure_airport_id"); + + //migrationBuilder.AddForeignKey( + // name: "fk_flight_aircraft_aircraft_id", + // table: "flight", + // column: "aircraft_id", + // principalTable: "aircraft", + // principalColumn: "id", + // onDelete: ReferentialAction.Cascade); + + //migrationBuilder.AddForeignKey( + // name: "fk_flight_airport_arrive_airport_id", + // table: "flight", + // column: "arrive_airport_id", + // principalTable: "airport", + // principalColumn: "id"); + + //migrationBuilder.AddForeignKey( + // name: "fk_flight_airport_departure_airport_id", + // table: "flight", + // column: "departure_airport_id", + // principalTable: "airport", + // principalColumn: "id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_flight_aircraft_aircraft_id", + table: "flight"); + + migrationBuilder.DropForeignKey( + name: "fk_flight_airport_arrive_airport_id", + table: "flight"); + + migrationBuilder.DropForeignKey( + name: "fk_flight_airport_departure_airport_id", + table: "flight"); + + migrationBuilder.DropIndex( + name: "ix_flight_departure_airport_id", + table: "flight"); + + migrationBuilder.AlterColumn( + name: "seat_number", + table: "seat", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(50)", + oldMaxLength: 50); + + migrationBuilder.AlterColumn( + name: "price", + table: "flight", + type: "numeric", + nullable: false, + defaultValue: 0m, + oldClrType: typeof(decimal), + oldType: "numeric", + oldMaxLength: 10, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "flight_number", + table: "flight", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(50)", + oldMaxLength: 50, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "flight_date", + table: "flight", + type: "timestamp with time zone", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "duration_minutes", + table: "flight", + type: "numeric", + nullable: false, + defaultValue: 0m, + oldClrType: typeof(decimal), + oldType: "numeric", + oldMaxLength: 50, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "departure_date", + table: "flight", + type: "timestamp with time zone", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "departure_airport_id", + table: "flight", + type: "uuid", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + oldClrType: typeof(Guid), + oldType: "uuid", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "arrive_date", + table: "flight", + type: "timestamp with time zone", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "arrive_airport_id", + table: "flight", + type: "uuid", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + oldClrType: typeof(Guid), + oldType: "uuid", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "aircraft_id", + table: "flight", + type: "uuid", + nullable: true, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AlterColumn( + name: "name", + table: "airport", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(50)", + oldMaxLength: 50); + + migrationBuilder.AlterColumn( + name: "code", + table: "airport", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(50)", + oldMaxLength: 50); + + migrationBuilder.AlterColumn( + name: "address", + table: "airport", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(50)", + oldMaxLength: 50); + + migrationBuilder.AlterColumn( + name: "name", + table: "aircraft", + type: "character varying(50)", + maxLength: 50, + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(50)", + oldMaxLength: 50); + + migrationBuilder.AlterColumn( + name: "model", + table: "aircraft", + type: "character varying(50)", + maxLength: 50, + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(50)", + oldMaxLength: 50); + + migrationBuilder.AlterColumn( + name: "manufacturing_year", + table: "aircraft", + type: "integer", + maxLength: 5, + nullable: true, + oldClrType: typeof(int), + oldType: "integer", + oldMaxLength: 5); + + migrationBuilder.AddForeignKey( + name: "fk_flight_aircraft_aircraft_id", + table: "flight", + column: "aircraft_id", + principalTable: "aircraft", + principalColumn: "id"); + + migrationBuilder.AddForeignKey( + name: "fk_flight_airport_arrive_airport_id", + table: "flight", + column: "arrive_airport_id", + principalTable: "airport", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/src/Services/Flight/src/Flight/Data/Migrations/FlightDbContextModelSnapshot.cs b/src/Services/Flight/src/Flight/Data/Migrations/FlightDbContextModelSnapshot.cs index 1ea716d0..11fb2cde 100644 --- a/src/Services/Flight/src/Flight/Data/Migrations/FlightDbContextModelSnapshot.cs +++ b/src/Services/Flight/src/Flight/Data/Migrations/FlightDbContextModelSnapshot.cs @@ -65,14 +65,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("uuid") .HasColumnName("id"); - b.Property("Address") - .HasColumnType("text") - .HasColumnName("address"); - - b.Property("Code") - .HasColumnType("text") - .HasColumnName("code"); - b.Property("CreatedAt") .HasColumnType("timestamp with time zone") .HasColumnName("created_at"); @@ -93,10 +85,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("bigint") .HasColumnName("last_modified_by"); - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - b.Property("Version") .IsConcurrencyToken() .HasColumnType("bigint") @@ -114,18 +102,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("uuid") .HasColumnName("id"); - b.Property("AircraftId") + b.Property("AircraftId") .HasColumnType("uuid") .HasColumnName("aircraft_id"); - b.Property("ArriveAirportId") + b.Property("ArriveAirportId") .HasColumnType("uuid") .HasColumnName("arrive_airport_id"); - b.Property("ArriveDate") - .HasColumnType("timestamp with time zone") - .HasColumnName("arrive_date"); - b.Property("CreatedAt") .HasColumnType("timestamp with time zone") .HasColumnName("created_at"); @@ -134,26 +118,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("bigint") .HasColumnName("created_by"); - b.Property("DepartureAirportId") + b.Property("DepartureAirportId") .HasColumnType("uuid") .HasColumnName("departure_airport_id"); - b.Property("DepartureDate") - .HasColumnType("timestamp with time zone") - .HasColumnName("departure_date"); - - b.Property("DurationMinutes") - .HasColumnType("numeric") - .HasColumnName("duration_minutes"); - - b.Property("FlightDate") - .HasColumnType("timestamp with time zone") - .HasColumnName("flight_date"); - - b.Property("FlightNumber") - .HasColumnType("text") - .HasColumnName("flight_number"); - b.Property("IsDeleted") .HasColumnType("boolean") .HasColumnName("is_deleted"); @@ -166,10 +134,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("bigint") .HasColumnName("last_modified_by"); - b.Property("Price") - .HasColumnType("numeric") - .HasColumnName("price"); - b.Property("Status") .IsRequired() .ValueGeneratedOnAdd() @@ -191,6 +155,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("ArriveAirportId") .HasDatabaseName("ix_flight_arrive_airport_id"); + b.HasIndex("DepartureAirportId") + .HasDatabaseName("ix_flight_departure_airport_id"); + b.ToTable("flight", (string)null); }); @@ -231,10 +198,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("bigint") .HasColumnName("last_modified_by"); - b.Property("SeatNumber") - .HasColumnType("text") - .HasColumnName("seat_number"); - b.Property("Type") .IsRequired() .ValueGeneratedOnAdd() @@ -258,7 +221,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Flight.Aircrafts.Models.Aircraft", b => { - b.OwnsOne("Flight.Aircrafts.Models.ValueObjects.ManufacturingYearValue", "ManufacturingYear", b1 => + b.OwnsOne("Flight.Aircrafts.ValueObjects.ManufacturingYear", "ManufacturingYear", b1 => { b1.Property("AircraftId") .HasColumnType("uuid") @@ -279,7 +242,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasConstraintName("fk_aircraft_aircraft_id"); }); - b.OwnsOne("Flight.Aircrafts.Models.ValueObjects.ModelValue", "Model", b1 => + b.OwnsOne("Flight.Aircrafts.ValueObjects.Model", "Model", b1 => { b1.Property("AircraftId") .HasColumnType("uuid") @@ -301,7 +264,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasConstraintName("fk_aircraft_aircraft_id"); }); - b.OwnsOne("Flight.Aircrafts.Models.ValueObjects.NameValue", "Name", b1 => + b.OwnsOne("Flight.Aircrafts.ValueObjects.Name", "Name", b1 => { b1.Property("AircraftId") .HasColumnType("uuid") @@ -323,11 +286,92 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasConstraintName("fk_aircraft_aircraft_id"); }); - b.Navigation("ManufacturingYear"); + b.Navigation("ManufacturingYear") + .IsRequired(); - b.Navigation("Model"); + b.Navigation("Model") + .IsRequired(); - b.Navigation("Name"); + b.Navigation("Name") + .IsRequired(); + }); + + modelBuilder.Entity("Flight.Airports.Models.Airport", b => + { + b.OwnsOne("Flight.Airports.ValueObjects.Address", "Address", b1 => + { + b1.Property("AirportId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("address"); + + b1.HasKey("AirportId") + .HasName("pk_airport"); + + b1.ToTable("airport"); + + b1.WithOwner() + .HasForeignKey("AirportId") + .HasConstraintName("fk_airport_airport_id"); + }); + + b.OwnsOne("Flight.Airports.ValueObjects.Code", "Code", b1 => + { + b1.Property("AirportId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("code"); + + b1.HasKey("AirportId") + .HasName("pk_airport"); + + b1.ToTable("airport"); + + b1.WithOwner() + .HasForeignKey("AirportId") + .HasConstraintName("fk_airport_airport_id"); + }); + + b.OwnsOne("Flight.Airports.ValueObjects.Name", "Name", b1 => + { + b1.Property("AirportId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("name"); + + b1.HasKey("AirportId") + .HasName("pk_airport"); + + b1.ToTable("airport"); + + b1.WithOwner() + .HasForeignKey("AirportId") + .HasConstraintName("fk_airport_airport_id"); + }); + + b.Navigation("Address") + .IsRequired(); + + b.Navigation("Code") + .IsRequired(); + + b.Navigation("Name") + .IsRequired(); }); modelBuilder.Entity("Flight.Flights.Models.Flight", b => @@ -335,14 +379,155 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasOne("Flight.Aircrafts.Models.Aircraft", null) .WithMany() .HasForeignKey("AircraftId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() .HasConstraintName("fk_flight_aircraft_aircraft_id"); b.HasOne("Flight.Airports.Models.Airport", null) .WithMany() .HasForeignKey("ArriveAirportId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() .HasConstraintName("fk_flight_airport_arrive_airport_id"); + + b.HasOne("Flight.Airports.Models.Airport", null) + .WithMany() + .HasForeignKey("DepartureAirportId") + .HasConstraintName("fk_flight_airport_departure_airport_id"); + + b.OwnsOne("Flight.Flights.ValueObjects.ArriveDate", "ArriveDate", b1 => + { + b1.Property("FlightId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .HasColumnType("timestamp with time zone") + .HasColumnName("arrive_date"); + + b1.HasKey("FlightId") + .HasName("pk_flight"); + + b1.ToTable("flight"); + + b1.WithOwner() + .HasForeignKey("FlightId") + .HasConstraintName("fk_flight_flight_id"); + }); + + b.OwnsOne("Flight.Flights.ValueObjects.DepartureDate", "DepartureDate", b1 => + { + b1.Property("FlightId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .HasColumnType("timestamp with time zone") + .HasColumnName("departure_date"); + + b1.HasKey("FlightId") + .HasName("pk_flight"); + + b1.ToTable("flight"); + + b1.WithOwner() + .HasForeignKey("FlightId") + .HasConstraintName("fk_flight_flight_id"); + }); + + b.OwnsOne("Flight.Flights.ValueObjects.DurationMinutes", "DurationMinutes", b1 => + { + b1.Property("FlightId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .HasMaxLength(50) + .HasColumnType("numeric") + .HasColumnName("duration_minutes"); + + b1.HasKey("FlightId") + .HasName("pk_flight"); + + b1.ToTable("flight"); + + b1.WithOwner() + .HasForeignKey("FlightId") + .HasConstraintName("fk_flight_flight_id"); + }); + + b.OwnsOne("Flight.Flights.ValueObjects.FlightDate", "FlightDate", b1 => + { + b1.Property("FlightId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .HasColumnType("timestamp with time zone") + .HasColumnName("flight_date"); + + b1.HasKey("FlightId") + .HasName("pk_flight"); + + b1.ToTable("flight"); + + b1.WithOwner() + .HasForeignKey("FlightId") + .HasConstraintName("fk_flight_flight_id"); + }); + + b.OwnsOne("Flight.Flights.ValueObjects.FlightNumber", "FlightNumber", b1 => + { + b1.Property("FlightId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("flight_number"); + + b1.HasKey("FlightId") + .HasName("pk_flight"); + + b1.ToTable("flight"); + + b1.WithOwner() + .HasForeignKey("FlightId") + .HasConstraintName("fk_flight_flight_id"); + }); + + b.OwnsOne("Flight.Flights.ValueObjects.Price", "Price", b1 => + { + b1.Property("FlightId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .HasMaxLength(10) + .HasColumnType("numeric") + .HasColumnName("price"); + + b1.HasKey("FlightId") + .HasName("pk_flight"); + + b1.ToTable("flight"); + + b1.WithOwner() + .HasForeignKey("FlightId") + .HasConstraintName("fk_flight_flight_id"); + }); + + b.Navigation("ArriveDate"); + + b.Navigation("DepartureDate"); + + b.Navigation("DurationMinutes"); + + b.Navigation("FlightDate"); + + b.Navigation("FlightNumber"); + + b.Navigation("Price"); }); modelBuilder.Entity("Flight.Seats.Models.Seat", b => @@ -353,6 +538,31 @@ protected override void BuildModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired() .HasConstraintName("fk_seat_flight_flight_id"); + + b.OwnsOne("Flight.Seats.ValueObjects.SeatNumber", "SeatNumber", b1 => + { + b1.Property("SeatId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("seat_number"); + + b1.HasKey("SeatId") + .HasName("pk_seat"); + + b1.ToTable("seat"); + + b1.WithOwner() + .HasForeignKey("SeatId") + .HasConstraintName("fk_seat_seat_id"); + }); + + b.Navigation("SeatNumber") + .IsRequired(); }); #pragma warning restore 612, 618 } diff --git a/src/Services/Flight/src/Flight/Data/Seed/InitialData.cs b/src/Services/Flight/src/Flight/Data/Seed/InitialData.cs index a0004890..70b5494f 100644 --- a/src/Services/Flight/src/Flight/Data/Seed/InitialData.cs +++ b/src/Services/Flight/src/Flight/Data/Seed/InitialData.cs @@ -5,10 +5,15 @@ namespace Flight.Data.Seed; using System.Linq; using Aircrafts.Models; using Airports.Models; +using Airports.ValueObjects; using Flight.Aircrafts.ValueObjects; using Flights.Models; +using Flights.ValueObjects; using MassTransit; using Seats.Models; +using Seats.ValueObjects; +using AirportName = Airports.ValueObjects.Name; +using Name = Aircrafts.ValueObjects.Name; public static class InitialData { @@ -22,8 +27,8 @@ static InitialData() { Airports = new List { - Airport.Create(new Guid("3c5c0000-97c6-fc34-a0cb-08db322230c8"), "Lisbon International Airport", "LIS", "12988"), - Airport.Create(new Guid("3c5c0000-97c6-fc34-fc3c-08db322230c8"), "Sao Paulo International Airport", "BRZ", "11200") + Airport.Create(AirportId.Of(new Guid("3c5c0000-97c6-fc34-a0cb-08db322230c8")), AirportName.Of("Lisbon International Airport"), Address.Of("LIS"), Code.Of("12988")), + Airport.Create(AirportId.Of(new Guid("3c5c0000-97c6-fc34-fc3c-08db322230c8")), AirportName.Of("Sao Paulo International Airport"), Address.Of("BRZ"), Code.Of("11200")) }; Aircrafts = new List @@ -36,21 +41,21 @@ static InitialData() Flights = new List { - Flight.Create(new Guid("3c5c0000-97c6-fc34-2eb9-08db322230c9"), "BD467", Aircrafts.First().Id, Airports.First().Id, new DateTime(2022, 1, 31, 12, 0, 0), - new DateTime(2022, 1, 31, 14, 0, 0), - Airports.Last().Id, 120m, - new DateTime(2022, 1, 31), global::Flight.Flights.Enums.FlightStatus.Completed, - 8000) + Flight.Create(FlightId.Of(new Guid("3c5c0000-97c6-fc34-2eb9-08db322230c9")), FlightNumber.Of("BD467"), AircraftId.Of(Aircrafts.First().Id.Value), AirportId.Of( Airports.First().Id), DepartureDate.Of(new DateTime(2022, 1, 31, 12, 0, 0)), + ArriveDate.Of(new DateTime(2022, 1, 31, 14, 0, 0)), + AirportId.Of(Airports.Last().Id), DurationMinutes.Of(120m), + FlightDate.Of(new DateTime(2022, 1, 31, 13, 0, 0)), global::Flight.Flights.Enums.FlightStatus.Completed, + Price.Of((decimal)8000)) }; Seats = new List { - Seat.Create(NewId.NextGuid(), "12A", global::Flight.Seats.Enums.SeatType.Window, global::Flight.Seats.Enums.SeatClass.Economy, Flights.First().Id), - Seat.Create(NewId.NextGuid(), "12B", global::Flight.Seats.Enums.SeatType.Window, global::Flight.Seats.Enums.SeatClass.Economy, Flights.First().Id), - Seat.Create(NewId.NextGuid(), "12C", global::Flight.Seats.Enums.SeatType.Middle, global::Flight.Seats.Enums.SeatClass.Economy, Flights.First().Id), - Seat.Create(NewId.NextGuid(), "12D", global::Flight.Seats.Enums.SeatType.Middle, global::Flight.Seats.Enums.SeatClass.Economy, Flights.First().Id), - Seat.Create(NewId.NextGuid(), "12E", global::Flight.Seats.Enums.SeatType.Aisle, global::Flight.Seats.Enums.SeatClass.Economy, Flights.First().Id), - Seat.Create(NewId.NextGuid(), "12F", global::Flight.Seats.Enums.SeatType.Aisle, global::Flight.Seats.Enums.SeatClass.Economy, Flights.First().Id) + Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of( "12A"), global::Flight.Seats.Enums.SeatType.Window, global::Flight.Seats.Enums.SeatClass.Economy, FlightId.Of((Guid)Flights.First().Id)), + Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12B"), global::Flight.Seats.Enums.SeatType.Window, global::Flight.Seats.Enums.SeatClass.Economy, FlightId.Of((Guid)Flights.First().Id)), + Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12C"), global::Flight.Seats.Enums.SeatType.Middle, global::Flight.Seats.Enums.SeatClass.Economy, FlightId.Of((Guid) Flights.First().Id)), + Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12D"), global::Flight.Seats.Enums.SeatType.Middle, global::Flight.Seats.Enums.SeatClass.Economy, FlightId.Of((Guid) Flights.First().Id)), + Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12E"), global::Flight.Seats.Enums.SeatType.Aisle, global::Flight.Seats.Enums.SeatClass.Economy, FlightId.Of((Guid) Flights.First().Id)), + Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12F"), global::Flight.Seats.Enums.SeatType.Aisle, global::Flight.Seats.Enums.SeatClass.Economy, FlightId.Of((Guid) Flights.First().Id)) }; } } diff --git a/src/Services/Flight/src/Flight/Flights/Exceptions/FlightExceptions.cs b/src/Services/Flight/src/Flight/Flights/Exceptions/FlightExceptions.cs new file mode 100644 index 00000000..0e425c41 --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/Exceptions/FlightExceptions.cs @@ -0,0 +1,14 @@ +namespace Flight.Flights.Exceptions; +using System; +using BuildingBlocks.Exception; + +public class FlightExceptions : BadRequestException +{ + public FlightExceptions(DateTime departureDate, DateTime arriveDate) : + base($"Departure date: '{departureDate}' must be before arrive date: '{arriveDate}'.") + { } + + public FlightExceptions(DateTime flightDate) : + base($"Flight date: '{flightDate}' must be between departure and arrive dates.") + { } +} diff --git a/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidArriveDateExceptions.cs b/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidArriveDateExceptions.cs new file mode 100644 index 00000000..a379df76 --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidArriveDateExceptions.cs @@ -0,0 +1,11 @@ +namespace Flight.Flights.Exceptions; +using System; +using BuildingBlocks.Exception; + +public class InvalidArriveDateExceptions : BadRequestException +{ + public InvalidArriveDateExceptions(DateTime arriveDate) + : base($"Arrive Date: '{arriveDate}' is invalid.") + { + } +} diff --git a/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidDepartureDateExceptions.cs b/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidDepartureDateExceptions.cs new file mode 100644 index 00000000..b173a4e0 --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidDepartureDateExceptions.cs @@ -0,0 +1,11 @@ +namespace Flight.Flights.Exceptions; +using System; +using BuildingBlocks.Exception; + +public class InvalidDepartureDateExceptions : BadRequestException +{ + public InvalidDepartureDateExceptions(DateTime departureDate) + : base($"Departure Date: '{departureDate}' is invalid.") + { + } +} diff --git a/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidDurationException.cs b/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidDurationException.cs new file mode 100644 index 00000000..7e135bdd --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidDurationException.cs @@ -0,0 +1,10 @@ +namespace Flight.Flights.Exceptions; +using BuildingBlocks.Exception; + +public class InvalidDurationException : BadRequestException +{ + public InvalidDurationException() + : base("Duration cannot be negative.") + { + } +} diff --git a/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidFlightDateExceptions.cs b/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidFlightDateExceptions.cs new file mode 100644 index 00000000..8e0d878d --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidFlightDateExceptions.cs @@ -0,0 +1,11 @@ +namespace Flight.Flights.Exceptions; +using System; +using BuildingBlocks.Exception; + +public class InvalidFlightDateExceptions : BadRequestException +{ + public InvalidFlightDateExceptions(DateTime flightDate) + : base($"Flight Date: '{flightDate}' is invalid.") + { + } +} diff --git a/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidFlightIdExceptions.cs b/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidFlightIdExceptions.cs new file mode 100644 index 00000000..115bf604 --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidFlightIdExceptions.cs @@ -0,0 +1,11 @@ +namespace Flight.Flights.Exceptions; +using System; +using BuildingBlocks.Exception; + +public class InvalidFlightIdExceptions : BadRequestException +{ + public InvalidFlightIdExceptions(Guid flightId) + : base($"flightId: '{flightId}' is invalid.") + { + } +} diff --git a/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidFlightNumberException.cs b/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidFlightNumberException.cs new file mode 100644 index 00000000..a77b8f18 --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidFlightNumberException.cs @@ -0,0 +1,10 @@ +namespace Flight.Flights.Exceptions; +using BuildingBlocks.Exception; + +public class InvalidFlightNumberException : BadRequestException +{ + public InvalidFlightNumberException(string flightNumber) + : base($"Flight Number: '{flightNumber}' is invalid.") + { + } +} diff --git a/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidPriceException.cs b/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidPriceException.cs new file mode 100644 index 00000000..ed37c319 --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/Exceptions/InvalidPriceException.cs @@ -0,0 +1,11 @@ +namespace Flight.Flights.Exceptions; +using BuildingBlocks.Exception; + + +public class InvalidPriceException : BadRequestException +{ + public InvalidPriceException() + : base($"Price Cannot be negative.") + { + } +} diff --git a/src/Services/Flight/src/Flight/Flights/Features/CreatingFlight/V1/CreateFlight.cs b/src/Services/Flight/src/Flight/Flights/Features/CreatingFlight/V1/CreateFlight.cs index 83c424ca..4424fe17 100644 --- a/src/Services/Flight/src/Flight/Flights/Features/CreatingFlight/V1/CreateFlight.cs +++ b/src/Services/Flight/src/Flight/Flights/Features/CreatingFlight/V1/CreateFlight.cs @@ -11,6 +11,7 @@ namespace Flight.Flights.Features.CreatingFlight.V1; using Data; using Duende.IdentityServer.EntityFramework.Entities; using Exceptions; +using Flight.Airports.ValueObjects; using FluentValidation; using MapsterMapper; using MassTransit; @@ -19,6 +20,7 @@ namespace Flight.Flights.Features.CreatingFlight.V1; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.EntityFrameworkCore; +using ValueObjects; public record CreateFlight(string FlightNumber, Guid AircraftId, Guid DepartureAirportId, DateTime DepartureDate, DateTime ArriveDate, Guid ArriveAirportId, @@ -112,13 +114,13 @@ public async Task Handle(CreateFlight request, CancellationT throw new FlightAlreadyExistException(); } - var flightEntity = Models.Flight.Create(request.Id, request.FlightNumber, AircraftId.Of(request.AircraftId), - request.DepartureAirportId, request.DepartureDate, - request.ArriveDate, request.ArriveAirportId, request.DurationMinutes, request.FlightDate, request.Status, - request.Price); + var flightEntity = Models.Flight.Create(FlightId.Of(request.Id), FlightNumber.Of(request.FlightNumber), AircraftId.Of(request.AircraftId), + AirportId.Of(request.DepartureAirportId), DepartureDate.Of(request.DepartureDate), + ArriveDate.Of(request.ArriveDate), AirportId.Of(request.ArriveAirportId), DurationMinutes.Of(request.DurationMinutes), FlightDate.Of(request.FlightDate), request.Status, + Price.Of(request.Price)); var newFlight = (await _flightDbContext.Flights.AddAsync(flightEntity, cancellationToken))?.Entity; - return new CreateFlightResult(newFlight.Id); + return new CreateFlightResult(newFlight.Id.Value); } } diff --git a/src/Services/Flight/src/Flight/Flights/Features/DeletingFlight/V1/DeleteFlight.cs b/src/Services/Flight/src/Flight/Flights/Features/DeletingFlight/V1/DeleteFlight.cs index 575a27fc..f927e59f 100644 --- a/src/Services/Flight/src/Flight/Flights/Features/DeletingFlight/V1/DeleteFlight.cs +++ b/src/Services/Flight/src/Flight/Flights/Features/DeletingFlight/V1/DeleteFlight.cs @@ -1,6 +1,7 @@ -namespace Flight.Flights.Features.DeletingFlight.V1; +namespace Flight.Flights.Features.DeletingFlight.V1; using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Ardalis.GuardClauses; @@ -16,6 +17,8 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.EntityFrameworkCore; +using MongoDB.Driver.Linq; +using ValueObjects; public record DeleteFlight(Guid Id) : ICommand, IInternalCommand; @@ -71,8 +74,7 @@ public async Task Handle(DeleteFlight request, CancellationT { Guard.Against.Null(request, nameof(request)); - var flight = await _flightDbContext.Flights.SingleOrDefaultAsync(x => x.Id == request.Id, cancellationToken); - + var flight = await _flightDbContext.Flights.SingleOrDefaultAsync(x => x.Id == FlightId.Of(request.Id), cancellationToken); if (flight is null) { throw new FlightNotFountException(); @@ -82,8 +84,8 @@ public async Task Handle(DeleteFlight request, CancellationT flight.DepartureDate, flight.ArriveDate, flight.ArriveAirportId, flight.DurationMinutes, flight.FlightDate, flight.Status, flight.Price); - var deleteFlight = (_flightDbContext.Flights.Remove(flight))?.Entity; + var deleteFlight = _flightDbContext.Flights.Remove(flight)?.Entity; - return new DeleteFlightResult(deleteFlight.Id); + return new DeleteFlightResult(deleteFlight.Id.Value); } } diff --git a/src/Services/Flight/src/Flight/Flights/Features/UpdatingFlight/V1/UpdateFlight.cs b/src/Services/Flight/src/Flight/Flights/Features/UpdatingFlight/V1/UpdateFlight.cs index c34db93b..4844bcd8 100644 --- a/src/Services/Flight/src/Flight/Flights/Features/UpdatingFlight/V1/UpdateFlight.cs +++ b/src/Services/Flight/src/Flight/Flights/Features/UpdatingFlight/V1/UpdateFlight.cs @@ -12,6 +12,7 @@ namespace Flight.Flights.Features.UpdatingFlight.V1; using Data; using Duende.IdentityServer.EntityFramework.Entities; using Exceptions; +using Flight.Airports.ValueObjects; using Flight.Flights.Features.CreatingFlight.V1; using FluentValidation; using MapsterMapper; @@ -20,6 +21,7 @@ namespace Flight.Flights.Features.UpdatingFlight.V1; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.EntityFrameworkCore; +using ValueObjects; public record UpdateFlight(Guid Id, string FlightNumber, Guid AircraftId, Guid DepartureAirportId, DateTime DepartureDate, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate, @@ -102,7 +104,7 @@ public async Task Handle(UpdateFlight request, CancellationT { Guard.Against.Null(request, nameof(request)); - var flight = await _flightDbContext.Flights.SingleOrDefaultAsync(x => x.Id == request.Id, + var flight = await _flightDbContext.Flights.SingleOrDefaultAsync(x => x.Id == FlightId.Of(request.Id), cancellationToken); if (flight is null) @@ -111,13 +113,13 @@ public async Task Handle(UpdateFlight request, CancellationT } - flight.Update(request.Id, request.FlightNumber, AircraftId.Of(request.AircraftId), request.DepartureAirportId, - request.DepartureDate, - request.ArriveDate, request.ArriveAirportId, request.DurationMinutes, request.FlightDate, request.Status, - request.Price, request.IsDeleted); + flight.Update(FlightId.Of(request.Id), FlightNumber.Of(request.FlightNumber), AircraftId.Of(request.AircraftId), AirportId.Of(request.DepartureAirportId), + DepartureDate.Of(request.DepartureDate), + ArriveDate.Of(request.ArriveDate), AirportId.Of(request.ArriveAirportId), DurationMinutes.Of(request.DurationMinutes), FlightDate.Of(request.FlightDate), request.Status, + Price.Of(request.Price), request.IsDeleted); var updateFlight = (_flightDbContext.Flights.Update(flight))?.Entity; - return new UpdateFlightResult(updateFlight.Id); + return new UpdateFlightResult(updateFlight.Id.Value); } } diff --git a/src/Services/Flight/src/Flight/Flights/Models/Flight.cs b/src/Services/Flight/src/Flight/Flights/Models/Flight.cs index 7487431c..fc788157 100644 --- a/src/Services/Flight/src/Flight/Flights/Models/Flight.cs +++ b/src/Services/Flight/src/Flight/Flights/Models/Flight.cs @@ -1,30 +1,31 @@ -using System; using BuildingBlocks.Core.Model; namespace Flight.Flights.Models; using Aircrafts.ValueObjects; +using Airports.ValueObjects; using Features.CreatingFlight.V1; using Features.DeletingFlight.V1; using Features.UpdatingFlight.V1; +using global::Flight.Flights.ValueObjects; -public record Flight : Aggregate +public record Flight : Aggregate { - public string FlightNumber { get; private set; } + public FlightNumber? FlightNumber { get; private set; } = default!; public AircraftId AircraftId { get; private set; } - public DateTime DepartureDate { get; private set; } - public Guid DepartureAirportId { get; private set; } - public DateTime ArriveDate { get; private set; } - public Guid ArriveAirportId { get; private set; } - public decimal DurationMinutes { get; private set; } - public DateTime FlightDate { get; private set; } + public AirportId? DepartureAirportId { get; private set; } + public AirportId? ArriveAirportId { get; private set; } + public DurationMinutes? DurationMinutes { get; private set; } public Enums.FlightStatus Status { get; private set; } - public decimal Price { get; private set; } + public Price? Price { get; private set; } + public ArriveDate? ArriveDate { get; private set; } + public DepartureDate? DepartureDate { get; private set; } + public FlightDate? FlightDate { get; private set; } - public static Flight Create(Guid id, string flightNumber, AircraftId aircraftId, - Guid departureAirportId, DateTime departureDate, DateTime arriveDate, - Guid arriveAirportId, decimal durationMinutes, DateTime flightDate, Enums.FlightStatus status, - decimal price, bool isDeleted = false) + public static Flight Create(FlightId id, FlightNumber flightNumber, AircraftId aircraftId, + AirportId departureAirportId, DepartureDate departureDate, ArriveDate arriveDate, + AirportId arriveAirportId, DurationMinutes durationMinutes, FlightDate flightDate, Enums.FlightStatus status, + Price price, bool isDeleted = false) { var flight = new Flight { @@ -42,10 +43,10 @@ public static Flight Create(Guid id, string flightNumber, AircraftId aircraftId, IsDeleted = isDeleted, }; - var @event = new FlightCreatedDomainEvent(flight.Id, flight.FlightNumber, flight.AircraftId, - flight.DepartureDate, flight.DepartureAirportId, - flight.ArriveDate, flight.ArriveAirportId, flight.DurationMinutes, flight.FlightDate, flight.Status, - flight.Price, flight.IsDeleted); + var @event = new FlightCreatedDomainEvent(flight.Id.Value, flight.FlightNumber.Value, flight.AircraftId.Value, + flight.DepartureDate.Value, flight.DepartureAirportId.Value, + flight.ArriveDate.Value, flight.ArriveAirportId.Value, flight.DurationMinutes.Value, flight.FlightDate.Value, flight.Status, + flight.Price.Value, flight.IsDeleted); flight.AddDomainEvent(@event); @@ -53,16 +54,16 @@ public static Flight Create(Guid id, string flightNumber, AircraftId aircraftId, } - public void Update(Guid id, string flightNumber, AircraftId aircraftId, - Guid departureAirportId, DateTime departureDate, DateTime arriveDate, - Guid arriveAirportId, decimal durationMinutes, DateTime flightDate, Enums.FlightStatus status, - decimal price, bool isDeleted = false) + public void Update(FlightId id, FlightNumber flightNumber, AircraftId aircraftId, + AirportId departureAirportId, DepartureDate departureDate, ArriveDate arriveDate, + AirportId arriveAirportId, DurationMinutes durationMinutes, FlightDate flightDate, Enums.FlightStatus status, + Price price, bool isDeleted = false) { FlightNumber = flightNumber; AircraftId = aircraftId; DepartureAirportId = departureAirportId; DepartureDate = departureDate; - arriveDate = ArriveDate; + ArriveDate = arriveDate; ArriveAirportId = arriveAirportId; DurationMinutes = durationMinutes; FlightDate = flightDate; @@ -70,22 +71,22 @@ public void Update(Guid id, string flightNumber, AircraftId aircraftId, Price = price; IsDeleted = isDeleted; - var @event = new FlightUpdatedDomainEvent(id, flightNumber, aircraftId, departureDate, departureAirportId, - arriveDate, arriveAirportId, durationMinutes, flightDate, status, price, isDeleted); + var @event = new FlightUpdatedDomainEvent(id.Value, flightNumber.Value, aircraftId.Value, departureDate.Value, departureAirportId.Value, + arriveDate.Value, arriveAirportId.Value, durationMinutes.Value, flightDate.Value, status, price.Value, isDeleted); AddDomainEvent(@event); } - public void Delete(Guid id, string flightNumber, AircraftId aircraftId, - Guid departureAirportId, DateTime departureDate, DateTime arriveDate, - Guid arriveAirportId, decimal durationMinutes, DateTime flightDate, Enums.FlightStatus status, - decimal price, bool isDeleted = true) + public void Delete(FlightId id, FlightNumber flightNumber, AircraftId aircraftId, + AirportId departureAirportId, DepartureDate departureDate, ArriveDate arriveDate, + AirportId arriveAirportId, DurationMinutes durationMinutes, FlightDate flightDate, Enums.FlightStatus status, + Price price, bool isDeleted = true) { FlightNumber = flightNumber; AircraftId = aircraftId; DepartureAirportId = departureAirportId; DepartureDate = departureDate; - arriveDate = ArriveDate; + ArriveDate = arriveDate; ArriveAirportId = arriveAirportId; DurationMinutes = durationMinutes; FlightDate = flightDate; @@ -93,8 +94,8 @@ public void Delete(Guid id, string flightNumber, AircraftId aircraftId, Price = price; IsDeleted = isDeleted; - var @event = new FlightDeletedDomainEvent(id, flightNumber, aircraftId, departureDate, departureAirportId, - arriveDate, arriveAirportId, durationMinutes, flightDate, status, price, isDeleted); + var @event = new FlightDeletedDomainEvent(id.Value, flightNumber.Value, aircraftId.Value, departureDate.Value, departureAirportId.Value, + arriveDate.Value, arriveAirportId.Value, durationMinutes.Value, flightDate.Value, status, price.Value, isDeleted); AddDomainEvent(@event); } diff --git a/src/Services/Flight/src/Flight/Flights/ValueObjects/ArriveDate.cs b/src/Services/Flight/src/Flight/Flights/ValueObjects/ArriveDate.cs new file mode 100644 index 00000000..72fc181f --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/ValueObjects/ArriveDate.cs @@ -0,0 +1,27 @@ +namespace Flight.Flights.ValueObjects; +using System; +using Flight.Flights.Exceptions; + +public record ArriveDate +{ + public DateTime Value { get; } + + private ArriveDate(DateTime value) + { + if (value == null) + { + throw new InvalidArriveDateExceptions(value); + } + Value = value; + } + + public static ArriveDate Of(DateTime value) + { + return new ArriveDate(value); + } + + public static implicit operator DateTime(ArriveDate arriveDate) + { + return arriveDate.Value; + } +} diff --git a/src/Services/Flight/src/Flight/Flights/ValueObjects/DepartureDate.cs b/src/Services/Flight/src/Flight/Flights/ValueObjects/DepartureDate.cs new file mode 100644 index 00000000..a8af4a59 --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/ValueObjects/DepartureDate.cs @@ -0,0 +1,28 @@ +namespace Flight.Flights.ValueObjects; +using System; +using Flight.Flights.Exceptions; + + +public record DepartureDate +{ + public DateTime Value { get; } + + private DepartureDate(DateTime value) + { + if (value == null) + { + throw new InvalidDepartureDateExceptions(value); + } + Value = value; + } + + public static DepartureDate Of(DateTime value) + { + return new DepartureDate(value); + } + + public static implicit operator DateTime(DepartureDate departureDate) + { + return departureDate.Value; + } +} diff --git a/src/Services/Flight/src/Flight/Flights/ValueObjects/DurationMinutes.cs b/src/Services/Flight/src/Flight/Flights/ValueObjects/DurationMinutes.cs new file mode 100644 index 00000000..ed66f0af --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/ValueObjects/DurationMinutes.cs @@ -0,0 +1,31 @@ +namespace Flight.Flights.ValueObjects; +using Exceptions; + +public class DurationMinutes +{ + public decimal Value { get; } + + public DurationMinutes(decimal value) + { + if (value < 0) + { + throw new InvalidDurationException(); + } + Value = value; + } + + public static DurationMinutes Of(decimal value) + { + return new DurationMinutes(value); + } + + public static implicit operator decimal(DurationMinutes duration) + { + return duration.Value; + } + + public static explicit operator DurationMinutes(decimal value) + { + return new DurationMinutes(value); + } +} diff --git a/src/Services/Flight/src/Flight/Flights/ValueObjects/FlightDate.cs b/src/Services/Flight/src/Flight/Flights/ValueObjects/FlightDate.cs new file mode 100644 index 00000000..6c426ed5 --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/ValueObjects/FlightDate.cs @@ -0,0 +1,27 @@ +namespace Flight.Flights.ValueObjects; +using System; +using Flight.Flights.Exceptions; + +public record FlightDate +{ + public DateTime Value { get; } + + private FlightDate(DateTime value) + { + if (value == null) + { + throw new InvalidFlightDateExceptions(value); + } + Value = value; + } + + public static FlightDate Of(DateTime value) + { + return new FlightDate(value); + } + + public static implicit operator DateTime(FlightDate flightDate) + { + return flightDate.Value; + } +} diff --git a/src/Services/Flight/src/Flight/Flights/ValueObjects/FlightId.cs b/src/Services/Flight/src/Flight/Flights/ValueObjects/FlightId.cs new file mode 100644 index 00000000..e05855e5 --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/ValueObjects/FlightId.cs @@ -0,0 +1,28 @@ +namespace Flight.Flights.ValueObjects; +using System; +using Exceptions; + +public record FlightId +{ + public Guid Value { get; } + + private FlightId(Guid value) + { + if (value == Guid.Empty) + { + throw new InvalidFlightIdExceptions(value); + } + + Value = value; + } + + public static FlightId Of(Guid value) + { + return new FlightId(value); + } + + public static implicit operator Guid(FlightId flightId) + { + return flightId.Value; + } +} diff --git a/src/Services/Flight/src/Flight/Flights/ValueObjects/FlightNumber.cs b/src/Services/Flight/src/Flight/Flights/ValueObjects/FlightNumber.cs new file mode 100644 index 00000000..e5384e77 --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/ValueObjects/FlightNumber.cs @@ -0,0 +1,24 @@ +namespace Flight.Flights.ValueObjects; +using Exceptions; + +public record FlightNumber +{ + public string Value { get; } + public FlightNumber(string value) + { + if (string.IsNullOrWhiteSpace(value)) + { + throw new InvalidFlightNumberException(value); + } + Value = value; + } + public static FlightNumber Of(string value) + { + return new FlightNumber(value); + } + + public static implicit operator string(FlightNumber flightNumber) + { + return flightNumber.Value; + } +} diff --git a/src/Services/Flight/src/Flight/Flights/ValueObjects/Price.cs b/src/Services/Flight/src/Flight/Flights/ValueObjects/Price.cs new file mode 100644 index 00000000..88199612 --- /dev/null +++ b/src/Services/Flight/src/Flight/Flights/ValueObjects/Price.cs @@ -0,0 +1,26 @@ +namespace Flight.Flights.ValueObjects; +using Flight.Flights.Exceptions; + +public class Price +{ + public decimal Value { get; } + + public Price(decimal value) + { + if (value < 0) + { + throw new InvalidPriceException(); + } + Value = value; + } + + public static Price Of(decimal value) + { + return new Price(value); + } + + public static implicit operator decimal(Price price) + { + return price.Value; + } +} diff --git a/src/Services/Flight/src/Flight/Seats/Exceptions/InvalidSeatIdExceptions.cs b/src/Services/Flight/src/Flight/Seats/Exceptions/InvalidSeatIdExceptions.cs new file mode 100644 index 00000000..a9c37c60 --- /dev/null +++ b/src/Services/Flight/src/Flight/Seats/Exceptions/InvalidSeatIdExceptions.cs @@ -0,0 +1,12 @@ +namespace Flight.Seats.Exceptions; +using System; +using BuildingBlocks.Exception; + + +public class InvalidSeatIdExceptions : BadRequestException +{ + public InvalidSeatIdExceptions(Guid seatId) + : base($"seatId: '{seatId}' is invalid.") + { + } +} diff --git a/src/Services/Flight/src/Flight/Seats/Exceptions/InvalidSeatNumberException.cs b/src/Services/Flight/src/Flight/Seats/Exceptions/InvalidSeatNumberException.cs new file mode 100644 index 00000000..a654ed4e --- /dev/null +++ b/src/Services/Flight/src/Flight/Seats/Exceptions/InvalidSeatNumberException.cs @@ -0,0 +1,9 @@ +namespace Flight.Seats.Exceptions; +using BuildingBlocks.Exception; + +public class InvalidSeatNumberException : BadRequestException +{ + public InvalidSeatNumberException() : base("SeatNumber Cannot be null or negative") + { + } +} diff --git a/src/Services/Flight/src/Flight/Seats/Features/CreatingSeat/V1/CreateSeat.cs b/src/Services/Flight/src/Flight/Seats/Features/CreatingSeat/V1/CreateSeat.cs index 78888498..06f08c59 100644 --- a/src/Services/Flight/src/Flight/Seats/Features/CreatingSeat/V1/CreateSeat.cs +++ b/src/Services/Flight/src/Flight/Seats/Features/CreatingSeat/V1/CreateSeat.cs @@ -1,6 +1,7 @@ namespace Flight.Seats.Features.CreatingSeat.V1; using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Ardalis.GuardClauses; @@ -11,6 +12,7 @@ namespace Flight.Seats.Features.CreatingSeat.V1; using Flight.Data; using Flight.Seats.Exceptions; using Flight.Seats.Models; +using Flights.ValueObjects; using FluentValidation; using MapsterMapper; using MassTransit; @@ -19,6 +21,7 @@ namespace Flight.Seats.Features.CreatingSeat.V1; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.EntityFrameworkCore; +using ValueObjects; public record CreateSeat (string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, Guid FlightId) : ICommand, @@ -94,17 +97,16 @@ public async Task Handle(CreateSeat command, CancellationToken { Guard.Against.Null(command, nameof(command)); - var seat = await _flightDbContext.Seats.SingleOrDefaultAsync(x => x.Id == command.Id, cancellationToken); - + var seat = await _flightDbContext.Seats.AsNoTracking().SingleOrDefaultAsync(x => x.Id.Equals(SeatId.Of(command.Id)), cancellationToken); if (seat is not null) { throw new SeatAlreadyExistException(); } - var seatEntity = Seat.Create(command.Id, command.SeatNumber, command.Type, command.Class, command.FlightId); + var seatEntity = Seat.Create(SeatId.Of(command.Id), SeatNumber.Of(command.SeatNumber), command.Type, command.Class, FlightId.Of(command.FlightId)); var newSeat = (await _flightDbContext.Seats.AddAsync(seatEntity, cancellationToken))?.Entity; - return new CreateSeatResult(newSeat.Id); + return new CreateSeatResult(newSeat.Id.Value); } } diff --git a/src/Services/Flight/src/Flight/Seats/Features/ReservingSeat/Commands/V1/ReserveSeat.cs b/src/Services/Flight/src/Flight/Seats/Features/ReservingSeat/Commands/V1/ReserveSeat.cs index c765159d..60c0748c 100644 --- a/src/Services/Flight/src/Flight/Seats/Features/ReservingSeat/Commands/V1/ReserveSeat.cs +++ b/src/Services/Flight/src/Flight/Seats/Features/ReservingSeat/Commands/V1/ReserveSeat.cs @@ -10,6 +10,7 @@ namespace Flight.Seats.Features.ReservingSeat.Commands.V1; using Data; using Duende.IdentityServer.EntityFramework.Entities; using Exceptions; +using Flights.ValueObjects; using FluentValidation; using MapsterMapper; using MediatR; @@ -17,6 +18,7 @@ namespace Flight.Seats.Features.ReservingSeat.Commands.V1; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.EntityFrameworkCore; +using ValueObjects; public record ReserveSeat(Guid FlightId, string SeatNumber) : ICommand, IInternalCommand; @@ -82,8 +84,10 @@ public async Task Handle(ReserveSeat command, CancellationTok { Guard.Against.Null(command, nameof(command)); - var seat = await _flightDbContext.Seats.SingleOrDefaultAsync( - x => x.SeatNumber == command.SeatNumber && x.FlightId == command.FlightId, cancellationToken); + + + var seat = await _flightDbContext.Seats.AsNoTracking().SingleOrDefaultAsync( + x => x.SeatNumber.Value.Equals(SeatNumber.Of(command.SeatNumber)) && x.FlightId.Equals(FlightId.Of(command.FlightId)), cancellationToken); if (seat is null) { diff --git a/src/Services/Flight/src/Flight/Seats/Features/SeatMappings.cs b/src/Services/Flight/src/Flight/Seats/Features/SeatMappings.cs index d8a0d569..caeb7611 100644 --- a/src/Services/Flight/src/Flight/Seats/Features/SeatMappings.cs +++ b/src/Services/Flight/src/Flight/Seats/Features/SeatMappings.cs @@ -13,7 +13,7 @@ public class SeatMappings : IRegister public void Register(TypeAdapterConfig config) { config.NewConfig() - .ConstructUsing(x => new SeatDto(x.Id, x.SeatNumber, x.Type, x.Class, x.FlightId)); + .ConstructUsing(x => new SeatDto(x.Id.Value, x.SeatNumber.Value, x.Type, x.Class, x.FlightId.Value)); config.NewConfig() .Map(d => d.Id, s => NewId.NextGuid()) @@ -21,7 +21,7 @@ public void Register(TypeAdapterConfig config) config.NewConfig() .Map(d => d.Id, s => NewId.NextGuid()) - .Map(d => d.SeatId, s => s.Id); + .Map(d => d.SeatId, s => s.Id.Value); config.NewConfig() .Map(d => d.SeatId, s => s.Id); diff --git a/src/Services/Flight/src/Flight/Seats/Models/Seat.cs b/src/Services/Flight/src/Flight/Seats/Models/Seat.cs index 96ad13cd..6f2653af 100644 --- a/src/Services/Flight/src/Flight/Seats/Models/Seat.cs +++ b/src/Services/Flight/src/Flight/Seats/Models/Seat.cs @@ -6,10 +6,17 @@ namespace Flight.Seats.Models; using Features.CreatingSeat.V1; using Features.ReservingSeat.Commands.V1; +using Flight.Flights.ValueObjects; +using Flight.Seats.ValueObjects; -public record Seat : Aggregate +public record Seat : Aggregate { - public static Seat Create(Guid id, string seatNumber, Enums.SeatType type, Enums.SeatClass @class, Guid flightId, + public SeatNumber SeatNumber { get; private set; } = default!; + public Enums.SeatType Type { get; private set; } + public Enums.SeatClass Class { get; private set; } + public FlightId FlightId { get; private set; } + + public static Seat Create(SeatId id, SeatNumber seatNumber, Enums.SeatType type, Enums.SeatClass @class, FlightId flightId, bool isDeleted = false) { var seat = new Seat() @@ -23,11 +30,11 @@ public static Seat Create(Guid id, string seatNumber, Enums.SeatType type, Enums }; var @event = new SeatCreatedDomainEvent( - seat.Id, - seat.SeatNumber, + seat.Id.Value, + seat.SeatNumber.Value, seat.Type, seat.Class, - seat.FlightId, + seat.FlightId.Value, isDeleted); seat.AddDomainEvent(@event); @@ -41,20 +48,15 @@ public Task ReserveSeat(Seat seat) seat.LastModified = DateTime.Now; var @event = new SeatReservedDomainEvent( - seat.Id, - seat.SeatNumber, + seat.Id.Value, + seat.SeatNumber.Value, seat.Type, seat.Class, - seat.FlightId, + seat.FlightId.Value, seat.IsDeleted); seat.AddDomainEvent(@event); return Task.FromResult(this); } - - public string SeatNumber { get; private set; } - public Enums.SeatType Type { get; private set; } - public Enums.SeatClass Class { get; private set; } - public Guid FlightId { get; private set; } } diff --git a/src/Services/Flight/src/Flight/Seats/ValueObjects/SeatId.cs b/src/Services/Flight/src/Flight/Seats/ValueObjects/SeatId.cs new file mode 100644 index 00000000..0269a4c8 --- /dev/null +++ b/src/Services/Flight/src/Flight/Seats/ValueObjects/SeatId.cs @@ -0,0 +1,29 @@ +namespace Flight.Seats.ValueObjects; +using System; +using Exceptions; + + +public record SeatId +{ + public Guid Value { get; } + + private SeatId(Guid value) + { + if (value == Guid.Empty) + { + throw new InvalidSeatIdExceptions(value); + } + + Value = value; + } + + public static SeatId Of(Guid value) + { + return new SeatId(value); + } + + public static implicit operator Guid(SeatId seatId) + { + return seatId.Value; + } +} diff --git a/src/Services/Flight/src/Flight/Seats/ValueObjects/SeatNumber.cs b/src/Services/Flight/src/Flight/Seats/ValueObjects/SeatNumber.cs new file mode 100644 index 00000000..3c3e2e02 --- /dev/null +++ b/src/Services/Flight/src/Flight/Seats/ValueObjects/SeatNumber.cs @@ -0,0 +1,26 @@ +namespace Flight.Seats.ValueObjects; + +using Exceptions; + +public record SeatNumber +{ + public string Value { get; } + + public SeatNumber(string value) + { + if (string.IsNullOrWhiteSpace(value)) + { + throw new InvalidSeatNumberException(); + } + Value = value; + } + public static SeatNumber Of(string value) + { + return new SeatNumber(value); + } + + public static implicit operator string(SeatNumber seatNumber) + { + return seatNumber.Value; + } +} diff --git a/src/Services/Flight/tests/IntegrationTest/Flight/Features/DeleteFlightTests.cs b/src/Services/Flight/tests/IntegrationTest/Flight/Features/DeleteFlightTests.cs index 720c6580..6eb69596 100644 --- a/src/Services/Flight/tests/IntegrationTest/Flight/Features/DeleteFlightTests.cs +++ b/src/Services/Flight/tests/IntegrationTest/Flight/Features/DeleteFlightTests.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using System.Threading.Tasks; using BuildingBlocks.Contracts.EventBus.Messages; using BuildingBlocks.TestBase; @@ -10,10 +10,10 @@ namespace Integration.Test.Flight.Features; -using System; using global::Flight.Data.Seed; using global::Flight.Flights.Features.DeletingFlight.V1; using global::Flight.Flights.Models; +using global::Flight.Flights.ValueObjects; public class DeleteFlightTests : FlightIntegrationTestBase { @@ -26,13 +26,13 @@ public DeleteFlightTests( public async Task should_delete_flight_from_db() { // Arrange - var flightEntity = await Fixture.FindAsync( InitialData.Flights.First().Id); - var command = new DeleteFlight(flightEntity.Id); + var flightEntity = await Fixture.FindAsync(InitialData.Flights.First().Id); + var command = new DeleteFlight(flightEntity.Id.Value); // Act await Fixture.SendAsync(command); var deletedFlight = (await Fixture.ExecuteDbContextAsync(db => db.Flights - .Where(x => x.Id == command.Id) + .Where(x => x.Id == FlightId.Of(command.Id)) .IgnoreQueryFilters() .ToListAsync()) ).FirstOrDefault(); diff --git a/src/Services/Flight/tests/IntegrationTest/Flight/Features/UpdateFlightTests.cs b/src/Services/Flight/tests/IntegrationTest/Flight/Features/UpdateFlightTests.cs index 29f8adff..21e42e34 100644 --- a/src/Services/Flight/tests/IntegrationTest/Flight/Features/UpdateFlightTests.cs +++ b/src/Services/Flight/tests/IntegrationTest/Flight/Features/UpdateFlightTests.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using BuildingBlocks.Contracts.EventBus.Messages; using BuildingBlocks.TestBase; using Flight.Api; @@ -9,11 +9,10 @@ namespace Integration.Test.Flight.Features; -using System; using System.Linq; using global::Flight.Data.Seed; -using global::Flight.Flights.Features.UpdatingFlight.V1; using global::Flight.Flights.Models; +using global::Flight.Flights.ValueObjects; public class UpdateFlightTests : FlightIntegrationTestBase { @@ -26,7 +25,7 @@ public UpdateFlightTests( public async Task should_update_flight_to_db_and_publish_message_to_broker() { // Arrange - var flightEntity = await Fixture.FindAsync( InitialData.Flights.First().Id); + var flightEntity = await Fixture.FindAsync(InitialData.Flights.First().Id); var command = new FakeUpdateFlightCommand(flightEntity).Generate(); // Act diff --git a/src/Services/Flight/tests/IntegrationTest/Seat/Features/ReserveSeatTests.cs b/src/Services/Flight/tests/IntegrationTest/Seat/Features/ReserveSeatTests.cs index b55dd5ec..9b9a8fa9 100644 --- a/src/Services/Flight/tests/IntegrationTest/Seat/Features/ReserveSeatTests.cs +++ b/src/Services/Flight/tests/IntegrationTest/Seat/Features/ReserveSeatTests.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using BuildingBlocks.TestBase; using Flight; using Flight.Api; @@ -8,10 +8,6 @@ using Xunit; namespace Integration.Test.Seat.Features; - -using global::Flight.Flights.Features.CreatingFlight.V1; -using global::Flight.Seats.Features.CreatingSeat.V1; - public class ReserveSeatTests : FlightIntegrationTestBase { public ReserveSeatTests( @@ -36,11 +32,12 @@ public async Task should_return_valid_reserve_seat_from_grpc_service() // Act var response = await flightGrpcClient.ReserveSeatAsync(new ReserveSeatRequest() { - FlightId = seatCommand.FlightId.ToString(), SeatNumber = seatCommand.SeatNumber + FlightId = seatCommand.FlightId.ToString(), + SeatNumber = seatCommand.SeatNumber }); // Assert response?.Should().NotBeNull(); - response?.Id.Should().Be(seatCommand.Id.ToString()); + response?.Id.Should().Be(seatCommand?.Id.ToString()); } } diff --git a/src/Services/Flight/tests/UnitTest/Airport/Features/CreateAirportTests/CreateAirportCommandHandlerTests.cs b/src/Services/Flight/tests/UnitTest/Airport/Features/CreateAirportTests/CreateAirportCommandHandlerTests.cs index 351eca09..f430026c 100644 --- a/src/Services/Flight/tests/UnitTest/Airport/Features/CreateAirportTests/CreateAirportCommandHandlerTests.cs +++ b/src/Services/Flight/tests/UnitTest/Airport/Features/CreateAirportTests/CreateAirportCommandHandlerTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using FluentAssertions; @@ -8,8 +8,8 @@ namespace Unit.Test.Airport.Features.CreateAirportTests; -using global::Flight.Airports.Dtos; using global::Flight.Airports.Features.CreatingAirport.V1; +using global::Flight.Airports.ValueObjects; [Collection(nameof(UnitTestFixture))] public class CreateAirportCommandHandlerTests @@ -37,7 +37,7 @@ public async Task handler_with_valid_command_should_create_new_airport_and_retur var response = await Act(command, CancellationToken.None); // Assert - var entity = await _fixture.DbContext.Airports.FindAsync(response?.Id); + var entity = await _fixture.DbContext.Airports.FindAsync(AirportId.Of(response.Id)); entity?.Should().NotBeNull(); response?.Id.Should().Be(entity.Id); diff --git a/src/Services/Flight/tests/UnitTest/Common/DbContextFactory.cs b/src/Services/Flight/tests/UnitTest/Common/DbContextFactory.cs index 80e62f74..69abdb82 100644 --- a/src/Services/Flight/tests/UnitTest/Common/DbContextFactory.cs +++ b/src/Services/Flight/tests/UnitTest/Common/DbContextFactory.cs @@ -8,7 +8,12 @@ namespace Unit.Test.Common; using global::Flight.Aircrafts.ValueObjects; +using global::Flight.Airports.ValueObjects; +using global::Flight.Flights.ValueObjects; +using global::Flight.Seats.ValueObjects; using MassTransit; +using AirportName = global::Flight.Airports.ValueObjects.Name; +using Name = global::Flight.Aircrafts.ValueObjects.Name; public static class DbContextFactory { @@ -36,10 +41,10 @@ private static void FlightDataSeeder(FlightDbContext context) { var airports = new List { - global::Flight.Airports.Models.Airport.Create(_airportId1, "Lisbon International Airport", "LIS", - "12988"), - global::Flight.Airports.Models.Airport.Create(_airportId2, "Sao Paulo International Airport", "BRZ", - "11200") + global::Flight.Airports.Models.Airport.Create(AirportId.Of(_airportId1), AirportName.Of("Lisbon International Airport"), Address.Of("LIS"), + Code.Of("12988")), + global::Flight.Airports.Models.Airport.Create(AirportId.Of(_airportId2), AirportName.Of("Sao Paulo International Airport"), Address.Of("BRZ"), + Code.Of("11200")) }; context.Airports.AddRange(airports); @@ -55,29 +60,29 @@ private static void FlightDataSeeder(FlightDbContext context) var flights = new List { - global::Flight.Flights.Models.Flight.Create(_flightId1, "BD467", AircraftId.Of(_aircraft1), _airportId1, - new DateTime(2022, 1, 31, 12, 0, 0), - new DateTime(2022, 1, 31, 14, 0, 0), - _airportId2, 120m, - new DateTime(2022, 1, 31), FlightStatus.Completed, - 8000) + global::Flight.Flights.Models.Flight.Create(FlightId.Of(_flightId1), FlightNumber.Of( "BD467"), AircraftId.Of(_aircraft1), AirportId.Of( _airportId1), + DepartureDate.Of( new DateTime(2022, 1, 31, 12, 0, 0)), + ArriveDate.Of( new DateTime(2022, 1, 31, 14, 0, 0)), + AirportId.Of( _airportId2), DurationMinutes.Of(120m), + FlightDate.Of( new DateTime(2022, 1, 31)), FlightStatus.Completed, + Price.Of((decimal)8000)) }; context.Flights.AddRange(flights); var seats = new List { - global::Flight.Seats.Models.Seat.Create(NewId.NextGuid(), "12A", SeatType.Window, SeatClass.Economy, - _flightId1), - global::Flight.Seats.Models.Seat.Create(NewId.NextGuid(), "12B", SeatType.Window, SeatClass.Economy, - _flightId1), - global::Flight.Seats.Models.Seat.Create(NewId.NextGuid(), "12C", SeatType.Middle, SeatClass.Economy, - _flightId1), - global::Flight.Seats.Models.Seat.Create(NewId.NextGuid(), "12D", SeatType.Middle, SeatClass.Economy, - _flightId1), - global::Flight.Seats.Models.Seat.Create(NewId.NextGuid(), "12E", SeatType.Aisle, SeatClass.Economy, - _flightId1), - global::Flight.Seats.Models.Seat.Create(NewId.NextGuid(), "12F", SeatType.Aisle, SeatClass.Economy, - _flightId1) + global::Flight.Seats.Models.Seat.Create(SeatId.Of( NewId.NextGuid()), SeatNumber.Of("12A"), SeatType.Window, SeatClass.Economy, + FlightId.Of(_flightId1)), + global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12B"), SeatType.Window, SeatClass.Economy, + FlightId.Of(_flightId1)), + global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12C"), SeatType.Middle, SeatClass.Economy, + FlightId.Of(_flightId1)), + global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12D"), SeatType.Middle, SeatClass.Economy, + FlightId.Of(_flightId1)), + global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12E"), SeatType.Aisle, SeatClass.Economy, + FlightId.Of(_flightId1)), + global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12F"), SeatType.Aisle, SeatClass.Economy, + FlightId.Of(_flightId1)) }; context.Seats.AddRange(seats); diff --git a/src/Services/Flight/tests/UnitTest/Fakes/FakeFlightCreate.cs b/src/Services/Flight/tests/UnitTest/Fakes/FakeFlightCreate.cs index e9b936cf..d9c5e707 100644 --- a/src/Services/Flight/tests/UnitTest/Fakes/FakeFlightCreate.cs +++ b/src/Services/Flight/tests/UnitTest/Fakes/FakeFlightCreate.cs @@ -1,6 +1,8 @@ namespace Unit.Test.Fakes; using global::Flight.Aircrafts.ValueObjects; +using global::Flight.Airports.ValueObjects; +using global::Flight.Flights.ValueObjects; public static class FakeFlightCreate { @@ -8,9 +10,9 @@ public static class FakeFlightCreate { var command = new FakeCreateFlightCommand().Generate(); - return global::Flight.Flights.Models.Flight.Create(command.Id, command.FlightNumber, - AircraftId.Of(command.AircraftId), command.DepartureAirportId, command.DepartureDate, - command.ArriveDate, command.ArriveAirportId, command.DurationMinutes, - command.FlightDate, command.Status, command.Price); + return global::Flight.Flights.Models.Flight.Create(FlightId.Of(command.Id), FlightNumber.Of(command.FlightNumber), + AircraftId.Of(command.AircraftId), AirportId.Of(command.DepartureAirportId), DepartureDate.Of(command.DepartureDate), + ArriveDate.Of(command.ArriveDate), AirportId.Of(command.ArriveAirportId), DurationMinutes.Of(command.DurationMinutes), + FlightDate.Of(command.FlightDate), command.Status, Price.Of(command.Price)); } } diff --git a/src/Services/Flight/tests/UnitTest/Fakes/FakeFlightUpdate.cs b/src/Services/Flight/tests/UnitTest/Fakes/FakeFlightUpdate.cs index ad3bc7f4..0996583e 100644 --- a/src/Services/Flight/tests/UnitTest/Fakes/FakeFlightUpdate.cs +++ b/src/Services/Flight/tests/UnitTest/Fakes/FakeFlightUpdate.cs @@ -1,12 +1,13 @@ -namespace Unit.Test.Fakes; +namespace Unit.Test.Fakes; using global::Flight.Flights.Models; +using global::Flight.Flights.ValueObjects; public static class FakeFlightUpdate { public static void Generate(Flight flight) { flight.Update(flight.Id, flight.FlightNumber, flight.AircraftId, flight.DepartureAirportId, flight.DepartureDate, - flight.ArriveDate, flight.ArriveAirportId, flight.DurationMinutes, flight.FlightDate, flight.Status, 1000, flight.IsDeleted); + flight.ArriveDate, flight.ArriveAirportId, flight.DurationMinutes, flight.FlightDate, flight.Status, Price.Of(1000), flight.IsDeleted); } } diff --git a/src/Services/Flight/tests/UnitTest/Flight/Features/Domains/UpdateFlightTests.cs b/src/Services/Flight/tests/UnitTest/Flight/Features/Domains/UpdateFlightTests.cs index cd4f650d..d0aaadd6 100644 --- a/src/Services/Flight/tests/UnitTest/Flight/Features/Domains/UpdateFlightTests.cs +++ b/src/Services/Flight/tests/UnitTest/Flight/Features/Domains/UpdateFlightTests.cs @@ -1,4 +1,4 @@ -namespace Unit.Test.Flight.Features.Domains; +namespace Unit.Test.Flight.Features.Domains; using System.Linq; using FluentAssertions; @@ -20,7 +20,7 @@ public void can_update_valid_flight() FakeFlightUpdate.Generate(fakeFlight); // Assert - fakeFlight.Price.Should().Be(1000); + fakeFlight.Price.Value.Should().Be(1000); } [Fact] diff --git a/src/Services/Flight/tests/UnitTest/Flight/Features/Handlers/CreateFlight/CreateFlightCommandHandlerTests.cs b/src/Services/Flight/tests/UnitTest/Flight/Features/Handlers/CreateFlight/CreateFlightCommandHandlerTests.cs index 97862588..6a37fb40 100644 --- a/src/Services/Flight/tests/UnitTest/Flight/Features/Handlers/CreateFlight/CreateFlightCommandHandlerTests.cs +++ b/src/Services/Flight/tests/UnitTest/Flight/Features/Handlers/CreateFlight/CreateFlightCommandHandlerTests.cs @@ -1,10 +1,11 @@ -namespace Unit.Test.Flight.Features.Handlers.CreateFlight; +namespace Unit.Test.Flight.Features.Handlers.CreateFlight; using System; using System.Threading; using System.Threading.Tasks; using FluentAssertions; using global::Flight.Flights.Features.CreatingFlight.V1; +using global::Flight.Flights.ValueObjects; using Unit.Test.Common; using Unit.Test.Fakes; using Xunit; @@ -34,7 +35,7 @@ public async Task handler_with_valid_command_should_create_new_flight_and_return var response = await Act(command, CancellationToken.None); // Assert - var entity = await _fixture.DbContext.Flights.FindAsync(response?.Id); + var entity = await _fixture.DbContext.Flights.FindAsync(FlightId.Of(response.Id)); entity?.Should().NotBeNull(); response?.Id.Should().Be(entity.Id); diff --git a/src/Services/Flight/tests/UnitTest/Seat/Features/CreateSeatCommandHandlerTests.cs b/src/Services/Flight/tests/UnitTest/Seat/Features/CreateSeatCommandHandlerTests.cs index 3a8488b2..5f85681b 100644 --- a/src/Services/Flight/tests/UnitTest/Seat/Features/CreateSeatCommandHandlerTests.cs +++ b/src/Services/Flight/tests/UnitTest/Seat/Features/CreateSeatCommandHandlerTests.cs @@ -1,7 +1,6 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; -using Flight.Seats.Dtos; using FluentAssertions; using Unit.Test.Common; using Unit.Test.Fakes; @@ -10,6 +9,7 @@ namespace Unit.Test.Seat.Features; using global::Flight.Seats.Features.CreatingSeat.V1; +using global::Flight.Seats.ValueObjects; [Collection(nameof(UnitTestFixture))] public class CreateSeatCommandHandlerTests @@ -39,7 +39,7 @@ public async Task handler_with_valid_command_should_create_new_seat_and_return_c var response = await Act(command, CancellationToken.None); // Assert - var entity = await _fixture.DbContext.Seats.FindAsync(response?.Id); + var entity = await _fixture.DbContext.Seats.FindAsync(SeatId.Of(response.Id)); entity?.Should().NotBeNull(); response?.Id.Should().Be(entity.Id); diff --git a/src/Services/Flight/tests/UnitTest/Seat/SeatMappingTests.cs b/src/Services/Flight/tests/UnitTest/Seat/SeatMappingTests.cs index 04bdfd61..1f749102 100644 --- a/src/Services/Flight/tests/UnitTest/Seat/SeatMappingTests.cs +++ b/src/Services/Flight/tests/UnitTest/Seat/SeatMappingTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Flight.Seats.Dtos; using MapsterMapper; @@ -25,7 +25,7 @@ public static IEnumerable Data yield return new object[] { // these types will instantiate with reflection in the future - typeof(global::Flight.Seats.Models.Seat), typeof(SeatDto) + typeof(global::Flight.Seats.Models.SeatReadModel), typeof(SeatDto) }; } }