aboutsummaryrefslogtreecommitdiff
path: root/src/Costasdev.Busurbano.ServiceViewer/Data
diff options
context:
space:
mode:
Diffstat (limited to 'src/Costasdev.Busurbano.ServiceViewer/Data')
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/AppDbContext.cs52
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/DirectionId.cs7
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/ExceptionType.cs7
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/RouteType.cs15
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/TripBikesAllowed.cs8
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/TripWheelchairAccessible.cs8
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/WheelchairBoarding.cs8
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsAgency.cs41
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsCalendar.cs40
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsCalendarDate.cs21
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsRoute.cs66
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsStop.cs49
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsStopTime.cs40
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsTrip.cs60
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Migrations/20250821135143_InitialGtfsData.Designer.cs398
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Migrations/20250821135143_InitialGtfsData.cs215
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/Migrations/AppDbContextModelSnapshot.cs395
-rw-r--r--src/Costasdev.Busurbano.ServiceViewer/Data/QueryExtensions/GtfsCalendarQueryExtensions.cs21
18 files changed, 1451 insertions, 0 deletions
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/AppDbContext.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/AppDbContext.cs
new file mode 100644
index 0000000..55a5a08
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/AppDbContext.cs
@@ -0,0 +1,52 @@
+using Costasdev.ServiceViewer.Data.Gtfs;
+using Costasdev.ServiceViewer.Data.Gtfs.Enums;
+using Microsoft.EntityFrameworkCore;
+
+namespace Costasdev.ServiceViewer.Data;
+
+public class AppDbContext : DbContext
+{
+ public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
+ {
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ // Relación Trip -> StopTimes (cascade delete)
+ modelBuilder.Entity<GtfsTrip>()
+ .HasMany<GtfsStopTime>()
+ .WithOne(st => st.GtfsTrip)
+ .HasForeignKey(st => st.TripId)
+ .OnDelete(DeleteBehavior.Cascade);
+
+ // Relación Stop -> StopTimes (cascade delete)
+ modelBuilder.Entity<GtfsStop>()
+ .HasMany<GtfsStopTime>()
+ .WithOne(st => st.GtfsStop)
+ .HasForeignKey(st => st.StopId)
+ .OnDelete(DeleteBehavior.Cascade);
+
+ // Relación Route -> Trips (cascade delete)
+ modelBuilder.Entity<GtfsRoute>()
+ .HasMany<GtfsTrip>()
+ .WithOne(t => t.Route)
+ .HasForeignKey(t => t.RouteId)
+ .OnDelete(DeleteBehavior.Cascade);
+
+ modelBuilder.Entity<GtfsTrip>()
+ .Property(t => t.TripWheelchairAccessible)
+ .HasDefaultValue(TripWheelchairAccessible.Empty);
+
+ modelBuilder.Entity<GtfsTrip>()
+ .Property(t => t.TripBikesAllowed)
+ .HasDefaultValue(TripBikesAllowed.Empty);
+ }
+
+ public DbSet<GtfsAgency> Agencies { get; set; }
+ public DbSet<GtfsCalendar> Calendars { get; set; }
+ public DbSet<GtfsCalendarDate> CalendarDates { get; set; }
+ public DbSet<GtfsRoute> Routes { get; set; }
+ public DbSet<GtfsStop> Stops { get; set; }
+ public DbSet<GtfsStopTime> StopTimes { get; set; }
+ public DbSet<GtfsTrip> Trips { get; set; }
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/DirectionId.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/DirectionId.cs
new file mode 100644
index 0000000..cbcf80b
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/DirectionId.cs
@@ -0,0 +1,7 @@
+namespace Costasdev.ServiceViewer.Data.Gtfs.Enums;
+
+public enum DirectionId
+{
+ Outbound = 0,
+ Inbound = 1
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/ExceptionType.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/ExceptionType.cs
new file mode 100644
index 0000000..0ad0345
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/ExceptionType.cs
@@ -0,0 +1,7 @@
+namespace Costasdev.ServiceViewer.Data.Gtfs.Enums;
+
+public enum ExceptionType
+{
+ Added = 1,
+ Removed = 2
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/RouteType.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/RouteType.cs
new file mode 100644
index 0000000..e19d02a
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/RouteType.cs
@@ -0,0 +1,15 @@
+namespace Costasdev.ServiceViewer.Data.Gtfs.Enums;
+
+public enum RouteType
+{
+ Tram = 0,
+ Subway = 1,
+ Rail = 2,
+ Bus = 3,
+ Ferry = 4,
+ CableTram = 5,
+ AerialLift = 6,
+ Funicular = 7,
+ Trolleybus = 11,
+ Monorail = 12
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/TripBikesAllowed.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/TripBikesAllowed.cs
new file mode 100644
index 0000000..838bc81
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/TripBikesAllowed.cs
@@ -0,0 +1,8 @@
+namespace Costasdev.ServiceViewer.Data.Gtfs.Enums;
+
+public enum TripBikesAllowed
+{
+ Empty = 0,
+ CanAccommodate = 1,
+ NotAllowed = 2
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/TripWheelchairAccessible.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/TripWheelchairAccessible.cs
new file mode 100644
index 0000000..e84b699
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/TripWheelchairAccessible.cs
@@ -0,0 +1,8 @@
+namespace Costasdev.ServiceViewer.Data.Gtfs.Enums;
+
+public enum TripWheelchairAccessible
+{
+ Empty = 0,
+ CanAccommodate = 1,
+ NotAccessible = 2
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/WheelchairBoarding.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/WheelchairBoarding.cs
new file mode 100644
index 0000000..3cc550f
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/Enums/WheelchairBoarding.cs
@@ -0,0 +1,8 @@
+namespace Costasdev.ServiceViewer.Data.Gtfs.Enums;
+
+public enum WheelchairBoarding
+{
+ Unknown = 0,
+ SomeVehicles = 1,
+ NotPossible = 2
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsAgency.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsAgency.cs
new file mode 100644
index 0000000..999adb8
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsAgency.cs
@@ -0,0 +1,41 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace Costasdev.ServiceViewer.Data.Gtfs;
+
+[Table("agencies")]
+public class GtfsAgency
+{
+ [Key]
+ [Column("agency_id")]
+ [MaxLength(255)]
+ public required string Id { get; set; }
+
+ [Column("agency_name")]
+ [MaxLength(255)]
+ public string Name { get; set; } = string.Empty;
+
+ [Column("agency_url")]
+ [MaxLength(255)]
+ public string Url { get; set; } = string.Empty;
+
+ [Column("agency_timezone")]
+ [MaxLength(50)]
+ public string Timezone { get; set; } = string.Empty;
+
+ [Column("agency_lang")]
+ [MaxLength(5)]
+ public string Language { get; set; } = string.Empty;
+
+ [Column("agency_phone")]
+ [MaxLength(30)]
+ public string? Phone { get; set; } = string.Empty;
+
+ [Column("agency_email")]
+ [MaxLength(255)]
+ public string? Email { get; set; } = string.Empty;
+
+ [Column("agency_fare_url")]
+ [MaxLength(255)]
+ public string? FareUrl { get; set; } = string.Empty;
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsCalendar.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsCalendar.cs
new file mode 100644
index 0000000..56f3f85
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsCalendar.cs
@@ -0,0 +1,40 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace Costasdev.ServiceViewer.Data.Gtfs;
+
+[Table("calendar")]
+public class GtfsCalendar
+{
+ [Key]
+ [Column("service_id")]
+ [MaxLength(32)]
+ public string ServiceId { get; set; } = null!;
+
+ [Column("monday")]
+ public bool Monday { get; set; }
+
+ [Column("tuesday")]
+ public bool Tuesday { get; set; }
+
+ [Column("wednesday")]
+ public bool Wednesday { get; set; }
+
+ [Column("thursday")]
+ public bool Thursday { get; set; }
+
+ [Column("friday")]
+ public bool Friday { get; set; }
+
+ [Column("saturday")]
+ public bool Saturday { get; set; }
+
+ [Column("sunday")]
+ public bool Sunday { get; set; }
+
+ [Column("start_date")]
+ public DateOnly StartDate { get; set; }
+
+ [Column("end_date")]
+ public DateOnly EndDate { get; set; }
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsCalendarDate.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsCalendarDate.cs
new file mode 100644
index 0000000..977fb74
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsCalendarDate.cs
@@ -0,0 +1,21 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using Costasdev.ServiceViewer.Data.Gtfs.Enums;
+using Microsoft.EntityFrameworkCore;
+
+namespace Costasdev.ServiceViewer.Data.Gtfs;
+
+[Table("calendar_dates")]
+[PrimaryKey(nameof(ServiceId), nameof(Date))]
+public class GtfsCalendarDate
+{
+ [Column("service_id")]
+ [MaxLength(32)]
+ public required string ServiceId { get; set; }
+
+ [Column("date")]
+ public required DateTime Date { get; set; }
+
+ [Column("exception_type")]
+ public required ExceptionType ExceptionType { get; set; }
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsRoute.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsRoute.cs
new file mode 100644
index 0000000..261e183
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsRoute.cs
@@ -0,0 +1,66 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using Costasdev.ServiceViewer.Data.Gtfs.Enums;
+
+namespace Costasdev.ServiceViewer.Data.Gtfs;
+
+[Table("routes")]
+public class GtfsRoute
+{
+ [Key]
+ [Column("route_id")]
+ [MaxLength(255)]
+ public required string Id { get; set; }
+
+ public string SafeId => Id.Replace(" ", "_").Replace("-", "_");
+
+ [Column("agency_id")]
+ [ForeignKey(nameof(GtfsAgency))]
+ [MaxLength(255)]
+ public required string AgencyId { get; set; }
+
+ [ForeignKey(nameof(AgencyId))]
+ public GtfsAgency GtfsAgency { get; set; } = null!;
+
+ /// <summary>
+ /// Short name of a route. Often a short, abstract identifier (e.g., "32", "100X", "Green")
+ /// that riders use to identify a route. Both route_short_name and route_long_name may be defined.
+ /// </summary>
+ [Column("route_short_name")]
+ [MaxLength(32)]
+ public string ShortName { get; set; } = string.Empty;
+
+ /// <summary>
+ /// Full name of a route. This name is generally more descriptive than the route_short_name and often
+ /// includes the route's destination or stop. Both route_short_name and route_long_name may be defined.
+ /// </summary>
+ [Column("route_long_name")]
+ [MaxLength(255)]
+ public string LongName { get; set; } = string.Empty;
+
+ [Column("route_desc")]
+ [MaxLength(255)]
+ public string? Description { get; set; } = string.Empty;
+
+ [Column("route_type")]
+ public RouteType Type { get; set; } = RouteType.Bus;
+
+ [Column("route_url")]
+ [MaxLength(255)]
+ public string? Url { get; set; } = string.Empty;
+
+ [Column("route_color")]
+ [MaxLength(7)]
+ public string? Color { get; set; } = string.Empty;
+
+ [Column("route_text_color")]
+ [MaxLength(7)]
+ public string? TextColor { get; set; } = string.Empty;
+
+ /// <summary>
+ /// Orders the routes in a way which is ideal for presentation to customers.
+ /// Routes with smaller route_sort_order values should be displayed first.
+ /// </summary>
+ [Column("route_sort_order")]
+ public int SortOrder { get; set; } = 1;
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsStop.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsStop.cs
new file mode 100644
index 0000000..20900d7
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsStop.cs
@@ -0,0 +1,49 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using Costasdev.ServiceViewer.Data.Gtfs.Enums;
+
+namespace Costasdev.ServiceViewer.Data.Gtfs;
+
+[Table("stops")]
+public class GtfsStop
+{
+ [Key]
+ [Column("stop_id")]
+ [MaxLength(32)]
+ public required string Id { get; set; }
+
+ [Column("stop_code")]
+ [MaxLength(32)]
+ public string Code { get; set; } = string.Empty;
+
+ [Column("stop_name")]
+ [MaxLength(255)]
+ public string Name { get; set; } = string.Empty;
+
+ [Column("stop_desc")]
+ [MaxLength(255)]
+ public string? Description { get; set; }
+
+ [Column("stop_lat")]
+ public double Latitude { get; set; }
+
+ [Column("stop_lon")]
+ public double Longitude { get; set; }
+
+ [Column("stop_url")]
+ [MaxLength(255)]
+ public string? Url { get; set; }
+
+ [Column("stop_timezone")]
+ [MaxLength(50)]
+ public string? Timezone { get; set; }
+
+ [Column("wheelchair_boarding")]
+ public WheelchairBoarding WheelchairBoarding { get; set; } = WheelchairBoarding.Unknown;
+
+ // [Column("location_type")]
+ // public int LocationType { get; set; }
+ //
+ // [Column("parent_station")]
+ // public int? ParentStationId { get; set; }
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsStopTime.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsStopTime.cs
new file mode 100644
index 0000000..07b6732
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsStopTime.cs
@@ -0,0 +1,40 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using Microsoft.EntityFrameworkCore;
+
+namespace Costasdev.ServiceViewer.Data.Gtfs;
+
+[Table("stop_times")]
+[PrimaryKey(nameof(TripId), nameof(StopSequence))]
+public class GtfsStopTime
+{
+ [Column("trip_id")]
+ [ForeignKey("TripId")]
+ [MaxLength(32)]
+ public string TripId { get; set; } = null!;
+
+ [ForeignKey(nameof(TripId))] public GtfsTrip GtfsTrip { get; set; } = null!;
+
+ [Column("arrival_time")] public string ArrivalTime { get; set; }
+ public TimeOnly ArrivalTimeOnly => TimeOnly.Parse(ArrivalTime);
+
+ [Column("departure_time")] public string DepartureTime { get; set; }
+ public TimeOnly DepartureTimeOnly => TimeOnly.Parse(DepartureTime);
+
+ [Column("stop_id")]
+ [ForeignKey(nameof(GtfsStop))]
+ [MaxLength(32)]
+ public required string StopId { get; set; }
+
+ [ForeignKey(nameof(StopId))] public GtfsStop GtfsStop { get; set; } = null!;
+
+ [Column("stop_sequence")] public int StopSequence { get; set; } = 0;
+
+ // [Column("pickup_type")]
+ // public int? PickupType { get; set; }
+ //
+ // [Column("drop_off_type")]
+ // public int? DropOffType { get; set; }
+
+ [Column("shape_dist_traveled")] public double? ShapeDistTraveled { get; set; } = null!;
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsTrip.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsTrip.cs
new file mode 100644
index 0000000..d68cbdd
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Gtfs/GtfsTrip.cs
@@ -0,0 +1,60 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using Costasdev.ServiceViewer.Data.Gtfs.Enums;
+
+namespace Costasdev.ServiceViewer.Data.Gtfs;
+
+[Table("trips")]
+public class GtfsTrip
+{
+ [Key]
+ [Column("trip_id")]
+ [MaxLength(32)]
+ public string TripId { get; set; } = null!;
+
+ [Column("route_id")]
+ [MaxLength(32)]
+ [ForeignKey(nameof(Route))]
+ public string RouteId { get; set; } = null!;
+
+ [ForeignKey(nameof(RouteId))]
+ public GtfsRoute Route { get; set; } = null!;
+
+ [Column("service_id")]
+ [MaxLength(32)]
+ public string ServiceId { get; set; } = null!;
+
+ [Column("trip_headsign")]
+ [MaxLength(255)]
+ public string? TripHeadsign { get; set; }
+
+ [Column("trip_short_name")]
+ [MaxLength(255)]
+ public string? TripShortName { get; set; }
+
+ [Column("direction_id")]
+ public DirectionId DirectionId { get; set; } = DirectionId.Outbound;
+
+ /// <summary>
+ /// Identifies the block to which the trip belongs. A block consists of a single trip or many
+ /// sequential trips made using the same vehicle, defined by shared service days and block_id.
+ /// A block_id may have trips with different service days, making distinct blocks.
+ /// </summary>
+ [Column("block_id")]
+ [MaxLength(32)]
+ public string? BlockId { get; set; }
+
+ /// <summary>
+ /// Identifies a geospatial shape describing the vehicle travel path for a trip.
+ /// </summary>
+ /// <remarks>To be implemented: will be stored as a GeoJSON file instead of database records.</remarks>
+ [Column("shape_id")]
+ [MaxLength(32)]
+ public string? ShapeId { get; set; }
+
+ [Column("trip_wheelchair_accessible")]
+ public TripWheelchairAccessible TripWheelchairAccessible { get; set; } = TripWheelchairAccessible.Empty;
+
+ [Column("trip_bikes_allowed")]
+ public TripBikesAllowed TripBikesAllowed { get; set; } = TripBikesAllowed.Empty;
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Migrations/20250821135143_InitialGtfsData.Designer.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Migrations/20250821135143_InitialGtfsData.Designer.cs
new file mode 100644
index 0000000..d123034
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Migrations/20250821135143_InitialGtfsData.Designer.cs
@@ -0,0 +1,398 @@
+// <auto-generated />
+using System;
+using Costasdev.Busurbano.Database;
+using Costasdev.ServiceViewer;
+using Costasdev.ServiceViewer.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Costasdev.Busurbano.Database.Migrations
+{
+ [DbContext(typeof(AppDbContext))]
+ [Migration("20250821135143_InitialGtfsData")]
+ partial class InitialGtfsData
+ {
+ /// <inheritdoc />
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.8")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.Agency", b =>
+ {
+ b.Property<string>("Id")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("agency_id");
+
+ b.Property<string>("Email")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("agency_email");
+
+ b.Property<string>("FareUrl")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("agency_fare_url");
+
+ b.Property<string>("Language")
+ .IsRequired()
+ .HasMaxLength(5)
+ .HasColumnType("varchar(5)")
+ .HasColumnName("agency_lang");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("agency_name");
+
+ b.Property<string>("Phone")
+ .HasMaxLength(30)
+ .HasColumnType("varchar(30)")
+ .HasColumnName("agency_phone");
+
+ b.Property<string>("Timezone")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)")
+ .HasColumnName("agency_timezone");
+
+ b.Property<string>("Url")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("agency_url");
+
+ b.HasKey("Id");
+
+ b.ToTable("agencies");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.Calendar", b =>
+ {
+ b.Property<string>("ServiceId")
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("service_id");
+
+ b.Property<DateOnly>("EndDate")
+ .HasColumnType("date")
+ .HasColumnName("end_date");
+
+ b.Property<bool>("Friday")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("friday");
+
+ b.Property<bool>("Monday")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("monday");
+
+ b.Property<bool>("Saturday")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("saturday");
+
+ b.Property<DateOnly>("StartDate")
+ .HasColumnType("date")
+ .HasColumnName("start_date");
+
+ b.Property<bool>("Sunday")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("sunday");
+
+ b.Property<bool>("Thursday")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("thursday");
+
+ b.Property<bool>("Tuesday")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("tuesday");
+
+ b.Property<bool>("Wednesday")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("wednesday");
+
+ b.HasKey("ServiceId");
+
+ b.ToTable("calendar");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.CalendarDate", b =>
+ {
+ b.Property<string>("ServiceId")
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("service_id");
+
+ b.Property<DateOnly>("Date")
+ .HasColumnType("date")
+ .HasColumnName("date");
+
+ b.Property<int>("ExceptionType")
+ .HasColumnType("int")
+ .HasColumnName("exception_type");
+
+ b.HasKey("ServiceId", "Date");
+
+ b.ToTable("calendar_dates");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.Route", b =>
+ {
+ b.Property<string>("Id")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("route_id");
+
+ b.Property<string>("AgencyId")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("agency_id");
+
+ b.Property<string>("Color")
+ .HasMaxLength(7)
+ .HasColumnType("varchar(7)")
+ .HasColumnName("route_color");
+
+ b.Property<string>("Description")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("route_desc");
+
+ b.Property<string>("LongName")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("route_long_name");
+
+ b.Property<string>("ShortName")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("route_short_name");
+
+ b.Property<int>("SortOrder")
+ .HasColumnType("int")
+ .HasColumnName("route_sort_order");
+
+ b.Property<string>("TextColor")
+ .HasMaxLength(7)
+ .HasColumnType("varchar(7)")
+ .HasColumnName("route_text_color");
+
+ b.Property<int>("Type")
+ .HasColumnType("int")
+ .HasColumnName("route_type");
+
+ b.Property<string>("Url")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("route_url");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AgencyId");
+
+ b.ToTable("routes");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.Stop", b =>
+ {
+ b.Property<string>("Id")
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("stop_id");
+
+ b.Property<string>("Code")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("stop_code");
+
+ b.Property<string>("Description")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("stop_desc");
+
+ b.Property<double>("Latitude")
+ .HasColumnType("double")
+ .HasColumnName("stop_lat");
+
+ b.Property<double>("Longitude")
+ .HasColumnType("double")
+ .HasColumnName("stop_lon");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("stop_name");
+
+ b.Property<string>("Timezone")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)")
+ .HasColumnName("stop_timezone");
+
+ b.Property<string>("Url")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("stop_url");
+
+ b.Property<int>("WheelchairBoarding")
+ .HasColumnType("int")
+ .HasColumnName("wheelchair_boarding");
+
+ b.HasKey("Id");
+
+ b.ToTable("stops");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.StopTime", b =>
+ {
+ b.Property<string>("TripId")
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("trip_id");
+
+ b.Property<int>("StopSequence")
+ .HasColumnType("int")
+ .HasColumnName("stop_sequence");
+
+ b.Property<TimeOnly>("ArrivalTime")
+ .HasMaxLength(8)
+ .HasColumnType("varchar(8)")
+ .HasColumnName("arrival_time");
+
+ b.Property<TimeOnly>("DepartureTime")
+ .HasMaxLength(8)
+ .HasColumnType("varchar(8)")
+ .HasColumnName("departure_time");
+
+ b.Property<double?>("ShapeDistTraveled")
+ .HasColumnType("double")
+ .HasColumnName("shape_dist_traveled");
+
+ b.Property<string>("StopId")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("stop_id");
+
+ b.HasKey("TripId", "StopSequence");
+
+ b.HasIndex("StopId");
+
+ b.ToTable("stop_times");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.Trip", b =>
+ {
+ b.Property<string>("TripId")
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("trip_id");
+
+ b.Property<string>("BlockId")
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("block_id");
+
+ b.Property<int>("DirectionId")
+ .HasColumnType("int")
+ .HasColumnName("direction_id");
+
+ b.Property<string>("RouteId")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("route_id");
+
+ b.Property<string>("ServiceId")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("service_id");
+
+ b.Property<string>("ShapeId")
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("shape_id");
+
+ b.Property<int>("TripBikesAllowed")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasDefaultValue(0)
+ .HasColumnName("trip_bikes_allowed");
+
+ b.Property<string>("TripHeadsign")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("trip_headsign");
+
+ b.Property<string>("TripShortName")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("trip_short_name");
+
+ b.Property<int>("TripWheelchairAccessible")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasDefaultValue(0)
+ .HasColumnName("trip_wheelchair_accessible");
+
+ b.HasKey("TripId");
+
+ b.HasIndex("RouteId");
+
+ b.ToTable("trips");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.Route", b =>
+ {
+ b.HasOne("Costasdev.Busurbano.Database.Gtfs.Agency", "Agency")
+ .WithMany()
+ .HasForeignKey("AgencyId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Agency");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.StopTime", b =>
+ {
+ b.HasOne("Costasdev.Busurbano.Database.Gtfs.Stop", "Stop")
+ .WithMany()
+ .HasForeignKey("StopId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Costasdev.Busurbano.Database.Gtfs.Trip", "Trip")
+ .WithMany()
+ .HasForeignKey("TripId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Stop");
+
+ b.Navigation("Trip");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.Trip", b =>
+ {
+ b.HasOne("Costasdev.Busurbano.Database.Gtfs.Route", null)
+ .WithMany()
+ .HasForeignKey("RouteId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Migrations/20250821135143_InitialGtfsData.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Migrations/20250821135143_InitialGtfsData.cs
new file mode 100644
index 0000000..3cf6ab8
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Migrations/20250821135143_InitialGtfsData.cs
@@ -0,0 +1,215 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Costasdev.Busurbano.Database.Migrations
+{
+ /// <inheritdoc />
+ public partial class InitialGtfsData : Migration
+ {
+ /// <inheritdoc />
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AlterDatabase()
+ .Annotation("MySQL:Charset", "utf8mb4");
+
+ migrationBuilder.CreateTable(
+ name: "agencies",
+ columns: table => new
+ {
+ agency_id = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false),
+ agency_name = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false),
+ agency_url = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false),
+ agency_timezone = table.Column<string>(type: "varchar(50)", maxLength: 50, nullable: false),
+ agency_lang = table.Column<string>(type: "varchar(5)", maxLength: 5, nullable: false),
+ agency_phone = table.Column<string>(type: "varchar(30)", maxLength: 30, nullable: true),
+ agency_email = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: true),
+ agency_fare_url = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_agencies", x => x.agency_id);
+ })
+ .Annotation("MySQL:Charset", "utf8mb4");
+
+ migrationBuilder.CreateTable(
+ name: "calendar",
+ columns: table => new
+ {
+ service_id = table.Column<string>(type: "varchar(32)", maxLength: 32, nullable: false),
+ monday = table.Column<bool>(type: "tinyint(1)", nullable: false),
+ tuesday = table.Column<bool>(type: "tinyint(1)", nullable: false),
+ wednesday = table.Column<bool>(type: "tinyint(1)", nullable: false),
+ thursday = table.Column<bool>(type: "tinyint(1)", nullable: false),
+ friday = table.Column<bool>(type: "tinyint(1)", nullable: false),
+ saturday = table.Column<bool>(type: "tinyint(1)", nullable: false),
+ sunday = table.Column<bool>(type: "tinyint(1)", nullable: false),
+ start_date = table.Column<DateOnly>(type: "date", nullable: false),
+ end_date = table.Column<DateOnly>(type: "date", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_calendar", x => x.service_id);
+ })
+ .Annotation("MySQL:Charset", "utf8mb4");
+
+ migrationBuilder.CreateTable(
+ name: "calendar_dates",
+ columns: table => new
+ {
+ service_id = table.Column<string>(type: "varchar(32)", maxLength: 32, nullable: false),
+ date = table.Column<DateOnly>(type: "date", nullable: false),
+ exception_type = table.Column<int>(type: "int", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_calendar_dates", x => new { x.service_id, x.date });
+ })
+ .Annotation("MySQL:Charset", "utf8mb4");
+
+ migrationBuilder.CreateTable(
+ name: "stops",
+ columns: table => new
+ {
+ stop_id = table.Column<string>(type: "varchar(32)", maxLength: 32, nullable: false),
+ stop_code = table.Column<string>(type: "varchar(32)", maxLength: 32, nullable: false),
+ stop_name = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false),
+ stop_desc = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: true),
+ stop_lat = table.Column<double>(type: "double", nullable: false),
+ stop_lon = table.Column<double>(type: "double", nullable: false),
+ stop_url = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: true),
+ stop_timezone = table.Column<string>(type: "varchar(50)", maxLength: 50, nullable: true),
+ wheelchair_boarding = table.Column<int>(type: "int", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_stops", x => x.stop_id);
+ })
+ .Annotation("MySQL:Charset", "utf8mb4");
+
+ migrationBuilder.CreateTable(
+ name: "routes",
+ columns: table => new
+ {
+ route_id = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false),
+ agency_id = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false),
+ route_short_name = table.Column<string>(type: "varchar(32)", maxLength: 32, nullable: false),
+ route_long_name = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false),
+ route_desc = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: true),
+ route_type = table.Column<int>(type: "int", nullable: false),
+ route_url = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: true),
+ route_color = table.Column<string>(type: "varchar(7)", maxLength: 7, nullable: true),
+ route_text_color = table.Column<string>(type: "varchar(7)", maxLength: 7, nullable: true),
+ route_sort_order = table.Column<int>(type: "int", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_routes", x => x.route_id);
+ table.ForeignKey(
+ name: "FK_routes_agencies_agency_id",
+ column: x => x.agency_id,
+ principalTable: "agencies",
+ principalColumn: "agency_id",
+ onDelete: ReferentialAction.Cascade);
+ })
+ .Annotation("MySQL:Charset", "utf8mb4");
+
+ migrationBuilder.CreateTable(
+ name: "trips",
+ columns: table => new
+ {
+ trip_id = table.Column<string>(type: "varchar(32)", maxLength: 32, nullable: false),
+ route_id = table.Column<string>(type: "varchar(32)", maxLength: 32, nullable: false),
+ service_id = table.Column<string>(type: "varchar(32)", maxLength: 32, nullable: false),
+ trip_headsign = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: true),
+ trip_short_name = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: true),
+ direction_id = table.Column<int>(type: "int", nullable: false),
+ block_id = table.Column<string>(type: "varchar(32)", maxLength: 32, nullable: true),
+ shape_id = table.Column<string>(type: "varchar(32)", maxLength: 32, nullable: true),
+ trip_wheelchair_accessible = table.Column<int>(type: "int", nullable: false, defaultValue: 0),
+ trip_bikes_allowed = table.Column<int>(type: "int", nullable: false, defaultValue: 0)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_trips", x => x.trip_id);
+ table.ForeignKey(
+ name: "FK_trips_routes_route_id",
+ column: x => x.route_id,
+ principalTable: "routes",
+ principalColumn: "route_id",
+ onDelete: ReferentialAction.Cascade);
+ })
+ .Annotation("MySQL:Charset", "utf8mb4");
+
+ migrationBuilder.CreateTable(
+ name: "stop_times",
+ columns: table => new
+ {
+ trip_id = table.Column<string>(type: "varchar(32)", maxLength: 32, nullable: false),
+ stop_sequence = table.Column<int>(type: "int", nullable: false),
+ arrival_time = table.Column<TimeOnly>(type: "varchar(8)", maxLength: 8, nullable: false),
+ departure_time = table.Column<TimeOnly>(type: "varchar(8)", maxLength: 8, nullable: false),
+ stop_id = table.Column<string>(type: "varchar(32)", maxLength: 32, nullable: false),
+ shape_dist_traveled = table.Column<double>(type: "double", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_stop_times", x => new { x.trip_id, x.stop_sequence });
+ table.ForeignKey(
+ name: "FK_stop_times_stops_stop_id",
+ column: x => x.stop_id,
+ principalTable: "stops",
+ principalColumn: "stop_id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_stop_times_trips_trip_id",
+ column: x => x.trip_id,
+ principalTable: "trips",
+ principalColumn: "trip_id",
+ onDelete: ReferentialAction.Cascade);
+ })
+ .Annotation("MySQL:Charset", "utf8mb4");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_routes_agency_id",
+ table: "routes",
+ column: "agency_id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_stop_times_stop_id",
+ table: "stop_times",
+ column: "stop_id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_trips_route_id",
+ table: "trips",
+ column: "route_id");
+ }
+
+ /// <inheritdoc />
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "calendar");
+
+ migrationBuilder.DropTable(
+ name: "calendar_dates");
+
+ migrationBuilder.DropTable(
+ name: "stop_times");
+
+ migrationBuilder.DropTable(
+ name: "stops");
+
+ migrationBuilder.DropTable(
+ name: "trips");
+
+ migrationBuilder.DropTable(
+ name: "routes");
+
+ migrationBuilder.DropTable(
+ name: "agencies");
+ }
+ }
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/Migrations/AppDbContextModelSnapshot.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/Migrations/AppDbContextModelSnapshot.cs
new file mode 100644
index 0000000..a77ecf5
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/Migrations/AppDbContextModelSnapshot.cs
@@ -0,0 +1,395 @@
+// <auto-generated />
+using System;
+using Costasdev.Busurbano.Database;
+using Costasdev.ServiceViewer;
+using Costasdev.ServiceViewer.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Costasdev.Busurbano.Database.Migrations
+{
+ [DbContext(typeof(AppDbContext))]
+ partial class AppDbContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.8")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.Agency", b =>
+ {
+ b.Property<string>("Id")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("agency_id");
+
+ b.Property<string>("Email")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("agency_email");
+
+ b.Property<string>("FareUrl")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("agency_fare_url");
+
+ b.Property<string>("Language")
+ .IsRequired()
+ .HasMaxLength(5)
+ .HasColumnType("varchar(5)")
+ .HasColumnName("agency_lang");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("agency_name");
+
+ b.Property<string>("Phone")
+ .HasMaxLength(30)
+ .HasColumnType("varchar(30)")
+ .HasColumnName("agency_phone");
+
+ b.Property<string>("Timezone")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)")
+ .HasColumnName("agency_timezone");
+
+ b.Property<string>("Url")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("agency_url");
+
+ b.HasKey("Id");
+
+ b.ToTable("agencies");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.Calendar", b =>
+ {
+ b.Property<string>("ServiceId")
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("service_id");
+
+ b.Property<DateOnly>("EndDate")
+ .HasColumnType("date")
+ .HasColumnName("end_date");
+
+ b.Property<bool>("Friday")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("friday");
+
+ b.Property<bool>("Monday")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("monday");
+
+ b.Property<bool>("Saturday")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("saturday");
+
+ b.Property<DateOnly>("StartDate")
+ .HasColumnType("date")
+ .HasColumnName("start_date");
+
+ b.Property<bool>("Sunday")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("sunday");
+
+ b.Property<bool>("Thursday")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("thursday");
+
+ b.Property<bool>("Tuesday")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("tuesday");
+
+ b.Property<bool>("Wednesday")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("wednesday");
+
+ b.HasKey("ServiceId");
+
+ b.ToTable("calendar");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.CalendarDate", b =>
+ {
+ b.Property<string>("ServiceId")
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("service_id");
+
+ b.Property<DateOnly>("Date")
+ .HasColumnType("date")
+ .HasColumnName("date");
+
+ b.Property<int>("ExceptionType")
+ .HasColumnType("int")
+ .HasColumnName("exception_type");
+
+ b.HasKey("ServiceId", "Date");
+
+ b.ToTable("calendar_dates");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.Route", b =>
+ {
+ b.Property<string>("Id")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("route_id");
+
+ b.Property<string>("AgencyId")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("agency_id");
+
+ b.Property<string>("Color")
+ .HasMaxLength(7)
+ .HasColumnType("varchar(7)")
+ .HasColumnName("route_color");
+
+ b.Property<string>("Description")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("route_desc");
+
+ b.Property<string>("LongName")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("route_long_name");
+
+ b.Property<string>("ShortName")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("route_short_name");
+
+ b.Property<int>("SortOrder")
+ .HasColumnType("int")
+ .HasColumnName("route_sort_order");
+
+ b.Property<string>("TextColor")
+ .HasMaxLength(7)
+ .HasColumnType("varchar(7)")
+ .HasColumnName("route_text_color");
+
+ b.Property<int>("Type")
+ .HasColumnType("int")
+ .HasColumnName("route_type");
+
+ b.Property<string>("Url")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("route_url");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AgencyId");
+
+ b.ToTable("routes");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.Stop", b =>
+ {
+ b.Property<string>("Id")
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("stop_id");
+
+ b.Property<string>("Code")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("stop_code");
+
+ b.Property<string>("Description")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("stop_desc");
+
+ b.Property<double>("Latitude")
+ .HasColumnType("double")
+ .HasColumnName("stop_lat");
+
+ b.Property<double>("Longitude")
+ .HasColumnType("double")
+ .HasColumnName("stop_lon");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("stop_name");
+
+ b.Property<string>("Timezone")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)")
+ .HasColumnName("stop_timezone");
+
+ b.Property<string>("Url")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("stop_url");
+
+ b.Property<int>("WheelchairBoarding")
+ .HasColumnType("int")
+ .HasColumnName("wheelchair_boarding");
+
+ b.HasKey("Id");
+
+ b.ToTable("stops");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.StopTime", b =>
+ {
+ b.Property<string>("TripId")
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("trip_id");
+
+ b.Property<int>("StopSequence")
+ .HasColumnType("int")
+ .HasColumnName("stop_sequence");
+
+ b.Property<TimeOnly>("ArrivalTime")
+ .HasMaxLength(8)
+ .HasColumnType("varchar(8)")
+ .HasColumnName("arrival_time");
+
+ b.Property<TimeOnly>("DepartureTime")
+ .HasMaxLength(8)
+ .HasColumnType("varchar(8)")
+ .HasColumnName("departure_time");
+
+ b.Property<double?>("ShapeDistTraveled")
+ .HasColumnType("double")
+ .HasColumnName("shape_dist_traveled");
+
+ b.Property<string>("StopId")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("stop_id");
+
+ b.HasKey("TripId", "StopSequence");
+
+ b.HasIndex("StopId");
+
+ b.ToTable("stop_times");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.Trip", b =>
+ {
+ b.Property<string>("TripId")
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("trip_id");
+
+ b.Property<string>("BlockId")
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("block_id");
+
+ b.Property<int>("DirectionId")
+ .HasColumnType("int")
+ .HasColumnName("direction_id");
+
+ b.Property<string>("RouteId")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("route_id");
+
+ b.Property<string>("ServiceId")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("service_id");
+
+ b.Property<string>("ShapeId")
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("shape_id");
+
+ b.Property<int>("TripBikesAllowed")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasDefaultValue(0)
+ .HasColumnName("trip_bikes_allowed");
+
+ b.Property<string>("TripHeadsign")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("trip_headsign");
+
+ b.Property<string>("TripShortName")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)")
+ .HasColumnName("trip_short_name");
+
+ b.Property<int>("TripWheelchairAccessible")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasDefaultValue(0)
+ .HasColumnName("trip_wheelchair_accessible");
+
+ b.HasKey("TripId");
+
+ b.HasIndex("RouteId");
+
+ b.ToTable("trips");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.Route", b =>
+ {
+ b.HasOne("Costasdev.Busurbano.Database.Gtfs.Agency", "Agency")
+ .WithMany()
+ .HasForeignKey("AgencyId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Agency");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.StopTime", b =>
+ {
+ b.HasOne("Costasdev.Busurbano.Database.Gtfs.Stop", "Stop")
+ .WithMany()
+ .HasForeignKey("StopId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Costasdev.Busurbano.Database.Gtfs.Trip", "Trip")
+ .WithMany()
+ .HasForeignKey("TripId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Stop");
+
+ b.Navigation("Trip");
+ });
+
+ modelBuilder.Entity("Costasdev.Busurbano.Database.Gtfs.Trip", b =>
+ {
+ b.HasOne("Costasdev.Busurbano.Database.Gtfs.Route", null)
+ .WithMany()
+ .HasForeignKey("RouteId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Costasdev.Busurbano.ServiceViewer/Data/QueryExtensions/GtfsCalendarQueryExtensions.cs b/src/Costasdev.Busurbano.ServiceViewer/Data/QueryExtensions/GtfsCalendarQueryExtensions.cs
new file mode 100644
index 0000000..f5fc2bb
--- /dev/null
+++ b/src/Costasdev.Busurbano.ServiceViewer/Data/QueryExtensions/GtfsCalendarQueryExtensions.cs
@@ -0,0 +1,21 @@
+using Costasdev.ServiceViewer.Data.Gtfs;
+
+namespace Costasdev.ServiceViewer.Data.QueryExtensions;
+
+public static class GtfsCalendarQueryExtensions
+{
+ public static IQueryable<GtfsCalendar> WhereDayOfWeek(this IQueryable<GtfsCalendar> query, DayOfWeek dayOfWeek)
+ {
+ return dayOfWeek switch
+ {
+ DayOfWeek.Monday => query.Where(c => c.Monday),
+ DayOfWeek.Tuesday => query.Where(c => c.Tuesday),
+ DayOfWeek.Wednesday => query.Where(c => c.Wednesday),
+ DayOfWeek.Thursday => query.Where(c => c.Thursday),
+ DayOfWeek.Friday => query.Where(c => c.Friday),
+ DayOfWeek.Saturday => query.Where(c => c.Saturday),
+ DayOfWeek.Sunday => query.Where(c => c.Sunday),
+ _ => query
+ };
+ }
+}