from __future__ import annotations from datetime import datetime from typing import Generic, Sequence, TypeVar from pydantic import BaseModel, ConfigDict, Field def to_camel(string: str) -> str: head, *tail = string.split("_") return head + "".join(part.capitalize() for part in tail) IdT = TypeVar("IdT", bound=str) class CamelModel(BaseModel): model_config = ConfigDict( from_attributes=True, populate_by_name=True, alias_generator=to_camel, ) class TimestampedModel(CamelModel): created_at: datetime updated_at: datetime model_config = ConfigDict( frozen=True, from_attributes=True, populate_by_name=True, alias_generator=to_camel, ) class IdentifiedModel(TimestampedModel, Generic[IdT]): id: IdT class StationModel(IdentifiedModel[str]): name: str latitude: float longitude: float code: str | None = None osm_id: str | None = None elevation_m: float | None = None is_active: bool = True class TrackModel(IdentifiedModel[str]): start_station_id: str end_station_id: str length_meters: float max_speed_kph: float status: str | None = None is_bidirectional: bool = True coordinates: list[tuple[float, float]] = Field(default_factory=list) class TrainModel(IdentifiedModel[str]): designation: str capacity: int max_speed_kph: float operating_track_ids: list[str] class StationCreate(CamelModel): name: str latitude: float longitude: float osm_id: str | None = None code: str | None = None elevation_m: float | None = None is_active: bool = True class StationUpdate(CamelModel): name: str | None = None latitude: float | None = None longitude: float | None = None osm_id: str | None = None code: str | None = None elevation_m: float | None = None is_active: bool | None = None class TrackCreate(CamelModel): start_station_id: str end_station_id: str coordinates: Sequence[tuple[float, float]] name: str | None = None length_meters: float | None = None max_speed_kph: int | None = None is_bidirectional: bool = True status: str = "planned" class TrainCreate(CamelModel): designation: str capacity: int max_speed_kph: int operator_id: str | None = None home_station_id: str | None = None consist: str | None = None class TrainScheduleCreate(CamelModel): train_id: str station_id: str sequence_index: int scheduled_arrival: datetime | None = None scheduled_departure: datetime | None = None dwell_seconds: int | None = None class UserCreate(CamelModel): username: str password_hash: str email: str | None = None full_name: str | None = None role: str = "player" preferences: str | None = None