feat: add complex route addition and retrieval
This commit is contained in:
parent
a91af2f42a
commit
280d883213
@ -31,16 +31,20 @@ public class MapperInitializer : Profile
|
||||
CreateMap<Address, CreateAddressDto>().ReverseMap();
|
||||
CreateMap<Address, UpdateAddressDto>().ReverseMap();
|
||||
CreateMap<Address, InCityAddressDto>().ReverseMap();
|
||||
CreateMap<Address, CreateAddressInRouteAddress>().ReverseMap();
|
||||
CreateMap<Address, AddressInRouteAddress>().ReverseMap();
|
||||
|
||||
CreateMap<RouteAddress, RouteAddressDto>().ReverseMap();
|
||||
CreateMap<RouteAddress, CreateRouteAddressDto>().ReverseMap();
|
||||
CreateMap<RouteAddress, UpdateRouteAddressDto>().ReverseMap();
|
||||
CreateMap<RouteAddress, CreateRouteAddressWithAddressDto>().ReverseMap();
|
||||
CreateMap<RouteAddress, RouteAddressWithAddressDto>().ReverseMap();
|
||||
|
||||
CreateMap<Route, RouteDto>().ReverseMap();
|
||||
CreateMap<Route, CreateRouteDto>().ReverseMap();
|
||||
CreateMap<Route, UpdateRouteDto>().ReverseMap();
|
||||
CreateMap<Route, CreateRouteWithAddressesDto>().ReverseMap();
|
||||
CreateMap<Route, RouteWithAddressesDto>().ReverseMap();
|
||||
|
||||
|
||||
|
||||
|
@ -30,6 +30,19 @@ public class RouteController : ControllerBase
|
||||
return CreatedAtAction(nameof(GetRoute), new {id = result.route.Id}, result.route);
|
||||
}
|
||||
|
||||
[HttpPost("withAddresses")]
|
||||
public async Task<IActionResult> AddRouteWithAddresses(CreateRouteWithAddressesDto route)
|
||||
{
|
||||
var result = await _routeManagementService.AddRouteWithAddresses(route);
|
||||
|
||||
if (!result.isSucceed)
|
||||
{
|
||||
return result.actionResult;
|
||||
}
|
||||
|
||||
return CreatedAtAction(nameof(GetRoute), new {id = result.route.Id}, result.route);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetRoutes([FromQuery] RouteParameters parameters)
|
||||
{
|
||||
@ -45,6 +58,21 @@ public class RouteController : ControllerBase
|
||||
return Ok(result.routes);
|
||||
}
|
||||
|
||||
[HttpGet("withAddresses")]
|
||||
public async Task<IActionResult> GetRouteWithAddresses([FromQuery] RouteWithAddressesParameters parameters)
|
||||
{
|
||||
var result = await _routeManagementService.GetRoutesWithAddresses(parameters);
|
||||
|
||||
if (!result.isSucceed)
|
||||
{
|
||||
return result.actionResult;
|
||||
}
|
||||
|
||||
Response.Headers.Add("X-Pagination", JsonConvert.SerializeObject(result.pagingMetadata));
|
||||
|
||||
return Ok(result.routes);
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> GetRoute(int id, [FromQuery] string? fields)
|
||||
{
|
||||
@ -62,6 +90,24 @@ public class RouteController : ControllerBase
|
||||
|
||||
return Ok(result.route);
|
||||
}
|
||||
|
||||
[HttpGet("withAddresses/{id}")]
|
||||
public async Task<IActionResult> GetRouteWithAddresses(int id, [FromQuery] string? fields)
|
||||
{
|
||||
if (!await _routeManagementService.IsRouteExists(id))
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var result = await _routeManagementService.GetRouteWithAddresses(id, fields);
|
||||
|
||||
if (!result.isSucceed)
|
||||
{
|
||||
return BadRequest(result.message);
|
||||
}
|
||||
|
||||
return Ok(result.route);
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
public async Task<IActionResult> UpdateRoute(int id, UpdateRouteDto route)
|
||||
|
@ -18,6 +18,8 @@ public class ApplicationDbContext : IdentityDbContext<User>
|
||||
public DbSet<Route> Routes { get; set; } = null!;
|
||||
public DbSet<RouteAddress> RouteAddresses { get; set; } = null!;
|
||||
public DbSet<Address> Addresses { get; set; } = null!;
|
||||
|
||||
public DbSet<RouteAddressDetails> RouteAddressDetails { get; set; } = null!;
|
||||
public DbSet<City> Cities { get; set; } = null!;
|
||||
public DbSet<State> States { get; set; } = null!;
|
||||
public DbSet<Country> Countries { get; set; } = null!;
|
||||
|
8
Server/Helpers/IPager.cs
Normal file
8
Server/Helpers/IPager.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using SharedModels.QueryParameters;
|
||||
|
||||
namespace Server.Helpers;
|
||||
|
||||
public interface IPager<T>
|
||||
{
|
||||
PagingMetadata<T> ApplyPaging(ref IQueryable<T> obj, int pageNumber, int pageSize);
|
||||
}
|
19
Server/Helpers/Pager.cs
Normal file
19
Server/Helpers/Pager.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using SharedModels.QueryParameters;
|
||||
|
||||
namespace Server.Helpers;
|
||||
|
||||
public class Pager<T> : IPager<T>
|
||||
{
|
||||
public PagingMetadata<T> ApplyPaging(ref IQueryable<T> obj,
|
||||
int pageNumber, int pageSize)
|
||||
{
|
||||
var metadata = new PagingMetadata<T>(obj,
|
||||
pageNumber, pageSize);
|
||||
|
||||
obj = obj
|
||||
.Skip((pageNumber - 1) * pageSize)
|
||||
.Take(pageSize);
|
||||
|
||||
return metadata;
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
using System.Dynamic;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
@ -14,8 +15,9 @@ public class SortHelper<T> : ISortHelper<T>
|
||||
}
|
||||
|
||||
var orderParams = orderByQueryString.Trim().Split(",");
|
||||
var propertyInfos =
|
||||
typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
var propertyStrings = typeof(T) == typeof(ExpandoObject) ?
|
||||
(entities.First() as ExpandoObject).ToDictionary(o => o.Key, o => o.Value).Keys.ToList() :
|
||||
typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance).ToList().ConvertAll(o => o.GetType().ToString());
|
||||
var orderQueryBuilder = new StringBuilder();
|
||||
|
||||
foreach (var param in orderParams)
|
||||
@ -26,8 +28,8 @@ public class SortHelper<T> : ISortHelper<T>
|
||||
}
|
||||
|
||||
var propertyFromQueryName = param[0] == '-' || param[0] == '+' ? param.Substring(1) : param;
|
||||
var objectProperty = propertyInfos.FirstOrDefault(pi =>
|
||||
pi.Name.Equals(propertyFromQueryName, StringComparison.InvariantCultureIgnoreCase));
|
||||
var objectProperty = propertyStrings.FirstOrDefault(ps =>
|
||||
ps.Equals(propertyFromQueryName, StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
if (objectProperty == null)
|
||||
{
|
||||
@ -36,11 +38,13 @@ public class SortHelper<T> : ISortHelper<T>
|
||||
|
||||
var sortingOrder = param[0] == '-' ? "descending" : "ascending";
|
||||
|
||||
orderQueryBuilder.Append($"{objectProperty.Name} {sortingOrder}, ");
|
||||
orderQueryBuilder.Append($"{objectProperty} {sortingOrder}, ");
|
||||
}
|
||||
|
||||
var orderQuery = orderQueryBuilder.ToString().TrimEnd(',', ' ');
|
||||
|
||||
return entities.OrderBy(orderQuery);
|
||||
return typeof(T) == typeof(ExpandoObject) ?
|
||||
entities.Cast<dynamic>().OrderBy(orderQuery).Cast<T>() :
|
||||
entities.OrderBy(orderQuery);
|
||||
}
|
||||
}
|
915
Server/Migrations/20221129160345_Decouple_RouteAddress_and_RouteAddressDetails.Designer.cs
generated
Normal file
915
Server/Migrations/20221129160345_Decouple_RouteAddress_and_RouteAddressDetails.Designer.cs
generated
Normal file
@ -0,0 +1,915 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using Server.Data;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Server.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20221129160345_Decouple_RouteAddress_and_RouteAddressDetails")]
|
||||
partial class Decouple_RouteAddress_and_RouteAddressDetails
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "6.0.9")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Address", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("CityId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<double>("Latitude")
|
||||
.HasColumnType("double precision");
|
||||
|
||||
b.Property<double>("Longitude")
|
||||
.HasColumnType("double precision");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CityId");
|
||||
|
||||
b.ToTable("Addresses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.City", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int>("StateId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("StateId");
|
||||
|
||||
b.ToTable("Cities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Company", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("OwnerId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OwnerId");
|
||||
|
||||
b.ToTable("Companies");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Country", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Countries");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Review", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Comment")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("PostDateTimeUtc")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<int>("Rating")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int>("VehicleEnrollmentId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("VehicleEnrollmentId");
|
||||
|
||||
b.ToTable("Reviews");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Route", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Routes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.RouteAddress", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("AddressId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("Order")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("RouteAddressDetailsId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("RouteId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AddressId");
|
||||
|
||||
b.HasIndex("RouteId");
|
||||
|
||||
b.ToTable("RouteAddresses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.RouteAddressDetails", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<double>("CostToNextCity")
|
||||
.HasColumnType("double precision");
|
||||
|
||||
b.Property<int>("RouteAddressId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<TimeSpan>("TimeSpanToNextCity")
|
||||
.HasColumnType("interval");
|
||||
|
||||
b.Property<int>("VehicleEnrollmentId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<TimeSpan>("WaitTimeSpan")
|
||||
.HasColumnType("interval");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RouteAddressId");
|
||||
|
||||
b.HasIndex("VehicleEnrollmentId");
|
||||
|
||||
b.ToTable("RouteAddressDetails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.State", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("CountryId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CountryId");
|
||||
|
||||
b.ToTable("States");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Ticket", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("FirstRouteAddressId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool>("IsMissed")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("IsReturned")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<int>("LastRouteAddressId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<DateTime>("PurchaseDateTimeUtc")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<int>("TicketGroupId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("VehicleEnrollmentId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TicketGroupId");
|
||||
|
||||
b.HasIndex("VehicleEnrollmentId");
|
||||
|
||||
b.ToTable("Tickets");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.TicketGroup", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("TicketGroups");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.User", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("FirstName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("LastName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Vehicle", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("Capacity")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("CompanyId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool>("HasBelts")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("HasClimateControl")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("HasOutlet")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("HasStewardess")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("HasTV")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("HasWC")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("HasWiFi")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("Number")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CompanyId");
|
||||
|
||||
b.ToTable("Vehicles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.VehicleEnrollment", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("CancelationComment")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<TimeSpan?>("DelayTimeSpan")
|
||||
.HasColumnType("interval");
|
||||
|
||||
b.Property<DateTime>("DepartureDateTimeUtc")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<bool>("IsCanceled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<int>("RouteAddressDetailsId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("RouteId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("VehicleId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RouteId");
|
||||
|
||||
b.HasIndex("VehicleId");
|
||||
|
||||
b.ToTable("VehicleEnrollments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Server.Models.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Address", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.City", "City")
|
||||
.WithMany("Addresses")
|
||||
.HasForeignKey("CityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("City");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.City", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.State", "State")
|
||||
.WithMany("Cities")
|
||||
.HasForeignKey("StateId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("State");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Company", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.User", "Owner")
|
||||
.WithMany()
|
||||
.HasForeignKey("OwnerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Owner");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Review", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.User", "User")
|
||||
.WithMany("Reviews")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Server.Models.VehicleEnrollment", "VehicleEnrollment")
|
||||
.WithMany("Reviews")
|
||||
.HasForeignKey("VehicleEnrollmentId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
|
||||
b.Navigation("VehicleEnrollment");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.RouteAddress", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.Address", "Address")
|
||||
.WithMany("RouteAddresses")
|
||||
.HasForeignKey("AddressId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Server.Models.Route", "Route")
|
||||
.WithMany("RouteAddresses")
|
||||
.HasForeignKey("RouteId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Address");
|
||||
|
||||
b.Navigation("Route");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.RouteAddressDetails", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.RouteAddress", "RouteAddress")
|
||||
.WithMany("RouteAddressDetails")
|
||||
.HasForeignKey("RouteAddressId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Server.Models.VehicleEnrollment", "VehicleEnrollment")
|
||||
.WithMany("RouteAddressDetails")
|
||||
.HasForeignKey("VehicleEnrollmentId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("RouteAddress");
|
||||
|
||||
b.Navigation("VehicleEnrollment");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.State", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.Country", "Country")
|
||||
.WithMany("States")
|
||||
.HasForeignKey("CountryId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Country");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Ticket", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.TicketGroup", "TicketGroup")
|
||||
.WithMany("Tickets")
|
||||
.HasForeignKey("TicketGroupId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Server.Models.VehicleEnrollment", "VehicleEnrollment")
|
||||
.WithMany("Tickets")
|
||||
.HasForeignKey("VehicleEnrollmentId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("TicketGroup");
|
||||
|
||||
b.Navigation("VehicleEnrollment");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.TicketGroup", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.User", "User")
|
||||
.WithMany("TicketGroups")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.User", b =>
|
||||
{
|
||||
b.OwnsMany("Server.Models.RefreshToken", "RefreshTokens", b1 =>
|
||||
{
|
||||
b1.Property<string>("UserId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b1.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property<int>("Id"));
|
||||
|
||||
b1.Property<DateTime>("CreationDateTime")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b1.Property<DateTime>("ExpiryDateTime")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b1.Property<DateTime?>("Revoked")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b1.Property<string>("Token")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b1.HasKey("UserId", "Id");
|
||||
|
||||
b1.ToTable("RefreshToken");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
b.Navigation("RefreshTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Vehicle", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.Company", "Company")
|
||||
.WithMany("Vehicles")
|
||||
.HasForeignKey("CompanyId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Company");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.VehicleEnrollment", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.Route", "Route")
|
||||
.WithMany("VehicleEnrollments")
|
||||
.HasForeignKey("RouteId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Server.Models.Vehicle", "Vehicle")
|
||||
.WithMany("VehicleEnrollments")
|
||||
.HasForeignKey("VehicleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Route");
|
||||
|
||||
b.Navigation("Vehicle");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Address", b =>
|
||||
{
|
||||
b.Navigation("RouteAddresses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.City", b =>
|
||||
{
|
||||
b.Navigation("Addresses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Company", b =>
|
||||
{
|
||||
b.Navigation("Vehicles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Country", b =>
|
||||
{
|
||||
b.Navigation("States");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Route", b =>
|
||||
{
|
||||
b.Navigation("RouteAddresses");
|
||||
|
||||
b.Navigation("VehicleEnrollments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.RouteAddress", b =>
|
||||
{
|
||||
b.Navigation("RouteAddressDetails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.State", b =>
|
||||
{
|
||||
b.Navigation("Cities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.TicketGroup", b =>
|
||||
{
|
||||
b.Navigation("Tickets");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.User", b =>
|
||||
{
|
||||
b.Navigation("Reviews");
|
||||
|
||||
b.Navigation("TicketGroups");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.Vehicle", b =>
|
||||
{
|
||||
b.Navigation("VehicleEnrollments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.VehicleEnrollment", b =>
|
||||
{
|
||||
b.Navigation("Reviews");
|
||||
|
||||
b.Navigation("RouteAddressDetails");
|
||||
|
||||
b.Navigation("Tickets");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Server.Migrations
|
||||
{
|
||||
public partial class Decouple_RouteAddress_and_RouteAddressDetails : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CostToNextCity",
|
||||
table: "RouteAddresses");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TimeSpanToNextCity",
|
||||
table: "RouteAddresses");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "WaitTimeSpan",
|
||||
table: "RouteAddresses");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "RouteAddressDetailsId",
|
||||
table: "VehicleEnrollments",
|
||||
type: "integer",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "RouteAddressDetailsId",
|
||||
table: "RouteAddresses",
|
||||
type: "integer",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "RouteAddressDetails",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
VehicleEnrollmentId = table.Column<int>(type: "integer", nullable: false),
|
||||
RouteAddressId = table.Column<int>(type: "integer", nullable: false),
|
||||
TimeSpanToNextCity = table.Column<TimeSpan>(type: "interval", nullable: false),
|
||||
WaitTimeSpan = table.Column<TimeSpan>(type: "interval", nullable: false),
|
||||
CostToNextCity = table.Column<double>(type: "double precision", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_RouteAddressDetails", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_RouteAddressDetails_RouteAddresses_RouteAddressId",
|
||||
column: x => x.RouteAddressId,
|
||||
principalTable: "RouteAddresses",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_RouteAddressDetails_VehicleEnrollments_VehicleEnrollmentId",
|
||||
column: x => x.VehicleEnrollmentId,
|
||||
principalTable: "VehicleEnrollments",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_RouteAddressDetails_RouteAddressId",
|
||||
table: "RouteAddressDetails",
|
||||
column: "RouteAddressId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_RouteAddressDetails_VehicleEnrollmentId",
|
||||
table: "RouteAddressDetails",
|
||||
column: "VehicleEnrollmentId");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "RouteAddressDetails");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "RouteAddressDetailsId",
|
||||
table: "VehicleEnrollments");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "RouteAddressDetailsId",
|
||||
table: "RouteAddresses");
|
||||
|
||||
migrationBuilder.AddColumn<double>(
|
||||
name: "CostToNextCity",
|
||||
table: "RouteAddresses",
|
||||
type: "double precision",
|
||||
nullable: false,
|
||||
defaultValue: 0.0);
|
||||
|
||||
migrationBuilder.AddColumn<TimeSpan>(
|
||||
name: "TimeSpanToNextCity",
|
||||
table: "RouteAddresses",
|
||||
type: "interval",
|
||||
nullable: false,
|
||||
defaultValue: new TimeSpan(0, 0, 0, 0, 0));
|
||||
|
||||
migrationBuilder.AddColumn<TimeSpan>(
|
||||
name: "WaitTimeSpan",
|
||||
table: "RouteAddresses",
|
||||
type: "interval",
|
||||
nullable: false,
|
||||
defaultValue: new TimeSpan(0, 0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
}
|
@ -309,21 +309,15 @@ namespace Server.Migrations
|
||||
b.Property<int>("AddressId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<double>("CostToNextCity")
|
||||
.HasColumnType("double precision");
|
||||
|
||||
b.Property<int>("Order")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("RouteAddressDetailsId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("RouteId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<TimeSpan>("TimeSpanToNextCity")
|
||||
.HasColumnType("interval");
|
||||
|
||||
b.Property<TimeSpan>("WaitTimeSpan")
|
||||
.HasColumnType("interval");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AddressId");
|
||||
@ -333,6 +327,38 @@ namespace Server.Migrations
|
||||
b.ToTable("RouteAddresses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.RouteAddressDetails", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<double>("CostToNextCity")
|
||||
.HasColumnType("double precision");
|
||||
|
||||
b.Property<int>("RouteAddressId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<TimeSpan>("TimeSpanToNextCity")
|
||||
.HasColumnType("interval");
|
||||
|
||||
b.Property<int>("VehicleEnrollmentId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<TimeSpan>("WaitTimeSpan")
|
||||
.HasColumnType("interval");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RouteAddressId");
|
||||
|
||||
b.HasIndex("VehicleEnrollmentId");
|
||||
|
||||
b.ToTable("RouteAddressDetails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.State", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@ -552,6 +578,9 @@ namespace Server.Migrations
|
||||
b.Property<bool>("IsCanceled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<int>("RouteAddressDetailsId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("RouteId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
@ -689,6 +718,25 @@ namespace Server.Migrations
|
||||
b.Navigation("Route");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.RouteAddressDetails", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.RouteAddress", "RouteAddress")
|
||||
.WithMany("RouteAddressDetails")
|
||||
.HasForeignKey("RouteAddressId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Server.Models.VehicleEnrollment", "VehicleEnrollment")
|
||||
.WithMany("RouteAddressDetails")
|
||||
.HasForeignKey("VehicleEnrollmentId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("RouteAddress");
|
||||
|
||||
b.Navigation("VehicleEnrollment");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.State", b =>
|
||||
{
|
||||
b.HasOne("Server.Models.Country", "Country")
|
||||
@ -824,6 +872,11 @@ namespace Server.Migrations
|
||||
b.Navigation("VehicleEnrollments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.RouteAddress", b =>
|
||||
{
|
||||
b.Navigation("RouteAddressDetails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Models.State", b =>
|
||||
{
|
||||
b.Navigation("Cities");
|
||||
@ -850,6 +903,8 @@ namespace Server.Migrations
|
||||
{
|
||||
b.Navigation("Reviews");
|
||||
|
||||
b.Navigation("RouteAddressDetails");
|
||||
|
||||
b.Navigation("Tickets");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
|
@ -10,18 +10,25 @@ public class Address
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
public double Latitude { get; set; }
|
||||
public double Longitude { get; set; }
|
||||
|
||||
[ForeignKey("CityId")]
|
||||
public int CityId { get; set; }
|
||||
public City? City { get; set; }
|
||||
public City City { get; set; } = null!;
|
||||
|
||||
public virtual IList<RouteAddress> RouteAddresses { get; set; } = null!;
|
||||
|
||||
public override string ToString()
|
||||
public string GetFullName()
|
||||
{
|
||||
return $"{City.State.Country.Name}, {City.State.Name}, " +
|
||||
$"{City.Name}, {this.Name}";
|
||||
if (City == null || City.State == null || City.State.Country == null)
|
||||
{
|
||||
throw new NullReferenceException(
|
||||
$"Properties {nameof(City)}, {nameof(City.State)}, " +
|
||||
$"{nameof(City.State.Country)} must not be null");
|
||||
}
|
||||
|
||||
return $"{City.GetFullName()}, {Name}";
|
||||
}
|
||||
}
|
@ -10,10 +10,23 @@ public class City
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
|
||||
public virtual IList<Address>? Addresses { get; set; }
|
||||
|
||||
[ForeignKey("StateId")]
|
||||
public int StateId { get; set; }
|
||||
public State? State { get; set; }
|
||||
|
||||
public State State { get; set; } = null!;
|
||||
|
||||
public string GetFullName()
|
||||
{
|
||||
if (State == null || State.Country == null)
|
||||
{
|
||||
throw new NullReferenceException(
|
||||
$"Properties {nameof(State)}, " +
|
||||
$"{nameof(State.Country)} must not be null");
|
||||
}
|
||||
|
||||
return $"{State.GetFullName()}, {Name}";
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using SharedModels.DataTransferObjects;
|
||||
|
||||
namespace Server.Models;
|
||||
@ -12,4 +13,9 @@ public class Country
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
public virtual IList<State> States { get; set; } = null!;
|
||||
|
||||
public string GetFullName()
|
||||
{
|
||||
return $"{Name}";
|
||||
}
|
||||
}
|
@ -16,8 +16,9 @@ public class RouteAddress
|
||||
public int AddressId { get; set; }
|
||||
public Address Address { get; set; } = null!;
|
||||
|
||||
[ForeignKey("RouteAddressDetailsId")]
|
||||
public int RouteAddressDetailsId { get; set; }
|
||||
public virtual IList<RouteAddressDetails> RouteAddressDetails { get; set; } = null!;
|
||||
|
||||
public int Order { get; set; }
|
||||
public TimeSpan TimeSpanToNextCity { get; set; }
|
||||
public TimeSpan WaitTimeSpan { get; set; }
|
||||
public double CostToNextCity { get; set; }
|
||||
}
|
22
Server/Models/RouteAddressDetails.cs
Normal file
22
Server/Models/RouteAddressDetails.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Server.Models;
|
||||
|
||||
public class RouteAddressDetails
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
[ForeignKey("VehicleEnrollmentId")]
|
||||
public int VehicleEnrollmentId { get; set; }
|
||||
public VehicleEnrollment VehicleEnrollment { get; set; } = null!;
|
||||
|
||||
[ForeignKey("RouteAddressId")]
|
||||
public int RouteAddressId { get; set; }
|
||||
public RouteAddress RouteAddress { get; set; } = null!;
|
||||
|
||||
public TimeSpan TimeSpanToNextCity { get; set; }
|
||||
public TimeSpan WaitTimeSpan { get; set; }
|
||||
public double CostToNextCity { get; set; }
|
||||
}
|
@ -10,10 +10,20 @@ public class State
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
|
||||
public virtual IList<City> Cities { get; set; } = null!;
|
||||
|
||||
[ForeignKey("CountryId")]
|
||||
public int CountryId { get; set; }
|
||||
public Country? Country { get; set; } = null!;
|
||||
public Country Country { get; set; } = null!;
|
||||
|
||||
public string GetFullName()
|
||||
{
|
||||
if (Country == null)
|
||||
{
|
||||
throw new NullReferenceException($"Property {nameof(Country)} must not be null");
|
||||
}
|
||||
|
||||
return $"{Country.GetFullName()}, {Name}";
|
||||
}
|
||||
}
|
@ -16,6 +16,10 @@ public class VehicleEnrollment
|
||||
public int RouteId { get; set; }
|
||||
public Route Route { get; set; } = null!;
|
||||
|
||||
[ForeignKey("RouteAddressDetailsId")]
|
||||
public int RouteAddressDetailsId { get; set; }
|
||||
public virtual IList<RouteAddressDetails> RouteAddressDetails { get; set; } = null!;
|
||||
|
||||
public DateTime DepartureDateTimeUtc { get; set; }
|
||||
|
||||
public TimeSpan? DelayTimeSpan { get; set; }
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System.Dynamic;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
@ -105,7 +106,7 @@ builder.Services.AddScoped<IRouteManagementService, RouteManagementService>();
|
||||
builder.Services.AddScoped<IRouteAddressManagementService, RouteAddressManagementService>();
|
||||
|
||||
builder.Services.AddScoped<IStatisticsService, StatisticsService>();
|
||||
|
||||
builder.Services.AddScoped<IReportService, ReportService>();
|
||||
|
||||
builder.Services.AddScoped<ISortHelper<Country>, SortHelper<Country>>();
|
||||
builder.Services.AddScoped<ISortHelper<State>, SortHelper<State>>();
|
||||
@ -132,9 +133,15 @@ builder.Services.AddScoped<IDataShaper<VehicleEnrollment>, DataShaper<VehicleEnr
|
||||
builder.Services.AddScoped<IDataShaper<Route>, DataShaper<Route>>();
|
||||
builder.Services.AddScoped<IDataShaper<RouteAddress>, DataShaper<RouteAddress>>();
|
||||
|
||||
builder.Services.AddScoped<ISortHelper<ExpandoObject>, SortHelper<ExpandoObject>>();
|
||||
|
||||
builder.Services.AddScoped<IDataShaper<UserDto>, DataShaper<UserDto>>();
|
||||
builder.Services.AddScoped<IDataShaper<CompanyDto>, DataShaper<CompanyDto>>();
|
||||
builder.Services.AddScoped<IDataShaper<AddressDto>, DataShaper<AddressDto>>();
|
||||
builder.Services.AddScoped<IDataShaper<RouteDto>, DataShaper<RouteDto>>();
|
||||
builder.Services.AddScoped<IDataShaper<RouteWithAddressesDto>, DataShaper<RouteWithAddressesDto>>();
|
||||
|
||||
builder.Services.AddScoped<IPager<ExpandoObject>, Pager<ExpandoObject>>();
|
||||
|
||||
// Adding DB Context with PostgreSQL
|
||||
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
|
||||
|
@ -22,8 +22,12 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.10" />
|
||||
<PackageReference Include="MigraDocCore.DocumentObjectModel" Version="1.3.41" />
|
||||
<PackageReference Include="MigraDocCore.Rendering" Version="1.3.41" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.7" />
|
||||
<PackageReference Include="PdfSharpCore" Version="1.3.41" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.23.1" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.20" />
|
||||
</ItemGroup>
|
||||
|
@ -1,3 +1,5 @@
|
||||
using System.Dynamic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SharedModels.DataTransferObjects;
|
||||
using SharedModels.QueryParameters;
|
||||
using SharedModels.QueryParameters.Objects;
|
||||
@ -8,9 +10,13 @@ namespace Server.Services;
|
||||
public interface IRouteManagementService
|
||||
{
|
||||
Task<(bool isSucceed, string message, RouteDto route)> AddRoute(CreateRouteDto createRouteDto);
|
||||
Task<(bool isSucceed, string message, IEnumerable<RouteDto> routes,
|
||||
PagingMetadata<Route> pagingMetadata)> GetRoutes(RouteParameters parameters);
|
||||
Task<(bool isSucceed, string message, RouteDto route)> GetRoute(int id, string? fields);
|
||||
Task<(bool isSucceed, IActionResult? actionResult, RouteWithAddressesDto route)> AddRouteWithAddresses(CreateRouteWithAddressesDto createRouteWithAddressesDto);
|
||||
Task<(bool isSucceed, string message, IEnumerable<ExpandoObject> routes,
|
||||
PagingMetadata<ExpandoObject> pagingMetadata)> GetRoutes(RouteParameters parameters);
|
||||
Task<(bool isSucceed, IActionResult? actionResult, IEnumerable<ExpandoObject> routes,
|
||||
PagingMetadata<ExpandoObject> pagingMetadata)> GetRoutesWithAddresses(RouteWithAddressesParameters parameters);
|
||||
Task<(bool isSucceed, string message, ExpandoObject route)> GetRoute(int id, string? fields);
|
||||
Task<(bool isSucceed, string message, ExpandoObject route)> GetRouteWithAddresses(int id, string? fields);
|
||||
Task<(bool isSucceed, string message, UpdateRouteDto route)> UpdateRoute(UpdateRouteDto updateRouteDto);
|
||||
Task<(bool isSucceed, string message)> DeleteRoute(int id);
|
||||
Task<bool> IsRouteExists(int id);
|
||||
|
@ -26,6 +26,7 @@ public class ReportService : IReportService
|
||||
.ThenInclude(t => t.VehicleEnrollment)
|
||||
.ThenInclude(ve => ve.Vehicle)
|
||||
.ThenInclude(v => v.Company)
|
||||
|
||||
.Include(tg => tg.User)
|
||||
.Include(tg => tg.Tickets)
|
||||
.ThenInclude(t => t.VehicleEnrollment)
|
||||
@ -35,6 +36,12 @@ public class ReportService : IReportService
|
||||
.ThenInclude(a => a.City)
|
||||
.ThenInclude(c => c.State)
|
||||
.ThenInclude(s => s.Country)
|
||||
|
||||
.Include(tg => tg.User)
|
||||
.Include(tg => tg.Tickets)
|
||||
.ThenInclude(t => t.VehicleEnrollment)
|
||||
.ThenInclude(ve => ve.RouteAddressDetails)
|
||||
|
||||
.FirstOrDefaultAsync(tg => tg.Id == ticketGroupId);
|
||||
|
||||
// Define document
|
||||
@ -374,13 +381,16 @@ public class ReportService : IReportService
|
||||
|
||||
foreach (var routeAddress in routeAddresses)
|
||||
{
|
||||
var details = routeAddress.RouteAddressDetails
|
||||
.First(rad => rad.RouteAddressId == routeAddress.Id);
|
||||
|
||||
if (routeAddress.AddressId == ticket.FirstRouteAddressId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
departureDateTimeUtc += routeAddress.TimeSpanToNextCity;
|
||||
departureDateTimeUtc += routeAddress.WaitTimeSpan;
|
||||
departureDateTimeUtc += details.TimeSpanToNextCity;
|
||||
departureDateTimeUtc += details.WaitTimeSpan;
|
||||
}
|
||||
|
||||
return departureDateTimeUtc;
|
||||
@ -395,12 +405,15 @@ public class ReportService : IReportService
|
||||
|
||||
foreach (var routeAddress in routeAddresses)
|
||||
{
|
||||
var details = routeAddress.RouteAddressDetails
|
||||
.First(rad => rad.RouteAddressId == routeAddress.Id);
|
||||
|
||||
if (routeAddress.AddressId == ticket.LastRouteAddressId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
arrivalDateTimeUtc += routeAddress.TimeSpanToNextCity;
|
||||
arrivalDateTimeUtc += details.TimeSpanToNextCity;
|
||||
}
|
||||
|
||||
return arrivalDateTimeUtc;
|
||||
@ -432,7 +445,10 @@ public class ReportService : IReportService
|
||||
|
||||
foreach (var routeAddress in routeAddresses)
|
||||
{
|
||||
cost += routeAddress.CostToNextCity;
|
||||
var details = routeAddress.RouteAddressDetails
|
||||
.First(rad => rad.RouteAddressId == routeAddress.Id);
|
||||
|
||||
cost += details.CostToNextCity;
|
||||
}
|
||||
|
||||
return cost;
|
||||
|
@ -1,4 +1,7 @@
|
||||
using System.Dynamic;
|
||||
using AutoMapper;
|
||||
using AutoMapper.QueryableExtensions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Server.Data;
|
||||
using Server.Helpers;
|
||||
@ -13,17 +16,23 @@ public class RouteManagementService : IRouteManagementService
|
||||
{
|
||||
private readonly ApplicationDbContext _dbContext;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly ISortHelper<Route> _routeSortHelper;
|
||||
private readonly IDataShaper<Route> _routeDataShaper;
|
||||
private readonly ISortHelper<ExpandoObject> _routeSortHelper;
|
||||
private readonly IDataShaper<RouteDto> _routeDataShaper;
|
||||
private readonly IDataShaper<RouteWithAddressesDto> _routeWithAddressesDataShaper;
|
||||
private readonly IPager<ExpandoObject> _pager;
|
||||
|
||||
public RouteManagementService(ApplicationDbContext dbContext,
|
||||
IMapper mapper, ISortHelper<Route> routeSortHelper,
|
||||
IDataShaper<Route> routeDataShaper)
|
||||
IMapper mapper, ISortHelper<ExpandoObject> routeSortHelper,
|
||||
IDataShaper<RouteDto> routeDataShaper,
|
||||
IDataShaper<RouteWithAddressesDto> routeWithAddressesDataShaper,
|
||||
IPager<ExpandoObject> pager)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
_mapper = mapper;
|
||||
_routeSortHelper = routeSortHelper;
|
||||
_routeDataShaper = routeDataShaper;
|
||||
_routeWithAddressesDataShaper = routeWithAddressesDataShaper;
|
||||
_pager = pager;
|
||||
}
|
||||
|
||||
public async Task<(bool isSucceed, string message, RouteDto route)> AddRoute(CreateRouteDto createRouteDto)
|
||||
@ -36,8 +45,31 @@ public class RouteManagementService : IRouteManagementService
|
||||
return (true, String.Empty, _mapper.Map<RouteDto>(route));
|
||||
}
|
||||
|
||||
public async Task<(bool isSucceed, string message, IEnumerable<RouteDto> routes,
|
||||
PagingMetadata<Route> pagingMetadata)> GetRoutes(RouteParameters parameters)
|
||||
public async Task<(bool isSucceed, IActionResult? actionResult, RouteWithAddressesDto route)> AddRouteWithAddresses(CreateRouteWithAddressesDto createRouteWithAddressesDto)
|
||||
{
|
||||
var route = _mapper.Map<Route>(createRouteWithAddressesDto);
|
||||
|
||||
foreach (var routeAddress in route.RouteAddresses)
|
||||
{
|
||||
var dbAddress = await _dbContext.Addresses
|
||||
.FirstOrDefaultAsync(a => a.Id == routeAddress.AddressId);
|
||||
|
||||
if (dbAddress == null)
|
||||
{
|
||||
return (false, new BadRequestObjectResult($"Address with Id = {routeAddress.AddressId} doesn't exist"), null!);
|
||||
}
|
||||
|
||||
routeAddress.Address = dbAddress;
|
||||
}
|
||||
|
||||
await _dbContext.Routes.AddAsync(route);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
|
||||
return (true, null, _mapper.Map<RouteWithAddressesDto>(route));
|
||||
}
|
||||
|
||||
public async Task<(bool isSucceed, string message, IEnumerable<ExpandoObject> routes,
|
||||
PagingMetadata<ExpandoObject> pagingMetadata)> GetRoutes(RouteParameters parameters)
|
||||
{
|
||||
var dbRoutes = _dbContext.Routes
|
||||
.AsQueryable();
|
||||
@ -45,9 +77,12 @@ public class RouteManagementService : IRouteManagementService
|
||||
SearchByAllRouteFields(ref dbRoutes, parameters.Search);
|
||||
FilterByRouteType(ref dbRoutes, parameters.Type);
|
||||
|
||||
var routeDtos = _mapper.ProjectTo<RouteDto>(dbRoutes);
|
||||
var shapedData = _routeDataShaper.ShapeData(routeDtos, parameters.Fields).AsQueryable();
|
||||
|
||||
try
|
||||
{
|
||||
dbRoutes = _routeSortHelper.ApplySort(dbRoutes, parameters.Sort);
|
||||
shapedData = _routeSortHelper.ApplySort(shapedData, parameters.Sort);
|
||||
|
||||
// By calling Any() we will check if LINQ to Entities Query will be
|
||||
// executed. If not it will throw an InvalidOperationException exception
|
||||
@ -57,14 +92,11 @@ public class RouteManagementService : IRouteManagementService
|
||||
{
|
||||
return (false, "Invalid sorting string", null, null)!;
|
||||
}
|
||||
|
||||
var pagingMetadata = ApplyPaging(ref dbRoutes, parameters.PageNumber,
|
||||
parameters.PageSize);
|
||||
|
||||
var shapedRoutesData = _routeDataShaper.ShapeData(dbRoutes, parameters.Fields);
|
||||
var routeDtos = shapedRoutesData.ToList().ConvertAll(r => _mapper.Map<RouteDto>(r));
|
||||
|
||||
return (true, "", routeDtos, pagingMetadata);
|
||||
var pagingMetadata = _pager.ApplyPaging(ref shapedData, parameters.PageNumber,
|
||||
parameters.PageSize);
|
||||
|
||||
return (true, "", shapedData, pagingMetadata);
|
||||
|
||||
void SearchByAllRouteFields(ref IQueryable<Route> route,
|
||||
string? search)
|
||||
@ -88,23 +120,100 @@ public class RouteManagementService : IRouteManagementService
|
||||
|
||||
routes = routes.Where(r => r.Type == type);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool isSucceed, IActionResult? actionResult, IEnumerable<ExpandoObject> routes,
|
||||
PagingMetadata<ExpandoObject> pagingMetadata)> GetRoutesWithAddresses(RouteWithAddressesParameters parameters)
|
||||
{
|
||||
var dbRoutes = _dbContext.Routes
|
||||
.Include(r => r.RouteAddresses.OrderBy(ra => ra.Order))
|
||||
.ThenInclude(ra => ra.Address).ThenInclude(a => a.City)
|
||||
.ThenInclude(c => c.State).ThenInclude(s => s.Country)
|
||||
.AsQueryable();
|
||||
|
||||
SearchByAllRouteFields(ref dbRoutes, parameters.Search);
|
||||
FilterByRouteType(ref dbRoutes, parameters.Type);
|
||||
FilterByFromAddressName(ref dbRoutes, parameters.FromAddressName);
|
||||
FilterByToAddressName(ref dbRoutes, parameters.ToAddressName);
|
||||
|
||||
var routeDtos = _mapper.ProjectTo<RouteWithAddressesDto>(dbRoutes);
|
||||
var shapedData = _routeWithAddressesDataShaper.ShapeData(routeDtos, parameters.Fields).AsQueryable();
|
||||
|
||||
|
||||
PagingMetadata<Route> ApplyPaging(ref IQueryable<Route> routes,
|
||||
int pageNumber, int pageSize)
|
||||
try
|
||||
{
|
||||
var metadata = new PagingMetadata<Route>(routes,
|
||||
pageNumber, pageSize);
|
||||
|
||||
routes = routes
|
||||
.Skip((pageNumber - 1) * pageSize)
|
||||
.Take(pageSize);
|
||||
shapedData = _routeSortHelper.ApplySort(shapedData, parameters.Sort);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return (false, new BadRequestObjectResult("Invalid sorting string"), null, null)!;
|
||||
}
|
||||
|
||||
var pagingMetadata = _pager.ApplyPaging(ref shapedData, parameters.PageNumber,
|
||||
parameters.PageSize);
|
||||
|
||||
return metadata;
|
||||
return (true, null, shapedData, pagingMetadata);
|
||||
|
||||
void SearchByAllRouteFields(ref IQueryable<Route> route,
|
||||
string? search)
|
||||
{
|
||||
if (!route.Any() || String.IsNullOrWhiteSpace(search))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO Optimize (remove client evaluation)
|
||||
route = route.ToArray().Where(r =>
|
||||
r.Type.ToLower().Contains(search.ToLower()) ||
|
||||
r.RouteAddresses.OrderBy(ra => ra.Order).First().Address
|
||||
.GetFullName().ToLower().Contains(search.ToLower()) ||
|
||||
r.RouteAddresses.OrderBy(ra => ra.Order).Last().Address
|
||||
.GetFullName().ToLower().Contains(search.ToLower()))
|
||||
.AsQueryable();
|
||||
}
|
||||
|
||||
void FilterByRouteType(ref IQueryable<Route> routes,
|
||||
string? type)
|
||||
{
|
||||
if (!routes.Any() || String.IsNullOrWhiteSpace(type))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
routes = routes.Where(r => r.Type.ToLower().Contains(type.ToLower()));
|
||||
}
|
||||
|
||||
void FilterByFromAddressName(ref IQueryable<Route> routes,
|
||||
string? addressName)
|
||||
{
|
||||
if (!routes.Any() || String.IsNullOrWhiteSpace(addressName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO Optimize (remove client evaluation)
|
||||
routes = routes.ToArray().Where(r =>
|
||||
r.RouteAddresses.First().Address
|
||||
.GetFullName().ToLower().Contains(addressName.ToLower()))
|
||||
.AsQueryable();
|
||||
}
|
||||
|
||||
void FilterByToAddressName(ref IQueryable<Route> routes,
|
||||
string? addressName)
|
||||
{
|
||||
if (!routes.Any() || String.IsNullOrWhiteSpace(addressName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO Optimize (remove client evaluation)
|
||||
routes = routes.ToArray().Where(r =>
|
||||
r.RouteAddresses.Last().Address.
|
||||
GetFullName().ToLower().Contains(addressName.ToLower()))
|
||||
.AsQueryable();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool isSucceed, string message, RouteDto route)> GetRoute(int id, string? fields)
|
||||
public async Task<(bool isSucceed, string message, ExpandoObject route)> GetRoute(int id, string? fields)
|
||||
{
|
||||
var dbRoute = await _dbContext.Routes.Where(r => r.Id == id)
|
||||
.FirstOrDefaultAsync();
|
||||
@ -119,10 +228,33 @@ public class RouteManagementService : IRouteManagementService
|
||||
fields = RouteParameters.DefaultFields;
|
||||
}
|
||||
|
||||
var shapedRouteData = _routeDataShaper.ShapeData(dbRoute, fields);
|
||||
var routeDto = _mapper.Map<RouteDto>(shapedRouteData);
|
||||
var routeDto = _mapper.Map<RouteDto>(dbRoute);
|
||||
var shapedRouteData = _routeDataShaper.ShapeData(routeDto, fields);
|
||||
|
||||
return (true, "", routeDto);
|
||||
return (true, "", shapedRouteData);
|
||||
}
|
||||
|
||||
public async Task<(bool isSucceed, string message, ExpandoObject route)> GetRouteWithAddresses(int id, string? fields)
|
||||
{
|
||||
var dbRoute = await _dbContext.Routes.Where(r => r.Id == id)
|
||||
.Include(r => r.RouteAddresses).ThenInclude(ra => ra.Address)
|
||||
.ThenInclude(a => a.City).ThenInclude(c => c.State)
|
||||
.ThenInclude(s => s.Country).FirstOrDefaultAsync();
|
||||
|
||||
if (dbRoute == null)
|
||||
{
|
||||
return (false, $"Route doesn't exist", null)!;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(fields))
|
||||
{
|
||||
fields = RouteWithAddressesParameters.DefaultFields;
|
||||
}
|
||||
|
||||
var routeDto = _mapper.Map<RouteWithAddressesDto>(dbRoute);
|
||||
var shapedRouteData = _routeDataShaper.ShapeData(routeDto, fields);
|
||||
|
||||
return (true, "", shapedRouteData);
|
||||
}
|
||||
|
||||
public async Task<(bool isSucceed, string message, UpdateRouteDto route)> UpdateRoute(UpdateRouteDto updateRouteDto)
|
||||
|
@ -44,6 +44,8 @@ public class StateManagementService : IStateManagementService
|
||||
.Include(s => s.Cities)
|
||||
.ThenInclude(c => c.Addresses).AsQueryable();
|
||||
|
||||
var s = dbStates.ToList().ConvertAll(s => _mapper.Map<StateDto>(s));
|
||||
|
||||
SearchByAllStateFields(ref dbStates, parameters.Search);
|
||||
FilterByStateName(ref dbStates, parameters.Name);
|
||||
FilterByCountryId(ref dbStates, parameters.CountryId);
|
||||
|
@ -17,16 +17,18 @@ public class StatisticsService : IStatisticsService
|
||||
private readonly IDataShaper<UserDto> _userDataShaper;
|
||||
private readonly IDataShaper<CompanyDto> _companyDataShaper;
|
||||
private readonly IDataShaper<AddressDto> _addressDataShaper;
|
||||
private readonly IPager<ExpandoObject> _pager;
|
||||
|
||||
public StatisticsService(ApplicationDbContext dbContext, IMapper mapper,
|
||||
IDataShaper<UserDto> userDataShaper, IDataShaper<CompanyDto> companyDataShaper,
|
||||
IDataShaper<AddressDto> addressDataShaper)
|
||||
IDataShaper<AddressDto> addressDataShaper, IPager<ExpandoObject> pager)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
_mapper = mapper;
|
||||
_userDataShaper = userDataShaper;
|
||||
_companyDataShaper = companyDataShaper;
|
||||
_addressDataShaper = addressDataShaper;
|
||||
_pager = pager;
|
||||
}
|
||||
|
||||
// Popularity is measured in number of purchased tickets
|
||||
@ -76,8 +78,8 @@ public class StatisticsService : IStatisticsService
|
||||
}
|
||||
|
||||
var shapedData = shapedDataArray.AsQueryable();
|
||||
var pagingMetadata = ApplyPaging(ref shapedData, parameters.PageNumber,
|
||||
parameters.PageSize);
|
||||
var pagingMetadata = _pager.ApplyPaging(ref shapedData,
|
||||
parameters.PageNumber, parameters.PageSize);
|
||||
shapedDataArray = shapedData.ToArray();
|
||||
|
||||
return (true, null, shapedDataArray, pagingMetadata);
|
||||
@ -166,8 +168,8 @@ public class StatisticsService : IStatisticsService
|
||||
}
|
||||
|
||||
var shapedData = shapedDataArray.AsQueryable();
|
||||
var pagingMetadata = ApplyPaging(ref shapedData, parameters.PageNumber,
|
||||
parameters.PageSize);
|
||||
var pagingMetadata = _pager.ApplyPaging(ref shapedData,
|
||||
parameters.PageNumber, parameters.PageSize);
|
||||
shapedDataArray = shapedData.ToArray();
|
||||
|
||||
return (true, null, shapedDataArray, pagingMetadata);
|
||||
@ -265,23 +267,10 @@ public class StatisticsService : IStatisticsService
|
||||
}
|
||||
|
||||
var shapedData = shapedDataArray.AsQueryable();
|
||||
var pagingMetadata = ApplyPaging(ref shapedData, parameters.PageNumber,
|
||||
parameters.PageSize);
|
||||
var pagingMetadata = _pager.ApplyPaging(ref shapedData,
|
||||
parameters.PageNumber, parameters.PageSize);
|
||||
shapedDataArray = shapedData.ToArray();
|
||||
|
||||
return (true, null, shapedDataArray, pagingMetadata);
|
||||
}
|
||||
|
||||
PagingMetadata<T> ApplyPaging<T>(ref IQueryable<T> obj,
|
||||
int pageNumber, int pageSize)
|
||||
{
|
||||
var metadata = new PagingMetadata<T>(obj,
|
||||
pageNumber, pageSize);
|
||||
|
||||
obj = obj
|
||||
.Skip((pageNumber - 1) * pageSize)
|
||||
.Take(pageSize);
|
||||
|
||||
return metadata;
|
||||
}
|
||||
}
|
@ -5,8 +5,7 @@ namespace SharedModels.DataTransferObjects;
|
||||
public class AddressDto : CreateAddressDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public InAddressCityDto City { get; set; } = null!;
|
||||
public string FullName = null!;
|
||||
}
|
||||
|
||||
public class CreateAddressDto
|
||||
@ -37,4 +36,25 @@ public class InCityAddressDto
|
||||
public string Name { get; set; } = null!;
|
||||
public double Latitude { get; set; }
|
||||
public double Longitude { get; set; }
|
||||
}
|
||||
|
||||
public class CreateAddressInRouteAddress
|
||||
{
|
||||
public int? Id { get; set; }
|
||||
|
||||
[StringLength(maximumLength: 250, ErrorMessage = "Address name is too long")]
|
||||
public string? Name { get; set; } = null!;
|
||||
|
||||
[Range(-90, 90, ErrorMessage = "Latitude must be in range(-90, 90)")]
|
||||
public double? Latitude { get; set; }
|
||||
|
||||
[Range(-180, 180, ErrorMessage = "Longitude must be in range(-180, 180)")]
|
||||
public double? Longitude { get; set; }
|
||||
|
||||
public int? CityId { get; set; }
|
||||
}
|
||||
|
||||
public class AddressInRouteAddress : CreateAddressInRouteAddress
|
||||
{
|
||||
public string FullName = null!;
|
||||
}
|
@ -6,7 +6,7 @@ public class CityDto : CreateCityDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public InCityStateDto State { get; set; } = null!;
|
||||
public string FullName = null!;
|
||||
|
||||
public virtual IList<InCityAddressDto>? Addresses { get; set; }
|
||||
}
|
||||
|
@ -16,19 +16,8 @@ public class CreateRouteAddressDto
|
||||
public int AddressId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Range(0, Int32.MaxValue)]
|
||||
public int Order { get; set; }
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Duration)]
|
||||
public TimeSpan TimeSpanToNextCity { get; set; }
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Duration)]
|
||||
public TimeSpan WaitTimeSpan { get; set; }
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Currency)]
|
||||
public double CostToNextCity { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateRouteAddressDto : CreateRouteAddressDto
|
||||
@ -39,21 +28,16 @@ public class UpdateRouteAddressDto : CreateRouteAddressDto
|
||||
|
||||
public class CreateRouteAddressWithAddressDto
|
||||
{
|
||||
[Range(0, Int32.MaxValue)]
|
||||
public int Order { get; set; }
|
||||
|
||||
[Required]
|
||||
public CreateAddressInRouteAddress Address { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class RouteAddressWithAddressDto
|
||||
{
|
||||
public int Order { get; set; }
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Duration)]
|
||||
public TimeSpan TimeSpanToNextCity { get; set; }
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Duration)]
|
||||
public TimeSpan WaitTimeSpan { get; set; }
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Currency)]
|
||||
public double CostToNextCity { get; set; }
|
||||
|
||||
[Required]
|
||||
public CreateAddressDto Address { get; set; } = null!;
|
||||
public AddressInRouteAddress Address { get; set; } = null!;
|
||||
}
|
@ -24,4 +24,9 @@ public class CreateRouteWithAddressesDto : CreateRouteDto
|
||||
[Required]
|
||||
[MinLength(2)]
|
||||
public IList<CreateRouteAddressWithAddressDto> RouteAddresses { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class RouteWithAddressesDto : RouteDto
|
||||
{
|
||||
public IList<RouteAddressWithAddressDto> RouteAddresses { get; set; } = null!;
|
||||
}
|
@ -5,7 +5,8 @@ namespace SharedModels.DataTransferObjects;
|
||||
public class StateDto : CreateStateDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public InStateCountryDto Country { get; set; } = null!;
|
||||
|
||||
public string FullName = null!;
|
||||
|
||||
public virtual IList<InStateCityDto> Cities { get; set; } = null!;
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
namespace SharedModels.QueryParameters.Objects;
|
||||
|
||||
public class RouteWithAddressesParameters : ParametersBase
|
||||
{
|
||||
public const string DefaultFields = "id,type,routeAddresses";
|
||||
|
||||
public RouteWithAddressesParameters()
|
||||
{
|
||||
Fields = DefaultFields;
|
||||
}
|
||||
|
||||
public string? Type { get; set; }
|
||||
public string? FromAddressName { get; set; }
|
||||
public string? ToAddressName { get; set; }
|
||||
}
|
Loading…
Reference in New Issue
Block a user