"""Route calculator service - calculates transit routes using Google Maps API.""" from models.listing import DestinationMode, Route, RouteLegStep from repositories.listing_repository import ListingRepository from tqdm.asyncio import tqdm from rec import routing from models import Listing async def calculate_route( repository: ListingRepository, destination_address: str, travel_mode: routing.TravelMode, limit: int | None = None, ) -> None: """Calculate transit routes for listings to a destination.""" listings = await repository.get_listings() if limit is not None: listings = listings[:limit] destimation_mode = DestinationMode(destination_address, travel_mode) updated_listings = await tqdm.gather( *[update_routing_info(listing, destimation_mode) for listing in listings], total=len(listings), desc="Updating routing info", ) await repository.upsert_listings( [listing for listing in updated_listings if listing is not None] ) async def update_routing_info( listing: Listing, destination_mode: DestinationMode ) -> Listing | None: """Update routing information for a single listing.""" if listing.routing_info.get(destination_mode) is not None: # already calculated, do not recompute to save API calls return None routes_data = routing.transit_route( listing.latitude, listing.longitude, destination_mode.destination_address, destination_mode.travel_mode, ) routes: list[Route] = [] for route_data in routes_data["routes"]: duration_s = int(route_data["duration"].split("s")[0]) route = Route( legs=[ RouteLegStep( distance_meters=step_data["distanceMeters"], duration_s=int(step_data["staticDuration"].split("s")[0]), travel_mode=routing.TravelMode(step_data["travelMode"]), ) for step_data in route_data["legs"][0]["steps"] ], distance_meters=route_data["distanceMeters"], duration_s=duration_s, ) routes.append(route) listing.routing_info_json = listing.serialize_routing_info( {**listing.routing_info, **{destination_mode: routes}} ) return listing