AddValueObjects(Seats/Flights/Airports)

This commit is contained in:
amir.gholami 2023-06-09 21:37:03 +03:30
parent 39bee67fa1
commit 343d0d63c6
57 changed files with 2087 additions and 229 deletions

View File

@ -33,6 +33,10 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />
<PackageReference Include="Mongo2Go" Version="3.1.3" /> <PackageReference Include="Mongo2Go" Version="3.1.3" />
<PackageReference Include="Npgsql" Version="7.0.1" /> <PackageReference Include="Npgsql" Version="7.0.1" />

View File

@ -0,0 +1,9 @@
namespace Flight.Airports.Exceptions;
using BuildingBlocks.Exception;
public class InvalidAddressException : BadRequestException
{
public InvalidAddressException() : base("Address cannot be empty or whitespace.")
{
}
}

View File

@ -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.")
{
}
}

View File

@ -0,0 +1,10 @@
namespace Flight.Airports.Exceptions;
using BuildingBlocks.Exception;
public class InvalidCodeException : BadRequestException
{
public InvalidCodeException() : base("Code cannot be empty or whitespace.")
{
}
}

View File

@ -0,0 +1,10 @@
namespace Flight.Airports.Exceptions;
using BuildingBlocks.Exception;
public class InvalidNameException : BadRequestException
{
public InvalidNameException() : base("Name cannot be empty or whitespace.")
{
}
}

View File

@ -1,9 +1,9 @@
namespace Flight.Airports.Features; namespace Flight.Airports.Features;
using CreatingAirport.V1; using CreatingAirport.V1;
using Models;
using Mapster; using Mapster;
using MassTransit; using MassTransit;
using Models;
public class AirportMappings : IRegister public class AirportMappings : IRegister
{ {
@ -15,7 +15,7 @@ public class AirportMappings : IRegister
config.NewConfig<Airport, AirportReadModel>() config.NewConfig<Airport, AirportReadModel>()
.Map(d => d.Id, s => NewId.NextGuid()) .Map(d => d.Id, s => NewId.NextGuid())
.Map(d => d.AirportId, s => s.Id); .Map(d => d.AirportId, s => s.Id.Value);
config.NewConfig<CreateAirportRequestDto, CreateAirport>() config.NewConfig<CreateAirportRequestDto, CreateAirport>()
.ConstructUsing(x => new CreateAirport(x.Name, x.Address, x.Code)); .ConstructUsing(x => new CreateAirport(x.Name, x.Address, x.Code));

View File

@ -7,9 +7,9 @@ using Ardalis.GuardClauses;
using BuildingBlocks.Core.CQRS; using BuildingBlocks.Core.CQRS;
using BuildingBlocks.Core.Event; using BuildingBlocks.Core.Event;
using BuildingBlocks.Web; using BuildingBlocks.Web;
using Exceptions;
using Data; using Data;
using Duende.IdentityServer.EntityFramework.Entities; using Duende.IdentityServer.EntityFramework.Entities;
using Exceptions;
using FluentValidation; using FluentValidation;
using MapsterMapper; using MapsterMapper;
using MassTransit; using MassTransit;
@ -18,6 +18,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using ValueObjects;
public record CreateAirport(string Name, string Address, string Code) : ICommand<CreateAirportResult>, IInternalCommand public record CreateAirport(string Name, string Address, string Code) : ICommand<CreateAirportResult>, IInternalCommand
{ {
@ -87,17 +88,17 @@ internal class CreateAirportHandler : IRequestHandler<CreateAirport, CreateAirpo
Guard.Against.Null(request, nameof(request)); Guard.Against.Null(request, nameof(request));
var airport = 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) if (airport is not null)
{ {
throw new AirportAlreadyExistException(); 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; var newAirport = (await _flightDbContext.Airports.AddAsync(airportEntity, cancellationToken))?.Entity;
return new CreateAirportResult(newAirport.Id); return new CreateAirportResult(newAirport.Id.Value);
} }
} }

View File

@ -2,16 +2,16 @@ using BuildingBlocks.Core.Model;
namespace Flight.Airports.Models; namespace Flight.Airports.Models;
using System;
using Features.CreatingAirport.V1; using Features.CreatingAirport.V1;
using Flight.Airports.ValueObjects;
public record Airport : Aggregate<Guid> public record Airport : Aggregate<AirportId>
{ {
public string Name { get; private set; } public Name Name { get; private set; } = default!;
public string Address { get; private set; } public Address Address { get; private set; } = default!;
public string Code { get; private set; } 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 var airport = new Airport
{ {
@ -22,10 +22,10 @@ public record Airport : Aggregate<Guid>
}; };
var @event = new AirportCreatedDomainEvent( var @event = new AirportCreatedDomainEvent(
airport.Id, airport.Id.Value,
airport.Name, airport.Name.Value,
airport.Address, airport.Address.Value,
airport.Code, airport.Code.Value,
isDeleted); isDeleted);
airport.AddDomainEvent(@event); airport.AddDomainEvent(@event);

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -1,10 +1,13 @@
using System;
using Flight.Airports.Models; using Flight.Airports.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Flight.Data.Configurations; namespace Flight.Data.Configurations;
public class AirportConfiguration: IEntityTypeConfiguration<Airport> using Airports.ValueObjects;
public class AirportConfiguration : IEntityTypeConfiguration<Airport>
{ {
public void Configure(EntityTypeBuilder<Airport> builder) public void Configure(EntityTypeBuilder<Airport> builder)
{ {
@ -12,10 +15,43 @@ public class AirportConfiguration: IEntityTypeConfiguration<Airport>
builder.ToTable(nameof(Airport)); builder.ToTable(nameof(Airport));
builder.HasKey(r => r.Id); builder.HasKey(r => r.Id);
builder.Property(r => r.Id).ValueGeneratedNever(); builder.Property(r => r.Id).ValueGeneratedNever()
.HasConversion<Guid>(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.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();
}
);
} }
} }

View File

@ -1,4 +1,3 @@
using BuildingBlocks.EFCore;
using Flight.Aircrafts.Models; using Flight.Aircrafts.Models;
using Flight.Airports.Models; using Flight.Airports.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -7,6 +6,8 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Flight.Data.Configurations; namespace Flight.Data.Configurations;
using System; using System;
using Flights.Models;
using Flights.ValueObjects;
public class FlightConfiguration : IEntityTypeConfiguration<Flights.Models.Flight> public class FlightConfiguration : IEntityTypeConfiguration<Flights.Models.Flight>
{ {
@ -15,12 +16,23 @@ public class FlightConfiguration : IEntityTypeConfiguration<Flights.Models.Fligh
builder.ToTable(nameof(Flight)); builder.ToTable(nameof(Flight));
builder.HasKey(r => r.Id); builder.HasKey(r => r.Id);
builder.Property(r => r.Id).ValueGeneratedNever(); builder.Property(r => r.Id).ValueGeneratedNever()
.HasConversion<Guid>(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.Property(r => r.Version).IsConcurrencyToken();
builder.OwnsOne(
x => x.FlightNumber,
a =>
{
a.Property(p => p.Value)
.HasColumnName(nameof(Flight.FlightNumber))
.HasMaxLength(50)
.IsRequired();
}
);
builder builder
.HasOne<Aircraft>() .HasOne<Aircraft>()
.WithMany() .WithMany()
@ -29,9 +41,30 @@ public class FlightConfiguration : IEntityTypeConfiguration<Flights.Models.Fligh
builder builder
.HasOne<Airport>() .HasOne<Airport>()
.WithMany() .WithMany()
.HasForeignKey(d => d.DepartureAirportId) .HasForeignKey(d => d.DepartureAirportId);
.HasForeignKey(a => a.ArriveAirportId);
builder
.HasOne<Airport>()
.WithMany()
.HasForeignKey(d => d.ArriveAirportId);
//builder
// .HasOne<Airport>()
// .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) builder.Property(x => x.Status)
.HasDefaultValue(Flights.Enums.FlightStatus.Unknown) .HasDefaultValue(Flights.Enums.FlightStatus.Unknown)
@ -39,15 +72,45 @@ public class FlightConfiguration : IEntityTypeConfiguration<Flights.Models.Fligh
x => x.ToString(), x => x.ToString(),
x => (Flights.Enums.FlightStatus)Enum.Parse(typeof(Flights.Enums.FlightStatus), x)); x => (Flights.Enums.FlightStatus)Enum.Parse(typeof(Flights.Enums.FlightStatus), x));
// // https://docs.microsoft.com/en-us/ef/core/modeling/shadow-properties builder.OwnsOne(
// // https://docs.microsoft.com/en-us/ef/core/modeling/owned-entities x => x.Price,
// builder.OwnsMany(p => p.Seats, a => a =>
// { {
// a.WithOwner().HasForeignKey("FlightId"); a.Property(p => p.Value)
// a.Property<long>("Id"); .HasColumnName(nameof(Flight.Price))
// a.HasKey("Id"); .HasMaxLength(10)
// a.Property<long>("FlightId"); .IsRequired();
// a.ToTable("Seat"); }
// }); );
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();
}
);
} }
} }

