from fastapi import APIRouter from typing import Optional, List, Dict, Any from pydantic import BaseModel, Field from datetime import date from common.log.module_logger import ModuleLogger from backend.services.registration_analytics_service import RegistrationService class RegistrationDataPoint(BaseModel): """Single data point in registration time series.""" date: str = Field(..., description="Date in YYYY-MM-DD format") value: int = Field(..., description="Number of registered users") product_id: str = Field(..., description="Product identifier") class RegistrationTimeSeriesResponse(BaseModel): """Response model for registration time series data.""" metric_name: str = Field(..., description="Name of the queried metric") data_points: List[RegistrationDataPoint] = Field(..., description="List of data points") total_points: int = Field(..., description="Total number of data points") time_range: Dict[str, str] = Field(..., description="Start and end date of the query") total_registrations: int = Field(..., description="Total number of registrations in the period") class RegistrationQueryRequest(BaseModel): """Request model for registration query.""" product_id: str = Field("freeleaps", description="Product ID to identify which product's data to query") start_date: str = Field(..., description="Start date in YYYY-MM-DD format") end_date: str = Field(..., description="End date in YYYY-MM-DD format") router = APIRouter() # Initialize service and logger registration_service = RegistrationService() module_logger = ModuleLogger(__file__) @router.post("/starrocks/dru_query", response_model=RegistrationTimeSeriesResponse) async def metrics_query( request: RegistrationQueryRequest ): """ Query registration time series data. Returns XY curve data (time series) for user registrations within the given date range. """ await module_logger.log_info( f"Querying registration data for product '{request.product_id}' from {request.start_date} to {request.end_date}") # Parse dates - handle both YYYY-M-D and YYYY-MM-DD formats def parse_date(date_str: str) -> date: try: return date.fromisoformat(date_str) except ValueError: # Try to parse YYYY-M-D format and convert to YYYY-MM-DD parts = date_str.split('-') if len(parts) == 3: year, month, day = parts return date(int(year), int(month), int(day)) raise ValueError(f"Invalid date format: {date_str}") start_date = parse_date(request.start_date) end_date = parse_date(request.end_date) # Query the registration data result = registration_service.get_daily_registered_users( start_date=start_date, end_date=end_date, product_id=request.product_id ) # Format response response = RegistrationTimeSeriesResponse( metric_name="daily_registered_users", data_points=[ RegistrationDataPoint( date=date_str, value=count, product_id=request.product_id ) for date_str, count in zip(result.dates, result.counts) ], total_points=len(result.dates), time_range={ "start": request.start_date, "end": request.end_date }, total_registrations=result.total_registrations ) await module_logger.log_info( f"Successfully queried registration data with {len(result.dates)} data points, total registrations: {result.total_registrations}") return response