from typing import Union, Dict, List, Optional, Any from base import RedisRow class RedisResponse: """ Base class for Redis response handling. Provides a standardized way to return and process Redis operation results, with tools to convert between different data representations. """ def __init__( self, status: bool, message: str, data: Any = None, error: Optional[str] = None, ): """ Initialize a Redis response. Args: status: Operation success status message: Human-readable message about the operation data: Response data (can be None, RedisRow, list, or dict) error: Optional error message if operation failed """ self.status = status self.message = message self.data = data self.error = error # Determine the data type if isinstance(data, dict): self.data_type = "dict" elif isinstance(data, list): self.data_type = "list" elif isinstance(data, RedisRow): self.data_type = "row" elif isinstance(data, (int, float, str, bool)): self.data_type = "primitive" else: self.data_type = None def as_dict(self) -> Dict: """ Convert the response to a dictionary format suitable for serialization. Returns: Dictionary representation of the response """ # Base response fields main_dict = { "status": self.status, "message": self.message, "count": self.count, "dataType": self.data_type, } # Add error if present if self.error: main_dict["error"] = self.error data = self.all # Process single RedisRow if isinstance(data, RedisRow): result = {**main_dict} if hasattr(data, 'keys') and hasattr(data, 'row'): if not isinstance(data.keys, str): raise ValueError("RedisRow keys must be string type") result[data.keys] = data.row return result # Process list of RedisRows elif isinstance(data, list): result = {**main_dict} # Handle list of RedisRow objects rows_dict = {} for row in data: if isinstance(row, RedisRow) and hasattr(row, 'keys') and hasattr(row, 'row'): if not isinstance(row.keys, str): raise ValueError("RedisRow keys must be string type") rows_dict[row.keys] = row.row if rows_dict: result["data"] = rows_dict elif data: # If it's just a regular list with items result["data"] = data return result # Process dictionary elif isinstance(data, dict): return {**main_dict, "data": data} return main_dict @property def all(self) -> Any: """ Get all data from the response. Returns: All data or empty list if None """ return self.data if self.data is not None else [] @property def count(self) -> int: """ Count the number of items in the response data. Returns: Number of items (0 if no data) """ data = self.all if isinstance(data, list): return len(data) elif isinstance(data, (RedisRow, dict)): return 1 return 0 @property def first(self) -> Union[Dict, None]: """ Get the first item from the response data. Returns: First item as a dictionary or None if no data """ if not self.data: return None if isinstance(self.data, list) and self.data: item = self.data[0] if isinstance(item, RedisRow) and hasattr(item, 'row'): return item.row return item elif isinstance(self.data, RedisRow) and hasattr(self.data, 'row'): return self.data.row elif isinstance(self.data, dict): return self.data return None def is_successful(self) -> bool: """ Check if the operation was successful. Returns: Boolean indicating success status """ return self.status def to_api_response(self) -> Dict: """ Format the response for API consumption. Returns: API-friendly response dictionary """ try: response = { "success": self.status, "message": self.message, } if self.error: response["error"] = self.error if self.data is not None: if self.data_type == "row" and hasattr(self.data, 'to_dict'): response["data"] = self.data.to_dict() elif self.data_type == "list": try: if all(hasattr(item, 'to_dict') for item in self.data): response["data"] = [item.to_dict() for item in self.data] else: response["data"] = self.data except Exception as e: response["error"] = f"Error converting list items: {str(e)}" else: response["data"] = self.data response["count"] = self.count return response except Exception as e: return { "success": False, "message": "Error formatting response", "error": str(e) }