"""
Base Registry Client
Shared Supabase client and utilities for all registry types.
"""
import os
from typing import Optional
from supabase import create_client, Client
class BaseRegistry:
"""Base class for all registry clients with shared Supabase logic."""
def __init__(self):
"""Initialize Supabase client from environment."""
self.url = os.environ.get("SUPABASE_URL")
self.key = os.environ.get("SUPABASE_SECRET_KEY") or os.environ.get("SUPABASE_ANON_KEY")
self.client: Optional[Client] = None
if self.url and self.key:
try:
self.client = create_client(self.url, self.key)
except Exception as e:
self.client = None
@property
def is_configured(self) -> bool:
"""Check if Supabase is configured."""
return bool(self.url and self.key and self.client is not None)
def _parse_search_query(self, query: str) -> list[str]:
"""
Parse search query into normalized terms.
Handles:
- Multiple words (split by whitespace)
- Normalization (lowercase, strip)
- Filters out single characters
"""
if not query or not query.strip():
return []
terms = []
for word in query.split():
word = word.strip().lower()
if word and len(word) >= 2: # Ignore single characters
terms.append(word)
return terms
def _calculate_relevance_score(
self,
query_terms: list[str],
primary_text: str,
secondary_text: str = ""
) -> float:
"""
Calculate relevance score based on term matches.
Scoring:
- Exact match: 100
- All terms in primary: 80
- Some terms in primary: 60 * (matches/terms)
- All terms in secondary: 40
- Some terms in secondary: 20 * (matches/terms)
Args:
query_terms: List of normalized search terms
primary_text: Primary text to search (name/title)
secondary_text: Secondary text to search (description)
Returns:
Relevance score (0-100)
"""
primary_lower = primary_text.lower()
secondary_lower = (secondary_text or "").lower()
# Check exact match
primary_normalized = primary_lower.replace("_", " ").replace("-", " ")
query_normalized = " ".join(query_terms)
if primary_normalized == query_normalized or primary_lower == query_normalized.replace(" ", "_"):
return 100.0
# Count term matches
primary_matches = sum(1 for term in query_terms if term in primary_lower)
secondary_matches = sum(1 for term in query_terms if term in secondary_lower)
# Calculate score
score = 0.0
if primary_matches == len(query_terms):
score = 80.0 # All terms in primary
elif primary_matches > 0:
score = 60.0 * (primary_matches / len(query_terms)) # Some terms in primary
if secondary_matches == len(query_terms):
score = max(score, 40.0) # All terms in secondary
elif secondary_matches > 0:
score = max(score, 20.0 * (secondary_matches / len(query_terms))) # Some terms in secondary
return score