diff --git a/YongeStreet/Controllers/ApiController.cs b/YongeStreet/Controllers/ApiController.cs index 636813e..d114bec 100644 --- a/YongeStreet/Controllers/ApiController.cs +++ b/YongeStreet/Controllers/ApiController.cs @@ -17,9 +17,16 @@ public class ApiController: Controller _logger = logger; } - public JsonResult Roads(string city, int year=2025) + public ActionResult Roads(string city, string date="") { - return Json(_dataService.GetRoads(city, year)); + var extractDate = Util.ParseDateOnly(date); + if (!extractDate.HasValue) + { + return BadRequest($"Cannot parse provided date {date}. The date must be in the format yyyy-MM-dd."); + } + return Json(_dataService.GetRoads(city, extractDate.Value)); + + } } \ No newline at end of file diff --git a/YongeStreet/Controllers/HomeController.cs b/YongeStreet/Controllers/HomeController.cs index 539fc3c..bc45fa5 100644 --- a/YongeStreet/Controllers/HomeController.cs +++ b/YongeStreet/Controllers/HomeController.cs @@ -5,7 +5,7 @@ using YongeStreet.Services; namespace YongeStreet.Controllers; -public record CityModel(string City, IList CityRoadLengthStats); +public record CityModel(string City, IList CityRoadLengthStats, DateOnly Date); public record IndexModel(IList Cities); @@ -20,10 +20,11 @@ public class HomeController : Controller _dataService = dataService; } - public IActionResult City(string city) + public IActionResult City(string city, string date) { var cityRoadLengthStats = _dataService.GetCityRoadLengthStats(city); - return View(new CityModel(city, cityRoadLengthStats)); + var parsedDate = Util.ParseDateOnly(date) ?? new DateOnly(2025, 1, 1); + return View(new CityModel(city, cityRoadLengthStats, parsedDate )); } public IActionResult Index() diff --git a/YongeStreet/Controllers/Util.cs b/YongeStreet/Controllers/Util.cs new file mode 100644 index 0000000..c8593c5 --- /dev/null +++ b/YongeStreet/Controllers/Util.cs @@ -0,0 +1,21 @@ +namespace YongeStreet.Controllers; + +public static class Util +{ + public static DateOnly? ParseDateOnly(string? date) + { + if (string.IsNullOrEmpty(date)) + { + return new DateOnly(2025, 1, 1); + } + try + { + return DateOnly.ParseExact(date, "yyyy-MM-dd"); + } + catch (FormatException e) + { + return null; + } + } + +} \ No newline at end of file diff --git a/YongeStreet/Services/DataService.cs b/YongeStreet/Services/DataService.cs index d0a9526..80c4e13 100644 --- a/YongeStreet/Services/DataService.cs +++ b/YongeStreet/Services/DataService.cs @@ -4,9 +4,9 @@ namespace YongeStreet.Services; public record Road(int RelationId, List> Points); -public record CityOverview(string Name, double TotalStreetSize, IList AvailableYears); +public record CityOverview(string Name, double TotalStreetSize, IList AvailableDates); -public record CityRoadLengthStats(string Name, double MunicipalRoadLength, int Year); +public record CityRoadLengthStats(string Name, double MunicipalRoadLength, DateOnly Date); public class DataService { @@ -20,7 +20,7 @@ public class DataService "unclassified"]; private readonly string path = "/home/didier/dev/YongeStreet/real.duckdb"; - public IList GetRoads(string city, int year) + public IList GetRoads(string city, DateOnly extractDate) { using var duckDBConnection = new DuckDBConnection($"Data Source={path};ACCESS_MODE=READ_ONLY"); duckDBConnection.Open(); @@ -34,7 +34,7 @@ public class DataService AND list_contains($allowed_highway, highway) """; command.Parameters.Add(new DuckDBParameter("city_name", city)); - command.Parameters.Add(new DuckDBParameter("extract_date", new DateOnly(year, 1, 1))); + command.Parameters.Add(new DuckDBParameter("extract_date", extractDate)); command.Parameters.Add(new DuckDBParameter("allowed_highway", CITY_STREET_HIGHWAY)); using var reader = command.ExecuteReader(); @@ -57,7 +57,7 @@ public class DataService command.CommandText = """ SELECT city_name, SUM(length) FILTER (list_contains($allowed_highway, highway) AND extract_date = (Date '2025-01-01')) AS length, - LIST(DISTINCT extract('year' FROM extract_date)) AS available_years + LIST(DISTINCT extract_date) AS available_years FROM city_road GROUP BY city_name ORDER BY length desc @@ -70,7 +70,7 @@ public class DataService while (reader.Read()) ret.Add(new CityOverview(reader.GetString(0), reader.GetDouble(1), - reader.GetFieldValue>(2))); + reader.GetFieldValue>(2))); return ret; } @@ -83,11 +83,11 @@ public class DataService using var command = duckDBConnection.CreateCommand(); command.CommandText = """ SELECT SUM(length) FILTER (list_contains($allowed_highway, highway)) AS length, - extract('year' FROM extract_date) AS year + extract_date AS date FROM city_road WHERE city_name = $city_name GROUP BY extract_date - ORDER BY year DESC + ORDER BY date DESC """; command.Parameters.Add(new DuckDBParameter("city_name", city)); command.Parameters.Add(new DuckDBParameter("allowed_highway", CITY_STREET_HIGHWAY)); @@ -98,7 +98,7 @@ public class DataService { ret.Add(new CityRoadLengthStats(city, reader.GetInt32(0), - reader.GetInt32(1))); + reader.GetFieldValue(1))); } return ret; diff --git a/YongeStreet/Views/Home/City.cshtml b/YongeStreet/Views/Home/City.cshtml index ce4d6fa..3f588ae 100644 --- a/YongeStreet/Views/Home/City.cshtml +++ b/YongeStreet/Views/Home/City.cshtml @@ -1,9 +1,14 @@ +@using System.Runtime.InteropServices.JavaScript @model YongeStreet.Controllers.CityModel @{ ViewData["Title"] = "La Province"; } +
+

@Model.City - @Model.Date.ToString("yyyy-MM-dd")

+
+
- @foreach(var stats in Model.CityRoadLengthStats) + + @foreach (var stats in Model.CityRoadLengthStats) { - @stats.Year + + @if (stats.Date != Model.Date) + { + @Html.ActionLink(stats.Date.ToString("yyyy-MM-dd"), + "City", + "Home", + new { City = Model.City, Date = stats.Date.ToString("yyyy-MM-dd"), }) + + } + else + { + @stats.Date.ToString("yyyy-MM-dd") + } + + @((stats.MunicipalRoadLength / 1000).ToString("N")) diff --git a/YongeStreet/Views/Home/Index.cshtml b/YongeStreet/Views/Home/Index.cshtml index 5d1b446..99feff1 100644 --- a/YongeStreet/Views/Home/Index.cshtml +++ b/YongeStreet/Views/Home/Index.cshtml @@ -21,7 +21,7 @@ @Html.ActionLink(city.Name, "City", "Home", new {City=city.Name}) @((city.TotalStreetSize / 1000 ).ToString("N")) - @string.Join(", ", city.AvailableYears) + @string.Join(", ", city.AvailableDates) }