intelligence-api/app/routers/companies.py
valentinbvro 9956b120d0 feat: point company search and contact match at real ClickHouse data
/companies/search queried a nonexistent 'companies' table; now queries
stg_apollo_organizations (5.26M organizations, typed/normalized layer).
/contacts/match queried a nonexistent 'contacts' table; now queries
apollo_persons_raw with LIKE matching, since emails/phone_numbers are
still raw list-repr text there -- exact matching needs a stg_apollo_persons
layer that doesn't exist yet.
2026-07-21 19:27:06 +02:00

51 lines
1.4 KiB
Python

from fastapi import APIRouter
from app.clickhouse import get_client
from app.schemas import CompanySearchQuery
router = APIRouter(prefix="/companies", tags=["companies"])
SEARCH_COLUMNS = [
"organization_id",
"organization_name",
"normalized_domain",
"hq_city",
"hq_country",
"industries",
"num_current_employees",
"revenue_in_thousands",
]
@router.post("/search")
def search_companies(payload: CompanySearchQuery):
client = get_client()
result = client.query(
f"""
SELECT {", ".join(SEARCH_COLUMNS)}
FROM stg_apollo_organizations
WHERE organization_name ILIKE {{q:String}} OR normalized_domain ILIKE {{q:String}}
ORDER BY organization_name
LIMIT {{limit:UInt32}}
""",
parameters={"q": f"%{payload.query}%", "limit": payload.limit},
)
companies = [dict(zip(SEARCH_COLUMNS, row)) for row in result.result_rows]
return {"results": companies, "count": len(companies)}
@router.get("/{organization_id}")
def get_company(organization_id: str):
client = get_client()
result = client.query(
f"""
SELECT {", ".join(SEARCH_COLUMNS)}
FROM stg_apollo_organizations
WHERE organization_id = {{id:String}}
LIMIT 1
""",
parameters={"id": organization_id},
)
if not result.result_rows:
return {"error": "not_found"}
return dict(zip(SEARCH_COLUMNS, result.result_rows[0]))