diff --git a/src/BSMS.API/BackgroundJobs/ScheduleTripsJob.cs b/src/BSMS.API/BackgroundJobs/ScheduleTripsJob.cs
index 469545e..759f986 100644
--- a/src/BSMS.API/BackgroundJobs/ScheduleTripsJob.cs
+++ b/src/BSMS.API/BackgroundJobs/ScheduleTripsJob.cs
@@ -34,7 +34,9 @@ private async Task GenerateTrips()
var currentDateTime = DateTime.Now;
var currentDayOfWeek = currentDateTime.DayOfWeek;
- var isTripsScheduled = await dbContext.Trips.AnyAsync(t => t.DepartureTime.Value.Date == currentDateTime.Date);
+ var isTripsScheduled = await dbContext.Trips
+ .AnyAsync(t => t.DepartureTime != null && t.DepartureTime.Value.Date == currentDateTime.Date);
+
if (!isTripsScheduled)
{
// Query for bus schedule entries for the current day of the week
diff --git a/src/BSMS.API/BackgroundJobs/TripStartOrStopPeriodicJob.cs b/src/BSMS.API/BackgroundJobs/TripStartOrStopPeriodicJob.cs
index f08d3d2..b5a87b4 100644
--- a/src/BSMS.API/BackgroundJobs/TripStartOrStopPeriodicJob.cs
+++ b/src/BSMS.API/BackgroundJobs/TripStartOrStopPeriodicJob.cs
@@ -9,8 +9,10 @@ namespace BSMS.API.BackgroundJobs;
/// Periodic job that handles start or stop of trips based on current time
///
///
+///
public class TripStartOrStopPeriodicJob(
- IServiceProvider serviceProvider) : BackgroundService
+ IServiceProvider serviceProvider,
+ ILogger logger) : BackgroundService
{
///
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
@@ -29,13 +31,14 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
// Query for bus schedule entries where departure time has arrived
var tripsToStart = await dbContext.Trips
- .Where(t => t.Status != TripStatus.Canceled
+ .Where(t => t.Status != TripStatus.Canceled && t.Status != TripStatus.Delayed
&& t.BusScheduleEntry != null
&& t.BusScheduleEntry.Day == currentDay
&& t.BusScheduleEntry.DepartureTime.Minute == currentMinute
&& t.BusScheduleEntry.DepartureTime.Hour == currentHour)
.ToListAsync(cancellationToken: stoppingToken);
+ var tripsToSetInTransit = new List();
foreach (var trip in tripsToStart)
{
if (trip is not null)
@@ -50,12 +53,18 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
trip.Status = TripStatus.Delayed;
}
- dbContext.Trips.Update(trip);
+ tripsToSetInTransit.Add(trip);
}
}
+ if (tripsToSetInTransit.Count is not 0)
+ {
+ await dbContext.BulkUpdateAsync(tripsToSetInTransit);
+ logger.LogInformation("Some trips has started");
+ }
+
// Query for bus schedule entries where arival time has come
- await dbContext.Trips
+ var updatedRows = await dbContext.Trips
.Where(t => t.Status == TripStatus.InTransit
&& t.BusScheduleEntry != null
&& t.BusScheduleEntry.Day == currentDay
@@ -65,24 +74,36 @@ await dbContext.Trips
t => t.SetProperty(e => e.Status, TripStatus.Completed)
.SetProperty(e => e.ArrivalTime, DateTime.Now),
cancellationToken: stoppingToken);
+
+ if(updatedRows > 0)
+ {
+ logger.LogInformation("Some trips has completed");
+ }
// Double check delayed trips, try to start them
var delayedTrips = await dbContext.Trips
.Where(t => t.Status == TripStatus.Delayed
- && t.DepartureTime.Value.Date == currentTime.Date)
+ && t.DepartureTime != null
+ && t.DepartureTime.Value.Date == currentTime.Date)
.ToListAsync(cancellationToken: stoppingToken);
+ var tripsToRestart = new List();
foreach (var trip in delayedTrips)
{
if (await CanStart(dbContext, trip))
{
- // Update trip status to "Scheduled" and set departure time to current time
trip.Status = TripStatus.Scheduled;
trip.DepartureTime = currentTime;
+ tripsToRestart.Add(trip);
}
}
+ if (tripsToRestart.Count is not 0)
+ {
+ await dbContext.BulkUpdateAsync(tripsToRestart);
+ }
+
await dbContext.SaveChangesAsync(stoppingToken);
}
diff --git a/src/BSMS.API/Controllers/TicketController.cs b/src/BSMS.API/Controllers/TicketController.cs
index c2de13f..523fc6c 100644
--- a/src/BSMS.API/Controllers/TicketController.cs
+++ b/src/BSMS.API/Controllers/TicketController.cs
@@ -10,7 +10,7 @@ namespace BSMS.API.Controllers;
///
[ApiController]
[Route("api/[controller]")]
-[Authorization(Role.Admin)]
+[Authorization(Role.Admin, Role.Passenger)]
public class TicketController(ISender sender) : ControllerBase
{
///
diff --git a/src/BSMS.API/Controllers/TripController.cs b/src/BSMS.API/Controllers/TripController.cs
index 6fefd4f..15ba86a 100644
--- a/src/BSMS.API/Controllers/TripController.cs
+++ b/src/BSMS.API/Controllers/TripController.cs
@@ -1,6 +1,7 @@
using BSMS.API.Filters;
using BSMS.Application.Features.Common;
using BSMS.Application.Features.Trip.Queries.GetAll;
+using BSMS.Core.Enums;
using MediatR;
using Microsoft.AspNetCore.Mvc;
@@ -9,7 +10,7 @@ namespace BSMS.API.Controllers;
///
[ApiController]
[Route("/api/[controller]")]
-[Authorization]
+[Authorization(Role.Admin, Role.Driver, Role.Passenger)]
public class TripController(ISender sender) : ControllerBase
{
///
diff --git a/src/BSMS.API/Program.cs b/src/BSMS.API/Program.cs
index 8cd15ea..353ed71 100644
--- a/src/BSMS.API/Program.cs
+++ b/src/BSMS.API/Program.cs
@@ -44,9 +44,9 @@
.AddCustomIdentityServices();
builder.Services.AddHostedService();
-builder.Services.AddHostedService(); // comment if you have already filled DB
-// builder.Services.AddHostedService();
-// builder.Services.AddHostedService();
+//builder.Services.AddHostedService(); // comment if you have already filled DB
+builder.Services.AddHostedService();
+builder.Services.AddHostedService();
builder.Services.AddCors(options =>
{
diff --git a/src/BSMS.Application/Features/Ticket/Commands/Create/CreateTicketCommandHandler.cs b/src/BSMS.Application/Features/Ticket/Commands/Create/CreateTicketCommandHandler.cs
index 484d194..c837a7d 100644
--- a/src/BSMS.Application/Features/Ticket/Commands/Create/CreateTicketCommandHandler.cs
+++ b/src/BSMS.Application/Features/Ticket/Commands/Create/CreateTicketCommandHandler.cs
@@ -36,7 +36,6 @@ public async Task> Handle(
}
var ticket = mapper.Map(request);
- // 'Active' ticket status creation is handled by sql trigger
await repository.InsertAsync(ticket);
result.Data = new CreatedEntityResponse(ticket.TicketId);
diff --git a/src/BSMS.Core/Entities/BusScheduleEntry.cs b/src/BSMS.Core/Entities/BusScheduleEntry.cs
index 4114dbd..a7b2ed9 100644
--- a/src/BSMS.Core/Entities/BusScheduleEntry.cs
+++ b/src/BSMS.Core/Entities/BusScheduleEntry.cs
@@ -5,6 +5,8 @@
namespace BSMS.Core.Entities;
[Index(nameof(Day))]
+[Index(nameof(DepartureTime))]
+[Index(nameof(ArrivalTime))]
public class BusScheduleEntry
{
[Key]
diff --git a/src/BSMS.Infrastructure/Persistence/Migrations/20240502012043_AddTripView.cs b/src/BSMS.Infrastructure/Persistence/Migrations/20240502012043_AddTripView.cs
index 5058e54..f8c6714 100644
--- a/src/BSMS.Infrastructure/Persistence/Migrations/20240502012043_AddTripView.cs
+++ b/src/BSMS.Infrastructure/Persistence/Migrations/20240502012043_AddTripView.cs
@@ -40,8 +40,8 @@ create or alter view TripView
WITH SCHEMABINDING AS
select
t.TripId,
- bse.DepartureTime,
- bse.ArrivalTime,
+ t.DepartureTime,
+ t.ArrivalTime,
r.Origin + ' - ' + r.Destination as RouteName,
b.Brand as BusBrand,
b.CompanyName,
diff --git a/src/BSMS.Infrastructure/Persistence/Migrations/20240502182731_AddIndexesForDepartureAndArrivalTime.Designer.cs b/src/BSMS.Infrastructure/Persistence/Migrations/20240502182731_AddIndexesForDepartureAndArrivalTime.Designer.cs
new file mode 100644
index 0000000..ce71509
--- /dev/null
+++ b/src/BSMS.Infrastructure/Persistence/Migrations/20240502182731_AddIndexesForDepartureAndArrivalTime.Designer.cs
@@ -0,0 +1,791 @@
+//
+using System;
+using BSMS.Infrastructure.Persistence;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace BSMS.Infrastructure.Persistence.Migrations
+{
+ [DbContext(typeof(BusStationContext))]
+ [Migration("20240502182731_AddIndexesForDepartureAndArrivalTime")]
+ partial class AddIndexesForDepartureAndArrivalTime
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("BSMS.Core.Entities.Bus", b =>
+ {
+ b.Property("BusId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("BusId"));
+
+ b.Property("Brand")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("Capacity")
+ .HasColumnType("int");
+
+ b.Property("DriverId")
+ .HasColumnType("int");
+
+ b.Property("Number")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("nvarchar(20)");
+
+ b.HasKey("BusId");
+
+ b.HasIndex("DriverId");
+
+ b.HasIndex("Number");
+
+ b.ToTable("Buses");
+
+ b.HasAnnotation("SqlServer:UseSqlOutputClause", false);
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.BusReview", b =>
+ {
+ b.Property("BusReviewId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("BusReviewId"));
+
+ b.Property("BusId")
+ .HasColumnType("int");
+
+ b.Property("ComfortRating")
+ .HasColumnType("int");
+
+ b.Property("Comments")
+ .HasMaxLength(200)
+ .HasColumnType("nvarchar(200)");
+
+ b.Property("InternetConnectionRating")
+ .HasColumnType("int");
+
+ b.Property("PassengerId")
+ .HasColumnType("int");
+
+ b.Property("PriceQualityRatioRating")
+ .HasColumnType("int");
+
+ b.Property("PunctualityRating")
+ .HasColumnType("int");
+
+ b.Property("ReviewDate")
+ .HasColumnType("datetime2");
+
+ b.Property("SanitaryConditionsRating")
+ .HasColumnType("int");
+
+ b.HasKey("BusReviewId");
+
+ b.HasIndex("BusId");
+
+ b.HasIndex("PassengerId");
+
+ b.ToTable("BusReviews");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.BusScheduleEntry", b =>
+ {
+ b.Property("BusScheduleEntryId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("BusScheduleEntryId"));
+
+ b.Property("ArrivalTime")
+ .HasColumnType("time");
+
+ b.Property("BusId")
+ .HasColumnType("int");
+
+ b.Property("Day")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("nvarchar(20)");
+
+ b.Property("DepartureTime")
+ .HasColumnType("time");
+
+ b.Property("MoveDirection")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("nvarchar(20)");
+
+ b.Property("RouteId")
+ .HasColumnType("int");
+
+ b.HasKey("BusScheduleEntryId");
+
+ b.HasIndex("ArrivalTime");
+
+ b.HasIndex("BusId");
+
+ b.HasIndex("Day");
+
+ b.HasIndex("DepartureTime");
+
+ b.HasIndex("RouteId");
+
+ b.ToTable("BusScheduleEntries");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Company", b =>
+ {
+ b.Property("CompanyId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("CompanyId"));
+
+ b.Property("City")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("ContactEmail")
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("ContactPhone")
+ .HasMaxLength(20)
+ .HasColumnType("nvarchar(20)");
+
+ b.Property("Country")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("Street")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("ZipCode")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("nvarchar(10)");
+
+ b.HasKey("CompanyId");
+
+ b.ToTable("Companies");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Driver", b =>
+ {
+ b.Property("DriverId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("DriverId"));
+
+ b.Property("CompanyId")
+ .HasColumnType("int");
+
+ b.Property("DriverLicense")
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("FirstName")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("LastName")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.HasKey("DriverId");
+
+ b.HasIndex("CompanyId");
+
+ b.HasIndex("FirstName");
+
+ b.HasIndex("LastName");
+
+ b.ToTable("Drivers");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Passenger", b =>
+ {
+ b.Property("PassengerId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("PassengerId"));
+
+ b.Property("Email")
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("FirstName")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("LastName")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("PhoneNumber")
+ .HasMaxLength(20)
+ .HasColumnType("nvarchar(20)");
+
+ b.HasKey("PassengerId");
+
+ b.HasIndex("FirstName");
+
+ b.HasIndex("LastName");
+
+ b.ToTable("Passengers");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Route", b =>
+ {
+ b.Property("RouteId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("RouteId"));
+
+ b.Property("Destination")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("Origin")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("OverallDistance")
+ .ValueGeneratedOnAddOrUpdate()
+ .HasColumnType("int")
+ .HasComputedColumnSql("dbo.CalculateTotalDistanceForRoute([RouteId])");
+
+ b.HasKey("RouteId");
+
+ b.ToTable("Routes");
+
+ b.HasAnnotation("SqlServer:UseSqlOutputClause", false);
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Seat", b =>
+ {
+ b.Property("SeatId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("SeatId"));
+
+ b.Property("BusId")
+ .HasColumnType("int");
+
+ b.Property("IsFree")
+ .HasColumnType("bit");
+
+ b.Property("SeatNumber")
+ .HasColumnType("int");
+
+ b.HasKey("SeatId");
+
+ b.HasIndex("BusId");
+
+ b.ToTable("Seats");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Stop", b =>
+ {
+ b.Property("StopId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("StopId"));
+
+ b.Property("DistanceToPrevious")
+ .HasColumnType("int");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("PreviousStopId")
+ .HasColumnType("int");
+
+ b.Property("RouteId")
+ .HasColumnType("int");
+
+ b.HasKey("StopId");
+
+ b.HasIndex("PreviousStopId");
+
+ b.HasIndex("RouteId");
+
+ b.ToTable("Stops");
+
+ b.HasAnnotation("SqlServer:UseSqlOutputClause", false);
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Ticket", b =>
+ {
+ b.Property("TicketId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("TicketId"));
+
+ b.Property("EndStopId")
+ .HasColumnType("int");
+
+ b.Property("IsSold")
+ .HasColumnType("bit");
+
+ b.Property("Price")
+ .ValueGeneratedOnAddOrUpdate()
+ .HasColumnType("decimal(18,2)")
+ .HasComputedColumnSql("dbo.CalculateTicketPrice([EndStopId])");
+
+ b.Property("SeatId")
+ .HasColumnType("int");
+
+ b.Property("StartStopId")
+ .HasColumnType("int");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("nvarchar(20)");
+
+ b.HasKey("TicketId");
+
+ b.HasIndex("EndStopId");
+
+ b.HasIndex("SeatId");
+
+ b.HasIndex("StartStopId");
+
+ b.ToTable("Tickets");
+
+ b.HasAnnotation("SqlServer:UseSqlOutputClause", false);
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.TicketPayment", b =>
+ {
+ b.Property("TicketPaymentId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("TicketPaymentId"));
+
+ b.Property("PassengerId")
+ .HasColumnType("int");
+
+ b.Property("PaymentDate")
+ .HasColumnType("datetime2");
+
+ b.Property("PaymentType")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("nvarchar(20)");
+
+ b.Property("TicketId")
+ .HasColumnType("int");
+
+ b.Property("TripId")
+ .HasColumnType("int");
+
+ b.HasKey("TicketPaymentId");
+
+ b.HasIndex("PassengerId");
+
+ b.HasIndex("TicketId")
+ .IsUnique();
+
+ b.HasIndex("TripId");
+
+ b.ToTable("TicketPayments");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Trip", b =>
+ {
+ b.Property("TripId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("TripId"));
+
+ b.Property("ArrivalTime")
+ .HasColumnType("datetime2");
+
+ b.Property("BusScheduleEntryId")
+ .HasColumnType("int");
+
+ b.Property("DepartureTime")
+ .HasColumnType("datetime2");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("nvarchar(20)");
+
+ b.HasKey("TripId");
+
+ b.HasIndex("BusScheduleEntryId");
+
+ b.HasIndex("Status");
+
+ b.ToTable("Trips");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.User", b =>
+ {
+ b.Property("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UserId"));
+
+ b.Property("Email")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("LastLoginDate")
+ .HasColumnType("datetime2");
+
+ b.Property("PasswordHash")
+ .IsRequired()
+ .HasColumnType("varbinary(max)");
+
+ b.Property("PasswordSalt")
+ .IsRequired()
+ .HasColumnType("varbinary(max)");
+
+ b.Property("Role")
+ .HasColumnType("int");
+
+ b.Property("Username")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.HasKey("UserId");
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Views.BusDetailsView", b =>
+ {
+ b.Property("BusId")
+ .HasColumnType("int");
+
+ b.Property("Brand")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Capacity")
+ .HasColumnType("int");
+
+ b.Property("CompanyName")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("DriverName")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Number")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Rating")
+ .HasColumnType("float");
+
+ b.HasKey("BusId");
+
+ b.ToTable((string)null);
+
+ b.ToView("BusDetailsView", (string)null);
+ });
+
+ modelBuilder.Entity("BSMS.Core.Views.TripView", b =>
+ {
+ b.Property("TripId")
+ .HasColumnType("int");
+
+ b.Property("ArrivalTime")
+ .HasColumnType("datetime2");
+
+ b.Property("BusBrand")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("BusRating")
+ .HasColumnType("int");
+
+ b.Property("CompanyName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("DepartureTime")
+ .HasColumnType("datetime2");
+
+ b.Property("FreeSeatsCount")
+ .HasColumnType("int");
+
+ b.Property("RouteName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("TripStatus")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("TripId");
+
+ b.ToTable((string)null);
+
+ b.ToView("TripView", (string)null);
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Bus", b =>
+ {
+ b.HasOne("BSMS.Core.Entities.Driver", "Driver")
+ .WithMany("Buses")
+ .HasForeignKey("DriverId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Driver");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.BusReview", b =>
+ {
+ b.HasOne("BSMS.Core.Entities.Bus", "Bus")
+ .WithMany("BusReviews")
+ .HasForeignKey("BusId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("BSMS.Core.Entities.Passenger", "Passenger")
+ .WithMany("BusReviews")
+ .HasForeignKey("PassengerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Bus");
+
+ b.Navigation("Passenger");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.BusScheduleEntry", b =>
+ {
+ b.HasOne("BSMS.Core.Entities.Bus", "Bus")
+ .WithMany("BusScheduleEntries")
+ .HasForeignKey("BusId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("BSMS.Core.Entities.Route", "Route")
+ .WithMany("BusScheduleEntries")
+ .HasForeignKey("RouteId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Bus");
+
+ b.Navigation("Route");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Driver", b =>
+ {
+ b.HasOne("BSMS.Core.Entities.Company", "Company")
+ .WithMany("Drivers")
+ .HasForeignKey("CompanyId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Company");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Seat", b =>
+ {
+ b.HasOne("BSMS.Core.Entities.Bus", "Bus")
+ .WithMany("Seats")
+ .HasForeignKey("BusId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Bus");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Stop", b =>
+ {
+ b.HasOne("BSMS.Core.Entities.Stop", "PreviousStop")
+ .WithMany()
+ .HasForeignKey("PreviousStopId");
+
+ b.HasOne("BSMS.Core.Entities.Route", "Route")
+ .WithMany("Stops")
+ .HasForeignKey("RouteId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("PreviousStop");
+
+ b.Navigation("Route");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Ticket", b =>
+ {
+ b.HasOne("BSMS.Core.Entities.Stop", "EndStop")
+ .WithMany("TicketEndStops")
+ .HasForeignKey("EndStopId")
+ .IsRequired();
+
+ b.HasOne("BSMS.Core.Entities.Seat", "Seat")
+ .WithMany("Tickets")
+ .HasForeignKey("SeatId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("BSMS.Core.Entities.Stop", "StartStop")
+ .WithMany("TicketStartStops")
+ .HasForeignKey("StartStopId")
+ .IsRequired();
+
+ b.Navigation("EndStop");
+
+ b.Navigation("Seat");
+
+ b.Navigation("StartStop");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.TicketPayment", b =>
+ {
+ b.HasOne("BSMS.Core.Entities.Passenger", "Passenger")
+ .WithMany("Payments")
+ .HasForeignKey("PassengerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("BSMS.Core.Entities.Ticket", "Ticket")
+ .WithOne("Payment")
+ .HasForeignKey("BSMS.Core.Entities.TicketPayment", "TicketId")
+ .OnDelete(DeleteBehavior.ClientCascade)
+ .IsRequired();
+
+ b.HasOne("BSMS.Core.Entities.Trip", "Trip")
+ .WithMany("BoughtTickets")
+ .HasForeignKey("TripId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Passenger");
+
+ b.Navigation("Ticket");
+
+ b.Navigation("Trip");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Trip", b =>
+ {
+ b.HasOne("BSMS.Core.Entities.BusScheduleEntry", "BusScheduleEntry")
+ .WithMany("Trips")
+ .HasForeignKey("BusScheduleEntryId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("BusScheduleEntry");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Bus", b =>
+ {
+ b.Navigation("BusReviews");
+
+ b.Navigation("BusScheduleEntries");
+
+ b.Navigation("Seats");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.BusScheduleEntry", b =>
+ {
+ b.Navigation("Trips");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Company", b =>
+ {
+ b.Navigation("Drivers");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Driver", b =>
+ {
+ b.Navigation("Buses");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Passenger", b =>
+ {
+ b.Navigation("BusReviews");
+
+ b.Navigation("Payments");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Route", b =>
+ {
+ b.Navigation("BusScheduleEntries");
+
+ b.Navigation("Stops");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Seat", b =>
+ {
+ b.Navigation("Tickets");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Stop", b =>
+ {
+ b.Navigation("TicketEndStops");
+
+ b.Navigation("TicketStartStops");
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Ticket", b =>
+ {
+ b.Navigation("Payment")
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("BSMS.Core.Entities.Trip", b =>
+ {
+ b.Navigation("BoughtTickets");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/BSMS.Infrastructure/Persistence/Migrations/20240502182731_AddIndexesForDepartureAndArrivalTime.cs b/src/BSMS.Infrastructure/Persistence/Migrations/20240502182731_AddIndexesForDepartureAndArrivalTime.cs
new file mode 100644
index 0000000..c9a0977
--- /dev/null
+++ b/src/BSMS.Infrastructure/Persistence/Migrations/20240502182731_AddIndexesForDepartureAndArrivalTime.cs
@@ -0,0 +1,36 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace BSMS.Infrastructure.Persistence.Migrations
+{
+ ///
+ public partial class AddIndexesForDepartureAndArrivalTime : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateIndex(
+ name: "IX_BusScheduleEntries_ArrivalTime",
+ table: "BusScheduleEntries",
+ column: "ArrivalTime");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BusScheduleEntries_DepartureTime",
+ table: "BusScheduleEntries",
+ column: "DepartureTime");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropIndex(
+ name: "IX_BusScheduleEntries_ArrivalTime",
+ table: "BusScheduleEntries");
+
+ migrationBuilder.DropIndex(
+ name: "IX_BusScheduleEntries_DepartureTime",
+ table: "BusScheduleEntries");
+ }
+ }
+}
diff --git a/src/BSMS.Infrastructure/Persistence/Migrations/BusStationContextModelSnapshot.cs b/src/BSMS.Infrastructure/Persistence/Migrations/BusStationContextModelSnapshot.cs
index ff3adea..21e7ce1 100644
--- a/src/BSMS.Infrastructure/Persistence/Migrations/BusStationContextModelSnapshot.cs
+++ b/src/BSMS.Infrastructure/Persistence/Migrations/BusStationContextModelSnapshot.cs
@@ -134,10 +134,14 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.HasKey("BusScheduleEntryId");
+ b.HasIndex("ArrivalTime");
+
b.HasIndex("BusId");
b.HasIndex("Day");
+ b.HasIndex("DepartureTime");
+
b.HasIndex("RouteId");
b.ToTable("BusScheduleEntries");
@@ -527,6 +531,46 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.ToView("BusDetailsView", (string)null);
});
+ modelBuilder.Entity("BSMS.Core.Views.TripView", b =>
+ {
+ b.Property("TripId")
+ .HasColumnType("int");
+
+ b.Property("ArrivalTime")
+ .HasColumnType("datetime2");
+
+ b.Property("BusBrand")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("BusRating")
+ .HasColumnType("int");
+
+ b.Property("CompanyName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("DepartureTime")
+ .HasColumnType("datetime2");
+
+ b.Property("FreeSeatsCount")
+ .HasColumnType("int");
+
+ b.Property("RouteName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("TripStatus")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("TripId");
+
+ b.ToTable((string)null);
+
+ b.ToView("TripView", (string)null);
+ });
+
modelBuilder.Entity("BSMS.Core.Entities.Bus", b =>
{
b.HasOne("BSMS.Core.Entities.Driver", "Driver")