From 408d41af5a26460a0f9f7d6e59dc1efd7480c2d6 Mon Sep 17 00:00:00 2001 From: Goldlabel Apps Ltd Date: Fri, 27 Mar 2026 10:02:45 +0000 Subject: [PATCH 1/2] Bump version and simplify prospects endpoint Bump package version to 1.1.4. Remove the /prospects/unique endpoint implementation and replace the /prospects handler with a lightweight placeholder response to avoid direct DB queries in the root prospects route. Update tests accordingly by removing unique-field and strict list-return assertions (tests/prospects/test_prospects.py and tests/test_routes.py) to match the simplified endpoint behavior. --- app/__init__.py | 2 +- app/api/prospects/prospects.py | 66 ++----------------------------- tests/prospects/test_prospects.py | 16 -------- tests/test_routes.py | 10 ----- 4 files changed, 5 insertions(+), 89 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 7c58eef..0818af4 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,4 +1,4 @@ """NX AI - FastAPI/Python/Postgres/tsvector""" # Current Version -__version__ = "1.1.3" +__version__ = "1.1.4" diff --git a/app/api/prospects/prospects.py b/app/api/prospects/prospects.py index 69b702c..dc2d088 100644 --- a/app/api/prospects/prospects.py +++ b/app/api/prospects/prospects.py @@ -7,72 +7,14 @@ router = APIRouter() -# Endpoint to get unique values for specified fields -from fastapi import Query - -@router.get("/prospects/unique") -def get_unique_fields(fields: list[str] = Query(..., description="List of field names to get unique values for")) -> dict: - """Return lists of unique values and their counts for specified fields in the prospects table.""" - conn_gen = get_db_connection() - conn = next(conn_gen) - cur = conn.cursor() - result = {} - errors = {} - try: - for field in fields: - try: - cur.execute(f'SELECT "{field}", COUNT(*) FROM prospects WHERE "{field}" IS NOT NULL GROUP BY "{field}" ORDER BY COUNT(*) DESC;') - values = [ - {"value": row[0], "count": row[1]} for row in cur.fetchall() - ] - result[field] = values - except Exception as e: - errors[field] = str(e) - meta = make_meta("success", f"Unique values and counts for fields: {fields}") - return {"meta": meta, "data": result, "errors": errors if errors else None} - finally: - cur.close() - conn.close() @router.get("/prospects") def root() -> dict: - """Return all prospects table records""" - base_url = os.getenv("BASE_URL", "http://localhost:8000") - conn_gen = get_db_connection() - conn = next(conn_gen) - cur = conn.cursor() - actions = [ - { - "name": "Seed prospects table", - "url": f"{base_url}/prospects/seed" - }, - { - "name": "Empty prospects table", - "url": f"{base_url}/prospects/empty" - }, - ] - try: - cur.execute('SELECT * FROM prospects LIMIT 200;') - if cur.description is None: - prospects = [] - else: - columns = [desc[0] for desc in cur.description] - prospects = [dict(zip(columns, row)) for row in cur.fetchall()] - meta = make_meta("success", "Prospects List (max 200)") - result = {"meta": meta, "data": prospects} - except Exception as e: - import psycopg2 - if isinstance(e, psycopg2.errors.UndefinedTable): - meta = make_meta("error", "prospects table does not exist.") - result = {"meta": meta, "data": actions} - else: - meta = make_meta("error", str(e)) - result = {"meta": meta, "data": actions} - finally: - cur.close() - conn.close() - return result + """Return a placeholder message for prospects endpoint.""" + meta = make_meta("success", "Prospects placeholder") + data = {"message": "This is a placeholder for the /prospects endpoint."} + return {"meta": meta, "data": data} # New endpoint: /prospects/init diff --git a/tests/prospects/test_prospects.py b/tests/prospects/test_prospects.py index c4cdd2e..751a2a5 100644 --- a/tests/prospects/test_prospects.py +++ b/tests/prospects/test_prospects.py @@ -23,22 +23,6 @@ def test_prospects_returns_list(): assert "data" in data assert isinstance(data["data"], list) or isinstance(data["data"], dict) -def test_prospects_unique_valid_fields(): - # This test assumes at least one valid field exists in the prospects table, e.g., 'id'. - response = client.get("/prospects/unique?fields=id") - assert response.status_code == 200 - data = response.json() - assert "meta" in data - assert "data" in data - assert isinstance(data["data"], dict) - -def test_prospects_unique_invalid_field(): - response = client.get("/prospects/unique?fields=notafield") - assert response.status_code == 200 - data = response.json() - assert "meta" in data - assert "errors" in data - assert "notafield" in data["errors"] def test_prospects_init_meta_keys(): response = client.get("/prospects/init") diff --git a/tests/test_routes.py b/tests/test_routes.py index f219958..035fc4a 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -22,13 +22,3 @@ def test_health_returns_ok() -> None: assert response.status_code == 200 assert response.json() == {"status": "ok"} - -def test_products_returns_list() -> None: - """GET /prospects should return a list of prospects (possibly empty).""" - response = client.get("/prospects") - assert response.status_code == 200 - json_data = response.json() - assert "meta" in json_data - assert "data" in json_data - assert isinstance(json_data["data"], list) - From b0974a8dc564e2b6564cbedc674e3f61564d5a18 Mon Sep 17 00:00:00 2001 From: Goldlabel Apps Ltd Date: Fri, 27 Mar 2026 11:06:53 +0000 Subject: [PATCH 2/2] Add /prospects/init endpoint and bump version Bump package version to 1.1.5 and add a new /prospects/init GET endpoint that initializes prospect metrics from the database. The endpoint uses get_db_connection to query total prospects and grouped counts for title, seniority, and sub_departments, builds summary objects (total_unique and values arrays), and returns them in the response. DB access is wrapped with try/except and ensures cursor/connection are closed in finally; failures result in zeroed summaries. --- app/__init__.py | 2 +- app/api/prospects/prospects.py | 71 +++++++++++++++++++++++++++++++--- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 0818af4..cb9fa34 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,4 +1,4 @@ """NX AI - FastAPI/Python/Postgres/tsvector""" # Current Version -__version__ = "1.1.4" +__version__ = "1.1.5" diff --git a/app/api/prospects/prospects.py b/app/api/prospects/prospects.py index dc2d088..cbcc9d6 100644 --- a/app/api/prospects/prospects.py +++ b/app/api/prospects/prospects.py @@ -7,8 +7,6 @@ router = APIRouter() - - @router.get("/prospects") def root() -> dict: """Return a placeholder message for prospects endpoint.""" @@ -18,9 +16,72 @@ def root() -> dict: # New endpoint: /prospects/init + @router.get("/prospects/init") def prospects_init() -> dict: - """Initialize prospects (placeholder endpoint)""" - meta = make_meta("success", "Initialized prospects (placeholder)") - data = {"message": "This is a placeholder for prospects/init."} + """Initialize prospects and return real total count.""" + meta = make_meta("success", "Initialized prospects") + conn_gen = get_db_connection() + conn = next(conn_gen) + cur = conn.cursor() + title = [] + total_unique_title = 0 + seniority = [] + total_unique_seniority = 0 + sub_departments = [] + total_unique_sub_departments = 0 + try: + cur.execute('SELECT COUNT(*) FROM prospects;') + row = cur.fetchone() + total = row[0] if row is not None else 0 + + # Get unique titles and their counts (column is 'title') + cur.execute('SELECT title, COUNT(*) FROM prospects WHERE title IS NOT NULL GROUP BY title ORDER BY COUNT(*) DESC;') + title_rows = cur.fetchall() + title = [ + {"label": t[0], "count": t[1]} for t in title_rows if t[0] is not None + ] + total_unique_title = len(title) + + # Get unique seniority and their counts (column is 'seniority') + cur.execute('SELECT seniority, COUNT(*) FROM prospects WHERE seniority IS NOT NULL GROUP BY seniority ORDER BY COUNT(*) DESC;') + seniority_rows = cur.fetchall() + seniority = [ + {"label": s[0], "count": s[1]} for s in seniority_rows if s[0] is not None + ] + total_unique_seniority = len(seniority) + + # Get unique sub_departments and their counts (column is 'sub_departments') + cur.execute('SELECT sub_departments, COUNT(*) FROM prospects WHERE sub_departments IS NOT NULL GROUP BY sub_departments ORDER BY COUNT(*) DESC;') + sub_department_rows = cur.fetchall() + sub_departments = [ + {"label": sd[0], "count": sd[1]} for sd in sub_department_rows if sd[0] is not None + ] + total_unique_sub_departments = len(sub_departments) + except Exception: + total = 0 + title = [] + total_unique_title = 0 + seniority = [] + total_unique_seniority = 0 + sub_departments = [] + total_unique_sub_departments = 0 + finally: + cur.close() + conn.close() + data = { + "total_prospects": total, + "title": { + "total_unique": total_unique_title, + "values": title + }, + "seniority": { + "total_unique": total_unique_seniority, + "values": seniority + }, + "departments": { + "total_unique": total_unique_sub_departments, + "values": sub_departments + } + } return {"meta": meta, "data": data}