import uuid from repositories.pocketbase_client import pb_client from repositories.repo_config import USE_MOCK_REPOSITORIES COLLECTION = 'products' class ProductRepository: """Data access for the `products` collection.""" def get_latest_for_competitor(self, competitor_id, limit=10): """Returns a competitor's most recently scraped products, newest first.""" return pb_client.list( COLLECTION, filter_str=f'competitor_id = "{competitor_id}" && is_active = true', sort='-last_seen', per_page=limit ) def get_by_competitor_and_name(self, competitor_id, trip_name): """ Finds an existing active product for this competitor matching trip_name exactly — the dedup key used to decide whether a scrape found a genuinely new product or an update to one already on record (CLAUDE.md §15/§19 is_new + price diffing). Returns None if no match (i.e. this is a new product). """ if not trip_name: return None safe_name = trip_name.replace('"', '\\"') return pb_client.get_first( COLLECTION, f'competitor_id = "{competitor_id}" && trip_name = "{safe_name}" && is_active = true' ) def list_for_tenant(self, tenant_id): """Returns all active products for a tenant — used for embedding/comparable matching.""" return pb_client.list(COLLECTION, filter_str=f'tenant_id = "{tenant_id}" && is_active = true', per_page=500) def create(self, data): return pb_client.create(COLLECTION, data) def update(self, product_id, data): return pb_client.update(COLLECTION, product_id, data) class MockProductRepository: """In-memory stand-in for ProductRepository.""" def __init__(self): self._records = {} def get_latest_for_competitor(self, competitor_id, limit=10): items = [r for r in self._records.values() if r.get('competitor_id') == competitor_id and r.get('is_active', True)] items.sort(key=lambda r: r.get('last_seen') or '', reverse=True) return items[:limit] def get_by_competitor_and_name(self, competitor_id, trip_name): if not trip_name: return None return next(( r for r in self._records.values() if r.get('competitor_id') == competitor_id and r.get('trip_name') == trip_name and r.get('is_active', True) ), None) def list_for_tenant(self, tenant_id): return [r for r in self._records.values() if r.get('tenant_id') == tenant_id and r.get('is_active', True)] def create(self, data): record_id = data.get('id') or str(uuid.uuid4()) record = {'id': record_id, 'is_active': True, **data} self._records[record_id] = record return record def update(self, product_id, data): if product_id not in self._records: return None self._records[product_id] = {**self._records[product_id], **data} return self._records[product_id] product_repository = MockProductRepository() if USE_MOCK_REPOSITORIES else ProductRepository()