82 lines
2.6 KiB
Python
82 lines
2.6 KiB
Python
import datetime
|
|
from collections.abc import Sequence
|
|
from dataclasses import dataclass
|
|
|
|
from sqlalchemy import Date, DateTime, Float, Integer, String, UniqueConstraint, select
|
|
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column
|
|
from sqlalchemy.sql import func
|
|
|
|
|
|
class Base(DeclarativeBase):
|
|
pass
|
|
|
|
|
|
class WeatherForecast(Base):
|
|
__tablename__ = "weather_forecast"
|
|
__table_args__ = (
|
|
UniqueConstraint("city", "forecast_date", name="unique_city_forecast_date"),
|
|
)
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
city: Mapped[str] = mapped_column(String, nullable=False)
|
|
forecast_date: Mapped[datetime.date] = mapped_column(Date, nullable=False)
|
|
temp_min: Mapped[float] = mapped_column(Float, nullable=False)
|
|
temp_max: Mapped[float] = mapped_column(Float, nullable=False)
|
|
humidity: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
wind_speed: Mapped[float] = mapped_column(Float, nullable=False)
|
|
description: Mapped[str | None] = mapped_column(String, nullable=True)
|
|
created_at: Mapped[datetime.datetime] = mapped_column(
|
|
DateTime, default=func.now(), nullable=False
|
|
)
|
|
|
|
def __repr__(self) -> str:
|
|
return (
|
|
f"WeatherForecast(id={self.id!r}, city={self.city!r}, "
|
|
f"forecast_date={self.forecast_date!r}, temp_min={self.temp_min!r}, "
|
|
f"temp_max={self.temp_max!r}, humidity={self.humidity!r}, "
|
|
f"wind_speed={self.wind_speed!r}, description={self.description!r})"
|
|
)
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class DailyForecast:
|
|
city: str
|
|
forecast_date: datetime.date
|
|
temp_min: float
|
|
temp_max: float
|
|
humidity: int
|
|
wind_speed: float
|
|
description: str
|
|
|
|
|
|
def save_forecasts(session: Session, forecasts: Sequence[DailyForecast]) -> int:
|
|
if not forecasts:
|
|
return 0
|
|
|
|
known: dict[str, set[datetime.date]] = {}
|
|
for city in {f.city for f in forecasts}:
|
|
known[city] = set(
|
|
session.scalars(
|
|
select(WeatherForecast.forecast_date).where(
|
|
WeatherForecast.city == city
|
|
)
|
|
).all()
|
|
)
|
|
|
|
add = [
|
|
WeatherForecast(
|
|
city=f.city,
|
|
forecast_date=f.forecast_date,
|
|
temp_min=f.temp_min,
|
|
temp_max=f.temp_max,
|
|
humidity=f.humidity,
|
|
wind_speed=f.wind_speed,
|
|
description=f.description,
|
|
)
|
|
for f in forecasts
|
|
if f.forecast_date not in known[f.city]
|
|
]
|
|
session.add_all(add)
|
|
session.commit()
|
|
return len(add)
|