Limit all dates asking to 3 months range
This commit is contained in:
@@ -81,6 +81,20 @@ class DBService(log: Logger[IO]) extends DataServiceTrait {
|
|||||||
} yield dates.sorted
|
} yield dates.sorted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def getDatesByMonths(monthList: List[LocalDate]): IO[List[LocalDate]] = {
|
||||||
|
val dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd")
|
||||||
|
val monthFormatter = DateTimeFormatter.ofPattern("yyyyMM")
|
||||||
|
val monthStrList = monthList.map(_.format(monthFormatter))
|
||||||
|
for {
|
||||||
|
fileNames <- readFileNames(dataPath)
|
||||||
|
datesStr <- IO(fileNames.map(_.take(8)).distinct) // take yyyyMMdd
|
||||||
|
filteredDatesStr = datesStr.filter(date => monthStrList.contains(date.take(6)))
|
||||||
|
dates <- filteredDatesStr.traverse { str =>
|
||||||
|
IO(LocalDate.parse(str, dateFormatter)).option
|
||||||
|
}.map(_.flatten)
|
||||||
|
} yield dates.sorted
|
||||||
|
}
|
||||||
|
|
||||||
def getDateFileNames(date: LocalDate): IO[List[String]] = {
|
def getDateFileNames(date: LocalDate): IO[List[String]] = {
|
||||||
val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd")
|
val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd")
|
||||||
val dateStr: String = date.format(formatter)
|
val dateStr: String = date.format(formatter)
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ class DataService private(
|
|||||||
|
|
||||||
def getDates: IO[List[LocalDate]] = dbService.getDates
|
def getDates: IO[List[LocalDate]] = dbService.getDates
|
||||||
|
|
||||||
|
def getDatesByMonths(monthList: List[LocalDate]): IO[List[LocalDate]] = dbService.getDatesByMonths(monthList)
|
||||||
|
|
||||||
def getDateFileNames(date: LocalDate): IO[List[String]] = dbService.getDateFileNames(date)
|
def getDateFileNames(date: LocalDate): IO[List[String]] = dbService.getDateFileNames(date)
|
||||||
|
|
||||||
// TODO implement getting full data from state
|
// TODO implement getting full data from state
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import com.comcast.ip4s.IpLiteralSyntax
|
|||||||
import db.DataService
|
import db.DataService
|
||||||
import fetch.FetchService
|
import fetch.FetchService
|
||||||
import parse.{Aggregate, Parser, WeatherData}
|
import parse.{Aggregate, Parser, WeatherData}
|
||||||
import server.ValidateRoutes.{AggKey, CityList, DateTimeRange, Granularity, ValidDate}
|
import server.ValidateRoutes.{AggKey, CityList, DateTimeRange, Granularity, ValidDate, ValidateMonths}
|
||||||
import io.circe.{Json, Printer}
|
import io.circe.{Json, Printer}
|
||||||
import org.http4s._
|
import org.http4s._
|
||||||
import org.http4s.dsl.io._
|
import org.http4s.dsl.io._
|
||||||
@@ -89,6 +89,12 @@ class Server(dataService: DataService, fetch: FetchService, log: Logger[IO]) {
|
|||||||
Ok(dates.asJson.pretty)
|
Ok(dates.asJson.pretty)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// http://0.0.0.0:8080/api/show/months/202304,202305,202306
|
||||||
|
case GET -> Root / "show" / "months" / ValidateMonths(monthList) =>
|
||||||
|
dataService.getDatesByMonths(monthList).flatMap(dates =>
|
||||||
|
Ok(dates.asJson.pretty)
|
||||||
|
)
|
||||||
|
|
||||||
// http://0.0.0.0:8080/api/show/date/20230423
|
// http://0.0.0.0:8080/api/show/date/20230423
|
||||||
case GET -> Root / "show" / "date" / ValidDate(date) =>
|
case GET -> Root / "show" / "date" / ValidDate(date) =>
|
||||||
dataService.getDateFileNames(date).flatMap(fileNames =>
|
dataService.getDateFileNames(date).flatMap(fileNames =>
|
||||||
|
|||||||
@@ -27,6 +27,21 @@ object ValidateRoutes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object ValidateMonths {
|
||||||
|
def unapply(str: String): Option[List[LocalDate]] = {
|
||||||
|
val formatter = DateTimeFormatter.ofPattern("yyyyMMdd")
|
||||||
|
val monthList = str
|
||||||
|
.split(",")
|
||||||
|
.toList
|
||||||
|
.flatMap(str => Try(LocalDate.parse(str + "01", formatter)).toOption)
|
||||||
|
|
||||||
|
monthList match {
|
||||||
|
case Nil => None
|
||||||
|
case list => Some(list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object CityList {
|
object CityList {
|
||||||
def unapply(str: String): Option[List[String]] = {
|
def unapply(str: String): Option[List[String]] = {
|
||||||
str.split(",").toList match {
|
str.split(",").toList match {
|
||||||
|
|||||||
@@ -34,6 +34,27 @@ class DBServiceSpec extends AnyFunSuite with Matchers {
|
|||||||
lines.length shouldBe 2142
|
lines.length shouldBe 2142
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("getDatesByMonths should return filtered dates") {
|
||||||
|
val monthFormatter = DateTimeFormatter.ofPattern("yyyyMMdd")
|
||||||
|
val monthList = List(
|
||||||
|
LocalDate.parse("20230401", monthFormatter),
|
||||||
|
LocalDate.parse("20230501", monthFormatter),
|
||||||
|
LocalDate.parse("20230601", monthFormatter),
|
||||||
|
)
|
||||||
|
val dbService = DBService.of.unsafeRunSync()
|
||||||
|
val dates = dbService.getDatesByMonths(monthList).unsafeRunSync()
|
||||||
|
|
||||||
|
dates should not be empty
|
||||||
|
|
||||||
|
val exportFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
|
||||||
|
val validPrefixes = Set("2023-04", "2023-05", "2023-06")
|
||||||
|
val invalidDates = dates
|
||||||
|
.map(_.format(exportFormatter))
|
||||||
|
.filterNot(date => validPrefixes.exists(prefix => date.startsWith(prefix)))
|
||||||
|
|
||||||
|
invalidDates shouldBe empty
|
||||||
|
}
|
||||||
|
|
||||||
test("DBService.save should return correct result") {
|
test("DBService.save should return correct result") {
|
||||||
val dbService = DBService.of.unsafeRunSync()
|
val dbService = DBService.of.unsafeRunSync()
|
||||||
val fileName = "testFile.txt"
|
val fileName = "testFile.txt"
|
||||||
|
|||||||
@@ -1,24 +1,31 @@
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { Accessor, Component, createSignal, Setter } from "solid-js";
|
import { Accessor, Component, Setter } from "solid-js";
|
||||||
|
|
||||||
import "../css/calendar.css";
|
import "../css/calendar.css";
|
||||||
|
|
||||||
export const Calendar: Component<{
|
export const Calendar: Component<{
|
||||||
getSelectedDate: Accessor<Date>,
|
getSelectedDate: Accessor<Date>,
|
||||||
setSelectedDate: Setter<Date>,
|
setSelectedDate: Setter<Date>,
|
||||||
datesWithData: Date[],
|
setCurrentMonth: Setter<Date>,
|
||||||
}> = ({getSelectedDate, setSelectedDate, datesWithData}) => {
|
datesWithData: () => Date[],
|
||||||
const dateStrArr = () => datesWithData.map(d => d.toDateString());
|
}> = ({getSelectedDate, setSelectedDate, setCurrentMonth, datesWithData}) => {
|
||||||
|
const dateStrArr = () => datesWithData().map(d => d.toDateString());
|
||||||
|
|
||||||
|
function changeMonths(delta: number): void {
|
||||||
|
const newDate = moment(getSelectedDate()).add(delta, "months").toDate();
|
||||||
|
setCurrentMonth(newDate);
|
||||||
|
setSelectedDate(newDate);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h3>Calendar</h3>
|
<h3>Calendar</h3>
|
||||||
<div class="calendar-top">
|
<div class="calendar-top">
|
||||||
<button onClick={() => setSelectedDate(moment(getSelectedDate()).subtract(1, "months").toDate()) }><<</button>
|
<button onClick={() => changeMonths(-1) }><<</button>
|
||||||
<div class="calendar-year-month">
|
<div class="calendar-year-month">
|
||||||
{moment(getSelectedDate()).format("YYYY, MMM")}
|
{moment(getSelectedDate()).format("YYYY, MMM")}
|
||||||
</div>
|
</div>
|
||||||
<button onclick={() => setSelectedDate(moment(getSelectedDate()).add(1, "months").toDate())}>>></button>
|
<button onclick={() => changeMonths(1)}>>></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="calendar">
|
<div class="calendar">
|
||||||
{ getPaddedMonth(getSelectedDate()).map(d => {
|
{ getPaddedMonth(getSelectedDate()).map(d => {
|
||||||
|
|||||||
@@ -1,18 +1,26 @@
|
|||||||
import { Accessor, Component, createResource, Setter } from "solid-js";
|
import moment from "moment";
|
||||||
|
import { Accessor, Component, createResource, createSignal, Setter } from "solid-js";
|
||||||
|
|
||||||
import { apiHost } from "../consts";
|
import { apiHost } from "../consts";
|
||||||
|
|
||||||
import "../css/spinner.css";
|
import "../css/spinner.css";
|
||||||
import { Calendar } from "./Calendar";
|
import { Calendar } from "./Calendar";
|
||||||
|
|
||||||
export const DateList: Component<{getDate: Accessor<Date>, setDate: Setter<Date>;}> = (props) => {
|
export const DateList: Component<{getDate: Accessor<Date>, setDate: Setter<Date>;}> = (props) => {
|
||||||
|
const [getCurrentMonth, setCurrentMonth] = createSignal(new Date());
|
||||||
const fetchDates = async () => {
|
const fetchDates = async () => {
|
||||||
|
const months = [
|
||||||
|
moment(getCurrentMonth()).format("yyyyMM"),
|
||||||
|
moment(getCurrentMonth()).subtract(1, "months").format("yyyyMM"),
|
||||||
|
moment(getCurrentMonth()).add(1, "months").format("yyyyMM"),
|
||||||
|
];
|
||||||
await new Promise(resolve => setTimeout(resolve, 500))
|
await new Promise(resolve => setTimeout(resolve, 500))
|
||||||
const response = await fetch(`${apiHost}/api/show/all_dates`);
|
const response = await fetch(`${apiHost}/api/show/months/${months.join(",")}`);
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [datesResource] = createResource(fetchDates);
|
const [datesResource] = createResource(getCurrentMonth, fetchDates);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -25,10 +33,11 @@ export const DateList: Component<{getDate: Accessor<Date>, setDate: Setter<Date>
|
|||||||
{ datesResource.error && (
|
{ datesResource.error && (
|
||||||
<div>Error while loading dates: ${datesResource.error}</div>
|
<div>Error while loading dates: ${datesResource.error}</div>
|
||||||
)}
|
)}
|
||||||
{ datesResource() && <Calendar
|
{ !datesResource.loading && datesResource() && <Calendar
|
||||||
getSelectedDate={props.getDate}
|
getSelectedDate={props.getDate}
|
||||||
setSelectedDate={props.setDate}
|
setSelectedDate={props.setDate}
|
||||||
datesWithData={datesResource().map((str: string) => new Date(str))}
|
setCurrentMonth={setCurrentMonth}
|
||||||
|
datesWithData={() => datesResource().map((str: string) => new Date(str))}
|
||||||
/> }
|
/> }
|
||||||
|
|
||||||
{/* Backup date view */}
|
{/* Backup date view */}
|
||||||
|
|||||||
Reference in New Issue
Block a user