feat: Use NewId instead of IdGen for generate Id for unique id in distributed system

This commit is contained in:
Pc 2023-04-01 02:03:05 +03:30
parent e1d99a6f24
commit c60af19a0a
160 changed files with 760 additions and 672 deletions

View File

@ -8,8 +8,8 @@
@booking-api=http://localhost:6010
@contentType = application/json
@flightid = 1
@passengerId = 1
@flightid = "3c5c0000-97c6-fc34-2eb9-08db322230c9"
@passengerId = "8c9c0000-97c6-fc34-2eb9-66db322230c9"
################################# Identity API #################################
@ -70,7 +70,7 @@ authorization: bearer {{Authenticate.response.body.access_token}}
"seatNumber": "1255",
"type": 1,
"class": 1,
"flightId": 1
"flightId": "3c5c0000-97c6-fc34-2eb9-08db322230c9"
}
###
@ -83,7 +83,7 @@ Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"flightId": 1,
"flightId": "3c5c0000-97c6-fc34-2eb9-08db322230c9",
"seatNumber": "1255"
}
###
@ -125,11 +125,11 @@ authorization: bearer {{Authenticate.response.body.access_token}}
{
"flightNumber": "12BB",
"aircraftId": 1,
"departureAirportId": 1,
"aircraftId": "3c5c0000-97c6-fc34-fcd3-08db322230c8",
"departureAirportId": "3c5c0000-97c6-fc34-a0cb-08db322230c8",
"departureDate": "2022-03-01T14:55:41.255Z",
"arriveDate": "2022-03-01T14:55:41.255Z",
"arriveAirportId": 2,
"arriveAirportId": "3c5c0000-97c6-fc34-fc3c-08db322230c8",
"durationMinutes": 120,
"flightDate": "2022-03-01T14:55:41.255Z",
"status": 1,
@ -148,11 +148,11 @@ authorization: bearer {{Authenticate.response.body.access_token}}
{
"id": 1,
"flightNumber": "BD467",
"aircraftId": 1,
"departureAirportId": 1,
"aircraftId": "3c5c0000-97c6-fc34-fcd3-08db322230c8",
"departureAirportId": "3c5c0000-97c6-fc34-a0cb-08db322230c8",
"departureDate": "2022-04-23T12:17:45.140Z",
"arriveDate": "2022-04-23T12:17:45.140Z",
"arriveAirportId": 2,
"arriveAirportId": "3c5c0000-97c6-fc34-fc3c-08db322230c8",
"durationMinutes": 120,
"flightDate": "2022-04-23T12:17:45.140Z",
"status": 4,
@ -250,8 +250,8 @@ Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"passengerId": 8765596234940416,
"flightId": 1,
"passengerId": "8c9c0000-97c6-fc34-2eb9-66db322230c9",
"flightId": "3c5c0000-97c6-fc34-2eb9-08db322230c9",
"description": "I want to fly to iran"
}
###

View File

@ -18,7 +18,6 @@
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="6.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.UI.SQLite.Storage" Version="6.0.5" />
<PackageReference Include="Ben.BlockingDetector" Version="0.0.4" />
<PackageReference Include="DotNetEnv" Version="2.5.0" />
<PackageReference Include="EasyCaching.Core" Version="1.8.0" />
<PackageReference Include="EasyCaching.InMemory" Version="1.8.0" />
<PackageReference Include="EasyNetQ.Management.Client" Version="1.4.2" />

View File

@ -2,10 +2,10 @@ using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Contracts.EventBus.Messages;
public record FlightCreated(long Id) : IIntegrationEvent;
public record FlightUpdated(long Id) : IIntegrationEvent;
public record FlightDeleted(long Id) : IIntegrationEvent;
public record AircraftCreated(long Id) : IIntegrationEvent;
public record AirportCreated(long Id) : IIntegrationEvent;
public record SeatCreated(long Id) : IIntegrationEvent;
public record SeatReserved(long Id) : IIntegrationEvent;
public record FlightCreated(Guid Id) : IIntegrationEvent;
public record FlightUpdated(Guid Id) : IIntegrationEvent;
public record FlightDeleted(Guid Id) : IIntegrationEvent;
public record AircraftCreated(Guid Id) : IIntegrationEvent;
public record AirportCreated(Guid Id) : IIntegrationEvent;
public record SeatCreated(Guid Id) : IIntegrationEvent;
public record SeatReserved(Guid Id) : IIntegrationEvent;

View File

@ -2,4 +2,4 @@ using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Contracts.EventBus.Messages;
public record UserCreated(long Id, string Name, string PassportNumber) : IIntegrationEvent;
public record UserCreated(Guid Id, string Name, string PassportNumber) : IIntegrationEvent;

View File

@ -2,5 +2,5 @@ using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Contracts.EventBus.Messages;
public record PassengerRegistrationCompleted(long Id) : IIntegrationEvent;
public record PassengerCreated(long Id) : IIntegrationEvent;
public record PassengerRegistrationCompleted(Guid Id) : IIntegrationEvent;
public record PassengerCreated(Guid Id) : IIntegrationEvent;

View File

@ -2,4 +2,4 @@ using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Contracts.EventBus.Messages;
public record BookingCreated(long Id) : IIntegrationEvent;
public record BookingCreated(Guid Id) : IIntegrationEvent;

View File

@ -1,11 +1,12 @@
using BuildingBlocks.IdsGenerator;
using MediatR;
namespace BuildingBlocks.Core.Event;
using global::MassTransit;
public interface IEvent : INotification
{
long EventId => SnowflakeIdGenerator.NewId();
Guid EventId => NewId.NextGuid();
public DateTime OccurredOn => DateTime.Now;
public string EventType => GetType().AssemblyQualifiedName;
}

View File

@ -1,5 +1,4 @@
using BuildingBlocks.Core.CQRS;
using BuildingBlocks.IdsGenerator;
namespace BuildingBlocks.Core.Event;

View File

@ -1,32 +1,29 @@
using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Core.Model
namespace BuildingBlocks.Core.Model;
public abstract record Aggregate : Aggregate<long>;
public abstract record Aggregate<TId> : Audit, IAggregate<TId>
{
public abstract record Aggregate : Aggregate<long>
private readonly List<IDomainEvent> _domainEvents = new();
public IReadOnlyList<IDomainEvent> DomainEvents => _domainEvents.AsReadOnly();
public void AddDomainEvent(IDomainEvent domainEvent)
{
_domainEvents.Add(domainEvent);
}
public abstract record Aggregate<TId> : Audit, IAggregate<TId>
public IEvent[] ClearDomainEvents()
{
private readonly List<IDomainEvent> _domainEvents = new();
public IReadOnlyList<IDomainEvent> DomainEvents => _domainEvents.AsReadOnly();
IEvent[] dequeuedEvents = _domainEvents.ToArray();
public void AddDomainEvent(IDomainEvent domainEvent)
{
_domainEvents.Add(domainEvent);
}
_domainEvents.Clear();
public IEvent[] ClearDomainEvents()
{
IEvent[] dequeuedEvents = _domainEvents.ToArray();
_domainEvents.Clear();
return dequeuedEvents;
}
public long Version { get; set; }
public TId Id { get; set; }
return dequeuedEvents;
}
public long Version { get; set; }
public TId Id { get; set; }
}

View File

@ -7,7 +7,7 @@ public static class AggregateStreamExtensions
{
public static async Task<T?> AggregateStream<T>(
this EventStoreClient eventStore,
long id,
Guid id,
CancellationToken cancellationToken,
ulong? fromVersion = null
) where T : class, IProjection
@ -19,11 +19,13 @@ public static class AggregateStreamExtensions
cancellationToken: cancellationToken
);
// TODO: consider adding extension method for the aggregation and deserialisation
// TODO: consider adding extension method for the aggregation and deserialization
var aggregate = (T)Activator.CreateInstance(typeof(T), true)!;
if (await readResult.ReadState == ReadState.StreamNotFound)
{
return null;
}
await foreach (var @event in readResult)
{

View File

@ -4,9 +4,9 @@ using EventStore.Client;
namespace BuildingBlocks.EventStoreDB.Repository;
public interface IEventStoreDBRepository<T> where T : class, IAggregateEventSourcing<long>
public interface IEventStoreDBRepository<T> where T : class, IAggregateEventSourcing<Guid>
{
Task<T?> Find(long id, CancellationToken cancellationToken);
Task<T?> Find(Guid id, CancellationToken cancellationToken);
Task<ulong> Add(T aggregate, CancellationToken cancellationToken);
Task<ulong> Update(T aggregate, long? expectedRevision = null,
@ -15,7 +15,7 @@ public interface IEventStoreDBRepository<T> where T : class, IAggregateEventSour
Task<ulong> Delete(T aggregate, long? expectedRevision = null, CancellationToken cancellationToken = default);
}
public class EventStoreDBRepository<T> : IEventStoreDBRepository<T> where T : class, IAggregateEventSourcing<long>
public class EventStoreDBRepository<T> : IEventStoreDBRepository<T> where T : class, IAggregateEventSourcing<Guid>
{
private static readonly long _currentUserId;
private readonly EventStoreClient eventStore;
@ -25,7 +25,7 @@ public class EventStoreDBRepository<T> : IEventStoreDBRepository<T> where T : cl
this.eventStore = eventStore ?? throw new ArgumentNullException(nameof(eventStore));
}
public Task<T?> Find(long id, CancellationToken cancellationToken)
public Task<T?> Find(Guid id, CancellationToken cancellationToken)
{
return eventStore.AggregateStream<T>(
id,

View File

@ -7,9 +7,9 @@ public static class RepositoryExtensions
{
public static async Task<T> Get<T>(
this IEventStoreDBRepository<T> repository,
long id,
Guid id,
CancellationToken cancellationToken
) where T : class, IAggregateEventSourcing<long>
) where T : class, IAggregateEventSourcing<Guid>
{
var entity = await repository.Find(id, cancellationToken);
@ -18,11 +18,11 @@ public static class RepositoryExtensions
public static async Task<ulong> GetAndUpdate<T>(
this IEventStoreDBRepository<T> repository,
long id,
Guid id,
Action<T> action,
long? expectedVersion = null,
CancellationToken cancellationToken = default
) where T : class, IAggregateEventSourcing<long>
) where T : class, IAggregateEventSourcing<Guid>
{
var entity = await repository.Get(id, cancellationToken);

View File

@ -2,11 +2,11 @@ namespace BuildingBlocks.Exception;
public class AggregateNotFoundException : System.Exception
{
public AggregateNotFoundException(string typeName, long id) : base($"{typeName} with id '{id}' was not found")
public AggregateNotFoundException(string typeName, Guid id) : base($"{typeName} with id '{id}' was not found")
{
}
public static AggregateNotFoundException For<T>(long id)
public static AggregateNotFoundException For<T>(Guid id)
{
return new AggregateNotFoundException(typeof(T).Name, id);
}

View File

@ -1,35 +0,0 @@
using IdGen;
namespace BuildingBlocks.IdsGenerator;
// Ref: https://github.com/RobThree/IdGen
// https://github.com/RobThree/IdGen/issues/34
// https://www.callicoder.com/distributed-unique-id-sequence-number-generator/
public static class SnowflakeIdGenerator
{
private static readonly IdGenerator Generator;
static SnowflakeIdGenerator()
{
// Read `GENERATOR_ID` from .env file in service root folder or system environment variables
var generatorId = DotNetEnv.Env.GetInt("GENERATOR_ID", 0);
// Let's say we take current time as our epoch
var epoch = DateTime.Now;
// Create an ID with 45 bits for timestamp, 2 for generator-id
// and 16 for sequence
var structure = new IdStructure(45, 2, 16);
// Prepare options
var options = new IdGeneratorOptions(structure, new DefaultTimeSource(epoch));
// Create an IdGenerator with it's generator-id set to 0, our custom epoch
// and id-structure
Generator = new IdGenerator(generatorId, options);
}
public static long NewId()
{
return Generator.CreateId();
}
}

View File

@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BuildingBlocks.PersistMessageProcessor.Data.Migrations
{
[DbContext(typeof(PersistMessageDbContext))]
[Migration("20230122204943_initial")]
[Migration("20230331173133_initial")]
partial class initial
{
/// <inheritdoc />
@ -20,15 +20,15 @@ namespace BuildingBlocks.PersistMessageProcessor.Data.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.1")
.HasAnnotation("ProductVersion", "7.0.2")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("BuildingBlocks.PersistMessageProcessor.PersistMessage", b =>
{
b.Property<long>("Id")
.HasColumnType("bigint")
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<DateTime>("Created")

View File

@ -15,7 +15,7 @@ namespace BuildingBlocks.PersistMessageProcessor.Data.Migrations
name: "persist_message",
columns: table => new
{
id = table.Column<long>(type: "bigint", nullable: false),
id = table.Column<Guid>(type: "uuid", nullable: false),
datatype = table.Column<string>(name: "data_type", type: "text", nullable: true),
data = table.Column<string>(type: "text", nullable: true),
created = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),

View File

@ -17,15 +17,15 @@ namespace BuildingBlocks.PersistMessageProcessor.Data.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.1")
.HasAnnotation("ProductVersion", "7.0.2")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("BuildingBlocks.PersistMessageProcessor.PersistMessage", b =>
{
b.Property<long>("Id")
.HasColumnType("bigint")
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<DateTime>("Created")

View File

@ -15,7 +15,7 @@ public interface IPersistMessageProcessor
CancellationToken cancellationToken = default)
where TMessageEnvelope : MessageEnvelope;
Task<long> AddReceivedMessageAsync<TMessageEnvelope>(
Task<Guid> AddReceivedMessageAsync<TMessageEnvelope>(
TMessageEnvelope messageEnvelope,
CancellationToken cancellationToken = default)
where TMessageEnvelope : MessageEnvelope;
@ -30,14 +30,14 @@ public interface IPersistMessageProcessor
CancellationToken cancellationToken = default);
Task<PersistMessage> ExistMessageAsync(
long messageId,
Guid messageId,
CancellationToken cancellationToken = default);
Task ProcessInboxAsync(
long messageId,
Guid messageId,
CancellationToken cancellationToken = default);
Task ProcessAsync(long messageId, MessageDeliveryType deliveryType, CancellationToken cancellationToken = default);
Task ProcessAsync(Guid messageId, MessageDeliveryType deliveryType, CancellationToken cancellationToken = default);
Task ProcessAllAsync(CancellationToken cancellationToken = default);
}

View File

@ -4,7 +4,7 @@ using Core.Model;
public class PersistMessage: IVersion
{
public PersistMessage(long id, string dataType, string data, MessageDeliveryType deliveryType)
public PersistMessage(Guid id, string dataType, string data, MessageDeliveryType deliveryType)
{
Id = id;
DataType = dataType;
@ -15,7 +15,7 @@ public class PersistMessage: IVersion
RetryCount = 0;
}
public long Id { get; private set; }
public Guid Id { get; private set; }
public string DataType { get; private set; }
public string Data { get; private set; }
public DateTime Created { get; private set; }

View File

@ -2,7 +2,6 @@
using System.Text.Json;
using Ardalis.GuardClauses;
using BuildingBlocks.Core.Event;
using BuildingBlocks.IdsGenerator;
using BuildingBlocks.Utils;
using MassTransit;
using MediatR;
@ -40,7 +39,7 @@ public class PersistMessageProcessor : IPersistMessageProcessor
await SavePersistMessageAsync(messageEnvelope, MessageDeliveryType.Outbox, cancellationToken);
}
public Task<long> AddReceivedMessageAsync<TMessageEnvelope>(TMessageEnvelope messageEnvelope,
public Task<Guid> AddReceivedMessageAsync<TMessageEnvelope>(TMessageEnvelope messageEnvelope,
CancellationToken cancellationToken = default) where TMessageEnvelope : MessageEnvelope
{
return SavePersistMessageAsync(messageEnvelope, MessageDeliveryType.Inbox, cancellationToken);
@ -60,7 +59,7 @@ public class PersistMessageProcessor : IPersistMessageProcessor
.AsReadOnly();
}
public Task<PersistMessage> ExistMessageAsync(long messageId, CancellationToken cancellationToken = default)
public Task<PersistMessage> ExistMessageAsync(Guid messageId, CancellationToken cancellationToken = default)
{
return _persistMessageDbContext.PersistMessages.FirstOrDefaultAsync(x =>
x.Id == messageId &&
@ -70,7 +69,7 @@ public class PersistMessageProcessor : IPersistMessageProcessor
}
public async Task ProcessAsync(
long messageId,
Guid messageId,
MessageDeliveryType deliveryType,
CancellationToken cancellationToken = default)
{
@ -131,7 +130,7 @@ public class PersistMessageProcessor : IPersistMessageProcessor
}
}
public async Task ProcessInboxAsync(long messageId, CancellationToken cancellationToken = default)
public async Task ProcessInboxAsync(Guid messageId, CancellationToken cancellationToken = default)
{
var message = await _persistMessageDbContext.PersistMessages.FirstOrDefaultAsync(
x => x.Id == messageId &&
@ -191,18 +190,18 @@ public class PersistMessageProcessor : IPersistMessageProcessor
return true;
}
private async Task<long> SavePersistMessageAsync(
private async Task<Guid> SavePersistMessageAsync(
MessageEnvelope messageEnvelope,
MessageDeliveryType deliveryType,
CancellationToken cancellationToken = default)
{
Guard.Against.Null(messageEnvelope.Message, nameof(messageEnvelope.Message));
long id;
Guid id;
if (messageEnvelope.Message is IEvent message)
id = message.EventId;
else
id = SnowflakeIdGenerator.NewId();
id = NewId.NextGuid();
await _persistMessageDbContext.PersistMessages.AddAsync(
new PersistMessage(

View File

@ -398,7 +398,7 @@ public class TestWriteFixture<TEntryPoint, TWContext> : TestFixture<TEntryPoint>
});
}
public Task<T> FindAsync<T>(long id)
public Task<T> FindAsync<T>(Guid id)
where T : class, IAudit
{
return ExecuteDbContextAsync(db => db.Set<T>().FindAsync(id).AsTask());

View File

@ -1 +0,0 @@
GENERATOR_ID=4

View File

@ -1,4 +1,4 @@
namespace Booking.Booking.Dtos;
public record BookingResponseDto(long Id, string Name, string FlightNumber, long AircraftId, decimal Price,
DateTime FlightDate, string SeatNumber, long DepartureAirportId, long ArriveAirportId, string Description);
public record BookingResponseDto(Guid Id, string Name, string FlightNumber, Guid AircraftId, decimal Price,
DateTime FlightDate, string SeatNumber, Guid DepartureAirportId, Guid ArriveAirportId, string Description);

View File

@ -4,4 +4,4 @@ using BuildingBlocks.Core.Event;
using BuildingBlocks.Core.Model;
using Models.ValueObjects;
public record BookingCreatedDomainEvent(long Id, PassengerInfo PassengerInfo, Trip Trip) : Audit, IDomainEvent;
public record BookingCreatedDomainEvent(Guid Id, PassengerInfo PassengerInfo, Trip Trip) : Audit, IDomainEvent;

View File

@ -5,17 +5,17 @@ using BuildingBlocks.Core;
using BuildingBlocks.Core.CQRS;
using BuildingBlocks.Core.Event;
using BuildingBlocks.EventStoreDB.Repository;
using BuildingBlocks.IdsGenerator;
using BuildingBlocks.Web;
using Exceptions;
using Flight;
using FluentValidation;
using MassTransit;
using Models.ValueObjects;
using Passenger;
public record CreateBooking(long PassengerId, long FlightId, string Description) : ICommand<CreateBookingResult>, IInternalCommand
public record CreateBooking(Guid PassengerId, Guid FlightId, string Description) : ICommand<CreateBookingResult>, IInternalCommand
{
public long Id { get; init; } = SnowflakeIdGenerator.NewId();
public Guid Id { get; init; } = NewId.NextGuid();
}
public record CreateBookingResult(ulong Id);
@ -54,19 +54,17 @@ internal class CreateBookingCommandHandler : ICommandHandler<CreateBooking, Crea
{
Guard.Against.Null(command, nameof(command));
var flight = await _flightGrpcServiceClient.GetByIdAsync(new Flight.GetByIdRequest { Id = command.FlightId });
var flight = await _flightGrpcServiceClient.GetByIdAsync(new Flight.GetByIdRequest { Id = command.FlightId.ToString()});
if (flight is null)
{
throw new FlightNotFoundException();
}
var passenger =
await _passengerGrpcServiceClient.GetByIdAsync(new Passenger.GetByIdRequest { Id = command.PassengerId });
var passenger = await _passengerGrpcServiceClient.GetByIdAsync(new Passenger.GetByIdRequest { Id = command.PassengerId.ToString() });
var emptySeat = (await _flightGrpcServiceClient
.GetAvailableSeatsAsync(new GetAvailableSeatsRequest { FlightId = command.FlightId }).ResponseAsync)
?.Items?.FirstOrDefault();
var emptySeat = (await _flightGrpcServiceClient.GetAvailableSeatsAsync(new GetAvailableSeatsRequest { FlightId = command.FlightId.ToString() }).ResponseAsync)
?.SeatDtos?.FirstOrDefault();
var reservation = await _eventStoreDbRepository.Find(command.Id, cancellationToken);
@ -75,9 +73,9 @@ internal class CreateBookingCommandHandler : ICommandHandler<CreateBooking, Crea
throw new BookingAlreadyExistException();
}
var aggrigate = Models.Booking.Create(command.Id, new PassengerInfo(passenger.Name), new Trip(
flight.FlightNumber, flight.AircraftId, flight.DepartureAirportId,
flight.ArriveAirportId, flight.FlightDate.ToDateTime(), (decimal)flight.Price, command.Description,
var aggrigate = Models.Booking.Create(command.Id, new PassengerInfo(passenger.PassengerDto?.Name), new Trip(
flight.FlightDto.FlightNumber, new Guid(flight.FlightDto.AircraftId), new Guid(flight.FlightDto.DepartureAirportId),
new Guid(flight.FlightDto.ArriveAirportId), flight.FlightDto.FlightDate.ToDateTime(), (decimal)flight.FlightDto.Price, command.Description,
emptySeat?.SeatNumber),
false, _currentUserProvider.GetCurrentUserId());
@ -85,7 +83,7 @@ internal class CreateBookingCommandHandler : ICommandHandler<CreateBooking, Crea
await _flightGrpcServiceClient.ReserveSeatAsync(new ReserveSeatRequest
{
FlightId = flight.Id, SeatNumber = emptySeat?.SeatNumber
FlightId = flight.FlightDto.Id, SeatNumber = emptySeat?.SeatNumber
});
var result = await _eventStoreDbRepository.Add(

View File

@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Swashbuckle.AspNetCore.Annotations;
public record CreateBookingRequestDto(long PassengerId, long FlightId, string Description);
public record CreateBookingRequestDto(Guid PassengerId, Guid FlightId, string Description);
public record CreateBookingResponseDto(ulong Id);
public class CreateBookingEndpoint : IMinimalEndpoint

View File

@ -5,12 +5,12 @@ namespace Booking.Booking.Models;
using Features.CreatingBook.Commands.V1;
public record Booking : AggregateEventSourcing<long>
public record Booking : AggregateEventSourcing<Guid>
{
public Trip Trip { get; private set; }
public PassengerInfo PassengerInfo { get; private set; }
public static Booking Create(long id, PassengerInfo passengerInfo, Trip trip, bool isDeleted = false, long? userId = null)
public static Booking Create(Guid id, PassengerInfo passengerInfo, Trip trip, bool isDeleted = false, long? userId = null)
{
var booking = new Booking { Id = id, Trip = trip, PassengerInfo = passengerInfo, IsDeleted = isDeleted };

View File

@ -1,11 +1,11 @@
using Booking.Booking.Models.ValueObjects;
namespace Booking.Booking.Models;
namespace Booking.Booking.Models.Reads;
using ValueObjects;
public class BookingReadModel
{
public long Id { get; init; }
public long BookId { get; init; }
public Guid Id { get; init; }
public Guid BookId { get; init; }
public Trip Trip { get; init; }
public PassengerInfo PassengerInfo { get; init; }
public bool IsDeleted { get; init; }

View File

@ -1,4 +1,4 @@
namespace Booking.Booking.Models.ValueObjects;
public record Trip(string FlightNumber, long AircraftId, long DepartureAirportId, long ArriveAirportId,
public record Trip(string FlightNumber, Guid AircraftId, Guid DepartureAirportId, Guid ArriveAirportId,
DateTime FlightDate, decimal Price, string Description, string SeatNumber);

View File

@ -1,8 +1,6 @@
using Booking.Booking.Models.Reads;
using Booking.Data;
using BuildingBlocks.EventStoreDB.Events;
using BuildingBlocks.EventStoreDB.Projections;
using BuildingBlocks.IdsGenerator;
using MediatR;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
@ -10,6 +8,8 @@ using MongoDB.Driver.Linq;
namespace Booking;
using Booking.Features.CreatingBook.Commands.V1;
using Booking.Models;
using MassTransit;
public class BookingProjection : IProjectionProcessor
{
@ -41,7 +41,7 @@ public class BookingProjection : IProjectionProcessor
{
var bookingReadModel = new BookingReadModel
{
Id = SnowflakeIdGenerator.NewId(),
Id = NewId.NextGuid(),
Trip = @event.Trip,
BookId = @event.Id,
PassengerInfo = @event.PassengerInfo,

View File

@ -1,11 +1,12 @@
using Booking.Booking.Models.Reads;
using BuildingBlocks.Mongo;
using BuildingBlocks.Mongo;
using Humanizer;
using Microsoft.Extensions.Options;
using MongoDB.Driver;
namespace Booking.Data;
using Booking.Models;
public class BookingReadDbContext : MongoDbContext
{
public BookingReadDbContext(IOptions<MongoOptions> options) : base(options)

View File

@ -33,9 +33,6 @@ public static class InfrastructureExtensions
var configuration = builder.Configuration;
var env = builder.Environment;
// https://github.com/tonerdo/dotnet-env
DotNetEnv.Env.TraversePath().Load();
builder.Services.AddScoped<ICurrentUserProvider, CurrentUserProvider>();
builder.Services.AddScoped<IEventMapper, EventMapper>();
builder.Services.AddScoped<IEventDispatcher, EventDispatcher>();

View File

@ -5,51 +5,60 @@ import "google/protobuf/timestamp.proto";
service FlightGrpcService {
rpc GetById (GetByIdRequest) returns (FlightResponse);
rpc GetAvailableSeats (GetAvailableSeatsRequest) returns (ListSeatsResponse);
rpc ReserveSeat (ReserveSeatRequest) returns (SeatsResponse);
rpc GetById (GetByIdRequest) returns (GetFlightByIdResult);
rpc GetAvailableSeats (GetAvailableSeatsRequest) returns (GetAvailableSeatsResult);
rpc ReserveSeat (ReserveSeatRequest) returns (ReserveSeatResult);
}
message GetByIdRequest {
int64 Id = 1;
string Id = 1;
}
message GetFlightByIdResult{
FlightResponse FlightDto = 1;
}
message GetAvailableSeatsResult{
repeated SeatDtoResponse SeatDtos = 1;
}
message ReserveSeatResult{
string Id = 1;
}
message FlightResponse {
int64 Id = 1;
string Id = 1;
string FlightNumber = 2;
int64 AircraftId = 3;
int64 DepartureAirportId = 4;
string AircraftId = 3;
string DepartureAirportId = 4;
google.protobuf.Timestamp DepartureDate = 5;
google.protobuf.Timestamp ArriveDate = 6;
int64 ArriveAirportId = 7;
string ArriveAirportId = 7;
double DurationMinutes = 8;
google.protobuf.Timestamp FlightDate = 9;
FlightStatus Status = 10;
double Price = 11;
int64 FlightId = 12;
string FlightId = 12;
}
message GetAvailableSeatsRequest {
int64 FlightId = 1;
string FlightId = 1;
}
message SeatsResponse {
int64 Id = 1;
message SeatDtoResponse {
string Id = 1;
string SeatNumber = 2;
SeatType Type = 3;
SeatClass Class = 4;
int64 FlightId = 5;
string FlightId = 5;
}
message ReserveSeatRequest {
int64 FlightId = 1;
string FlightId = 1;
string SeatNumber = 2;
}
message ListSeatsResponse {
repeated SeatsResponse items = 1;
}
enum FlightStatus {
FLIGHT_STATUS_UNKNOWN = 0;

View File

@ -4,15 +4,19 @@ package passenger;
service PassengerGrpcService {
rpc GetById (GetByIdRequest) returns (PassengerResponse);
rpc GetById (GetByIdRequest) returns (GetPassengerByIdResult);
}
message GetByIdRequest {
int64 Id = 1;
string Id = 1;
}
message GetPassengerByIdResult {
PassengerResponse PassengerDto = 1;
}
message PassengerResponse {
int64 Id = 1;
string Id = 1;
string Name = 2;
string PassportNumber = 3;
PassengerType PassengerType = 4;

View File

@ -1,5 +1,4 @@
using System.Linq;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Booking.Api;
using Booking.Data;
using BuildingBlocks.Contracts.EventBus.Messages;
@ -54,7 +53,7 @@ namespace Integration.Test.Booking.Features
var mockPassenger = Substitute.For<PassengerGrpcService.PassengerGrpcServiceClient>();
mockPassenger.GetByIdAsync(Arg.Any<Passenger.GetByIdRequest>())
.Returns(TestCalls.AsyncUnaryCall(Task.FromResult(new FakePassengerResponse().Generate()),
.Returns(TestCalls.AsyncUnaryCall(Task.FromResult(FakePassengerResponse.Generate()),
Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }));
return mockPassenger;
@ -68,15 +67,15 @@ namespace Integration.Test.Booking.Features
var mockFlight = Substitute.For<FlightGrpcService.FlightGrpcServiceClient>();
mockFlight.GetByIdAsync(Arg.Any<GetByIdRequest>())
.Returns(TestCalls.AsyncUnaryCall(Task.FromResult(new FakeFlightResponse().Generate()),
.Returns(TestCalls.AsyncUnaryCall(Task.FromResult(FakeFlightResponse.Generate()),
Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }));
mockFlight.GetAvailableSeatsAsync(Arg.Any<GetAvailableSeatsRequest>())
.Returns(TestCalls.AsyncUnaryCall(Task.FromResult(FakeSeatsResponse.Generate()),
.Returns(TestCalls.AsyncUnaryCall(Task.FromResult(FakeGetAvailableSeatsResponse.Generate()),
Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }));
mockFlight.ReserveSeatAsync(Arg.Any<ReserveSeatRequest>())
.Returns(TestCalls.AsyncUnaryCall(Task.FromResult(FakeSeatsResponse.Generate()?.Items?.First()),
.Returns(TestCalls.AsyncUnaryCall(Task.FromResult(FakeReserveSeatResponse.Generate()),
Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }));
return mockFlight;

View File

@ -1,16 +1,17 @@
using AutoBogus;
using BuildingBlocks.IdsGenerator;
namespace Integration.Test.Fakes;
using System;
using global::Booking.Booking.Features.CreatingBook.Commands.V1;
using MassTransit;
public sealed class FakeCreateBookingCommand : AutoFaker<CreateBooking>
{
public FakeCreateBookingCommand()
{
RuleFor(r => r.Id, _ => SnowflakeIdGenerator.NewId());
RuleFor(r => r.FlightId, _ => 1);
RuleFor(r => r.PassengerId, _ => 1);
RuleFor(r => r.Id, _ => NewId.NextGuid());
RuleFor(r => r.FlightId, _ => new Guid("3c5c0000-97c6-fc34-2eb9-08db322230c9"));
RuleFor(r => r.PassengerId, _ => new Guid("4c5c8888-97c6-fc34-2eb9-18db322230c1"));
}
}

View File

@ -5,19 +5,27 @@ using Google.Protobuf.WellKnownTypes;
namespace Integration.Test.Fakes;
public class FakeFlightResponse : AutoFaker<FlightResponse>
public static class FakeFlightResponse
{
public FakeFlightResponse()
public static GetFlightByIdResult Generate()
{
RuleFor(r => r.Id, _ => 1);
RuleFor(r => r.Price, _ => 100);
RuleFor(r => r.Status, _ => FlightStatus.Completed);
RuleFor(r => r.AircraftId, _ => 1);
RuleFor(r => r.ArriveAirportId, _ => 1);
RuleFor(r => r.ArriveDate, _ => DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc).ToTimestamp());
RuleFor(r => r.DepartureDate, _ => DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc).ToTimestamp());
RuleFor(r => r.FlightDate, _ => DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc).ToTimestamp());
RuleFor(r => r.FlightNumber, r => r.Random.Number(1000, 2000).ToString());
RuleFor(r => r.DepartureAirportId, _ => 2);
var flightMock = new GetFlightByIdResult
{
FlightDto = new FlightResponse
{
Id = new Guid("3c5c0000-97c6-fc34-2eb9-08db322230c9").ToString(),
Price = 100,
Status = FlightStatus.Completed,
AircraftId = new Guid("3c5c0000-97c6-fc34-fcd3-08db322230c8").ToString(),
ArriveAirportId = new Guid("3c5c0000-97c6-fc34-a0cb-08db322230c8").ToString(),
ArriveDate = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc).ToTimestamp(),
DepartureDate = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc).ToTimestamp(),
FlightDate = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc).ToTimestamp(),
FlightNumber = "1500B",
DepartureAirportId = new Guid("3c5c0000-97c6-fc34-fc3c-08db322230c8").ToString()
}
};
return flightMock;
}
}

View File

@ -0,0 +1,36 @@
using System.Collections.Generic;
using Flight;
namespace Integration.Test.Fakes;
using System;
using MassTransit;
public static class FakeGetAvailableSeatsResponse
{
public static GetAvailableSeatsResult Generate()
{
var result = new GetAvailableSeatsResult();
result.SeatDtos.AddRange(new List<SeatDtoResponse>
{
new SeatDtoResponse()
{
FlightId = new Guid("3c5c0000-97c6-fc34-2eb9-08db322230c9").ToString(),
Class = SeatClass.Economy,
Type = SeatType.Aisle,
SeatNumber = "33F",
Id = NewId.NextGuid().ToString()
},
new SeatDtoResponse()
{
FlightId = new Guid("3c5c0000-97c6-fc34-2eb9-08db322230c9").ToString(),
Class = SeatClass.Economy,
Type = SeatType.Window,
SeatNumber = "22D",
Id = NewId.NextGuid().ToString()
}
});
return result;
}
}

View File

@ -1,13 +1,22 @@
using AutoBogus;
using BuildingBlocks.IdsGenerator;
namespace Integration.Test.Fakes;
using MassTransit;
using Passenger;
namespace Integration.Test.Fakes;
public class FakePassengerResponse : AutoFaker<PassengerResponse>
public static class FakePassengerResponse
{
public FakePassengerResponse()
public static GetPassengerByIdResult Generate()
{
RuleFor(r => r.Id, _ => SnowflakeIdGenerator.NewId());
var result = new GetPassengerByIdResult
{
PassengerDto = new PassengerResponse()
{
Id = NewId.NextGuid().ToString(),
Name = "Test",
PassportNumber = "121618"
}
};
return result;
}
}

View File

@ -0,0 +1,14 @@
namespace Integration.Test.Fakes;
using Flight;
using MassTransit;
public static class FakeReserveSeatResponse
{
public static ReserveSeatResult Generate()
{
var result = new ReserveSeatResult();
result.Id = NewId.NextGuid().ToString();
return result;
}
}

View File

@ -1,33 +0,0 @@
using System.Collections.Generic;
using Flight;
namespace Integration.Test.Fakes;
public static class FakeSeatsResponse
{
public static ListSeatsResponse Generate()
{
var result = new ListSeatsResponse();
result.Items.AddRange(new List<SeatsResponse>
{
new SeatsResponse()
{
FlightId = 1,
Class = SeatClass.Economy,
Type = SeatType.Aisle,
SeatNumber = "33F",
Id = 1
},
new SeatsResponse()
{
FlightId = 1,
Class = SeatClass.Economy,
Type = SeatType.Window,
SeatNumber = "22D",
Id = 2
}
});
return result;
}
}

View File

@ -1 +0,0 @@
GENERATOR_ID=1

View File

@ -1,21 +1,21 @@
using BuildingBlocks.IdsGenerator;
using Flight.Aircrafts.Models;
using Flight.Aircrafts.Models;
using Mapster;
namespace Flight.Aircrafts.Features;
using CreatingAircraft.V1;
using MassTransit;
public class AircraftMappings : IRegister
{
public void Register(TypeAdapterConfig config)
{
config.NewConfig<CreateAircraftMongo, AircraftReadModel>()
.Map(d => d.Id, s => SnowflakeIdGenerator.NewId())
.Map(d => d.Id, s => NewId.NextGuid())
.Map(d => d.AircraftId, s => s.Id);
config.NewConfig<Aircraft, AircraftReadModel>()
.Map(d => d.Id, s => SnowflakeIdGenerator.NewId())
.Map(d => d.Id, s => NewId.NextGuid())
.Map(d => d.AircraftId, s => s.Id);
config.NewConfig<CreateAircraftRequestDto, CreatingAircraft.V1.CreateAircraft>()

View File

@ -1,5 +1,6 @@
namespace Flight.Aircrafts.Features.CreatingAircraft.V1;
using System;
using BuildingBlocks.Core.Event;
public record AircraftCreatedDomainEvent(long Id, string Name, string Model, int ManufacturingYear, bool IsDeleted) : IDomainEvent;
public record AircraftCreatedDomainEvent(Guid Id, string Name, string Model, int ManufacturingYear, bool IsDeleted) : IDomainEvent;

View File

@ -1,26 +1,25 @@
namespace Flight.Aircrafts.Features.CreatingAircraft.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using Ardalis.GuardClauses;
using BuildingBlocks.Core.CQRS;
using BuildingBlocks.Core.Event;
using BuildingBlocks.IdsGenerator;
using Exceptions;
using Flight.Aircrafts.Dtos;
using Flight.Aircrafts.Models;
using Flight.Data;
using Models;
using Data;
using FluentValidation;
using MapsterMapper;
using MassTransit;
using MediatR;
using Microsoft.EntityFrameworkCore;
public record CreateAircraft(string Name, string Model, int ManufacturingYear) : ICommand<CreateAircraftResult>, IInternalCommand
{
public long Id { get; init; } = SnowflakeIdGenerator.NewId();
public Guid Id { get; init; } = NewId.NextGuid();
}
public record CreateAircraftResult(long Id);
public record CreateAircraftResult(Guid Id);
internal class CreateAircraftValidator : AbstractValidator<CreateAircraft>
{

View File

@ -1,5 +1,6 @@
namespace Flight.Aircrafts.Features.CreatingAircraft.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
@ -11,7 +12,7 @@ using Microsoft.AspNetCore.Routing;
using Swashbuckle.AspNetCore.Annotations;
public record CreateAircraftRequestDto(string Name, string Model, int ManufacturingYear);
public record CreateAircraftResponseDto(long Id);
public record CreateAircraftResponseDto(Guid Id);
public class CreateAircraftEndpoint : IMinimalEndpoint
{

View File

@ -1,5 +1,6 @@
namespace Flight.Aircrafts.Features.CreatingAircraft.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using Ardalis.GuardClauses;
@ -13,7 +14,7 @@ using MediatR;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
public record CreateAircraftMongo(long Id, string Name, string Model, int ManufacturingYear, bool IsDeleted) : InternalCommand;
public record CreateAircraftMongo(Guid Id, string Name, string Model, int ManufacturingYear, bool IsDeleted) : InternalCommand;
public class CreateAircraftMongoHandler : ICommandHandler<CreateAircraftMongo>
{

View File

@ -2,15 +2,16 @@ using BuildingBlocks.Core.Model;
namespace Flight.Aircrafts.Models;
using System;
using Features.CreatingAircraft.V1;
public record Aircraft : Aggregate<long>
public record Aircraft : Aggregate<Guid>
{
public string Name { get; private set; }
public string Model { get; private set; }
public int ManufacturingYear { get; private set; }
public static Aircraft Create(long id, string name, string model, int manufacturingYear, bool isDeleted = false)
public static Aircraft Create(Guid id, string name, string model, int manufacturingYear, bool isDeleted = false)
{
var aircraft = new Aircraft
{

View File

@ -1,9 +1,11 @@
namespace Flight.Aircrafts.Models;
using System;
public class AircraftReadModel
{
public long Id { get; init; }
public long AircraftId { get; init; }
public Guid Id { get; init; }
public Guid AircraftId { get; init; }
public string Name { get; init; }
public string Model { get; init; }
public int ManufacturingYear { get; init; }

View File

@ -1,20 +1,20 @@
namespace Flight.Airports.Features;
using BuildingBlocks.IdsGenerator;
using Flight.Airports.Features.CreatingAirport.V1;
using Flight.Airports.Models;
using CreatingAirport.V1;
using Models;
using Mapster;
using MassTransit;
public class AirportMappings : IRegister
{
public void Register(TypeAdapterConfig config)
{
config.NewConfig<CreateAirportMongo, AirportReadModel>()
.Map(d => d.Id, s => SnowflakeIdGenerator.NewId())
.Map(d => d.Id, s => NewId.NextGuid())
.Map(d => d.AirportId, s => s.Id);
config.NewConfig<Airport, AirportReadModel>()
.Map(d => d.Id, s => SnowflakeIdGenerator.NewId())
.Map(d => d.Id, s => NewId.NextGuid())
.Map(d => d.AirportId, s => s.Id);
config.NewConfig<CreateAirportRequestDto, CreateAirport>()

View File

@ -1,5 +1,6 @@
namespace Flight.Airports.Features.CreatingAirport.V1;
using System;
using BuildingBlocks.Core.Event;
public record AirportCreatedDomainEvent(long Id, string Name, string Address, string Code, bool IsDeleted) : IDomainEvent;
public record AirportCreatedDomainEvent(Guid Id, string Name, string Address, string Code, bool IsDeleted) : IDomainEvent;

View File

@ -1,25 +1,24 @@
namespace Flight.Airports.Features.CreatingAirport.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using Ardalis.GuardClauses;
using BuildingBlocks.Core.CQRS;
using BuildingBlocks.Core.Event;
using BuildingBlocks.IdsGenerator;
using Dtos;
using Exceptions;
using Data;
using FluentValidation;
using MapsterMapper;
using MassTransit;
using MediatR;
using Microsoft.EntityFrameworkCore;
public record CreateAirport(string Name, string Address, string Code) : ICommand<CreateAirportResult>, IInternalCommand
{
public long Id { get; init; } = SnowflakeIdGenerator.NewId();
public Guid Id { get; init; } = NewId.NextGuid();
}
public record CreateAirportResult(long Id);
public record CreateAirportResult(Guid Id);
internal class CreateAirportValidator : AbstractValidator<CreateAirport>
{

View File

@ -1,5 +1,6 @@
namespace Flight.Airports.Features.CreatingAirport.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
@ -11,7 +12,7 @@ using Microsoft.AspNetCore.Routing;
using Swashbuckle.AspNetCore.Annotations;
public record CreateAirportRequestDto(string Name, string Address, string Code);
public record CreateAirportResponseDto(long Id);
public record CreateAirportResponseDto(Guid Id);
public class CreateAirportEndpoint : IMinimalEndpoint
{

View File

@ -1,5 +1,6 @@
namespace Flight.Airports.Features.CreatingAirport.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using Ardalis.GuardClauses;
@ -13,7 +14,7 @@ using MediatR;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
public record CreateAirportMongo(long Id, string Name, string Address, string Code, bool IsDeleted) : InternalCommand;
public record CreateAirportMongo(Guid Id, string Name, string Address, string Code, bool IsDeleted) : InternalCommand;
internal class CreateAirportMongoHandler : ICommandHandler<CreateAirportMongo>
{

View File

@ -1,17 +1,17 @@
using BuildingBlocks.Core.Model;
using BuildingBlocks.IdsGenerator;
namespace Flight.Airports.Models;
using System;
using Features.CreatingAirport.V1;
public record Airport : Aggregate<long>
public record Airport : Aggregate<Guid>
{
public string Name { get; private set; }
public string Address { get; private set; }
public string Code { get; private set; }
public static Airport Create(long id, string name, string address, string code, bool isDeleted = false)
public static Airport Create(Guid id, string name, string address, string code, bool isDeleted = false)
{
var airport = new Airport
{

View File

@ -1,9 +1,11 @@
namespace Flight.Airports.Models;
using System;
public class AirportReadModel
{
public long Id { get; init; }
public long AirportId { get; init; }
public Guid Id { get; init; }
public Guid AirportId { get; init; }
public string Name { get; init; }
public string Address { get; init; }
public string Code { get; init; }

View File

@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Flight.Data.Migrations
{
[DbContext(typeof(FlightDbContext))]
[Migration("20230120222458_Init")]
[Migration("20230331144237_Init")]
partial class Init
{
/// <inheritdoc />
@ -20,15 +20,15 @@ namespace Flight.Data.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.1")
.HasAnnotation("ProductVersion", "7.0.2")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Flight.Aircrafts.Models.Aircraft", b =>
{
b.Property<long>("Id")
.HasColumnType("bigint")
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<DateTime?>("CreatedAt")
@ -76,8 +76,8 @@ namespace Flight.Data.Migrations
modelBuilder.Entity("Flight.Airports.Models.Airport", b =>
{
b.Property<long>("Id")
.HasColumnType("bigint")
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<string>("Address")
@ -125,16 +125,16 @@ namespace Flight.Data.Migrations
modelBuilder.Entity("Flight.Flights.Models.Flight", b =>
{
b.Property<long>("Id")
.HasColumnType("bigint")
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<long>("AircraftId")
.HasColumnType("bigint")
b.Property<Guid>("AircraftId")
.HasColumnType("uuid")
.HasColumnName("aircraft_id");
b.Property<long>("ArriveAirportId")
.HasColumnType("bigint")
b.Property<Guid>("ArriveAirportId")
.HasColumnType("uuid")
.HasColumnName("arrive_airport_id");
b.Property<DateTime>("ArriveDate")
@ -149,8 +149,8 @@ namespace Flight.Data.Migrations
.HasColumnType("bigint")
.HasColumnName("created_by");
b.Property<long>("DepartureAirportId")
.HasColumnType("bigint")
b.Property<Guid>("DepartureAirportId")
.HasColumnType("uuid")
.HasColumnName("departure_airport_id");
b.Property<DateTime>("DepartureDate")
@ -211,8 +211,8 @@ namespace Flight.Data.Migrations
modelBuilder.Entity("Flight.Seats.Models.Seat", b =>
{
b.Property<long>("Id")
.HasColumnType("bigint")
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<string>("Class")
@ -230,8 +230,8 @@ namespace Flight.Data.Migrations
.HasColumnType("bigint")
.HasColumnName("created_by");
b.Property<long>("FlightId")
.HasColumnType("bigint")
b.Property<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("flight_id");
b.Property<bool>("IsDeleted")

View File

@ -15,7 +15,7 @@ namespace Flight.Data.Migrations
name: "aircraft",
columns: table => new
{
id = table.Column<long>(type: "bigint", nullable: false),
id = table.Column<Guid>(type: "uuid", nullable: false),
name = table.Column<string>(type: "text", nullable: true),
model = table.Column<string>(type: "text", nullable: true),
manufacturingyear = table.Column<int>(name: "manufacturing_year", type: "integer", nullable: false),
@ -35,7 +35,7 @@ namespace Flight.Data.Migrations
name: "airport",
columns: table => new
{
id = table.Column<long>(type: "bigint", nullable: false),
id = table.Column<Guid>(type: "uuid", nullable: false),
name = table.Column<string>(type: "text", nullable: true),
address = table.Column<string>(type: "text", nullable: true),
code = table.Column<string>(type: "text", nullable: true),
@ -55,13 +55,13 @@ namespace Flight.Data.Migrations
name: "flight",
columns: table => new
{
id = table.Column<long>(type: "bigint", nullable: false),
id = table.Column<Guid>(type: "uuid", nullable: false),
flightnumber = table.Column<string>(name: "flight_number", type: "text", nullable: true),
aircraftid = table.Column<long>(name: "aircraft_id", type: "bigint", nullable: false),
aircraftid = table.Column<Guid>(name: "aircraft_id", type: "uuid", nullable: false),
departuredate = table.Column<DateTime>(name: "departure_date", type: "timestamp with time zone", nullable: false),
departureairportid = table.Column<long>(name: "departure_airport_id", type: "bigint", nullable: false),
departureairportid = table.Column<Guid>(name: "departure_airport_id", type: "uuid", nullable: false),
arrivedate = table.Column<DateTime>(name: "arrive_date", type: "timestamp with time zone", nullable: false),
arriveairportid = table.Column<long>(name: "arrive_airport_id", type: "bigint", nullable: false),
arriveairportid = table.Column<Guid>(name: "arrive_airport_id", type: "uuid", nullable: false),
durationminutes = table.Column<decimal>(name: "duration_minutes", type: "numeric", nullable: false),
flightdate = table.Column<DateTime>(name: "flight_date", type: "timestamp with time zone", nullable: false),
status = table.Column<string>(type: "text", nullable: false, defaultValue: "Unknown"),
@ -94,11 +94,11 @@ namespace Flight.Data.Migrations
name: "seat",
columns: table => new
{
id = table.Column<long>(type: "bigint", nullable: false),
id = table.Column<Guid>(type: "uuid", nullable: false),
seatnumber = table.Column<string>(name: "seat_number", type: "text", nullable: true),
type = table.Column<string>(type: "text", nullable: false, defaultValue: "Unknown"),
@class = table.Column<string>(name: "class", type: "text", nullable: false, defaultValue: "Unknown"),
flightid = table.Column<long>(name: "flight_id", type: "bigint", nullable: false),
flightid = table.Column<Guid>(name: "flight_id", type: "uuid", nullable: false),
createdat = table.Column<DateTime>(name: "created_at", type: "timestamp with time zone", nullable: true),
createdby = table.Column<long>(name: "created_by", type: "bigint", nullable: true),
lastmodified = table.Column<DateTime>(name: "last_modified", type: "timestamp with time zone", nullable: true),

View File

@ -17,15 +17,15 @@ namespace Flight.Data.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.1")
.HasAnnotation("ProductVersion", "7.0.2")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Flight.Aircrafts.Models.Aircraft", b =>
{
b.Property<long>("Id")
.HasColumnType("bigint")
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<DateTime?>("CreatedAt")
@ -73,8 +73,8 @@ namespace Flight.Data.Migrations
modelBuilder.Entity("Flight.Airports.Models.Airport", b =>
{
b.Property<long>("Id")
.HasColumnType("bigint")
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<string>("Address")
@ -122,16 +122,16 @@ namespace Flight.Data.Migrations
modelBuilder.Entity("Flight.Flights.Models.Flight", b =>
{
b.Property<long>("Id")
.HasColumnType("bigint")
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<long>("AircraftId")
.HasColumnType("bigint")
b.Property<Guid>("AircraftId")
.HasColumnType("uuid")
.HasColumnName("aircraft_id");
b.Property<long>("ArriveAirportId")
.HasColumnType("bigint")
b.Property<Guid>("ArriveAirportId")
.HasColumnType("uuid")
.HasColumnName("arrive_airport_id");
b.Property<DateTime>("ArriveDate")
@ -146,8 +146,8 @@ namespace Flight.Data.Migrations
.HasColumnType("bigint")
.HasColumnName("created_by");
b.Property<long>("DepartureAirportId")
.HasColumnType("bigint")
b.Property<Guid>("DepartureAirportId")
.HasColumnType("uuid")
.HasColumnName("departure_airport_id");
b.Property<DateTime>("DepartureDate")
@ -208,8 +208,8 @@ namespace Flight.Data.Migrations
modelBuilder.Entity("Flight.Seats.Models.Seat", b =>
{
b.Property<long>("Id")
.HasColumnType("bigint")
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<string>("Class")
@ -227,8 +227,8 @@ namespace Flight.Data.Migrations
.HasColumnType("bigint")
.HasColumnName("created_by");
b.Property<long>("FlightId")
.HasColumnType("bigint")
b.Property<Guid>("FlightId")
.HasColumnType("uuid")
.HasColumnName("flight_id");
b.Property<bool>("IsDeleted")

View File

@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using BuildingBlocks.EFCore;
@ -41,17 +40,13 @@ public class FlightDataSeeder : IDataSeeder
{
if (!await _flightDbContext.Airports.AnyAsync())
{
var airports = new List<Airport>
{
Airport.Create(1, "Lisbon International Airport", "LIS", "12988"),
Airport.Create(2, "Sao Paulo International Airport", "BRZ", "11200")
};
await _flightDbContext.Airports.AddRangeAsync(airports);
await _flightDbContext.Airports.AddRangeAsync(InitialData.Airports);
await _flightDbContext.SaveChangesAsync();
if (!await _flightReadDbContext.Airport.AsQueryable().AnyAsync())
await _flightReadDbContext.Airport.InsertManyAsync(_mapper.Map<List<AirportReadModel>>(airports));
{
await _flightReadDbContext.Airport.InsertManyAsync(_mapper.Map<List<AirportReadModel>>(InitialData.Airports));
}
}
}
@ -59,18 +54,13 @@ public class FlightDataSeeder : IDataSeeder
{
if (!await _flightDbContext.Aircraft.AnyAsync())
{
var aircrafts = new List<Aircraft>
{
Aircraft.Create(1, "Boeing 737", "B737", 2005),
Aircraft.Create(2, "Airbus 300", "A300", 2000),
Aircraft.Create(3, "Airbus 320", "A320", 2003)
};
await _flightDbContext.Aircraft.AddRangeAsync(aircrafts);
await _flightDbContext.Aircraft.AddRangeAsync(InitialData.Aircrafts);
await _flightDbContext.SaveChangesAsync();
if (!await _flightReadDbContext.Aircraft.AsQueryable().AnyAsync())
await _flightReadDbContext.Aircraft.InsertManyAsync(_mapper.Map<List<AircraftReadModel>>(aircrafts));
{
await _flightReadDbContext.Aircraft.InsertManyAsync(_mapper.Map<List<AircraftReadModel>>(InitialData.Aircrafts));
}
}
}
@ -79,21 +69,13 @@ public class FlightDataSeeder : IDataSeeder
{
if (!await _flightDbContext.Seats.AnyAsync())
{
var seats = new List<Seat>
{
Seat.Create(1, "12A", Seats.Enums.SeatType.Window, Seats.Enums.SeatClass.Economy, 1),
Seat.Create(2, "12B", Seats.Enums.SeatType.Window, Seats.Enums.SeatClass.Economy, 1),
Seat.Create(3, "12C", Seats.Enums.SeatType.Middle, Seats.Enums.SeatClass.Economy, 1),
Seat.Create(4, "12D", Seats.Enums.SeatType.Middle, Seats.Enums.SeatClass.Economy, 1),
Seat.Create(5, "12E", Seats.Enums.SeatType.Aisle, Seats.Enums.SeatClass.Economy, 1),
Seat.Create(6, "12F", Seats.Enums.SeatType.Aisle, Seats.Enums.SeatClass.Economy, 1)
};
await _flightDbContext.Seats.AddRangeAsync(seats);
await _flightDbContext.Seats.AddRangeAsync(InitialData.Seats);
await _flightDbContext.SaveChangesAsync();
if (!await _flightReadDbContext.Seat.AsQueryable().AnyAsync())
await _flightReadDbContext.Seat.InsertManyAsync(_mapper.Map<List<SeatReadModel>>(seats));
{
await _flightReadDbContext.Seat.InsertManyAsync(_mapper.Map<List<SeatReadModel>>(InitialData.Seats));
}
}
}
@ -101,19 +83,13 @@ public class FlightDataSeeder : IDataSeeder
{
if (!await _flightDbContext.Flights.AnyAsync())
{
var flights = new List<Flights.Models.Flight>
{
Flights.Models.Flight.Create(1, "BD467", 1, 1, new DateTime(2022, 1, 31, 12, 0, 0),
new DateTime(2022, 1, 31, 14, 0, 0),
2, 120m,
new DateTime(2022, 1, 31), Flights.Enums.FlightStatus.Completed,
8000)
};
await _flightDbContext.Flights.AddRangeAsync(flights);
await _flightDbContext.Flights.AddRangeAsync(InitialData.Flights);
await _flightDbContext.SaveChangesAsync();
if (!await _flightReadDbContext.Flight.AsQueryable().AnyAsync())
await _flightReadDbContext.Flight.InsertManyAsync(_mapper.Map<List<FlightReadModel>>(flights));
{
await _flightReadDbContext.Flight.InsertManyAsync(_mapper.Map<List<FlightReadModel>>(InitialData.Flights));
}
}
}
}

View File

@ -0,0 +1,55 @@
namespace Flight.Data.Seed;
using System;
using System.Collections.Generic;
using System.Linq;
using Aircrafts.Models;
using Airports.Models;
using Flights.Models;
using MassTransit;
using Seats.Models;
public static class InitialData
{
public static List<Airport> Airports { get;}
public static List<Aircraft> Aircrafts { get;}
public static List<Seat> Seats { get;}
public static List<Flight> Flights { get; }
static InitialData()
{
Airports = new List<Airport>
{
Airport.Create(new Guid("3c5c0000-97c6-fc34-a0cb-08db322230c8"), "Lisbon International Airport", "LIS", "12988"),
Airport.Create(new Guid("3c5c0000-97c6-fc34-fc3c-08db322230c8"), "Sao Paulo International Airport", "BRZ", "11200")
};
Aircrafts = new List<Aircraft>
{
Aircraft.Create(new Guid("3c5c0000-97c6-fc34-fcd3-08db322230c8"), "Boeing 737", "B737", 2005),
Aircraft.Create(new Guid("3c5c0000-97c6-fc34-2e04-08db322230c9"), "Airbus 300", "A300", 2000),
Aircraft.Create(new Guid("3c5c0000-97c6-fc34-2e11-08db322230c9"), "Airbus 320", "A320", 2003)
};
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),
new DateTime(2022, 1, 31, 14, 0, 0),
Airports.Last().Id, 120m,
new DateTime(2022, 1, 31), global::Flight.Flights.Enums.FlightStatus.Completed,
8000)
};
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(NewId.NextGuid(), "12B", global::Flight.Seats.Enums.SeatType.Window, global::Flight.Seats.Enums.SeatClass.Economy, Flights.First().Id),
Seat.Create(NewId.NextGuid(), "12C", global::Flight.Seats.Enums.SeatType.Middle, global::Flight.Seats.Enums.SeatClass.Economy, Flights.First().Id),
Seat.Create(NewId.NextGuid(), "12D", global::Flight.Seats.Enums.SeatType.Middle, global::Flight.Seats.Enums.SeatClass.Economy, Flights.First().Id),
Seat.Create(NewId.NextGuid(), "12E", global::Flight.Seats.Enums.SeatType.Aisle, global::Flight.Seats.Enums.SeatClass.Economy, Flights.First().Id),
Seat.Create(NewId.NextGuid(), "12F", global::Flight.Seats.Enums.SeatType.Aisle, global::Flight.Seats.Enums.SeatClass.Economy, Flights.First().Id)
};
}
}

View File

@ -4,7 +4,6 @@ using BuildingBlocks.Core;
using BuildingBlocks.EFCore;
using BuildingBlocks.Exception;
using BuildingBlocks.HealthCheck;
using BuildingBlocks.IdsGenerator;
using BuildingBlocks.Jwt;
using BuildingBlocks.Logging;
using BuildingBlocks.Mapster;
@ -38,9 +37,6 @@ public static class InfrastructureExtensions
var configuration = builder.Configuration;
var env = builder.Environment;
// https://github.com/tonerdo/dotnet-env
DotNetEnv.Env.TraversePath().Load();
builder.Services.AddScoped<ICurrentUserProvider, CurrentUserProvider>();
builder.Services.AddScoped<IEventMapper, EventMapper>();
builder.Services.AddScoped<IEventDispatcher, EventDispatcher>();

View File

@ -2,6 +2,6 @@ using System;
namespace Flight.Flights.Dtos;
public record FlightDto(long Id, string FlightNumber, long AircraftId, long DepartureAirportId,
DateTime DepartureDate, DateTime ArriveDate, long ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
public record FlightDto(Guid Id, string FlightNumber, Guid AircraftId, Guid DepartureAirportId,
DateTime DepartureDate, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
Enums.FlightStatus Status, decimal Price);

View File

@ -6,23 +6,21 @@ using System.Threading.Tasks;
using Ardalis.GuardClauses;
using BuildingBlocks.Core.CQRS;
using BuildingBlocks.Core.Event;
using BuildingBlocks.IdsGenerator;
using Data;
using Dtos;
using Exceptions;
using FluentValidation;
using MapsterMapper;
using MassTransit;
using Microsoft.EntityFrameworkCore;
public record CreateFlight(string FlightNumber, long AircraftId, long DepartureAirportId,
DateTime DepartureDate, DateTime ArriveDate, long ArriveAirportId,
public record CreateFlight(string FlightNumber, Guid AircraftId, Guid DepartureAirportId,
DateTime DepartureDate, DateTime ArriveDate, Guid ArriveAirportId,
decimal DurationMinutes, DateTime FlightDate, Enums.FlightStatus Status,
decimal Price) : ICommand<CreateFlightResult>, IInternalCommand
{
public long Id { get; init; } = SnowflakeIdGenerator.NewId();
public Guid Id { get; init; } = NewId.NextGuid();
}
public record CreateFlightResult(long Id);
public record CreateFlightResult(Guid Id);
internal class CreateFlightValidator : AbstractValidator<CreateFlight>
{

View File

@ -11,11 +11,11 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Swashbuckle.AspNetCore.Annotations;
public record CreateFlightRequestDto(string FlightNumber, long AircraftId, long DepartureAirportId,
DateTime DepartureDate, DateTime ArriveDate, long ArriveAirportId,
public record CreateFlightRequestDto(string FlightNumber, Guid AircraftId, Guid DepartureAirportId,
DateTime DepartureDate, DateTime ArriveDate, Guid ArriveAirportId,
decimal DurationMinutes, DateTime FlightDate, Enums.FlightStatus Status, decimal Price);
public record CreateFlightResponseDto(long Id);
public record CreateFlightResponseDto(Guid Id);
public class CreateFlightEndpoint : IMinimalEndpoint
{

View File

@ -6,16 +6,16 @@ using System.Threading.Tasks;
using Ardalis.GuardClauses;
using BuildingBlocks.Core.CQRS;
using BuildingBlocks.Core.Event;
using Flight.Data;
using Flight.Flights.Exceptions;
using Data;
using Exceptions;
using MapsterMapper;
using MediatR;
using Models;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
public record CreateFlightMongo(long Id, string FlightNumber, long AircraftId, DateTime DepartureDate,
long DepartureAirportId, DateTime ArriveDate, long ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
public record CreateFlightMongo(Guid Id, string FlightNumber, Guid AircraftId, DateTime DepartureDate,
Guid DepartureAirportId, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
Enums.FlightStatus Status, decimal Price, bool IsDeleted) : InternalCommand;
internal class CreateFlightMongoHandler : ICommandHandler<CreateFlightMongo>

View File

@ -3,6 +3,6 @@ namespace Flight.Flights.Features.CreatingFlight.V1;
using System;
using BuildingBlocks.Core.Event;
public record FlightCreatedDomainEvent(long Id, string FlightNumber, long AircraftId, DateTime DepartureDate,
long DepartureAirportId, DateTime ArriveDate, long ArriveAirportId, decimal DurationMinutes,
public record FlightCreatedDomainEvent(Guid Id, string FlightNumber, Guid AircraftId, DateTime DepartureDate,
Guid DepartureAirportId, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes,
DateTime FlightDate, Enums.FlightStatus Status, decimal Price, bool IsDeleted) : IDomainEvent;

View File

@ -1,20 +1,19 @@
namespace Flight.Flights.Features.DeletingFlight.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using Ardalis.GuardClauses;
using BuildingBlocks.Core.CQRS;
using BuildingBlocks.Core.Event;
using Data;
using Dtos;
using Exceptions;
using FluentValidation;
using MapsterMapper;
using Microsoft.EntityFrameworkCore;
public record DeleteFlight(long Id) : ICommand<DeleteFlightResult>, IInternalCommand;
public record DeleteFlight(Guid Id) : ICommand<DeleteFlightResult>, IInternalCommand;
public record DeleteFlightResult(long Id);
public record DeleteFlightResult(Guid Id);
internal class DeleteFlightValidator : AbstractValidator<DeleteFlight>
{

View File

@ -1,5 +1,6 @@
namespace Flight.Flights.Features.DeletingFlight.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
@ -25,7 +26,7 @@ public class DeleteFlightEndpoint : IMinimalEndpoint
return builder;
}
private async Task<IResult> DeleteFlight(long id, IMediator mediator, CancellationToken cancellationToken)
private async Task<IResult> DeleteFlight(Guid id, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(new DeleteFlight(id), cancellationToken);

View File

@ -14,8 +14,8 @@ using Models;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
public record DeleteFlightMongo(long Id, string FlightNumber, long AircraftId, DateTime DepartureDate,
long DepartureAirportId, DateTime ArriveDate, long ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
public record DeleteFlightMongo(Guid Id, string FlightNumber, Guid AircraftId, DateTime DepartureDate,
Guid DepartureAirportId, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
Enums.FlightStatus Status, decimal Price, bool IsDeleted) : InternalCommand;
internal class DeleteFlightMongoCommandHandler : ICommandHandler<DeleteFlightMongo>

View File

@ -3,6 +3,6 @@
using System;
using BuildingBlocks.Core.Event;
public record FlightDeletedDomainEvent(long Id, string FlightNumber, long AircraftId, DateTime DepartureDate,
long DepartureAirportId, DateTime ArriveDate, long ArriveAirportId, decimal DurationMinutes,
public record FlightDeletedDomainEvent(Guid Id, string FlightNumber, Guid AircraftId, DateTime DepartureDate,
Guid DepartureAirportId, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes,
DateTime FlightDate, Enums.FlightStatus Status, decimal Price, bool IsDeleted) : IDomainEvent;

View File

@ -1,4 +1,3 @@
using BuildingBlocks.IdsGenerator;
using Mapster;
namespace Flight.Flights.Features;
@ -6,6 +5,7 @@ namespace Flight.Flights.Features;
using CreatingFlight.V1;
using DeletingFlight.V1;
using GettingAvailableFlights.V1;
using MassTransit;
using Models;
using UpdatingFlight.V1;
using FlightDto = Dtos.FlightDto;
@ -19,11 +19,11 @@ public class FlightMappings : IRegister
x.ArriveDate, x.ArriveAirportId, x.DurationMinutes, x.FlightDate, x.Status, x.Price));
config.NewConfig<CreateFlightMongo, FlightReadModel>()
.Map(d => d.Id, s => SnowflakeIdGenerator.NewId())
.Map(d => d.Id, s => NewId.NextGuid())
.Map(d => d.FlightId, s => s.Id);
config.NewConfig<Models.Flight, FlightReadModel>()
.Map(d => d.Id, s => SnowflakeIdGenerator.NewId())
.Map(d => d.Id, s => NewId.NextGuid())
.Map(d => d.FlightId, s => s.Id);
config.NewConfig<FlightReadModel, FlightDto>()

View File

@ -1,5 +1,6 @@
namespace Flight.Flights.Features.GettingFlightById.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using Ardalis.GuardClauses;
@ -12,7 +13,7 @@ using MapsterMapper;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
public record GetFlightById(long Id) : IQuery<GetFlightByIdResult>;
public record GetFlightById(Guid Id) : IQuery<GetFlightByIdResult>;
public record GetFlightByIdResult(FlightDto FlightDto);

View File

@ -1,5 +1,6 @@
namespace Flight.Flights.Features.GettingFlightById.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
@ -28,7 +29,7 @@ public class GetFlightByIdEndpoint : IMinimalEndpoint
return builder;
}
private async Task<IResult> GetById(long id, IMediator mediator, CancellationToken cancellationToken)
private async Task<IResult> GetById(Guid id, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(new GetFlightById(id), cancellationToken);

View File

@ -3,6 +3,6 @@ namespace Flight.Flights.Features.UpdatingFlight.V1;
using System;
using BuildingBlocks.Core.Event;
public record FlightUpdatedDomainEvent(long Id, string FlightNumber, long AircraftId, DateTime DepartureDate,
long DepartureAirportId, DateTime ArriveDate, long ArriveAirportId, decimal DurationMinutes,
public record FlightUpdatedDomainEvent(Guid Id, string FlightNumber, Guid AircraftId, DateTime DepartureDate,
Guid DepartureAirportId, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes,
DateTime FlightDate, Enums.FlightStatus Status, decimal Price, bool IsDeleted) : IDomainEvent;

View File

@ -7,23 +7,21 @@ using Ardalis.GuardClauses;
using BuildingBlocks.Caching;
using BuildingBlocks.Core.CQRS;
using BuildingBlocks.Core.Event;
using Flight.Data;
using Flight.Flights.Dtos;
using Flight.Flights.Exceptions;
using Data;
using Exceptions;
using Flight.Flights.Features.CreatingFlight.V1;
using FluentValidation;
using MapsterMapper;
using Microsoft.EntityFrameworkCore;
public record UpdateFlight(long Id, string FlightNumber, long AircraftId, long DepartureAirportId,
DateTime DepartureDate, DateTime ArriveDate, long ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
public record UpdateFlight(Guid Id, string FlightNumber, Guid AircraftId, Guid DepartureAirportId,
DateTime DepartureDate, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
Enums.FlightStatus Status, bool IsDeleted, decimal Price) : ICommand<UpdateFlightResult>, IInternalCommand,
IInvalidateCacheRequest
{
public string CacheKey => "GetAvailableFlights";
}
public record UpdateFlightResult(long Id);
public record UpdateFlightResult(Guid Id);
internal class UpdateFlightValidator : AbstractValidator<CreateFlight>
{

View File

@ -11,8 +11,8 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Swashbuckle.AspNetCore.Annotations;
public record UpdateFlightRequestDto(long Id, string FlightNumber, long AircraftId, long DepartureAirportId, DateTime DepartureDate, DateTime ArriveDate,
long ArriveAirportId, decimal DurationMinutes, DateTime FlightDate, Enums.FlightStatus Status, decimal Price, bool IsDeleted);
public record UpdateFlightRequestDto(Guid Id, string FlightNumber, Guid AircraftId, Guid DepartureAirportId, DateTime DepartureDate, DateTime ArriveDate,
Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate, Enums.FlightStatus Status, decimal Price, bool IsDeleted);
public class UpdateFlightEndpoint : IMinimalEndpoint
{

View File

@ -14,8 +14,8 @@ using Models;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
public record UpdateFlightMongo(long Id, string FlightNumber, long AircraftId, DateTime DepartureDate,
long DepartureAirportId, DateTime ArriveDate, long ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
public record UpdateFlightMongo(Guid Id, string FlightNumber, Guid AircraftId, DateTime DepartureDate,
Guid DepartureAirportId, DateTime ArriveDate, Guid ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
Enums.FlightStatus Status, decimal Price, bool IsDeleted) : InternalCommand;

View File

@ -7,22 +7,22 @@ using Features.CreatingFlight.V1;
using Features.DeletingFlight.V1;
using Features.UpdatingFlight.V1;
public record Flight : Aggregate<long>
public record Flight : Aggregate<Guid>
{
public string FlightNumber { get; private set; }
public long AircraftId { get; private set; }
public Guid AircraftId { get; private set; }
public DateTime DepartureDate { get; private set; }
public long DepartureAirportId { get; private set; }
public Guid DepartureAirportId { get; private set; }
public DateTime ArriveDate { get; private set; }
public long ArriveAirportId { 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 decimal Price { get; private set; }
public static Flight Create(long id, string flightNumber, long aircraftId,
long departureAirportId, DateTime departureDate, DateTime arriveDate,
long arriveAirportId, decimal durationMinutes, DateTime flightDate, Enums.FlightStatus status,
public static Flight Create(Guid id, string flightNumber, Guid aircraftId,
Guid departureAirportId, DateTime departureDate, DateTime arriveDate,
Guid arriveAirportId, decimal durationMinutes, DateTime flightDate, Enums.FlightStatus status,
decimal price, bool isDeleted = false)
{
var flight = new Flight
@ -52,9 +52,9 @@ public record Flight : Aggregate<long>
}
public void Update(long id, string flightNumber, long aircraftId,
long departureAirportId, DateTime departureDate, DateTime arriveDate,
long arriveAirportId, decimal durationMinutes, DateTime flightDate, Enums.FlightStatus status,
public void Update(Guid id, string flightNumber, Guid aircraftId,
Guid departureAirportId, DateTime departureDate, DateTime arriveDate,
Guid arriveAirportId, decimal durationMinutes, DateTime flightDate, Enums.FlightStatus status,
decimal price, bool isDeleted = false)
{
FlightNumber = flightNumber;
@ -75,9 +75,9 @@ public record Flight : Aggregate<long>
AddDomainEvent(@event);
}
public void Delete(long id, string flightNumber, long aircraftId,
long departureAirportId, DateTime departureDate, DateTime arriveDate,
long arriveAirportId, decimal durationMinutes, DateTime flightDate, Enums.FlightStatus status,
public void Delete(Guid id, string flightNumber, Guid aircraftId,
Guid departureAirportId, DateTime departureDate, DateTime arriveDate,
Guid arriveAirportId, decimal durationMinutes, DateTime flightDate, Enums.FlightStatus status,
decimal price, bool isDeleted = true)
{
FlightNumber = flightNumber;

View File

@ -4,14 +4,14 @@ using System;
public class FlightReadModel
{
public long Id { get; init; }
public long FlightId { get; init; }
public Guid Id { get; init; }
public Guid FlightId { get; init; }
public string FlightNumber { get; init; }
public long AircraftId { get; init; }
public Guid AircraftId { get; init; }
public DateTime DepartureDate { get; init; }
public long DepartureAirportId { get; init; }
public Guid DepartureAirportId { get; init; }
public DateTime ArriveDate { get; init; }
public long ArriveAirportId { get; init; }
public Guid ArriveAirportId { get; init; }
public decimal DurationMinutes { get; init; }
public DateTime FlightDate { get; init; }
public Enums.FlightStatus Status { get; init; }

View File

@ -11,7 +11,7 @@ service FlightGrpcService {
}
message GetByIdRequest {
int64 Id = 1;
string Id = 1;
}
message GetFlightByIdResult{
@ -23,39 +23,39 @@ repeated SeatDtoResponse SeatDtos = 1;
}
message ReserveSeatResult{
int64 Id = 1;
string Id = 1;
}
message FlightResponse {
int64 Id = 1;
string Id = 1;
string FlightNumber = 2;
int64 AircraftId = 3;
int64 DepartureAirportId = 4;
string AircraftId = 3;
string DepartureAirportId = 4;
google.protobuf.Timestamp DepartureDate = 5;
google.protobuf.Timestamp ArriveDate = 6;
int64 ArriveAirportId = 7;
string ArriveAirportId = 7;
double DurationMinutes = 8;
google.protobuf.Timestamp FlightDate = 9;
FlightStatus Status = 10;
double Price = 11;
int64 FlightId = 12;
string FlightId = 12;
}
message GetAvailableSeatsRequest {
int64 FlightId = 1;
string FlightId = 1;
}
message SeatDtoResponse {
int64 Id = 1;
string Id = 1;
string SeatNumber = 2;
SeatType Type = 3;
SeatClass Class = 4;
int64 FlightId = 5;
string FlightId = 5;
}
message ReserveSeatRequest {
int64 FlightId = 1;
string FlightId = 1;
string SeatNumber = 2;
}

View File

@ -5,6 +5,7 @@ using MediatR;
namespace Flight.GrpcServer.Services;
using System;
using Flights.Features.GettingFlightById.V1;
using Seats.Features.GettingAvailableSeats.V1;
using Seats.Features.ReservingSeat.Commands.V1;
@ -23,7 +24,7 @@ public class FlightGrpcServices : FlightGrpcService.FlightGrpcServiceBase
public override async Task<GetFlightByIdResult> GetById(GetByIdRequest request, ServerCallContext context)
{
var result = await _mediator.Send(new GetFlightById(request.Id));
var result = await _mediator.Send(new GetFlightById(new Guid(request.Id)));
return result.Adapt<GetFlightByIdResult>();
}
@ -31,7 +32,7 @@ public class FlightGrpcServices : FlightGrpcService.FlightGrpcServiceBase
{
var result = new GetAvailableSeatsResult();
var availableSeats = await _mediator.Send(new GetAvailableSeats(request.FlightId));
var availableSeats = await _mediator.Send(new GetAvailableSeats(new Guid(request.FlightId)));
if (availableSeats?.SeatDtos == null)
{
@ -48,7 +49,7 @@ public class FlightGrpcServices : FlightGrpcService.FlightGrpcServiceBase
public override async Task<ReserveSeatResult> ReserveSeat(ReserveSeatRequest request, ServerCallContext context)
{
var result = await _mediator.Send(new ReserveSeat(request.FlightId, request.SeatNumber));
var result = await _mediator.Send(new ReserveSeat(new Guid(request.FlightId), request.SeatNumber));
return result.Adapt<ReserveSeatResult>();
}
}

View File

@ -1,3 +1,5 @@
namespace Flight.Seats.Dtos;
public record SeatDto(long Id, string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, long FlightId);
using System;
public record SeatDto(Guid Id, string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, Guid FlightId);

View File

@ -1,26 +1,25 @@
namespace Flight.Seats.Features.CreatingSeat.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using Ardalis.GuardClauses;
using BuildingBlocks.Core.CQRS;
using BuildingBlocks.Core.Event;
using BuildingBlocks.IdsGenerator;
using Flight.Data;
using Flight.Seats.Dtos;
using Flight.Seats.Exceptions;
using Flight.Seats.Models;
using FluentValidation;
using MapsterMapper;
using MassTransit;
using MediatR;
using Microsoft.EntityFrameworkCore;
public record CreateSeat(string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, long FlightId) : ICommand<CreateSeatResult>, IInternalCommand
public record CreateSeat(string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, Guid FlightId) : ICommand<CreateSeatResult>, IInternalCommand
{
public long Id { get; init; } = SnowflakeIdGenerator.NewId();
public Guid Id { get; init; } = NewId.NextGuid();
}
public record CreateSeatResult(long Id);
public record CreateSeatResult(Guid Id);
internal class CreateSeatValidator : AbstractValidator<CreateSeat>
{

View File

@ -1,5 +1,6 @@
namespace Flight.Seats.Features.CreatingSeat.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
@ -10,8 +11,8 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Swashbuckle.AspNetCore.Annotations;
public record CreateSeatRequestDto(string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, long FlightId);
public record CreateSeatResponseDto(long Id);
public record CreateSeatRequestDto(string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, Guid FlightId);
public record CreateSeatResponseDto(Guid Id);
public class CreateSeatEndpoint : IMinimalEndpoint
{

View File

@ -1,5 +1,6 @@
namespace Flight.Seats.Features.CreatingSeat.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using Ardalis.GuardClauses;
@ -13,8 +14,8 @@ using MediatR;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
public record CreateSeatMongo(long Id, string SeatNumber, Enums.SeatType Type,
Enums.SeatClass Class, long FlightId, bool IsDeleted) : InternalCommand;
public record CreateSeatMongo(Guid Id, string SeatNumber, Enums.SeatType Type,
Enums.SeatClass Class, Guid FlightId, bool IsDeleted) : InternalCommand;
public class CreateSeatMongoHandler : ICommandHandler<CreateSeatMongo>
{

View File

@ -1,5 +1,6 @@
namespace Flight.Seats.Features.CreatingSeat.V1;
using System;
using BuildingBlocks.Core.Event;
public record SeatCreatedDomainEvent(long Id, string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, long FlightId, bool IsDeleted) : IDomainEvent;
public record SeatCreatedDomainEvent(Guid Id, string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, Guid FlightId, bool IsDeleted) : IDomainEvent;

View File

@ -1,5 +1,6 @@
namespace Flight.Seats.Features.GettingAvailableSeats.V1;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@ -14,7 +15,7 @@ using MapsterMapper;
using MediatR;
using MongoDB.Driver;
public record GetAvailableSeats(long FlightId) : IQuery<GetAvailableSeatsResult>;
public record GetAvailableSeats(Guid FlightId) : IQuery<GetAvailableSeatsResult>;
public record GetAvailableSeatsResult(IEnumerable<SeatDto> SeatDtos);

View File

@ -1,5 +1,6 @@
namespace Flight.Seats.Features.GettingAvailableSeats.V1;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@ -29,7 +30,7 @@ public class GetAvailableSeatsEndpoint : IMinimalEndpoint
return builder;
}
private async Task<IResult> GetAvailableSeats(long id, IMediator mediator, CancellationToken cancellationToken)
private async Task<IResult> GetAvailableSeats(Guid id, IMediator mediator, CancellationToken cancellationToken)
{
var result = await mediator.Send(new GetAvailableSeats(id), cancellationToken);

View File

@ -1,5 +1,6 @@
namespace Flight.Seats.Features.ReservingSeat.Commands.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using Ardalis.GuardClauses;
@ -11,9 +12,9 @@ using FluentValidation;
using MediatR;
using Microsoft.EntityFrameworkCore;
public record ReserveSeat(long FlightId, string SeatNumber) : ICommand<ReserveSeatResult>, IInternalCommand;
public record ReserveSeat(Guid FlightId, string SeatNumber) : ICommand<ReserveSeatResult>, IInternalCommand;
public record ReserveSeatResult(long Id);
public record ReserveSeatResult(Guid Id);
internal class ReserveSeatValidator : AbstractValidator<ReserveSeat>
{

View File

@ -1,5 +1,6 @@
namespace Flight.Seats.Features.ReservingSeat.Commands.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using BuildingBlocks.Web;
@ -10,8 +11,8 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Swashbuckle.AspNetCore.Annotations;
public record ReserveSeatRequestDto(long FlightId, string SeatNumber);
public record ReserveSeatResponseDto(long Id);
public record ReserveSeatRequestDto(Guid FlightId, string SeatNumber);
public record ReserveSeatResponseDto(Guid Id);
public class ReserveSeatEndpoint : IMinimalEndpoint
{

View File

@ -1,5 +1,6 @@
namespace Flight.Seats.Features.ReservingSeat.Commands.V1;
using System;
using System.Threading;
using System.Threading.Tasks;
using Ardalis.GuardClauses;
@ -11,8 +12,8 @@ using MapsterMapper;
using MediatR;
using MongoDB.Driver;
public record ReserveSeatMongo(long Id, string SeatNumber, Enums.SeatType Type,
Enums.SeatClass Class, long FlightId, bool IsDeleted) : InternalCommand;
public record ReserveSeatMongo(Guid Id, string SeatNumber, Enums.SeatType Type,
Enums.SeatClass Class, Guid FlightId, bool IsDeleted) : InternalCommand;
internal class ReserveSeatMongoHandler : ICommandHandler<ReserveSeatMongo>
{

View File

@ -1,5 +1,6 @@
namespace Flight.Seats.Features.ReservingSeat.Commands.V1;
using System;
using BuildingBlocks.Core.Event;
public record SeatReservedDomainEvent(long Id, string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, long FlightId, bool IsDeleted) : IDomainEvent;
public record SeatReservedDomainEvent(Guid Id, string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, Guid FlightId, bool IsDeleted) : IDomainEvent;

View File

@ -1,4 +1,3 @@
using BuildingBlocks.IdsGenerator;
using Flight.Seats.Dtos;
using Flight.Seats.Models;
using Mapster;
@ -6,6 +5,7 @@ using Mapster;
namespace Flight.Seats.Features;
using CreatingSeat.V1;
using MassTransit;
using ReservingSeat.Commands.V1;
public class SeatMappings : IRegister
@ -16,11 +16,11 @@ public class SeatMappings : IRegister
.ConstructUsing(x => new SeatDto(x.Id, x.SeatNumber, x.Type, x.Class, x.FlightId));
config.NewConfig<CreateSeatMongo, SeatReadModel>()
.Map(d => d.Id, s => SnowflakeIdGenerator.NewId())
.Map(d => d.Id, s => NewId.NextGuid())
.Map(d => d.SeatId, s => s.Id);
config.NewConfig<Seat, SeatReadModel>()
.Map(d => d.Id, s => SnowflakeIdGenerator.NewId())
.Map(d => d.Id, s => NewId.NextGuid())
.Map(d => d.SeatId, s => s.Id);
config.NewConfig<ReserveSeatMongo, SeatReadModel>()

View File

@ -7,9 +7,9 @@ namespace Flight.Seats.Models;
using Features.CreatingSeat.V1;
using Features.ReservingSeat.Commands.V1;
public record Seat : Aggregate<long>
public record Seat : Aggregate<Guid>
{
public static Seat Create(long id, string seatNumber, Enums.SeatType type, Enums.SeatClass @class, long flightId,
public static Seat Create(Guid id, string seatNumber, Enums.SeatType type, Enums.SeatClass @class, Guid flightId,
bool isDeleted = false)
{
var seat = new Seat()
@ -56,5 +56,5 @@ public record Seat : Aggregate<long>
public string SeatNumber { get; private set; }
public Enums.SeatType Type { get; private set; }
public Enums.SeatClass Class { get; private set; }
public long FlightId { get; private set; }
public Guid FlightId { get; private set; }
}

View File

@ -1,12 +1,14 @@
namespace Flight.Seats.Models;
using System;
public class SeatReadModel
{
public long Id { get; init; }
public long SeatId { get; init; }
public Guid Id { get; init; }
public Guid SeatId { get; init; }
public string SeatNumber { get; init; }
public Enums.SeatType Type { get; init; }
public Enums.SeatClass Class { get; init; }
public long FlightId { get; init; }
public Guid FlightId { get; init; }
public bool IsDeleted { get; init; }
}

View File

@ -1,20 +1,21 @@
using AutoBogus;
using BuildingBlocks.IdsGenerator;
using Flight.Flights.Enums;
namespace EndToEnd.Test.Fakes;
using global::Flight.Data.Seed;
using global::Flight.Flights.Features.CreatingFlight.V1;
using MassTransit;
public sealed class FakeCreateFlightCommand : AutoFaker<CreateFlight>
{
public FakeCreateFlightCommand()
{
RuleFor(r => r.Id, _ => SnowflakeIdGenerator.NewId());
RuleFor(r => r.Id, _ => NewId.NextGuid());
RuleFor(r => r.FlightNumber, r => "12FF");
RuleFor(r => r.DepartureAirportId, _ => 1);
RuleFor(r => r.ArriveAirportId, _ => 2);
RuleFor(r => r.DepartureAirportId, _ => InitialData.Airports.First().Id);
RuleFor(r => r.ArriveAirportId, _ => InitialData.Airports.Last().Id);
RuleFor(r => r.Status, _ => FlightStatus.Flying);
RuleFor(r => r.AircraftId, _ => 1);
RuleFor(r => r.AircraftId, _ => InitialData.Aircrafts.First().Id);
}
}

View File

@ -1,14 +1,14 @@
using AutoBogus;
using BuildingBlocks.IdsGenerator;
namespace Integration.Test.Fakes;
using global::Flight.Aircrafts.Features.CreatingAircraft.V1;
using MassTransit;
public class FakeCreateAircraftCommand : AutoFaker<CreateAircraft>
{
public FakeCreateAircraftCommand()
{
RuleFor(r => r.Id, _ => SnowflakeIdGenerator.NewId());
RuleFor(r => r.Id, _ => NewId.NextGuid());
}
}

View File

@ -1,14 +1,14 @@
using AutoBogus;
using BuildingBlocks.IdsGenerator;
namespace Integration.Test.Fakes;
using global::Flight.Airports.Features.CreatingAirport.V1;
using MassTransit;
public class FakeCreateAirportCommand : AutoFaker<CreateAirport>
{
public FakeCreateAirportCommand()
{
RuleFor(r => r.Id, _ => SnowflakeIdGenerator.NewId());
RuleFor(r => r.Id, _ => NewId.NextGuid());
}
}

View File

@ -1,20 +1,22 @@
using AutoBogus;
using BuildingBlocks.IdsGenerator;
using Flight.Flights.Enums;
namespace Integration.Test.Fakes;
using System.Linq;
using global::Flight.Data.Seed;
using global::Flight.Flights.Features.CreatingFlight.V1;
using MassTransit;
public sealed class FakeCreateFlightCommand : AutoFaker<CreateFlight>
{
public FakeCreateFlightCommand()
{
RuleFor(r => r.Id, _ => SnowflakeIdGenerator.NewId());
RuleFor(r => r.Id, _ => NewId.NextGuid());
RuleFor(r => r.FlightNumber, r => r.Random.Number(1000, 2000).ToString());
RuleFor(r => r.DepartureAirportId, _ => 1);
RuleFor(r => r.ArriveAirportId, _ => 2);
RuleFor(r => r.DepartureAirportId, _ => InitialData.Airports.First().Id);
RuleFor(r => r.ArriveAirportId, _ => InitialData.Airports.Last().Id);
RuleFor(r => r.Status, _ => FlightStatus.Flying);
RuleFor(r => r.AircraftId, _ => 1);
RuleFor(r => r.AircraftId, _ => InitialData.Aircrafts.First().Id);
}
}

Some files were not shown because too many files have changed in this diff Show More