Coverage for src/data_api/domain/locations/services.py: 96%
27 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-11-13 19:28 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-11-13 19:28 +0000
1"""
2Locations domain service.
4Handles location/map data fetching and search.
5"""
7from typing import Optional
9from thefuzz import fuzz
11from data_api.data.manager import nthudata
12from data_api.data.nthudata import NTHUDataManager
14JSON_PATH = "maps.json"
15FUZZY_SEARCH_THRESHOLD = 60
18class LocationsService:
19 """Service for location data operations."""
21 def __init__(self, manager: NTHUDataManager = nthudata):
22 self.manager = manager
24 async def get_all_locations(self) -> tuple[Optional[str], list[dict]]:
25 """Get all locations."""
26 return await self.get_locations()
28 async def get_locations(self, name: str | None = None) -> tuple[Optional[str], list[dict]]:
29 """Get locations with an optional exact name filter."""
30 commit_hash, map_data = await self.manager.get(JSON_PATH)
31 locations = [
32 {
33 "name": location_name,
34 "latitude": coordinates["latitude"],
35 "longitude": coordinates["longitude"],
36 }
37 for campus_locations in map_data.values()
38 for location_name, coordinates in campus_locations.items()
39 if not name or location_name == name
40 ]
41 return commit_hash, locations
43 async def fuzzy_search_locations(self, query: str) -> tuple[Optional[str], list[dict]]:
44 """Fuzzy search locations by name."""
45 commit_hash, map_data = await self.manager.get(JSON_PATH)
46 tmp_results = []
47 for campus_locations in map_data.values():
48 for location_name, coordinates in campus_locations.items():
49 similarity = fuzz.partial_ratio(query, location_name)
50 if similarity >= FUZZY_SEARCH_THRESHOLD:
51 location = {
52 "name": location_name,
53 "latitude": coordinates["latitude"],
54 "longitude": coordinates["longitude"],
55 }
56 tmp_results.append((similarity, location))
58 # Sort by exact match first, then by similarity
59 tmp_results.sort(key=lambda x: (x[1]["name"] == query, x[0]), reverse=True)
60 return commit_hash, [item[1] for item in tmp_results]
63# Global service instance
64locations_service = LocationsService()