View File

@ -1,4 +1,3 @@
using BuildingBlocks.EFCore;
using Flight.Seats.Models; using Flight.Seats.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Builders;
@ -6,6 +5,7 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Flight.Data.Configurations; namespace Flight.Data.Configurations;
using System; using System;
using Seats.ValueObjects;
public class SeatConfiguration : IEntityTypeConfiguration<Seat> public class SeatConfiguration : IEntityTypeConfiguration<Seat>
{ {
@ -14,10 +14,21 @@ public class SeatConfiguration : IEntityTypeConfiguration<Seat>
builder.ToTable(nameof(Seat)); builder.ToTable(nameof(Seat));
builder.HasKey(r => r.Id); builder.HasKey(r => r.Id);
builder.Property(r => r.Id).ValueGeneratedNever(); builder.Property(r => r.Id).ValueGeneratedNever()
.HasConversion<Guid>(seatId => seatId.Value, dbId => SeatId.Of(dbId));
// // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api builder.Property(r => r.Version).IsConcurrencyToken();
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 builder
.HasOne<Flights.Models.Flight>() .HasOne<Flights.Models.Flight>()

View File

@ -0,0 +1,573 @@
// <auto-generated />
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
{
/// <inheritdoc />
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<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<DateTime?>("CreatedAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at");
b.Property<long?>("CreatedBy")
.HasColumnType("bigint")
.HasColumnName("created_by");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean")
.HasColumnName("is_deleted");
b.Property<DateTime?>("LastModified")
.HasColumnType("timestamp with time zone")
.HasColumnName("last_modified");
b.Property<long?>("LastModifiedBy")
.HasColumnType("bigint")
.HasColumnName("last_modified_by");
b.Property<long>("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<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<DateTime?>("CreatedAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at");
b.Property<long?>("CreatedBy")
.HasColumnType("bigint")
.HasColumnName("created_by");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean")
.HasColumnName("is_deleted");
b.Property<DateTime?>("LastModified")
.HasColumnType("timestamp with time zone")
.HasColumnName("last_modified");
b.Property<long?>("LastModifiedBy")
.HasColumnType("bigint")
.HasColumnName("last_modified_by");
b.Property<long>("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<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<Guid>("AircraftId")
.HasColumnType("uuid")
.HasColumnName("aircraft_id");
b.Property<Guid?>("ArriveAirportId")
.HasColumnType("uuid")
.HasColumnName("arrive_airport_id");
b.Property<DateTime?>("CreatedAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at");
b.Property<long?>("CreatedBy")
.HasColumnType("bigint")
.HasColumnName("created_by");
b.Property<Guid?>("DepartureAirportId")
.HasColumnType("uuid")
.HasColumnName("departure_airport_id");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean")
.HasColumnName("is_deleted");
b.Property<DateTime?>("LastModified")
.HasColumnType("timestamp with time zone")
.HasColumnName("last_modified");
b.Property<long?>("LastModifiedBy")
.HasColumnType("bigint")
.HasColumnName("last_modified_by");
b.Property<string>("Status")
.IsRequired()
.ValueGeneratedOnAdd()
.HasColumnType("text")
.HasDefaultValue("Unknown")
.HasColumnName("status");
b.Property<long>("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<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<string>("Class")
.IsRequired()
.ValueGeneratedOnAdd()
.HasColumnType("text")
.HasDefaultValue("Unknown")
.HasColumnName("class");
b.Property<DateTime?>("CreatedAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at");
b.Property<long?>("CreatedBy")
.HasColumnType("bigint")
.HasColumnName("created_by");
b.Property<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("flight_id");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean")
.HasColumnName("is_deleted");
b.Property<DateTime?>("LastModified")
.HasColumnType("timestamp with time zone")
.HasColumnName("last_modified");
b.Property<long?>("LastModifiedBy")
.HasColumnType("bigint")
.HasColumnName("last_modified_by");
b.Property<string>("Type")
.IsRequired()
.ValueGeneratedOnAdd()
.HasColumnType("text")
.HasDefaultValue("Unknown")
.HasColumnName("type");
b.Property<long>("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<Guid>("AircraftId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<int>("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<Guid>("AircraftId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<string>("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<Guid>("AircraftId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<string>("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<Guid>("AirportId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<string>("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<Guid>("AirportId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<string>("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<Guid>("AirportId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<string>("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<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<DateTime>("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<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<DateTime>("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<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<decimal>("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<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<DateTime>("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<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<string>("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<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<decimal>("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<Guid>("SeatId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<string>("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
}
}
}

View File

@ -0,0 +1,391 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Flight.Data.Migrations
{
/// <inheritdoc />
public partial class AddValueObjectForSeatAirportFlight : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "seat_number",
table: "seat",
type: "character varying(50)",
maxLength: 50,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<decimal>(
name: "price",
table: "flight",
type: "numeric",
maxLength: 10,
nullable: true,
oldClrType: typeof(decimal),
oldType: "numeric");
migrationBuilder.AlterColumn<string>(
name: "flight_number",
table: "flight",
type: "character varying(50)",
maxLength: 50,
nullable: true,
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "flight_date",
table: "flight",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<decimal>(
name: "duration_minutes",
table: "flight",
type: "numeric",
maxLength: 50,
nullable: true,
oldClrType: typeof(decimal),
oldType: "numeric");
migrationBuilder.AlterColumn<DateTime>(
name: "departure_date",
table: "flight",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<Guid>(
name: "departure_airport_id",
table: "flight",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<DateTime>(
name: "arrive_date",
table: "flight",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<Guid>(
name: "arrive_airport_id",
table: "flight",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<Guid>(
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<string>(
name: "name",
table: "airport",
type: "character varying(50)",
maxLength: 50,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "code",
table: "airport",
type: "character varying(50)",
maxLength: 50,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "address",
table: "airport",
type: "character varying(50)",
maxLength: 50,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
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<string>(
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<int>(
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");
}
/// <inheritdoc />
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<string>(
name: "seat_number",
table: "seat",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(50)",
oldMaxLength: 50);
migrationBuilder.AlterColumn<decimal>(
name: "price",
table: "flight",
type: "numeric",
nullable: false,
defaultValue: 0m,
oldClrType: typeof(decimal),
oldType: "numeric",
oldMaxLength: 10,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "flight_number",
table: "flight",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(50)",
oldMaxLength: 50,
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
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<decimal>(
name: "duration_minutes",
table: "flight",
type: "numeric",
nullable: false,
defaultValue: 0m,
oldClrType: typeof(decimal),
oldType: "numeric",
oldMaxLength: 50,
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
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<Guid>(
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<DateTime>(
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<Guid>(
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<Guid>(
name: "aircraft_id",
table: "flight",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<string>(
name: "name",
table: "airport",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(50)",
oldMaxLength: 50);
migrationBuilder.AlterColumn<string>(
name: "code",
table: "airport",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(50)",
oldMaxLength: 50);
migrationBuilder.AlterColumn<string>(
name: "address",
table: "airport",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(50)",
oldMaxLength: 50);
migrationBuilder.AlterColumn<string>(
name: "name",
table: "aircraft",
type: "character varying(50)",
maxLength: 50,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(50)",
oldMaxLength: 50);
migrationBuilder.AlterColumn<string>(
name: "model",
table: "aircraft",
type: "character varying(50)",
maxLength: 50,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(50)",
oldMaxLength: 50);
migrationBuilder.AlterColumn<int>(
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);
}
}
}

View File

@ -65,14 +65,6 @@ namespace Flight.Data.Migrations
.HasColumnType("uuid") .HasColumnType("uuid")
.HasColumnName("id"); .HasColumnName("id");
b.Property<string>("Address")
.HasColumnType("text")
.HasColumnName("address");
b.Property<string>("Code")
.HasColumnType("text")
.HasColumnName("code");
b.Property<DateTime?>("CreatedAt") b.Property<DateTime?>("CreatedAt")
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasColumnName("created_at"); .HasColumnName("created_at");
@ -93,10 +85,6 @@ namespace Flight.Data.Migrations
.HasColumnType("bigint") .HasColumnType("bigint")
.HasColumnName("last_modified_by"); .HasColumnName("last_modified_by");
b.Property<string>("Name")
.HasColumnType("text")
.HasColumnName("name");
b.Property<long>("Version") b.Property<long>("Version")
.IsConcurrencyToken() .IsConcurrencyToken()
.HasColumnType("bigint") .HasColumnType("bigint")
@ -114,18 +102,14 @@ namespace Flight.Data.Migrations
.HasColumnType("uuid") .HasColumnType("uuid")
.HasColumnName("id"); .HasColumnName("id");
b.Property<Guid?>("AircraftId") b.Property<Guid>("AircraftId")
.HasColumnType("uuid") .HasColumnType("uuid")
.HasColumnName("aircraft_id"); .HasColumnName("aircraft_id");
b.Property<Guid>("ArriveAirportId") b.Property<Guid?>("ArriveAirportId")
.HasColumnType("uuid") .HasColumnType("uuid")
.HasColumnName("arrive_airport_id"); .HasColumnName("arrive_airport_id");
b.Property<DateTime>("ArriveDate")
.HasColumnType("timestamp with time zone")
.HasColumnName("arrive_date");
b.Property<DateTime?>("CreatedAt") b.Property<DateTime?>("CreatedAt")
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasColumnName("created_at"); .HasColumnName("created_at");
@ -134,26 +118,10 @@ namespace Flight.Data.Migrations
.HasColumnType("bigint") .HasColumnType("bigint")
.HasColumnName("created_by"); .HasColumnName("created_by");
b.Property<Guid>("DepartureAirportId") b.Property<Guid?>("DepartureAirportId")
.HasColumnType("uuid") .HasColumnType("uuid")
.HasColumnName("departure_airport_id"); .HasColumnName("departure_airport_id");
b.Property<DateTime>("DepartureDate")
.HasColumnType("timestamp with time zone")
.HasColumnName("departure_date");
b.Property<decimal>("DurationMinutes")
.HasColumnType("numeric")
.HasColumnName("duration_minutes");
b.Property<DateTime>("FlightDate")
.HasColumnType("timestamp with time zone")
.HasColumnName("flight_date");
b.Property<string>("FlightNumber")
.HasColumnType("text")
.HasColumnName("flight_number");
b.Property<bool>("IsDeleted") b.Property<bool>("IsDeleted")
.HasColumnType("boolean") .HasColumnType("boolean")
.HasColumnName("is_deleted"); .HasColumnName("is_deleted");
@ -166,10 +134,6 @@ namespace Flight.Data.Migrations
.HasColumnType("bigint") .HasColumnType("bigint")
.HasColumnName("last_modified_by"); .HasColumnName("last_modified_by");
b.Property<decimal>("Price")
.HasColumnType("numeric")
.HasColumnName("price");
b.Property<string>("Status") b.Property<string>("Status")
.IsRequired() .IsRequired()
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@ -191,6 +155,9 @@ namespace Flight.Data.Migrations
b.HasIndex("ArriveAirportId") b.HasIndex("ArriveAirportId")
.HasDatabaseName("ix_flight_arrive_airport_id"); .HasDatabaseName("ix_flight_arrive_airport_id");
b.HasIndex("DepartureAirportId")
.HasDatabaseName("ix_flight_departure_airport_id");
b.ToTable("flight", (string)null); b.ToTable("flight", (string)null);
}); });
@ -231,10 +198,6 @@ namespace Flight.Data.Migrations
.HasColumnType("bigint") .HasColumnType("bigint")
.HasColumnName("last_modified_by"); .HasColumnName("last_modified_by");
b.Property<string>("SeatNumber")
.HasColumnType("text")
.HasColumnName("seat_number");
b.Property<string>("Type") b.Property<string>("Type")
.IsRequired() .IsRequired()
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@ -258,7 +221,7 @@ namespace Flight.Data.Migrations
modelBuilder.Entity("Flight.Aircrafts.Models.Aircraft", b => 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<Guid>("AircraftId") b1.Property<Guid>("AircraftId")
.HasColumnType("uuid") .HasColumnType("uuid")
@ -279,7 +242,7 @@ namespace Flight.Data.Migrations
.HasConstraintName("fk_aircraft_aircraft_id"); .HasConstraintName("fk_aircraft_aircraft_id");
}); });
b.OwnsOne("Flight.Aircrafts.Models.ValueObjects.ModelValue", "Model", b1 => b.OwnsOne("Flight.Aircrafts.ValueObjects.Model", "Model", b1 =>
{ {
b1.Property<Guid>("AircraftId") b1.Property<Guid>("AircraftId")
.HasColumnType("uuid") .HasColumnType("uuid")
@ -301,7 +264,7 @@ namespace Flight.Data.Migrations
.HasConstraintName("fk_aircraft_aircraft_id"); .HasConstraintName("fk_aircraft_aircraft_id");
}); });
b.OwnsOne("Flight.Aircrafts.Models.ValueObjects.NameValue", "Name", b1 => b.OwnsOne("Flight.Aircrafts.ValueObjects.Name", "Name", b1 =>
{ {
b1.Property<Guid>("AircraftId") b1.Property<Guid>("AircraftId")
.HasColumnType("uuid") .HasColumnType("uuid")
@ -323,11 +286,92 @@ namespace Flight.Data.Migrations
.HasConstraintName("fk_aircraft_aircraft_id"); .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<Guid>("AirportId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<string>("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<Guid>("AirportId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<string>("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<Guid>("AirportId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<string>("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 => modelBuilder.Entity("Flight.Flights.Models.Flight", b =>
@ -335,14 +379,155 @@ namespace Flight.Data.Migrations
b.HasOne("Flight.Aircrafts.Models.Aircraft", null) b.HasOne("Flight.Aircrafts.Models.Aircraft", null)
.WithMany() .WithMany()
.HasForeignKey("AircraftId") .HasForeignKey("AircraftId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_flight_aircraft_aircraft_id"); .HasConstraintName("fk_flight_aircraft_aircraft_id");
b.HasOne("Flight.Airports.Models.Airport", null) b.HasOne("Flight.Airports.Models.Airport", null)
.WithMany() .WithMany()
.HasForeignKey("ArriveAirportId") .HasForeignKey("ArriveAirportId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_flight_airport_arrive_airport_id"); .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<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<DateTime>("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<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<DateTime>("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<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<decimal>("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<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<DateTime>("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<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<string>("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<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<decimal>("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 => modelBuilder.Entity("Flight.Seats.Models.Seat", b =>
@ -353,6 +538,31 @@ namespace Flight.Data.Migrations
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired() .IsRequired()
.HasConstraintName("fk_seat_flight_flight_id"); .HasConstraintName("fk_seat_flight_flight_id");
b.OwnsOne("Flight.Seats.ValueObjects.SeatNumber", "SeatNumber", b1 =>
{
b1.Property<Guid>("SeatId")
.HasColumnType("uuid")
.HasColumnName("id");
b1.Property<string>("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 #pragma warning restore 612, 618
} }

View File

@ -5,10 +5,15 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Aircrafts.Models; using Aircrafts.Models;
using Airports.Models; using Airports.Models;
using Airports.ValueObjects;
using Flight.Aircrafts.ValueObjects; using Flight.Aircrafts.ValueObjects;
using Flights.Models; using Flights.Models;
using Flights.ValueObjects;
using MassTransit; using MassTransit;
using Seats.Models; using Seats.Models;
using Seats.ValueObjects;
using AirportName = Airports.ValueObjects.Name;
using Name = Aircrafts.ValueObjects.Name;
public static class InitialData public static class InitialData
{ {
@ -22,8 +27,8 @@ public static class InitialData
{ {
Airports = new List<Airport> Airports = new List<Airport>
{ {
Airport.Create(new Guid("3c5c0000-97c6-fc34-a0cb-08db322230c8"), "Lisbon International Airport", "LIS", "12988"), Airport.Create(AirportId.Of(new Guid("3c5c0000-97c6-fc34-a0cb-08db322230c8")), AirportName.Of("Lisbon International Airport"), Address.Of("LIS"), Code.Of("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-fc3c-08db322230c8")), AirportName.Of("Sao Paulo International Airport"), Address.Of("BRZ"), Code.Of("11200"))
}; };
Aircrafts = new List<Aircraft> Aircrafts = new List<Aircraft>
@ -36,21 +41,21 @@ public static class InitialData
Flights = new List<Flight> Flights = new List<Flight>
{ {
Flight.Create(new Guid("3c5c0000-97c6-fc34-2eb9-08db322230c9"), "BD467", Aircrafts.First().Id, Airports.First().Id, new DateTime(2022, 1, 31, 12, 0, 0), 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)),
new DateTime(2022, 1, 31, 14, 0, 0), ArriveDate.Of(new DateTime(2022, 1, 31, 14, 0, 0)),
Airports.Last().Id, 120m, AirportId.Of(Airports.Last().Id), DurationMinutes.Of(120m),
new DateTime(2022, 1, 31), global::Flight.Flights.Enums.FlightStatus.Completed, FlightDate.Of(new DateTime(2022, 1, 31, 13, 0, 0)), global::Flight.Flights.Enums.FlightStatus.Completed,
8000) Price.Of((decimal)8000))
}; };
Seats = new List<Seat> Seats = new List<Seat>
{ {
Seat.Create(NewId.NextGuid(), "12A", global::Flight.Seats.Enums.SeatType.Window, 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(NewId.NextGuid(), "12B", global::Flight.Seats.Enums.SeatType.Window, global::Flight.Seats.Enums.SeatClass.Economy, 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(NewId.NextGuid(), "12C", global::Flight.Seats.Enums.SeatType.Middle, global::Flight.Seats.Enums.SeatClass.Economy, 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(NewId.NextGuid(), "12D", global::Flight.Seats.Enums.SeatType.Middle, global::Flight.Seats.Enums.SeatClass.Economy, 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(NewId.NextGuid(), "12E", global::Flight.Seats.Enums.SeatType.Aisle, global::Flight.Seats.Enums.SeatClass.Economy, 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(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("12F"), global::Flight.Seats.Enums.SeatType.Aisle, global::Flight.Seats.Enums.SeatClass.Economy, FlightId.Of((Guid) Flights.First().Id))
}; };
} }
} }

View File

@ -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.")
{ }
}

View File

@ -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.")
{
}
}

View File

@ -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.")
{
}
}

View File

@ -0,0 +1,10 @@
namespace Flight.Flights.Exceptions;
using BuildingBlocks.Exception;
public class InvalidDurationException : BadRequestException
{
public InvalidDurationException()
: base("Duration cannot be negative.")
{
}
}

View File

@ -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.")
{
}
}

View File

@ -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.")
{
}
}

View File

@ -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.")
{
}
}

View File

@ -0,0 +1,11 @@
namespace Flight.Flights.Exceptions;
using BuildingBlocks.Exception;
public class InvalidPriceException : BadRequestException
{
public InvalidPriceException()
: base($"Price Cannot be negative.")
{
}
}

View File

@ -11,6 +11,7 @@ using BuildingBlocks.Web;
using Data; using Data;
using Duende.IdentityServer.EntityFramework.Entities; using Duende.IdentityServer.EntityFramework.Entities;
using Exceptions; using Exceptions;
using Flight.Airports.ValueObjects;
using FluentValidation; using FluentValidation;
using MapsterMapper; using MapsterMapper;
using MassTransit; using MassTransit;
@ -19,6 +20,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using ValueObjects;
public record CreateFlight(string FlightNumber, Guid AircraftId, Guid DepartureAirportId, public record CreateFlight(string FlightNumber, Guid AircraftId, Guid DepartureAirportId,
DateTime DepartureDate, DateTime ArriveDate, Guid ArriveAirportId, DateTime DepartureDate, DateTime ArriveDate, Guid ArriveAirportId,
@ -112,13 +114,13 @@ internal class CreateFlightHandler : ICommandHandler<CreateFlight, CreateFlightR
throw new FlightAlreadyExistException(); throw new FlightAlreadyExistException();
} }
var flightEntity = Models.Flight.Create(request.Id, request.FlightNumber, AircraftId.Of(request.AircraftId), var flightEntity = Models.Flight.Create(FlightId.Of(request.Id), FlightNumber.Of(request.FlightNumber), AircraftId.Of(request.AircraftId),
request.DepartureAirportId, request.DepartureDate, AirportId.Of(request.DepartureAirportId), DepartureDate.Of(request.DepartureDate),
request.ArriveDate, request.ArriveAirportId, request.DurationMinutes, request.FlightDate, request.Status, ArriveDate.Of(request.ArriveDate), AirportId.Of(request.ArriveAirportId), DurationMinutes.Of(request.DurationMinutes), FlightDate.Of(request.FlightDate), request.Status,
request.Price); Price.Of(request.Price));
var newFlight = (await _flightDbContext.Flights.AddAsync(flightEntity, cancellationToken))?.Entity; var newFlight = (await _flightDbContext.Flights.AddAsync(flightEntity, cancellationToken))?.Entity;
return new CreateFlightResult(newFlight.Id); return new CreateFlightResult(newFlight.Id.Value);
} }
} }

View File

@ -1,6 +1,7 @@
namespace Flight.Flights.Features.DeletingFlight.V1; namespace Flight.Flights.Features.DeletingFlight.V1;
using System; using System;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ardalis.GuardClauses; using Ardalis.GuardClauses;
@ -16,6 +17,8 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using MongoDB.Driver.Linq;
using ValueObjects;
public record DeleteFlight(Guid Id) : ICommand<DeleteFlightResult>, IInternalCommand; public record DeleteFlight(Guid Id) : ICommand<DeleteFlightResult>, IInternalCommand;
@ -71,8 +74,7 @@ internal class DeleteFlightHandler : ICommandHandler<DeleteFlight, DeleteFlightR
{ {
Guard.Against.Null(request, nameof(request)); 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) if (flight is null)
{ {
throw new FlightNotFountException(); throw new FlightNotFountException();
@ -82,8 +84,8 @@ internal class DeleteFlightHandler : ICommandHandler<DeleteFlight, DeleteFlightR
flight.DepartureDate, flight.ArriveDate, flight.ArriveAirportId, flight.DurationMinutes, flight.DepartureDate, flight.ArriveDate, flight.ArriveAirportId, flight.DurationMinutes,
flight.FlightDate, flight.Status, flight.Price); 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);
} }
} }

View File

@ -12,6 +12,7 @@ using BuildingBlocks.Web;
using Data; using Data;
using Duende.IdentityServer.EntityFramework.Entities; using Duende.IdentityServer.EntityFramework.Entities;
using Exceptions; using Exceptions;
using Flight.Airports.ValueObjects;
using Flight.Flights.Features.CreatingFlight.V1; using Flight.Flights.Features.CreatingFlight.V1;
using FluentValidation; using FluentValidation;
using MapsterMapper; using MapsterMapper;
@ -20,6 +21,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using ValueObjects;
public record UpdateFlight(Guid Id, string FlightNumber, Guid AircraftId, Guid DepartureAirportId, public record UpdateFlight(Guid Id, string FlightNumber, Guid AircraftId, Guid DepartureAirportId,
DateTime DepartureDate, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate, DateTime DepartureDate, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
@ -102,7 +104,7 @@ internal class UpdateFlightHandler : ICommandHandler<UpdateFlight, UpdateFlightR
{ {
Guard.Against.Null(request, nameof(request)); 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); cancellationToken);
if (flight is null) if (flight is null)
@ -111,13 +113,13 @@ internal class UpdateFlightHandler : ICommandHandler<UpdateFlight, UpdateFlightR
} }
flight.Update(request.Id, request.FlightNumber, AircraftId.Of(request.AircraftId), request.DepartureAirportId, flight.Update(FlightId.Of(request.Id), FlightNumber.Of(request.FlightNumber), AircraftId.Of(request.AircraftId), AirportId.Of(request.DepartureAirportId),
request.DepartureDate, DepartureDate.Of(request.DepartureDate),
request.ArriveDate, request.ArriveAirportId, request.DurationMinutes, request.FlightDate, request.Status, ArriveDate.Of(request.ArriveDate), AirportId.Of(request.ArriveAirportId), DurationMinutes.Of(request.DurationMinutes), FlightDate.Of(request.FlightDate), request.Status,
request.Price, request.IsDeleted); Price.Of(request.Price), request.IsDeleted);
var updateFlight = (_flightDbContext.Flights.Update(flight))?.Entity; var updateFlight = (_flightDbContext.Flights.Update(flight))?.Entity;
return new UpdateFlightResult(updateFlight.Id); return new UpdateFlightResult(updateFlight.Id.Value);
} }
} }

View File

@ -4,28 +4,33 @@ using BuildingBlocks.Core.Model;
namespace Flight.Flights.Models; namespace Flight.Flights.Models;
using Aircrafts.ValueObjects; using Aircrafts.ValueObjects;
using Airports.ValueObjects;
using Features.CreatingFlight.V1; using Features.CreatingFlight.V1;
using Features.DeletingFlight.V1; using Features.DeletingFlight.V1;
using Features.UpdatingFlight.V1; using Features.UpdatingFlight.V1;
using global::Flight.Flights.Exceptions;
using global::Flight.Flights.ValueObjects;
public record Flight : Aggregate<Guid> public record Flight : Aggregate<FlightId>
{ {
public string FlightNumber { get; private set; } public FlightNumber? FlightNumber { get; private set; } = default!;
public AircraftId AircraftId { get; private set; } public AircraftId AircraftId { get; private set; }
public DateTime DepartureDate { get; private set; } public AirportId? DepartureAirportId { get; private set; }
public Guid DepartureAirportId { get; private set; } public AirportId? ArriveAirportId { get; private set; }
public DateTime ArriveDate { get; private set; } public DurationMinutes? DurationMinutes { get; private set; }
public Guid ArriveAirportId { get; private set; }
public decimal DurationMinutes { get; private set; }
public DateTime FlightDate { get; private set; }
public Enums.FlightStatus Status { 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, public static Flight Create(FlightId id, FlightNumber flightNumber, AircraftId aircraftId,
Guid departureAirportId, DateTime departureDate, DateTime arriveDate, AirportId departureAirportId, DepartureDate departureDate, ArriveDate arriveDate,
Guid arriveAirportId, decimal durationMinutes, DateTime flightDate, Enums.FlightStatus status, AirportId arriveAirportId, DurationMinutes durationMinutes, FlightDate flightDate, Enums.FlightStatus status,
decimal price, bool isDeleted = false) Price price, bool isDeleted = false)
{ {
//SimpleFlightValidate(departureDate.Value, arriveDate.Value, flightDate.Value);
var flight = new Flight var flight = new Flight
{ {
Id = id, Id = id,
@ -42,10 +47,10 @@ public record Flight : Aggregate<Guid>
IsDeleted = isDeleted, IsDeleted = isDeleted,
}; };
var @event = new FlightCreatedDomainEvent(flight.Id, flight.FlightNumber, flight.AircraftId, var @event = new FlightCreatedDomainEvent(flight.Id.Value, flight.FlightNumber.Value, flight.AircraftId.Value,
flight.DepartureDate, flight.DepartureAirportId, flight.DepartureDate.Value, flight.DepartureAirportId.Value,
flight.ArriveDate, flight.ArriveAirportId, flight.DurationMinutes, flight.FlightDate, flight.Status, flight.ArriveDate.Value, flight.ArriveAirportId.Value, flight.DurationMinutes.Value, flight.FlightDate.Value, flight.Status,
flight.Price, flight.IsDeleted); flight.Price.Value, flight.IsDeleted);
flight.AddDomainEvent(@event); flight.AddDomainEvent(@event);
@ -53,16 +58,16 @@ public record Flight : Aggregate<Guid>
} }
public void Update(Guid id, string flightNumber, AircraftId aircraftId, public void Update(FlightId id, FlightNumber flightNumber, AircraftId aircraftId,
Guid departureAirportId, DateTime departureDate, DateTime arriveDate, AirportId departureAirportId, DepartureDate departureDate, ArriveDate arriveDate,
Guid arriveAirportId, decimal durationMinutes, DateTime flightDate, Enums.FlightStatus status, AirportId arriveAirportId, DurationMinutes durationMinutes, FlightDate flightDate, Enums.FlightStatus status,
decimal price, bool isDeleted = false) Price price, bool isDeleted = false)
{ {
FlightNumber = flightNumber; FlightNumber = flightNumber;
AircraftId = aircraftId; AircraftId = aircraftId;
DepartureAirportId = departureAirportId; DepartureAirportId = departureAirportId;
DepartureDate = departureDate; DepartureDate = departureDate;
arriveDate = ArriveDate; ArriveDate = arriveDate;
ArriveAirportId = arriveAirportId; ArriveAirportId = arriveAirportId;
DurationMinutes = durationMinutes; DurationMinutes = durationMinutes;
FlightDate = flightDate; FlightDate = flightDate;
@ -70,22 +75,22 @@ public record Flight : Aggregate<Guid>
Price = price; Price = price;
IsDeleted = isDeleted; IsDeleted = isDeleted;
var @event = new FlightUpdatedDomainEvent(id, flightNumber, aircraftId, departureDate, departureAirportId, var @event = new FlightUpdatedDomainEvent(id.Value, flightNumber.Value, aircraftId.Value, departureDate.Value, departureAirportId.Value,
arriveDate, arriveAirportId, durationMinutes, flightDate, status, price, isDeleted); arriveDate.Value, arriveAirportId.Value, durationMinutes.Value, flightDate.Value, status, price.Value, isDeleted);
AddDomainEvent(@event); AddDomainEvent(@event);
} }
public void Delete(Guid id, string flightNumber, AircraftId aircraftId, public void Delete(FlightId id, FlightNumber flightNumber, AircraftId aircraftId,
Guid departureAirportId, DateTime departureDate, DateTime arriveDate, AirportId departureAirportId, DepartureDate departureDate, ArriveDate arriveDate,
Guid arriveAirportId, decimal durationMinutes, DateTime flightDate, Enums.FlightStatus status, AirportId arriveAirportId, DurationMinutes durationMinutes, FlightDate flightDate, Enums.FlightStatus status,
decimal price, bool isDeleted = true) Price price, bool isDeleted = true)
{ {
FlightNumber = flightNumber; FlightNumber = flightNumber;
AircraftId = aircraftId; AircraftId = aircraftId;
DepartureAirportId = departureAirportId; DepartureAirportId = departureAirportId;
DepartureDate = departureDate; DepartureDate = departureDate;
arriveDate = ArriveDate; ArriveDate = arriveDate;
ArriveAirportId = arriveAirportId; ArriveAirportId = arriveAirportId;
DurationMinutes = durationMinutes; DurationMinutes = durationMinutes;
FlightDate = flightDate; FlightDate = flightDate;
@ -93,9 +98,32 @@ public record Flight : Aggregate<Guid>
Price = price; Price = price;
IsDeleted = isDeleted; IsDeleted = isDeleted;
var @event = new FlightDeletedDomainEvent(id, flightNumber, aircraftId, departureDate, departureAirportId, var @event = new FlightDeletedDomainEvent(id.Value, flightNumber.Value, aircraftId.Value, departureDate.Value, departureAirportId.Value,
arriveDate, arriveAirportId, durationMinutes, flightDate, status, price, isDeleted); arriveDate.Value, arriveAirportId.Value, durationMinutes.Value, flightDate.Value, status, price.Value, isDeleted);
AddDomainEvent(@event); AddDomainEvent(@event);
} }
public static void SimpleFlightValidate(DateTime departureDate, DateTime arriveDate, DateTime flightDate)
{
if (departureDate >= arriveDate)
{
throw new FlightExceptions(departureDate, arriveDate);
}
if (flightDate < departureDate || flightDate > arriveDate)
{
throw new FlightExceptions(flightDate);
}
}
public static TimeSpan GetFlightDuration(DateTime departureDate, DateTime arriveDate)
{
return arriveDate - departureDate;
}
public static bool IsOnSameDay(DateTime departureDate, DateTime arriveDate)
{
return departureDate.Date == arriveDate.Date;
}
} }

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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.")
{
}
}

View File

@ -0,0 +1,9 @@
namespace Flight.Seats.Exceptions;
using BuildingBlocks.Exception;
public class InvalidSeatNumberException : BadRequestException
{
public InvalidSeatNumberException() : base("SeatNumber Cannot be null or negative")
{
}
}

View File

@ -1,6 +1,7 @@
namespace Flight.Seats.Features.CreatingSeat.V1; namespace Flight.Seats.Features.CreatingSeat.V1;
using System; using System;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ardalis.GuardClauses; using Ardalis.GuardClauses;
@ -11,6 +12,7 @@ using Duende.IdentityServer.EntityFramework.Entities;
using Flight.Data; using Flight.Data;
using Flight.Seats.Exceptions; using Flight.Seats.Exceptions;
using Flight.Seats.Models; using Flight.Seats.Models;
using Flights.ValueObjects;
using FluentValidation; using FluentValidation;
using MapsterMapper; using MapsterMapper;
using MassTransit; using MassTransit;
@ -19,6 +21,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using ValueObjects;
public record CreateSeat public record CreateSeat
(string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, Guid FlightId) : ICommand<CreateSeatResult>, (string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, Guid FlightId) : ICommand<CreateSeatResult>,
@ -94,17 +97,16 @@ internal class CreateSeatCommandHandler : IRequestHandler<CreateSeat, CreateSeat
{ {
Guard.Against.Null(command, nameof(command)); 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) if (seat is not null)
{ {
throw new SeatAlreadyExistException(); 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; var newSeat = (await _flightDbContext.Seats.AddAsync(seatEntity, cancellationToken))?.Entity;
return new CreateSeatResult(newSeat.Id); return new CreateSeatResult(newSeat.Id.Value);
} }
} }

View File

@ -10,6 +10,7 @@ using BuildingBlocks.Web;
using Data; using Data;
using Duende.IdentityServer.EntityFramework.Entities; using Duende.IdentityServer.EntityFramework.Entities;
using Exceptions; using Exceptions;
using Flights.ValueObjects;
using FluentValidation; using FluentValidation;
using MapsterMapper; using MapsterMapper;
using MediatR; using MediatR;
@ -17,6 +18,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using ValueObjects;
public record ReserveSeat(Guid FlightId, string SeatNumber) : ICommand<ReserveSeatResult>, IInternalCommand; public record ReserveSeat(Guid FlightId, string SeatNumber) : ICommand<ReserveSeatResult>, IInternalCommand;
@ -82,8 +84,10 @@ internal class ReserveSeatCommandHandler : IRequestHandler<ReserveSeat, ReserveS
{ {
Guard.Against.Null(command, nameof(command)); 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) if (seat is null)
{ {

View File

@ -13,7 +13,7 @@ public class SeatMappings : IRegister
public void Register(TypeAdapterConfig config) public void Register(TypeAdapterConfig config)
{ {
config.NewConfig<Seat, SeatDto>() config.NewConfig<Seat, SeatDto>()
.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<CreateSeatMongo, SeatReadModel>() config.NewConfig<CreateSeatMongo, SeatReadModel>()
.Map(d => d.Id, s => NewId.NextGuid()) .Map(d => d.Id, s => NewId.NextGuid())
@ -21,7 +21,7 @@ public class SeatMappings : IRegister
config.NewConfig<Seat, SeatReadModel>() config.NewConfig<Seat, SeatReadModel>()
.Map(d => d.Id, s => NewId.NextGuid()) .Map(d => d.Id, s => NewId.NextGuid())
.Map(d => d.SeatId, s => s.Id); .Map(d => d.SeatId, s => s.Id.Value);
config.NewConfig<ReserveSeatMongo, SeatReadModel>() config.NewConfig<ReserveSeatMongo, SeatReadModel>()
.Map(d => d.SeatId, s => s.Id); .Map(d => d.SeatId, s => s.Id);

View File

@ -6,10 +6,17 @@ namespace Flight.Seats.Models;
using Features.CreatingSeat.V1; using Features.CreatingSeat.V1;
using Features.ReservingSeat.Commands.V1; using Features.ReservingSeat.Commands.V1;
using Flight.Flights.ValueObjects;
using Flight.Seats.ValueObjects;
public record Seat : Aggregate<Guid> public record Seat : Aggregate<SeatId>
{ {
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) bool isDeleted = false)
{ {
var seat = new Seat() var seat = new Seat()
@ -23,11 +30,11 @@ public record Seat : Aggregate<Guid>
}; };
var @event = new SeatCreatedDomainEvent( var @event = new SeatCreatedDomainEvent(
seat.Id, seat.Id.Value,
seat.SeatNumber, seat.SeatNumber.Value,
seat.Type, seat.Type,
seat.Class, seat.Class,
seat.FlightId, seat.FlightId.Value,
isDeleted); isDeleted);
seat.AddDomainEvent(@event); seat.AddDomainEvent(@event);
@ -41,20 +48,15 @@ public record Seat : Aggregate<Guid>
seat.LastModified = DateTime.Now; seat.LastModified = DateTime.Now;
var @event = new SeatReservedDomainEvent( var @event = new SeatReservedDomainEvent(
seat.Id, seat.Id.Value,
seat.SeatNumber, seat.SeatNumber.Value,
seat.Type, seat.Type,
seat.Class, seat.Class,
seat.FlightId, seat.FlightId.Value,
seat.IsDeleted); seat.IsDeleted);
seat.AddDomainEvent(@event); seat.AddDomainEvent(@event);
return Task.FromResult(this); 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; }
} }

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -1,4 +1,4 @@
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using BuildingBlocks.Contracts.EventBus.Messages; using BuildingBlocks.Contracts.EventBus.Messages;
using BuildingBlocks.TestBase; using BuildingBlocks.TestBase;
@ -10,10 +10,10 @@ using Xunit;
namespace Integration.Test.Flight.Features; namespace Integration.Test.Flight.Features;
using System;
using global::Flight.Data.Seed; using global::Flight.Data.Seed;
using global::Flight.Flights.Features.DeletingFlight.V1; using global::Flight.Flights.Features.DeletingFlight.V1;
using global::Flight.Flights.Models; using global::Flight.Flights.Models;
using global::Flight.Flights.ValueObjects;
public class DeleteFlightTests : FlightIntegrationTestBase public class DeleteFlightTests : FlightIntegrationTestBase
{ {
@ -26,13 +26,13 @@ public class DeleteFlightTests : FlightIntegrationTestBase
public async Task should_delete_flight_from_db() public async Task should_delete_flight_from_db()
{ {
// Arrange // Arrange
var flightEntity = await Fixture.FindAsync<Flight, Guid>( InitialData.Flights.First().Id); var flightEntity = await Fixture.FindAsync<Flight, FlightId>(InitialData.Flights.First().Id);
var command = new DeleteFlight(flightEntity.Id); var command = new DeleteFlight(flightEntity.Id.Value);
// Act // Act
await Fixture.SendAsync(command); await Fixture.SendAsync(command);
var deletedFlight = (await Fixture.ExecuteDbContextAsync(db => db.Flights var deletedFlight = (await Fixture.ExecuteDbContextAsync(db => db.Flights
.Where(x => x.Id == command.Id) .Where(x => x.Id == FlightId.Of(command.Id))
.IgnoreQueryFilters() .IgnoreQueryFilters()
.ToListAsync()) .ToListAsync())
).FirstOrDefault(); ).FirstOrDefault();

View File

@ -1,4 +1,4 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using BuildingBlocks.Contracts.EventBus.Messages; using BuildingBlocks.Contracts.EventBus.Messages;
using BuildingBlocks.TestBase; using BuildingBlocks.TestBase;
using Flight.Api; using Flight.Api;
@ -9,11 +9,10 @@ using Xunit;
namespace Integration.Test.Flight.Features; namespace Integration.Test.Flight.Features;
using System;
using System.Linq; using System.Linq;
using global::Flight.Data.Seed; using global::Flight.Data.Seed;
using global::Flight.Flights.Features.UpdatingFlight.V1;
using global::Flight.Flights.Models; using global::Flight.Flights.Models;
using global::Flight.Flights.ValueObjects;
public class UpdateFlightTests : FlightIntegrationTestBase public class UpdateFlightTests : FlightIntegrationTestBase
{ {
@ -26,7 +25,7 @@ public class UpdateFlightTests : FlightIntegrationTestBase
public async Task should_update_flight_to_db_and_publish_message_to_broker() public async Task should_update_flight_to_db_and_publish_message_to_broker()
{ {
// Arrange // Arrange
var flightEntity = await Fixture.FindAsync<Flight, Guid>( InitialData.Flights.First().Id); var flightEntity = await Fixture.FindAsync<Flight, FlightId>(InitialData.Flights.First().Id);
var command = new FakeUpdateFlightCommand(flightEntity).Generate(); var command = new FakeUpdateFlightCommand(flightEntity).Generate();
// Act // Act

View File

@ -1,4 +1,4 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using BuildingBlocks.TestBase; using BuildingBlocks.TestBase;
using Flight; using Flight;
using Flight.Api; using Flight.Api;
@ -8,10 +8,6 @@ using Integration.Test.Fakes;
using Xunit; using Xunit;
namespace Integration.Test.Seat.Features; namespace Integration.Test.Seat.Features;
using global::Flight.Flights.Features.CreatingFlight.V1;
using global::Flight.Seats.Features.CreatingSeat.V1;
public class ReserveSeatTests : FlightIntegrationTestBase public class ReserveSeatTests : FlightIntegrationTestBase
{ {
public ReserveSeatTests( public ReserveSeatTests(
@ -36,11 +32,12 @@ public class ReserveSeatTests : FlightIntegrationTestBase
// Act // Act
var response = await flightGrpcClient.ReserveSeatAsync(new ReserveSeatRequest() var response = await flightGrpcClient.ReserveSeatAsync(new ReserveSeatRequest()
{ {
FlightId = seatCommand.FlightId.ToString(), SeatNumber = seatCommand.SeatNumber FlightId = seatCommand.FlightId.ToString(),
SeatNumber = seatCommand.SeatNumber
}); });
// Assert // Assert
response?.Should().NotBeNull(); response?.Should().NotBeNull();
response?.Id.Should().Be(seatCommand.Id.ToString()); response?.Id.Should().Be(seatCommand?.Id.ToString());
} }
} }

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FluentAssertions; using FluentAssertions;
@ -8,8 +8,8 @@ using Xunit;
namespace Unit.Test.Airport.Features.CreateAirportTests; namespace Unit.Test.Airport.Features.CreateAirportTests;
using global::Flight.Airports.Dtos;
using global::Flight.Airports.Features.CreatingAirport.V1; using global::Flight.Airports.Features.CreatingAirport.V1;
using global::Flight.Airports.ValueObjects;
[Collection(nameof(UnitTestFixture))] [Collection(nameof(UnitTestFixture))]
public class CreateAirportCommandHandlerTests public class CreateAirportCommandHandlerTests
@ -37,7 +37,7 @@ public class CreateAirportCommandHandlerTests
var response = await Act(command, CancellationToken.None); var response = await Act(command, CancellationToken.None);
// Assert // Assert
var entity = await _fixture.DbContext.Airports.FindAsync(response?.Id); var entity = await _fixture.DbContext.Airports.FindAsync(AirportId.Of(response.Id));
entity?.Should().NotBeNull(); entity?.Should().NotBeNull();
response?.Id.Should().Be(entity.Id); response?.Id.Should().Be(entity.Id);

View File

@ -8,7 +8,12 @@ using Microsoft.EntityFrameworkCore;
namespace Unit.Test.Common; namespace Unit.Test.Common;
using global::Flight.Aircrafts.ValueObjects; using global::Flight.Aircrafts.ValueObjects;
using global::Flight.Airports.ValueObjects;
using global::Flight.Flights.ValueObjects;
using global::Flight.Seats.ValueObjects;
using MassTransit; using MassTransit;
using AirportName = global::Flight.Airports.ValueObjects.Name;
using Name = global::Flight.Aircrafts.ValueObjects.Name;
public static class DbContextFactory public static class DbContextFactory
{ {
@ -36,10 +41,10 @@ public static class DbContextFactory
{ {
var airports = new List<global::Flight.Airports.Models.Airport> var airports = new List<global::Flight.Airports.Models.Airport>
{ {
global::Flight.Airports.Models.Airport.Create(_airportId1, "Lisbon International Airport", "LIS", global::Flight.Airports.Models.Airport.Create(AirportId.Of(_airportId1), AirportName.Of("Lisbon International Airport"), Address.Of("LIS"),
"12988"), Code.Of("12988")),
global::Flight.Airports.Models.Airport.Create(_airportId2, "Sao Paulo International Airport", "BRZ", global::Flight.Airports.Models.Airport.Create(AirportId.Of(_airportId2), AirportName.Of("Sao Paulo International Airport"), Address.Of("BRZ"),
"11200") Code.Of("11200"))
}; };
context.Airports.AddRange(airports); context.Airports.AddRange(airports);
@ -55,29 +60,29 @@ public static class DbContextFactory
var flights = new List<global::Flight.Flights.Models.Flight> var flights = new List<global::Flight.Flights.Models.Flight>
{ {
global::Flight.Flights.Models.Flight.Create(_flightId1, "BD467", AircraftId.Of(_aircraft1), _airportId1, global::Flight.Flights.Models.Flight.Create(FlightId.Of(_flightId1), FlightNumber.Of( "BD467"), AircraftId.Of(_aircraft1), AirportId.Of( _airportId1),
new DateTime(2022, 1, 31, 12, 0, 0), DepartureDate.Of( new DateTime(2022, 1, 31, 12, 0, 0)),
new DateTime(2022, 1, 31, 14, 0, 0), ArriveDate.Of( new DateTime(2022, 1, 31, 14, 0, 0)),
_airportId2, 120m, AirportId.Of( _airportId2), DurationMinutes.Of(120m),
new DateTime(2022, 1, 31), FlightStatus.Completed, FlightDate.Of( new DateTime(2022, 1, 31)), FlightStatus.Completed,
8000) Price.Of((decimal)8000))
}; };
context.Flights.AddRange(flights); context.Flights.AddRange(flights);
var seats = new List<global::Flight.Seats.Models.Seat> var seats = new List<global::Flight.Seats.Models.Seat>
{ {
global::Flight.Seats.Models.Seat.Create(NewId.NextGuid(), "12A", SeatType.Window, SeatClass.Economy, global::Flight.Seats.Models.Seat.Create(SeatId.Of( NewId.NextGuid()), SeatNumber.Of("12A"), SeatType.Window, SeatClass.Economy,
_flightId1), FlightId.Of(_flightId1)),
global::Flight.Seats.Models.Seat.Create(NewId.NextGuid(), "12B", SeatType.Window, SeatClass.Economy, global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12B"), SeatType.Window, SeatClass.Economy,
_flightId1), FlightId.Of(_flightId1)),
global::Flight.Seats.Models.Seat.Create(NewId.NextGuid(), "12C", SeatType.Middle, SeatClass.Economy, global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12C"), SeatType.Middle, SeatClass.Economy,
_flightId1), FlightId.Of(_flightId1)),
global::Flight.Seats.Models.Seat.Create(NewId.NextGuid(), "12D", SeatType.Middle, SeatClass.Economy, global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12D"), SeatType.Middle, SeatClass.Economy,
_flightId1), FlightId.Of(_flightId1)),
global::Flight.Seats.Models.Seat.Create(NewId.NextGuid(), "12E", SeatType.Aisle, SeatClass.Economy, global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12E"), SeatType.Aisle, SeatClass.Economy,
_flightId1), FlightId.Of(_flightId1)),
global::Flight.Seats.Models.Seat.Create(NewId.NextGuid(), "12F", SeatType.Aisle, SeatClass.Economy, global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12F"), SeatType.Aisle, SeatClass.Economy,
_flightId1) FlightId.Of(_flightId1))
}; };
context.Seats.AddRange(seats); context.Seats.AddRange(seats);

View File

@ -1,6 +1,8 @@
namespace Unit.Test.Fakes; namespace Unit.Test.Fakes;
using global::Flight.Aircrafts.ValueObjects; using global::Flight.Aircrafts.ValueObjects;
using global::Flight.Airports.ValueObjects;
using global::Flight.Flights.ValueObjects;
public static class FakeFlightCreate public static class FakeFlightCreate
{ {
@ -8,9 +10,9 @@ public static class FakeFlightCreate
{ {
var command = new FakeCreateFlightCommand().Generate(); var command = new FakeCreateFlightCommand().Generate();
return global::Flight.Flights.Models.Flight.Create(command.Id, command.FlightNumber, return global::Flight.Flights.Models.Flight.Create(FlightId.Of(command.Id), FlightNumber.Of(command.FlightNumber),
AircraftId.Of(command.AircraftId), command.DepartureAirportId, command.DepartureDate, AircraftId.Of(command.AircraftId), AirportId.Of(command.DepartureAirportId), DepartureDate.Of(command.DepartureDate),
command.ArriveDate, command.ArriveAirportId, command.DurationMinutes, ArriveDate.Of(command.ArriveDate), AirportId.Of(command.ArriveAirportId), DurationMinutes.Of(command.DurationMinutes),
command.FlightDate, command.Status, command.Price); FlightDate.Of(command.FlightDate), command.Status, Price.Of(command.Price));
} }
} }

View File

@ -1,12 +1,13 @@
namespace Unit.Test.Fakes; namespace Unit.Test.Fakes;
using global::Flight.Flights.Models; using global::Flight.Flights.Models;
using global::Flight.Flights.ValueObjects;
public static class FakeFlightUpdate public static class FakeFlightUpdate
{ {
public static void Generate(Flight flight) public static void Generate(Flight flight)
{ {
flight.Update(flight.Id, flight.FlightNumber, flight.AircraftId, flight.DepartureAirportId, flight.DepartureDate, 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);
} }
} }

View File

@ -1,4 +1,4 @@
namespace Unit.Test.Flight.Features.Domains; namespace Unit.Test.Flight.Features.Domains;
using System.Linq; using System.Linq;
using FluentAssertions; using FluentAssertions;
@ -20,7 +20,7 @@ public class UpdateFlightTests
FakeFlightUpdate.Generate(fakeFlight); FakeFlightUpdate.Generate(fakeFlight);
// Assert // Assert
fakeFlight.Price.Should().Be(1000); fakeFlight.Price.Value.Should().Be(1000);
} }
[Fact] [Fact]

View File

@ -1,10 +1,11 @@
namespace Unit.Test.Flight.Features.Handlers.CreateFlight; namespace Unit.Test.Flight.Features.Handlers.CreateFlight;
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FluentAssertions; using FluentAssertions;
using global::Flight.Flights.Features.CreatingFlight.V1; using global::Flight.Flights.Features.CreatingFlight.V1;
using global::Flight.Flights.ValueObjects;
using Unit.Test.Common; using Unit.Test.Common;
using Unit.Test.Fakes; using Unit.Test.Fakes;
using Xunit; using Xunit;
@ -34,7 +35,7 @@ public class CreateFlightCommandHandlerTests
var response = await Act(command, CancellationToken.None); var response = await Act(command, CancellationToken.None);
// Assert // Assert
var entity = await _fixture.DbContext.Flights.FindAsync(response?.Id); var entity = await _fixture.DbContext.Flights.FindAsync(FlightId.Of(response.Id));
entity?.Should().NotBeNull(); entity?.Should().NotBeNull();
response?.Id.Should().Be(entity.Id); response?.Id.Should().Be(entity.Id);

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Flight.Seats.Dtos;
using FluentAssertions; using FluentAssertions;
using Unit.Test.Common; using Unit.Test.Common;
using Unit.Test.Fakes; using Unit.Test.Fakes;
@ -10,6 +9,7 @@ using Xunit;
namespace Unit.Test.Seat.Features; namespace Unit.Test.Seat.Features;
using global::Flight.Seats.Features.CreatingSeat.V1; using global::Flight.Seats.Features.CreatingSeat.V1;
using global::Flight.Seats.ValueObjects;
[Collection(nameof(UnitTestFixture))] [Collection(nameof(UnitTestFixture))]
public class CreateSeatCommandHandlerTests public class CreateSeatCommandHandlerTests
@ -39,7 +39,7 @@ public class CreateSeatCommandHandlerTests
var response = await Act(command, CancellationToken.None); var response = await Act(command, CancellationToken.None);
// Assert // Assert
var entity = await _fixture.DbContext.Seats.FindAsync(response?.Id); var entity = await _fixture.DbContext.Seats.FindAsync(SeatId.Of(response.Id));
entity?.Should().NotBeNull(); entity?.Should().NotBeNull();
response?.Id.Should().Be(entity.Id); response?.Id.Should().Be(entity.Id);

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Flight.Seats.Dtos; using Flight.Seats.Dtos;
using MapsterMapper; using MapsterMapper;
@ -25,7 +25,7 @@ public class SeatMappingTests
yield return new object[] yield return new object[]
{ {
// these types will instantiate with reflection in the future // 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)
}; };
} }
} }