3da1b4242c
Feature 1.2: Python FastAPI microservice wrapping nba_api - GET /stats/season-avg, /stats/last-n, /stats/splits, /players/search - Redis caching (24hr/1hr/6hr/7day), 0.6s rate limiting, PRA derived stat - 27 Python tests passing Feature 1.4: Complete Supabase database schema - 6 tables: users, picks, scan_sessions, bets, outcomes, performance - RLS enabled on all tables with auth.uid() policies - 3 triggers: auto-create user, updated_at, scan count reset - 37 schema validation tests passing - Migration SQL ready, pending manual apply (WSL2 DNS blocker) Total: 92 tests (65 Node.js + 27 Python), all passing Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
51 lines
1.4 KiB
Python
51 lines
1.4 KiB
Python
from nba_api.stats.static import players
|
|
from app.utils.cache import cache_get, cache_set
|
|
from app.config import PLAYER_SEARCH_TTL
|
|
|
|
|
|
def normalize_name(name):
|
|
return name.strip().lower()
|
|
|
|
|
|
def search_players(name):
|
|
cache_key = f"nba:player:{normalize_name(name)}"
|
|
cached = cache_get(cache_key)
|
|
if cached is not None:
|
|
return cached
|
|
|
|
all_players = players.get_players()
|
|
search_lower = normalize_name(name)
|
|
|
|
matches = []
|
|
for p in all_players:
|
|
full_name = p["full_name"].lower()
|
|
if search_lower in full_name:
|
|
matches.append({
|
|
"player_id": p["id"],
|
|
"full_name": p["full_name"],
|
|
"is_active": p["is_active"],
|
|
})
|
|
|
|
cache_set(cache_key, matches, PLAYER_SEARCH_TTL)
|
|
return matches
|
|
|
|
|
|
def resolve_player(name):
|
|
"""Resolve a player name to a single active player. Returns (player_id, full_name) or raises."""
|
|
matches = search_players(name)
|
|
active = [m for m in matches if m["is_active"]]
|
|
|
|
if not active:
|
|
if matches:
|
|
# Return first inactive match as fallback
|
|
return matches[0]["player_id"], matches[0]["full_name"]
|
|
return None, None
|
|
|
|
# Prefer exact match
|
|
search_lower = normalize_name(name)
|
|
for m in active:
|
|
if m["full_name"].lower() == search_lower:
|
|
return m["player_id"], m["full_name"]
|
|
|
|
return active[0]["player_id"], active[0]["full_name"]
|