from typing import List, Optional, Dict, Any from sqlalchemy.orm import Session from sqlalchemy import func from datetime import datetime, timedelta from app.crud.base import CRUDBase from app.models.weather import City, WeatherRecord from app.schemas.weather import CityCreate, CityUpdate, WeatherRecordCreate class CRUDCity(CRUDBase[City, CityCreate, CityUpdate]): def get_by_name_and_country(self, db: Session, *, name: str, country: str) -> Optional[City]: return db.query(City).filter( func.lower(City.name) == func.lower(name), func.lower(City.country) == func.lower(country) ).first() def get_by_coordinates(self, db: Session, *, latitude: float, longitude: float) -> Optional[City]: # Use a small delta to find cities by approximate coordinates delta = 0.01 # About 1km at the equator return db.query(City).filter( City.latitude.between(latitude - delta, latitude + delta), City.longitude.between(longitude - delta, longitude + delta) ).first() class CRUDWeatherRecord(CRUDBase[WeatherRecord, WeatherRecordCreate, WeatherRecordCreate]): def get_latest_by_city_id(self, db: Session, *, city_id: int) -> Optional[WeatherRecord]: return db.query(WeatherRecord).filter( WeatherRecord.city_id == city_id ).order_by(WeatherRecord.timestamp.desc()).first() def get_history_by_city_id( self, db: Session, *, city_id: int, start_date: datetime, end_date: datetime ) -> List[WeatherRecord]: return db.query(WeatherRecord).filter( WeatherRecord.city_id == city_id, WeatherRecord.timestamp.between(start_date, end_date) ).order_by(WeatherRecord.timestamp).all() def get_forecast_by_city_id( self, db: Session, *, city_id: int ) -> List[WeatherRecord]: """ Get weather forecast data for a city. In a real application, this might fetch forecasts from an external API, but for this example, we'll just return the most recent data. """ current_time = datetime.utcnow() return db.query(WeatherRecord).filter( WeatherRecord.city_id == city_id, WeatherRecord.timestamp >= current_time ).order_by(WeatherRecord.timestamp).all() city = CRUDCity(City) weather_record = CRUDWeatherRecord(WeatherRecord)