import uuid from repositories.pocketbase_client import pb_client from repositories.repo_config import USE_MOCK_REPOSITORIES COLLECTION = 'comparable_matches' class ComparableRepository: """Data access for the `comparable_matches` collection (Phase 6).""" def create(self, data): return pb_client.create(COLLECTION, data) def update(self, match_id, data): return pb_client.update(COLLECTION, match_id, data) def get_by_client_and_competitor_product(self, tenant_id, client_product, competitor_product): """ Used to upsert on repeat matching runs (the Sunday-night n8n workflow) instead of duplicating a row for the same pair every week — first_matched/last_matched only make sense if the same pair is updated in place, not recreated. """ safe_client = client_product.replace('"', '\\"') return pb_client.get_first( COLLECTION, f'tenant_id = "{tenant_id}" && client_product = "{safe_client}" ' f'&& competitor_product = "{competitor_product}"' ) def list_for_tenant(self, tenant_id, include_dismissed=False): filter_str = f'tenant_id = "{tenant_id}"' if not include_dismissed: filter_str += ' && dismissed = false' return pb_client.list(COLLECTION, filter_str=filter_str, sort='-similarity_score', per_page=200) def dismiss(self, match_id): return pb_client.update(COLLECTION, match_id, {'dismissed': True}) class MockComparableRepository: """In-memory stand-in for ComparableRepository.""" def __init__(self): self._records = {} def create(self, data): record_id = data.get('id') or str(uuid.uuid4()) record = {'id': record_id, 'dismissed': False, **data} self._records[record_id] = record return record def update(self, match_id, data): if match_id not in self._records: return None self._records[match_id] = {**self._records[match_id], **data} return self._records[match_id] def get_by_client_and_competitor_product(self, tenant_id, client_product, competitor_product): return next(( r for r in self._records.values() if r.get('tenant_id') == tenant_id and r.get('client_product') == client_product and r.get('competitor_product') == competitor_product ), None) def list_for_tenant(self, tenant_id, include_dismissed=False): items = [ r for r in self._records.values() if r.get('tenant_id') == tenant_id and (include_dismissed or not r.get('dismissed')) ] items.sort(key=lambda r: r.get('similarity_score') or 0, reverse=True) return items def dismiss(self, match_id): if match_id not in self._records: return None self._records[match_id]['dismissed'] = True return self._records[match_id] comparable_repository = MockComparableRepository() if USE_MOCK_REPOSITORIES else ComparableRepository()