diff --git a/.gitignore b/.gitignore index d6ceb3e..0fceb20 100644 --- a/.gitignore +++ b/.gitignore @@ -435,4 +435,5 @@ fabric.properties *.jwk -**/keys \ No newline at end of file +**/keys +/src/ApiGateway/back.txt diff --git a/src/Services/Flight/src/Flight/Aircrafts/Exceptions/InvalidAircraftIdExceptions.cs b/src/Services/Flight/src/Flight/Aircrafts/Exceptions/InvalidAircraftIdExceptions.cs new file mode 100644 index 0000000..2487e37 --- /dev/null +++ b/src/Services/Flight/src/Flight/Aircrafts/Exceptions/InvalidAircraftIdExceptions.cs @@ -0,0 +1,12 @@ +namespace Flight.Aircrafts.Exceptions; +using System; +using BuildingBlocks.Exception; + + +public class InvalidAircraftIdExceptions : BadRequestException +{ + public InvalidAircraftIdExceptions(Guid aircraftId) + : base($"AircraftId: '{aircraftId}' is invalid.") + { + } +} diff --git a/src/Services/Flight/src/Flight/Aircrafts/Features/AircraftMappings.cs b/src/Services/Flight/src/Flight/Aircrafts/Features/AircraftMappings.cs index 9776895..deec0ca 100644 --- a/src/Services/Flight/src/Flight/Aircrafts/Features/AircraftMappings.cs +++ b/src/Services/Flight/src/Flight/Aircrafts/Features/AircraftMappings.cs @@ -1,9 +1,10 @@ -using Flight.Aircrafts.Models; +using Flight.Aircrafts.Models; using Mapster; namespace Flight.Aircrafts.Features; using CreatingAircraft.V1; +using Flight.Aircrafts.Models.ValueObjects; using MassTransit; public class AircraftMappings : IRegister @@ -11,12 +12,12 @@ public class AircraftMappings : IRegister public void Register(TypeAdapterConfig config) { config.NewConfig() - .Map(d => d.Id, s => NewId.NextGuid()) - .Map(d => d.AircraftId, s => s.Id); + .Map(d => d.Id, s => NewId.NextGuid()) + .Map(d => d.AircraftId, s => AircraftId.Of(s.Id)); config.NewConfig() .Map(d => d.Id, s => NewId.NextGuid()) - .Map(d => d.AircraftId, s => s.Id); + .Map(d => d.AircraftId, s => AircraftId.Of(s.Id)); config.NewConfig() .ConstructUsing(x => new CreatingAircraft.V1.CreateAircraft(x.Name, x.Model, x.ManufacturingYear)); diff --git a/src/Services/Flight/src/Flight/Aircrafts/Features/CreatingAircraft/V1/CreateAircraft.cs b/src/Services/Flight/src/Flight/Aircrafts/Features/CreatingAircraft/V1/CreateAircraft.cs index 0345498..06e2751 100644 --- a/src/Services/Flight/src/Flight/Aircrafts/Features/CreatingAircraft/V1/CreateAircraft.cs +++ b/src/Services/Flight/src/Flight/Aircrafts/Features/CreatingAircraft/V1/CreateAircraft.cs @@ -1,6 +1,7 @@ namespace Flight.Aircrafts.Features.CreatingAircraft.V1; using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Ardalis.GuardClauses; @@ -17,7 +18,6 @@ using MediatR; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Microsoft.EntityFrameworkCore; using Models; using Models.ValueObjects; @@ -27,7 +27,7 @@ public record CreateAircraft(string Name, string Model, int ManufacturingYear) : public Guid Id { get; init; } = NewId.NextGuid(); } -public record CreateAircraftResult(Guid Id); +public record CreateAircraftResult(AircraftId Id); public record AircraftCreatedDomainEvent (Guid Id, string Name, string Model, int ManufacturingYear, bool IsDeleted) : IDomainEvent; @@ -89,15 +89,19 @@ internal class CreateAircraftHandler : IRequestHandler x.Model == request.Model, cancellationToken); + //var aircraft = + // await _flightDbContext.Aircraft.SingleOrDefaultAsync(x => x.Model == Model.Of(request.Model), cancellationToken); + + var aircraft = _flightDbContext.Aircraft.AsEnumerable() + .FirstOrDefault(a => a.Model.Equals(Model.Of(request.Model))); + if (aircraft is not null) { throw new AircraftAlreadyExistException(); } - var aircraftEntity = Aircraft.Create(request.Id, NameValue.Of(request.Name), ModelValue.Of(request.Model), ManufacturingYearValue.Of(request.ManufacturingYear)); + var aircraftEntity = Aircraft.Create(AircraftId.Of(request.Id), Name.Of(request.Name), Model.Of(request.Model), ManufacturingYear.Of(request.ManufacturingYear)); var newAircraft = (await _flightDbContext.Aircraft.AddAsync(aircraftEntity, cancellationToken))?.Entity; diff --git a/src/Services/Flight/src/Flight/Aircrafts/Features/CreatingAircraft/V1/CreateAircraftMongo.cs b/src/Services/Flight/src/Flight/Aircrafts/Features/CreatingAircraft/V1/CreateAircraftMongo.cs index 92effba..6ed4b2b 100644 --- a/src/Services/Flight/src/Flight/Aircrafts/Features/CreatingAircraft/V1/CreateAircraftMongo.cs +++ b/src/Services/Flight/src/Flight/Aircrafts/Features/CreatingAircraft/V1/CreateAircraftMongo.cs @@ -1,4 +1,4 @@ -namespace Flight.Aircrafts.Features.CreatingAircraft.V1; +namespace Flight.Aircrafts.Features.CreatingAircraft.V1; using System; using System.Threading; @@ -6,11 +6,12 @@ using System.Threading.Tasks; using Ardalis.GuardClauses; using BuildingBlocks.Core.CQRS; using BuildingBlocks.Core.Event; -using Exceptions; -using Models; using Data; +using Exceptions; using MapsterMapper; using MediatR; +using Models; +using Models.ValueObjects; using MongoDB.Driver; using MongoDB.Driver.Linq; @@ -36,7 +37,7 @@ public class CreateAircraftMongoHandler : ICommandHandler var aircraftReadModel = _mapper.Map(request); var aircraft = await _flightReadDbContext.Aircraft.AsQueryable() - .FirstOrDefaultAsync(x => x.AircraftId == aircraftReadModel.AircraftId, cancellationToken); + .FirstOrDefaultAsync(x => x.AircraftId == AircraftId.Of(aircraftReadModel.AircraftId), cancellationToken); if (aircraft is not null) { diff --git a/src/Services/Flight/src/Flight/Aircrafts/Models/Aircraft.cs b/src/Services/Flight/src/Flight/Aircrafts/Models/Aircraft.cs index 0615cf4..1b812ed 100644 --- a/src/Services/Flight/src/Flight/Aircrafts/Models/Aircraft.cs +++ b/src/Services/Flight/src/Flight/Aircrafts/Models/Aircraft.cs @@ -2,17 +2,16 @@ using BuildingBlocks.Core.Model; namespace Flight.Aircrafts.Models; -using System; using Features.CreatingAircraft.V1; using ValueObjects; -public record Aircraft : Aggregate +public record Aircraft : Aggregate { - public NameValue Name { get; private set; } - public ModelValue Model { get; private set; } - public ManufacturingYearValue ManufacturingYear { get; private set; } + public Name Name { get; private set; } + public Model Model { get; private set; } + public ManufacturingYear ManufacturingYear { get; private set; } - public static Aircraft Create(Guid id, NameValue name, ModelValue model, ManufacturingYearValue manufacturingYear, bool isDeleted = false) + public static Aircraft Create(AircraftId id, Name name, Model model, ManufacturingYear manufacturingYear, bool isDeleted = false) { var aircraft = new Aircraft { diff --git a/src/Services/Flight/src/Flight/Aircrafts/Models/AircraftReadModel.cs b/src/Services/Flight/src/Flight/Aircrafts/Models/AircraftReadModel.cs index 3287652..893f3df 100644 --- a/src/Services/Flight/src/Flight/Aircrafts/Models/AircraftReadModel.cs +++ b/src/Services/Flight/src/Flight/Aircrafts/Models/AircraftReadModel.cs @@ -1,13 +1,14 @@ -namespace Flight.Aircrafts.Models; +namespace Flight.Aircrafts.Models; using System; +using Flight.Aircrafts.Models.ValueObjects; public class AircraftReadModel { public required Guid Id { get; init; } - public required Guid AircraftId { get; init; } - public required string Name { get; init; } - public required string Model { get; init; } - public required int ManufacturingYear { get; init; } + public required AircraftId AircraftId { get; init; } + public required Name Name { get; init; } + public required Model Model { get; init; } + public required ManufacturingYear ManufacturingYear { get; init; } public required bool IsDeleted { get; init; } } diff --git a/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/AircraftId.cs b/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/AircraftId.cs new file mode 100644 index 0000000..a225b06 --- /dev/null +++ b/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/AircraftId.cs @@ -0,0 +1,28 @@ +namespace Flight.Aircrafts.Models.ValueObjects; +using System; +using Exceptions; + +public record AircraftId +{ + public Guid Value { get; } + + private AircraftId(Guid value) + { + if (value == Guid.Empty) + { + throw new InvalidAircraftIdExceptions(value); + } + + Value = value; + } + + public static AircraftId Of(Guid value) + { + return new AircraftId(value); + } + + public static implicit operator Guid(AircraftId aircraftId) + { + return aircraftId.Value; + } +} diff --git a/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/ManufacturingYear.cs b/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/ManufacturingYear.cs new file mode 100644 index 0000000..5e68c6e --- /dev/null +++ b/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/ManufacturingYear.cs @@ -0,0 +1,19 @@ +namespace Flight.Aircrafts.Models.ValueObjects; + +using System; + +public record ManufacturingYear : GenericValueObject +{ + public ManufacturingYear(int value) : base(value) + { + if (string.IsNullOrWhiteSpace(value.ToString())) + { + throw new ArgumentException("ManufacturingYear cannot be empty or whitespace."); + } + } + + public static ManufacturingYear Of(int value) + { + return new ManufacturingYear(value); + } +} diff --git a/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/ManufacturingYearValue.cs b/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/ManufacturingYearValue.cs deleted file mode 100644 index 5d67e9c..0000000 --- a/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/ManufacturingYearValue.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Flight.Aircrafts.Models.ValueObjects; -using System; - -public record ManufacturingYearValue : GenericValueObject -{ - public ManufacturingYearValue(int value) : base(value) - { - if (value < 1900 || value > DateTime.Now.Year) - { - throw new ArgumentException("Manufacturing year is invalid."); - } - } - - public static ManufacturingYearValue Of(int value) - { - return new ManufacturingYearValue(value); - } -} diff --git a/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/ModelValue.cs b/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/Model.cs similarity index 55% rename from src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/ModelValue.cs rename to src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/Model.cs index 4284baa..ddbb0cc 100644 --- a/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/ModelValue.cs +++ b/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/Model.cs @@ -1,8 +1,8 @@ namespace Flight.Aircrafts.Models.ValueObjects; using System; -public record ModelValue : GenericValueObject +public record Model : GenericValueObject { - public ModelValue(string value) : base(value) + public Model(string value) : base(value) { if (string.IsNullOrWhiteSpace(value)) { @@ -10,8 +10,8 @@ public record ModelValue : GenericValueObject } } - public static ModelValue Of(string value) + public static Model Of(string value) { - return new ModelValue(value); + return new Model(value); } } diff --git a/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/NameValue.cs b/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/Name.cs similarity index 56% rename from src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/NameValue.cs rename to src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/Name.cs index 9ef89b7..577e62f 100644 --- a/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/NameValue.cs +++ b/src/Services/Flight/src/Flight/Aircrafts/Models/ValueObjects/Name.cs @@ -1,9 +1,9 @@ namespace Flight.Aircrafts.Models.ValueObjects; using System; -public record NameValue : GenericValueObject +public record Name : GenericValueObject { - public NameValue(string value) : base(value) + public Name(string value) : base(value) { if (string.IsNullOrWhiteSpace(value)) { @@ -11,8 +11,8 @@ public record NameValue : GenericValueObject } } - public static NameValue Of(string value) + public static Name Of(string value) { - return new NameValue(value); + return new Name(value); } } diff --git a/src/Services/Flight/src/Flight/Data/Configurations/AircraftConfiguration.cs b/src/Services/Flight/src/Flight/Data/Configurations/AircraftConfiguration.cs index 71fc974..b73a787 100644 --- a/src/Services/Flight/src/Flight/Data/Configurations/AircraftConfiguration.cs +++ b/src/Services/Flight/src/Flight/Data/Configurations/AircraftConfiguration.cs @@ -4,17 +4,53 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Flight.Data.Configurations; +using System; +using Flight.Aircrafts.Models.ValueObjects; + public class AircraftConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ToTable(nameof(Aircraft)); + builder.HasKey(r => r.Id); - builder.Property(r => r.Id).ValueGeneratedNever(); + builder.Property(r => r.Id).ValueGeneratedNever() + .HasConversion(aircraftId => aircraftId.Value, dbId => AircraftId.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(Aircraft.Name)) + .HasMaxLength(50) + .IsRequired(); + } + ); + + builder.OwnsOne( + x => x.Model, + a => + { + a.Property(p => p.Value) + .HasColumnName(nameof(Aircraft.Model)) + .HasMaxLength(50) + .IsRequired(); + } + ); + + builder.OwnsOne( + x => x.ManufacturingYear, + a => + { + a.Property(p => p.Value) + .HasColumnName(nameof(Aircraft.ManufacturingYear)) + .HasMaxLength(5) + .IsRequired(); + } + ); } } diff --git a/src/Services/Flight/src/Flight/Data/Migrations/20230525075149_aircraftValueObjects.Designer.cs b/src/Services/Flight/src/Flight/Data/Migrations/20230525075149_aircraftValueObjects.Designer.cs new file mode 100644 index 0000000..55dd254 --- /dev/null +++ b/src/Services/Flight/src/Flight/Data/Migrations/20230525075149_aircraftValueObjects.Designer.cs @@ -0,0 +1,363 @@ +// +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("20230525075149_aircraftValueObjects")] + partial class aircraftValueObjects + { + /// + 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("Address") + .HasColumnType("text") + .HasColumnName("address"); + + b.Property("Code") + .HasColumnType("text") + .HasColumnName("code"); + + 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("Name") + .HasColumnType("text") + .HasColumnName("name"); + + 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("ArriveDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("arrive_date"); + + 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("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"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified"); + + b.Property("LastModifiedBy") + .HasColumnType("bigint") + .HasColumnName("last_modified_by"); + + b.Property("Price") + .HasColumnType("numeric") + .HasColumnName("price"); + + 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.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("SeatNumber") + .HasColumnType("text") + .HasColumnName("seat_number"); + + 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.Models.ValueObjects.ManufacturingYearValue", "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.Models.ValueObjects.ModelValue", "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.Models.ValueObjects.NameValue", "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"); + + b.Navigation("Model"); + + b.Navigation("Name"); + }); + + modelBuilder.Entity("Flight.Flights.Models.Flight", b => + { + b.HasOne("Flight.Aircrafts.Models.Aircraft", null) + .WithMany() + .HasForeignKey("AircraftId") + .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"); + }); + + 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"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Services/Flight/src/Flight/Data/Migrations/20230525075149_aircraftValueObjects.cs b/src/Services/Flight/src/Flight/Data/Migrations/20230525075149_aircraftValueObjects.cs new file mode 100644 index 0000000..c08d4ca --- /dev/null +++ b/src/Services/Flight/src/Flight/Data/Migrations/20230525075149_aircraftValueObjects.cs @@ -0,0 +1,120 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Flight.Data.Migrations +{ + /// + public partial class aircraftValueObjects : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_flight_aircraft_aircraft_id", + table: "flight"); + + migrationBuilder.AlterColumn( + name: "aircraft_id", + table: "flight", + type: "uuid", + nullable: true, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AlterColumn( + name: "name", + table: "aircraft", + type: "character varying(50)", + maxLength: 50, + nullable: true, + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "model", + table: "aircraft", + type: "character varying(50)", + maxLength: 50, + nullable: true, + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "manufacturing_year", + table: "aircraft", + type: "integer", + maxLength: 5, + nullable: true, + oldClrType: typeof(int), + oldType: "integer"); + + migrationBuilder.AddForeignKey( + name: "fk_flight_aircraft_aircraft_id", + table: "flight", + column: "aircraft_id", + principalTable: "aircraft", + principalColumn: "id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_flight_aircraft_aircraft_id", + table: "flight"); + + 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: "aircraft", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(50)", + oldMaxLength: 50, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "model", + table: "aircraft", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(50)", + oldMaxLength: 50, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "manufacturing_year", + table: "aircraft", + type: "integer", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "integer", + oldMaxLength: 5, + oldNullable: true); + + migrationBuilder.AddForeignKey( + name: "fk_flight_aircraft_aircraft_id", + table: "flight", + column: "aircraft_id", + principalTable: "aircraft", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/src/Services/Flight/src/Flight/Data/Migrations/20230526093041_aircraftValueObject.Designer.cs b/src/Services/Flight/src/Flight/Data/Migrations/20230526093041_aircraftValueObject.Designer.cs new file mode 100644 index 0000000..72f0f19 --- /dev/null +++ b/src/Services/Flight/src/Flight/Data/Migrations/20230526093041_aircraftValueObject.Designer.cs @@ -0,0 +1,363 @@ +// +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("20230526093041_aircraftValueObject")] + partial class aircraftValueObject + { + /// + 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("Address") + .HasColumnType("text") + .HasColumnName("address"); + + b.Property("Code") + .HasColumnType("text") + .HasColumnName("code"); + + 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("Name") + .HasColumnType("text") + .HasColumnName("name"); + + 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("ArriveDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("arrive_date"); + + 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("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"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified"); + + b.Property("LastModifiedBy") + .HasColumnType("bigint") + .HasColumnName("last_modified_by"); + + b.Property("Price") + .HasColumnType("numeric") + .HasColumnName("price"); + + 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.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("SeatNumber") + .HasColumnType("text") + .HasColumnName("seat_number"); + + 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.Models.ValueObjects.ManufacturingYearValue", "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.Models.ValueObjects.ModelValue", "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.Models.ValueObjects.NameValue", "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"); + + b.Navigation("Model"); + + b.Navigation("Name"); + }); + + modelBuilder.Entity("Flight.Flights.Models.Flight", b => + { + b.HasOne("Flight.Aircrafts.Models.Aircraft", null) + .WithMany() + .HasForeignKey("AircraftId") + .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"); + }); + + 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"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Services/Flight/src/Flight/Data/Migrations/20230526093041_aircraftValueObject.cs b/src/Services/Flight/src/Flight/Data/Migrations/20230526093041_aircraftValueObject.cs new file mode 100644 index 0000000..82cf3d7 --- /dev/null +++ b/src/Services/Flight/src/Flight/Data/Migrations/20230526093041_aircraftValueObject.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Flight.Data.Migrations +{ + /// + public partial class aircraftValueObject : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/src/Services/Flight/src/Flight/Data/Migrations/FlightDbContextModelSnapshot.cs b/src/Services/Flight/src/Flight/Data/Migrations/FlightDbContextModelSnapshot.cs index 5df1ffd..1ea716d 100644 --- a/src/Services/Flight/src/Flight/Data/Migrations/FlightDbContextModelSnapshot.cs +++ b/src/Services/Flight/src/Flight/Data/Migrations/FlightDbContextModelSnapshot.cs @@ -48,18 +48,6 @@ namespace Flight.Data.Migrations .HasColumnType("bigint") .HasColumnName("last_modified_by"); - b.Property("ManufacturingYear") - .HasColumnType("integer") - .HasColumnName("manufacturing_year"); - - b.Property("Model") - .HasColumnType("text") - .HasColumnName("model"); - - b.Property("Name") - .HasColumnType("text") - .HasColumnName("name"); - b.Property("Version") .IsConcurrencyToken() .HasColumnType("bigint") @@ -126,7 +114,7 @@ namespace Flight.Data.Migrations .HasColumnType("uuid") .HasColumnName("id"); - b.Property("AircraftId") + b.Property("AircraftId") .HasColumnType("uuid") .HasColumnName("aircraft_id"); @@ -268,13 +256,85 @@ namespace Flight.Data.Migrations b.ToTable("seat", (string)null); }); + modelBuilder.Entity("Flight.Aircrafts.Models.Aircraft", b => + { + b.OwnsOne("Flight.Aircrafts.Models.ValueObjects.ManufacturingYearValue", "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.Models.ValueObjects.ModelValue", "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.Models.ValueObjects.NameValue", "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"); + + b.Navigation("Model"); + + b.Navigation("Name"); + }); + 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) diff --git a/src/Services/Flight/src/Flight/Data/Seed/InitialData.cs b/src/Services/Flight/src/Flight/Data/Seed/InitialData.cs index 3fe9c95..bd391db 100644 --- a/src/Services/Flight/src/Flight/Data/Seed/InitialData.cs +++ b/src/Services/Flight/src/Flight/Data/Seed/InitialData.cs @@ -28,9 +28,9 @@ public static class InitialData Aircrafts = new List { - Aircraft.Create(new Guid("3c5c0000-97c6-fc34-fcd3-08db322230c8"), NameValue.Of("Boeing 737"), ModelValue.Of("B737"), ManufacturingYearValue.Of(2005)), - Aircraft.Create(new Guid("3c5c0000-97c6-fc34-2e04-08db322230c9"), NameValue.Of("Airbus 300"), ModelValue.Of("A300"), ManufacturingYearValue.Of(2000)), - Aircraft.Create(new Guid("3c5c0000-97c6-fc34-2e11-08db322230c9"), NameValue.Of("Airbus 320"), ModelValue.Of("A320"), ManufacturingYearValue.Of(2003)) + Aircraft.Create(AircraftId.Of(new Guid("3c5c0000-97c6-fc34-fcd3-08db322230c8")), Name.Of("Boeing 737"), Model.Of("B737"), ManufacturingYear.Of(2005)), + Aircraft.Create(AircraftId.Of(new Guid("3c5c0000-97c6-fc34-2e04-08db322230c9")), Name.Of("Airbus 300"), Model.Of("A300"), ManufacturingYear.Of(2000)), + Aircraft.Create(AircraftId.Of(new Guid("3c5c0000-97c6-fc34-2e11-08db322230c9")), Name.Of("Airbus 320"), Model.Of("A320"), ManufacturingYear.Of(2003)) }; 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 14c53f0..bfa825d 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 @@ -3,6 +3,7 @@ namespace Flight.Flights.Features.CreatingFlight.V1; using System; using System.Threading; using System.Threading.Tasks; +using Aircrafts.Models.ValueObjects; using Ardalis.GuardClauses; using BuildingBlocks.Core.CQRS; using BuildingBlocks.Core.Event; @@ -111,7 +112,7 @@ internal class CreateFlightHandler : ICommandHandler { public string FlightNumber { get; private set; } - public Guid AircraftId { get; private set; } + public AircraftId AircraftId { get; private set; } public DateTime DepartureDate { get; private set; } public Guid DepartureAirportId { get; private set; } public DateTime ArriveDate { get; private set; } @@ -20,7 +21,7 @@ public record Flight : Aggregate public Enums.FlightStatus Status { get; private set; } public decimal Price { get; private set; } - public static Flight Create(Guid id, string flightNumber, Guid aircraftId, + 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) @@ -52,7 +53,7 @@ public record Flight : Aggregate } - public void Update(Guid id, string flightNumber, Guid 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) @@ -75,7 +76,7 @@ public record Flight : Aggregate AddDomainEvent(@event); } - public void Delete(Guid id, string flightNumber, Guid aircraftId, + 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) diff --git a/src/Services/Flight/tests/UnitTest/Common/DbContextFactory.cs b/src/Services/Flight/tests/UnitTest/Common/DbContextFactory.cs index d8cc94b..62c5bcb 100644 --- a/src/Services/Flight/tests/UnitTest/Common/DbContextFactory.cs +++ b/src/Services/Flight/tests/UnitTest/Common/DbContextFactory.cs @@ -46,16 +46,16 @@ public static class DbContextFactory var aircrafts = new List { - global::Flight.Aircrafts.Models.Aircraft.Create(_aircraft1, NameValue.Of("Boeing 737"), ModelValue.Of("B737"), ManufacturingYearValue.Of(2005)), - global::Flight.Aircrafts.Models.Aircraft.Create(_aircraft2, NameValue.Of("Airbus 300"), ModelValue.Of("A300"), ManufacturingYearValue.Of(2000)), - global::Flight.Aircrafts.Models.Aircraft.Create(_aircraft3, NameValue.Of("Airbus 320"), ModelValue.Of("A320"), ManufacturingYearValue.Of(2003)) + global::Flight.Aircrafts.Models.Aircraft.Create(AircraftId.Of(_aircraft1), Name.Of("Boeing 737"), Model.Of("B737"), ManufacturingYear.Of(2005)), + global::Flight.Aircrafts.Models.Aircraft.Create(AircraftId.Of(_aircraft2), Name.Of("Airbus 300"), Model.Of("A300"), ManufacturingYear.Of(2000)), + global::Flight.Aircrafts.Models.Aircraft.Create(AircraftId.Of(_aircraft3), Name.Of("Airbus 320"), Model.Of("A320"), ManufacturingYear.Of(2003)) }; context.Aircraft.AddRange(aircrafts); var flights = new List { - global::Flight.Flights.Models.Flight.Create(_flightId1, "BD467", _aircraft1, _airportId1, + 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, diff --git a/src/Services/Flight/tests/UnitTest/Fakes/FakeCreateAircraftCommand.cs b/src/Services/Flight/tests/UnitTest/Fakes/FakeCreateAircraftCommand.cs index 913c900..34d91ef 100644 --- a/src/Services/Flight/tests/UnitTest/Fakes/FakeCreateAircraftCommand.cs +++ b/src/Services/Flight/tests/UnitTest/Fakes/FakeCreateAircraftCommand.cs @@ -1,4 +1,4 @@ -using AutoBogus; +using AutoBogus; namespace Unit.Test.Fakes; diff --git a/src/Services/Flight/tests/UnitTest/Fakes/FakeFlightCreate.cs b/src/Services/Flight/tests/UnitTest/Fakes/FakeFlightCreate.cs index 5d4660b..767b2fa 100644 --- a/src/Services/Flight/tests/UnitTest/Fakes/FakeFlightCreate.cs +++ b/src/Services/Flight/tests/UnitTest/Fakes/FakeFlightCreate.cs @@ -1,4 +1,6 @@ -namespace Unit.Test.Fakes; +namespace Unit.Test.Fakes; + +using global::Flight.Aircrafts.Models.ValueObjects; public static class FakeFlightCreate { @@ -7,7 +9,7 @@ public static class FakeFlightCreate var command = new FakeCreateFlightCommand().Generate(); return global::Flight.Flights.Models.Flight.Create(command.Id, command.FlightNumber, - command.AircraftId, command.DepartureAirportId, command.DepartureDate, + AircraftId.Of(command.AircraftId), command.DepartureAirportId, command.DepartureDate, command.ArriveDate, command.ArriveAirportId, command.DurationMinutes, command.FlightDate, command.Status, command.Price); } diff --git a/src/Services/Passenger/src/Passenger/Data/Configurations/PassengerConfiguration.cs b/src/Services/Passenger/src/Passenger/Data/Configurations/PassengerConfiguration.cs index 9bfeff0..58117a8 100644 --- a/src/Services/Passenger/src/Passenger/Data/Configurations/PassengerConfiguration.cs +++ b/src/Services/Passenger/src/Passenger/Data/Configurations/PassengerConfiguration.cs @@ -3,16 +3,58 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Passenger.Data.Configurations; -public class PassengerConfiguration: IEntityTypeConfiguration +using Passengers.Models.ValueObjects; + +public class PassengerConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { - builder.ToTable(nameof(Passenger)); + builder.ToTable(nameof(Passengers.Models.Passenger)); builder.HasKey(r => r.Id); - builder.Property(r => r.Id).ValueGeneratedNever(); + builder.Property(r => r.Id).ValueGeneratedNever() + .HasConversion(passengerId => passengerId.Value, dbId => PassengerId.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(Passengers.Models.Passenger.Name)) + .HasMaxLength(50) + .IsRequired(); + } + ); + + builder.OwnsOne( + x => x.PassportNumber, + a => + { + a.Property(p => p.Value) + .HasColumnName(nameof(Passengers.Models.Passenger.PassportNumber)) + .HasMaxLength(10) + .IsRequired(); + } + ); + + builder.OwnsOne( + x => x.Age, + a => + { + a.Property(p => p.Value) + .HasColumnName(nameof(Passengers.Models.Passenger.Age)) + .HasMaxLength(3) + .IsRequired(); + } + ); + + builder.Property(x => x.PassengerType) + .IsRequired() + .HasDefaultValue(Passengers.Enums.PassengerType.Unknown) + .HasConversion( + x => x.ToString(), + x => (Passengers.Enums.PassengerType)Enum.Parse(typeof(Passengers.Enums.PassengerType), x)); } } diff --git a/src/Services/Passenger/src/Passenger/Data/Migrations/20230524195049_AddValueObject.Designer.cs b/src/Services/Passenger/src/Passenger/Data/Migrations/20230524195049_AddValueObject.Designer.cs new file mode 100644 index 0000000..f5359cc --- /dev/null +++ b/src/Services/Passenger/src/Passenger/Data/Migrations/20230524195049_AddValueObject.Designer.cs @@ -0,0 +1,148 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Passenger.Data; + +#nullable disable + +namespace Passenger.Data.Migrations +{ + [DbContext(typeof(PassengerDbContext))] + [Migration("20230524195049_AddValueObject")] + partial class AddValueObject + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Passenger.Passengers.Models.Passenger", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without 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 without time zone") + .HasColumnName("last_modified"); + + b.Property("LastModifiedBy") + .HasColumnType("bigint") + .HasColumnName("last_modified_by"); + + b.Property("PassengerType") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("text") + .HasDefaultValue("Unknown") + .HasColumnName("passenger_type"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("bigint") + .HasColumnName("version"); + + b.HasKey("Id") + .HasName("pk_passenger"); + + b.ToTable("passenger", (string)null); + }); + + modelBuilder.Entity("Passenger.Passengers.Models.Passenger", b => + { + b.OwnsOne("Passenger.Passengers.Models.ValueObjects.Age", "Age", b1 => + { + b1.Property("PassengerId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .HasMaxLength(3) + .HasColumnType("integer") + .HasColumnName("age"); + + b1.HasKey("PassengerId") + .HasName("pk_passenger"); + + b1.ToTable("passenger"); + + b1.WithOwner() + .HasForeignKey("PassengerId") + .HasConstraintName("fk_passenger_passenger_id"); + }); + + b.OwnsOne("Passenger.Passengers.Models.ValueObjects.Name", "Name", b1 => + { + b1.Property("PassengerId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("name"); + + b1.HasKey("PassengerId") + .HasName("pk_passenger"); + + b1.ToTable("passenger"); + + b1.WithOwner() + .HasForeignKey("PassengerId") + .HasConstraintName("fk_passenger_passenger_id"); + }); + + b.OwnsOne("Passenger.Passengers.Models.ValueObjects.PassportNumber", "PassportNumber", b1 => + { + b1.Property("PassengerId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("passport_number"); + + b1.HasKey("PassengerId") + .HasName("pk_passenger"); + + b1.ToTable("passenger"); + + b1.WithOwner() + .HasForeignKey("PassengerId") + .HasConstraintName("fk_passenger_passenger_id"); + }); + + b.Navigation("Age"); + + b.Navigation("Name"); + + b.Navigation("PassportNumber"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Services/Passenger/src/Passenger/Data/Migrations/20230524195049_AddValueObject.cs b/src/Services/Passenger/src/Passenger/Data/Migrations/20230524195049_AddValueObject.cs new file mode 100644 index 0000000..95f7654 --- /dev/null +++ b/src/Services/Passenger/src/Passenger/Data/Migrations/20230524195049_AddValueObject.cs @@ -0,0 +1,133 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Passenger.Data.Migrations +{ + /// + public partial class AddValueObject : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "passport_number", + table: "passenger", + type: "character varying(10)", + maxLength: 10, + nullable: true, + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "passenger_type", + table: "passenger", + type: "text", + nullable: false, + defaultValue: "Unknown", + oldClrType: typeof(int), + oldType: "integer"); + + migrationBuilder.AlterColumn( + name: "name", + table: "passenger", + type: "character varying(50)", + maxLength: 50, + nullable: true, + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "last_modified", + table: "passenger", + type: "timestamp without time zone", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "created_at", + table: "passenger", + type: "timestamp without time zone", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "age", + table: "passenger", + type: "integer", + maxLength: 3, + nullable: true, + oldClrType: typeof(int), + oldType: "integer"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "passport_number", + table: "passenger", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(10)", + oldMaxLength: 10, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "passenger_type", + table: "passenger", + type: "integer", + nullable: false, + oldClrType: typeof(string), + oldType: "text", + oldDefaultValue: "Unknown"); + + migrationBuilder.AlterColumn( + name: "name", + table: "passenger", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(50)", + oldMaxLength: 50, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "last_modified", + table: "passenger", + type: "timestamp with time zone", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp without time zone", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "created_at", + table: "passenger", + type: "timestamp with time zone", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp without time zone", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "age", + table: "passenger", + type: "integer", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "integer", + oldMaxLength: 3, + oldNullable: true); + } + } +} diff --git a/src/Services/Passenger/src/Passenger/Data/Migrations/20230526085126_change-behavior.Designer.cs b/src/Services/Passenger/src/Passenger/Data/Migrations/20230526085126_change-behavior.Designer.cs new file mode 100644 index 0000000..83dc119 --- /dev/null +++ b/src/Services/Passenger/src/Passenger/Data/Migrations/20230526085126_change-behavior.Designer.cs @@ -0,0 +1,148 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Passenger.Data; + +#nullable disable + +namespace Passenger.Data.Migrations +{ + [DbContext(typeof(PassengerDbContext))] + [Migration("20230526085126_change-behavior")] + partial class changebehavior + { + /// + 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("Passenger.Passengers.Models.Passenger", 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("PassengerType") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("text") + .HasDefaultValue("Unknown") + .HasColumnName("passenger_type"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("bigint") + .HasColumnName("version"); + + b.HasKey("Id") + .HasName("pk_passenger"); + + b.ToTable("passenger", (string)null); + }); + + modelBuilder.Entity("Passenger.Passengers.Models.Passenger", b => + { + b.OwnsOne("Passenger.Passengers.Models.ValueObjects.Age", "Age", b1 => + { + b1.Property("PassengerId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .HasMaxLength(3) + .HasColumnType("integer") + .HasColumnName("age"); + + b1.HasKey("PassengerId") + .HasName("pk_passenger"); + + b1.ToTable("passenger"); + + b1.WithOwner() + .HasForeignKey("PassengerId") + .HasConstraintName("fk_passenger_passenger_id"); + }); + + b.OwnsOne("Passenger.Passengers.Models.ValueObjects.Name", "Name", b1 => + { + b1.Property("PassengerId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("name"); + + b1.HasKey("PassengerId") + .HasName("pk_passenger"); + + b1.ToTable("passenger"); + + b1.WithOwner() + .HasForeignKey("PassengerId") + .HasConstraintName("fk_passenger_passenger_id"); + }); + + b.OwnsOne("Passenger.Passengers.Models.ValueObjects.PassportNumber", "PassportNumber", b1 => + { + b1.Property("PassengerId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("passport_number"); + + b1.HasKey("PassengerId") + .HasName("pk_passenger"); + + b1.ToTable("passenger"); + + b1.WithOwner() + .HasForeignKey("PassengerId") + .HasConstraintName("fk_passenger_passenger_id"); + }); + + b.Navigation("Age"); + + b.Navigation("Name"); + + b.Navigation("PassportNumber"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Services/Passenger/src/Passenger/Data/Migrations/20230526085126_change-behavior.cs b/src/Services/Passenger/src/Passenger/Data/Migrations/20230526085126_change-behavior.cs new file mode 100644 index 0000000..954e4f6 --- /dev/null +++ b/src/Services/Passenger/src/Passenger/Data/Migrations/20230526085126_change-behavior.cs @@ -0,0 +1,55 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Passenger.Data.Migrations +{ + /// + public partial class changebehavior : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "last_modified", + table: "passenger", + type: "timestamp with time zone", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp without time zone", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "created_at", + table: "passenger", + type: "timestamp with time zone", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp without time zone", + oldNullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "last_modified", + table: "passenger", + type: "timestamp without time zone", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "created_at", + table: "passenger", + type: "timestamp without time zone", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone", + oldNullable: true); + } + } +} diff --git a/src/Services/Passenger/src/Passenger/Data/Migrations/PassengerDbContextModelSnapshot.cs b/src/Services/Passenger/src/Passenger/Data/Migrations/PassengerDbContextModelSnapshot.cs index 2614a28..96a7468 100644 --- a/src/Services/Passenger/src/Passenger/Data/Migrations/PassengerDbContextModelSnapshot.cs +++ b/src/Services/Passenger/src/Passenger/Data/Migrations/PassengerDbContextModelSnapshot.cs @@ -28,10 +28,6 @@ namespace Passenger.Data.Migrations .HasColumnType("uuid") .HasColumnName("id"); - b.Property("Age") - .HasColumnType("integer") - .HasColumnName("age"); - b.Property("CreatedAt") .HasColumnType("timestamp with time zone") .HasColumnName("created_at"); @@ -52,18 +48,13 @@ namespace Passenger.Data.Migrations .HasColumnType("bigint") .HasColumnName("last_modified_by"); - b.Property("Name") + b.Property("PassengerType") + .IsRequired() + .ValueGeneratedOnAdd() .HasColumnType("text") - .HasColumnName("name"); - - b.Property("PassengerType") - .HasColumnType("integer") + .HasDefaultValue("Unknown") .HasColumnName("passenger_type"); - b.Property("PassportNumber") - .HasColumnType("text") - .HasColumnName("passport_number"); - b.Property("Version") .IsConcurrencyToken() .HasColumnType("bigint") @@ -74,6 +65,80 @@ namespace Passenger.Data.Migrations b.ToTable("passenger", (string)null); }); + + modelBuilder.Entity("Passenger.Passengers.Models.Passenger", b => + { + b.OwnsOne("Passenger.Passengers.Models.ValueObjects.Age", "Age", b1 => + { + b1.Property("PassengerId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .HasMaxLength(3) + .HasColumnType("integer") + .HasColumnName("age"); + + b1.HasKey("PassengerId") + .HasName("pk_passenger"); + + b1.ToTable("passenger"); + + b1.WithOwner() + .HasForeignKey("PassengerId") + .HasConstraintName("fk_passenger_passenger_id"); + }); + + b.OwnsOne("Passenger.Passengers.Models.ValueObjects.Name", "Name", b1 => + { + b1.Property("PassengerId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("name"); + + b1.HasKey("PassengerId") + .HasName("pk_passenger"); + + b1.ToTable("passenger"); + + b1.WithOwner() + .HasForeignKey("PassengerId") + .HasConstraintName("fk_passenger_passenger_id"); + }); + + b.OwnsOne("Passenger.Passengers.Models.ValueObjects.PassportNumber", "PassportNumber", b1 => + { + b1.Property("PassengerId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("passport_number"); + + b1.HasKey("PassengerId") + .HasName("pk_passenger"); + + b1.ToTable("passenger"); + + b1.WithOwner() + .HasForeignKey("PassengerId") + .HasConstraintName("fk_passenger_passenger_id"); + }); + + b.Navigation("Age"); + + b.Navigation("Name"); + + b.Navigation("PassportNumber"); + }); #pragma warning restore 612, 618 } } diff --git a/src/Services/Passenger/src/Passenger/Data/PassengerDbContext.cs b/src/Services/Passenger/src/Passenger/Data/PassengerDbContext.cs index 57ff89f..3f855eb 100644 --- a/src/Services/Passenger/src/Passenger/Data/PassengerDbContext.cs +++ b/src/Services/Passenger/src/Passenger/Data/PassengerDbContext.cs @@ -1,7 +1,7 @@ using System.Reflection; using BuildingBlocks.EFCore; -using Microsoft.EntityFrameworkCore; using BuildingBlocks.Web; +using Microsoft.EntityFrameworkCore; namespace Passenger.Data; diff --git a/src/Services/Passenger/src/Passenger/Exceptions/InvalidPassengerIdExceptions.cs b/src/Services/Passenger/src/Passenger/Exceptions/InvalidPassengerIdExceptions.cs new file mode 100644 index 0000000..c35ae6d --- /dev/null +++ b/src/Services/Passenger/src/Passenger/Exceptions/InvalidPassengerIdExceptions.cs @@ -0,0 +1,12 @@ +namespace Passenger.Exceptions; +using System; + +using BuildingBlocks.Exception; + +public class InvalidPassengerIdExceptions : BadRequestException +{ + public InvalidPassengerIdExceptions(Guid passengerId) + : base($"PassengerId: '{passengerId}' is invalid.") + { + } +} diff --git a/src/Services/Passenger/src/Passenger/Identity/Consumers/RegisteringNewUser/V1/RegisterNewUser.cs b/src/Services/Passenger/src/Passenger/Identity/Consumers/RegisteringNewUser/V1/RegisterNewUser.cs index cae62d6..db64e39 100644 --- a/src/Services/Passenger/src/Passenger/Identity/Consumers/RegisteringNewUser/V1/RegisterNewUser.cs +++ b/src/Services/Passenger/src/Passenger/Identity/Consumers/RegisteringNewUser/V1/RegisterNewUser.cs @@ -38,15 +38,15 @@ public class RegisterNewUserHandler : IConsumer _logger.LogInformation($"consumer for {nameof(UserCreated).Underscore()} in {_options.Name}"); var passengerExist = - await _passengerDbContext.Passengers.AnyAsync(x => x.PassportNumber == context.Message.PassportNumber); + await _passengerDbContext.Passengers.AnyAsync(x => x.PassportNumber == PassportNumber.Of(context.Message.PassportNumber)); if (passengerExist) { return; } - var passenger = Passengers.Models.Passenger.Create(NewId.NextGuid(), NameValue.Of(context.Message.Name), - PassportNumberValue.Of(context.Message.PassportNumber)); + var passenger = Passengers.Models.Passenger.Create(PassengerId.Of(NewId.NextGuid()), Name.Of(context.Message.Name), + PassportNumber.Of(context.Message.PassportNumber)); await _passengerDbContext.AddAsync(passenger); diff --git a/src/Services/Passenger/src/Passenger/Passengers/Dtos/PassengerDto.cs b/src/Services/Passenger/src/Passenger/Passengers/Dtos/PassengerDto.cs index 12b61cd..17fad5c 100644 --- a/src/Services/Passenger/src/Passenger/Passengers/Dtos/PassengerDto.cs +++ b/src/Services/Passenger/src/Passenger/Passengers/Dtos/PassengerDto.cs @@ -1,3 +1,2 @@ namespace Passenger.Passengers.Dtos; - public record PassengerDto(Guid Id, string Name, string PassportNumber, Enums.PassengerType PassengerType, int Age); diff --git a/src/Services/Passenger/src/Passenger/Passengers/Features/CompletingRegisterPassenger/V1/CompleteRegisterPassenger.cs b/src/Services/Passenger/src/Passenger/Passengers/Features/CompletingRegisterPassenger/V1/CompleteRegisterPassenger.cs index 5681936..bfec595 100644 --- a/src/Services/Passenger/src/Passenger/Passengers/Features/CompletingRegisterPassenger/V1/CompleteRegisterPassenger.cs +++ b/src/Services/Passenger/src/Passenger/Passengers/Features/CompletingRegisterPassenger/V1/CompleteRegisterPassenger.cs @@ -96,8 +96,11 @@ internal class CompleteRegisterPassengerCommandHandler : ICommandHandler x.PassportNumber == request.PassportNumber, cancellationToken); + //var passenger = await _passengerDbContext.Passengers.AsNoTracking().SingleOrDefaultAsync( + // x => x.PassportNumber == PassportNumber.Of(request.PassportNumber), cancellationToken); + + var passenger = _passengerDbContext.Passengers.AsEnumerable() + .FirstOrDefault(a => a.PassportNumber.Equals(PassportNumber.Of(request.PassportNumber))); if (passenger is null) { @@ -105,7 +108,7 @@ internal class CompleteRegisterPassengerCommandHandler : ICommandHandler(request); var passenger = await _passengerReadDbContext.Passenger.AsQueryable() - .FirstOrDefaultAsync(x => x.PassengerId == passengerReadModel.PassengerId && !x.IsDeleted, cancellationToken); + .FirstOrDefaultAsync(x => x.PassengerId == PassengerId.Of(passengerReadModel.PassengerId) && !x.IsDeleted, cancellationToken); if (passenger is not null) { await _passengerReadDbContext.Passenger.UpdateOneAsync( - x => x.PassengerId == passengerReadModel.PassengerId, + x => x.PassengerId == PassengerId.Of(passengerReadModel.PassengerId), Builders.Update - .Set(x => x.PassengerId, passengerReadModel.PassengerId) + .Set(x => x.PassengerId, PassengerId.Of(passengerReadModel.PassengerId)) .Set(x => x.Age, passengerReadModel.Age) .Set(x => x.Name, passengerReadModel.Name) .Set(x => x.IsDeleted, passengerReadModel.IsDeleted) diff --git a/src/Services/Passenger/src/Passenger/Passengers/Features/GettingPassengerById/Queries/V1/GetPassengerById.cs b/src/Services/Passenger/src/Passenger/Passengers/Features/GettingPassengerById/Queries/V1/GetPassengerById.cs index bfe3428..911108c 100644 --- a/src/Services/Passenger/src/Passenger/Passengers/Features/GettingPassengerById/Queries/V1/GetPassengerById.cs +++ b/src/Services/Passenger/src/Passenger/Passengers/Features/GettingPassengerById/Queries/V1/GetPassengerById.cs @@ -1,18 +1,19 @@ namespace Passenger.Passengers.Features.GettingPassengerById.Queries.V1; +using Ardalis.GuardClauses; using BuildingBlocks.Core.CQRS; +using BuildingBlocks.Web; using Data; using Dtos; -using FluentValidation; -using MapsterMapper; -using Ardalis.GuardClauses; -using BuildingBlocks.Web; using Duende.IdentityServer.EntityFramework.Entities; using Exceptions; +using FluentValidation; +using MapsterMapper; using MediatR; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; +using Models.ValueObjects; using MongoDB.Driver; using MongoDB.Driver.Linq; @@ -74,7 +75,7 @@ internal class GetPassengerByIdHandler : IQueryHandler x.PassengerId == query.Id && x.IsDeleted == false, cancellationToken); + .SingleOrDefaultAsync(x => x.PassengerId == PassengerId.Of(query.Id) && x.IsDeleted == false, cancellationToken); if (passenger is null) { diff --git a/src/Services/Passenger/src/Passenger/Passengers/Features/PassengerMappings.cs b/src/Services/Passenger/src/Passenger/Passengers/Features/PassengerMappings.cs index 2e59b3c..a0aebb2 100644 --- a/src/Services/Passenger/src/Passenger/Passengers/Features/PassengerMappings.cs +++ b/src/Services/Passenger/src/Passenger/Passengers/Features/PassengerMappings.cs @@ -6,14 +6,15 @@ using CompletingRegisterPassenger.V1; using Dtos; using MassTransit; using Models; +using Passenger.Passengers.Models.ValueObjects; public class PassengerMappings : IRegister { public void Register(TypeAdapterConfig config) { config.NewConfig() - .Map(d => d.Id, s => NewId.NextGuid()) - .Map(d => d.PassengerId, s => s.Id); + .Map(d => d.Id, s => NewId.NextGuid()) + .Map(d => d.PassengerId, s => PassengerId.Of(s.Id)); config.NewConfig() .ConstructUsing(x => new CompleteRegisterPassenger(x.PassportNumber, x.PassengerType, x.Age)); diff --git a/src/Services/Passenger/src/Passenger/Passengers/Models/Passenger.cs b/src/Services/Passenger/src/Passenger/Passengers/Models/Passenger.cs index d1dd8fc..0424c23 100644 --- a/src/Services/Passenger/src/Passenger/Passengers/Models/Passenger.cs +++ b/src/Services/Passenger/src/Passenger/Passengers/Models/Passenger.cs @@ -6,9 +6,14 @@ using Features.CompletingRegisterPassenger.V1; using global::Passenger.Passengers.Models.ValueObjects; using Identity.Consumers.RegisteringNewUser.V1; -public record Passenger : Aggregate +public record Passenger : Aggregate { - public Passenger CompleteRegistrationPassenger(Guid id, NameValue name, PassportNumberValue passportNumber, Enums.PassengerType passengerType, AgeValue age, bool isDeleted = false) + public PassportNumber PassportNumber { get; private set; } + public Name Name { get; private set; } + public Enums.PassengerType PassengerType { get; private set; } + public Age Age { get; private set; } + + public Passenger CompleteRegistrationPassenger(PassengerId id, Name name, PassportNumber passportNumber, Enums.PassengerType passengerType, Age age, bool isDeleted = false) { var passenger = new Passenger { @@ -29,7 +34,7 @@ public record Passenger : Aggregate } - public static Passenger Create(Guid id, NameValue name, PassportNumberValue passportNumber, bool isDeleted = false) + public static Passenger Create(PassengerId id, Name name, PassportNumber passportNumber, bool isDeleted = false) { var passenger = new Passenger { Id = id, Name = name, PassportNumber = passportNumber, IsDeleted = isDeleted }; @@ -39,10 +44,4 @@ public record Passenger : Aggregate return passenger; } - - - public PassportNumberValue PassportNumber { get; private set; } - public NameValue Name { get; private set; } - public Enums.PassengerType PassengerType { get; private set; } - public AgeValue Age { get; private set; } } diff --git a/src/Services/Passenger/src/Passenger/Passengers/Models/PassengerReadModel.cs b/src/Services/Passenger/src/Passenger/Passengers/Models/PassengerReadModel.cs index 8225399..faa64a3 100644 --- a/src/Services/Passenger/src/Passenger/Passengers/Models/PassengerReadModel.cs +++ b/src/Services/Passenger/src/Passenger/Passengers/Models/PassengerReadModel.cs @@ -1,5 +1,4 @@ -namespace Passenger.Passengers.Models; - +namespace Passenger.Passengers.Models; public class PassengerReadModel { public required Guid Id { get; init; } diff --git a/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/AgeValue.cs b/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/Age.cs similarity index 57% rename from src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/AgeValue.cs rename to src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/Age.cs index 5354395..7a13ee6 100644 --- a/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/AgeValue.cs +++ b/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/Age.cs @@ -1,9 +1,9 @@ namespace Passenger.Passengers.Models.ValueObjects; using System; -public record AgeValue : GenericValueObject +public record Age : GenericValueObject { - public AgeValue(int value) : base(value) + public Age(int value) : base(value) { if (value < 0) { @@ -11,8 +11,8 @@ public record AgeValue : GenericValueObject } Value = value; } - public static AgeValue Of(int value) + public static Age Of(int value) { - return new AgeValue(value); + return new Age(value); } } diff --git a/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/NameValue.cs b/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/Name.cs similarity index 58% rename from src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/NameValue.cs rename to src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/Name.cs index b34b381..aa35d74 100644 --- a/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/NameValue.cs +++ b/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/Name.cs @@ -1,9 +1,9 @@ namespace Passenger.Passengers.Models.ValueObjects; using System; -public record NameValue : GenericValueObject +public record Name : GenericValueObject { - public NameValue(string value) : base(value) + public Name(string value) : base(value) { if (string.IsNullOrWhiteSpace(value)) { @@ -11,8 +11,8 @@ public record NameValue : GenericValueObject } Value = value; } - public static NameValue Of(string value) + public static Name Of(string value) { - return new NameValue(value); + return new Name(value); } } diff --git a/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/PassengerId.cs b/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/PassengerId.cs new file mode 100644 index 0000000..c3cedfa --- /dev/null +++ b/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/PassengerId.cs @@ -0,0 +1,28 @@ +namespace Passenger.Passengers.Models.ValueObjects; +using System; +using global::Passenger.Exceptions; + +public record PassengerId +{ + public Guid Value { get; } + + private PassengerId(Guid value) + { + if (value == Guid.Empty) + { + throw new InvalidPassengerIdExceptions(value); + } + + Value = value; + } + + public static PassengerId Of(Guid value) + { + return new PassengerId(value); + } + + public static implicit operator Guid(PassengerId passengerId) + { + return passengerId.Value; + } +} diff --git a/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/PassportNumber.cs b/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/PassportNumber.cs new file mode 100644 index 0000000..28e0aec --- /dev/null +++ b/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/PassportNumber.cs @@ -0,0 +1,67 @@ +namespace Passenger.Passengers.Models.ValueObjects; +using System; + + +//public record PassportNumber : GenericValueObject +//{ + +// public PassportNumber(string value) : base(value) +// { +// if (string.IsNullOrWhiteSpace(value)) +// { +// throw new ArgumentException("Passport number cannot be empty or whitespace."); +// } +// Value = value; +// } +// public static PassportNumber Of(string value) +// { +// return new PassportNumber(value); +// } +//} +//public record PassportNumber +//{ +// public string Value { get; } + +// public PassportNumber(string value) +// { +// if (string.IsNullOrWhiteSpace(value)) +// { +// throw new ArgumentException("Passport number cannot be empty or whitespace."); +// } +// Value = value; +// } + +// public static PassportNumber Of(string value) +// { +// return new PassportNumber(value); +// } + +// public static implicit operator string(PassportNumber aircraftId) +// { +// return aircraftId.Value; +// } +//} +public record PassportNumber +{ + public string Value { get; } + + public override string ToString() + { + return Value; + } + + private PassportNumber(string value) + { + if (string.IsNullOrWhiteSpace(value)) + { + throw new ArgumentException("Passport number cannot be empty or whitespace."); + } + Value = value; + } + + public static PassportNumber Of(string value) + { + return new PassportNumber(value); + } + public static implicit operator string(PassportNumber passportNumber) => passportNumber.Value; +} diff --git a/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/PassportNumberValue.cs b/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/PassportNumberValue.cs deleted file mode 100644 index 436f388..0000000 --- a/src/Services/Passenger/src/Passenger/Passengers/Models/ValueObjects/PassportNumberValue.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Passenger.Passengers.Models.ValueObjects; -using System; - - -public record PassportNumberValue : GenericValueObject -{ - public PassportNumberValue(string value) : base(value) - { - if (string.IsNullOrWhiteSpace(value)) - { - throw new ArgumentException("Passport number cannot be empty or whitespace."); - } - Value = value; - } - public static PassportNumberValue Of(string value) - { - return new PassportNumberValue(value); - } -} diff --git a/src/Services/Passenger/tests/IntegrationTest/Passenger/Features/CompleteRegisterPassengerTests.cs b/src/Services/Passenger/tests/IntegrationTest/Passenger/Features/CompleteRegisterPassengerTests.cs index 7d5c436..ecc88af 100644 --- a/src/Services/Passenger/tests/IntegrationTest/Passenger/Features/CompleteRegisterPassengerTests.cs +++ b/src/Services/Passenger/tests/IntegrationTest/Passenger/Features/CompleteRegisterPassengerTests.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using BuildingBlocks.Contracts.EventBus.Messages; using BuildingBlocks.TestBase; using FluentAssertions; @@ -8,9 +8,9 @@ using Passenger.Data; using Xunit; namespace Integration.Test.Passenger.Features; - public class CompleteRegisterPassengerTests : PassengerIntegrationTestBase { + public CompleteRegisterPassengerTests( TestFixture integrationTestFactory) : base(integrationTestFactory) { @@ -23,8 +23,8 @@ public class CompleteRegisterPassengerTests : PassengerIntegrationTestBase var userCreated = new FakeUserCreated().Generate(); await Fixture.Publish(userCreated); - await Fixture.WaitForPublishing(); - await Fixture.WaitForConsuming(); + (await Fixture.WaitForPublishing()).Should().Be(true); + (await Fixture.WaitForConsuming()).Should().Be(true); var command = new FakeCompleteRegisterPassengerCommand(userCreated.PassportNumber).Generate();