diff --git a/src/api/main.py b/src/api/main.py index e1d3749..573c547 100644 --- a/src/api/main.py +++ b/src/api/main.py @@ -34,6 +34,8 @@ def _row_to_contact_out(row: dict) -> dict: for field in ["emails", "phones", "addresses", "urls", "categories"]: raw = row.get(field) row[field] = json.loads(raw) if raw else [] + if not row.get("full_name"): + row["full_name"] = db._build_full_name(row) row["updated_at"] = str(row["updated_at"]) return row @@ -64,9 +66,9 @@ def list_contacts( search_clause = "" if q: search_op = "AND" if where_clause else "WHERE" - search_clause = f" {search_op} (full_name LIKE %s OR organization LIKE %s OR emails LIKE %s)" + search_clause = f" {search_op} (full_name LIKE %s OR given_name LIKE %s OR family_name LIKE %s OR organization LIKE %s OR emails LIKE %s)" like = f"%{q}%" - params.extend([like, like, like]) + params.extend([like, like, like, like, like]) with conn.cursor() as cur: cur.execute(f"SELECT COUNT(*) AS total FROM contacts {where_clause}{search_clause}", params) @@ -225,13 +227,14 @@ def web_search( search_clause = "" if search: search_op = "AND" if where_clause else "WHERE" - search_clause = f" {search_op} (full_name LIKE %s OR organization LIKE %s)" + search_clause = f" {search_op} (full_name LIKE %s OR given_name LIKE %s OR family_name LIKE %s OR organization LIKE %s)" like = f"%{search}%" - params.extend([like, like]) + params.extend([like, like, like, like]) with conn.cursor() as cur: cur.execute( - f"""SELECT id, full_name, organization, birthday, account + f"""SELECT id, full_name, given_name, middle_name, family_name, + prefix, suffix, organization, birthday, account FROM contacts {where_clause}{search_clause} ORDER BY full_name LIMIT 200""", @@ -239,6 +242,10 @@ def web_search( ) rows = cur.fetchall() + for row in rows: + if not row.get("full_name"): + row["full_name"] = db._build_full_name(row) + return templates.TemplateResponse( "index.html", { diff --git a/src/db.py b/src/db.py index d420acb..5620c2d 100644 --- a/src/db.py +++ b/src/db.py @@ -122,6 +122,17 @@ def delete_contacts_by_href_uids(conn, account: str, uids: list[str]): conn.commit() +def _build_full_name(row: dict) -> str | None: + parts = [ + row.get("prefix"), + row.get("given_name"), + row.get("middle_name"), + row.get("family_name"), + row.get("suffix"), + ] + return " ".join(p for p in parts if p) or None + + def _account_filter_clause(account_name: str | None) -> tuple[str, list]: if account_name is None: return "", [] @@ -140,7 +151,8 @@ def get_upcoming_birthdays(conn, account: str | None, days: int = 7) -> list[dic today = date.today() with conn.cursor() as cur: cur.execute( - f"""SELECT id, full_name, organization, birthday, account + f"""SELECT id, full_name, given_name, middle_name, family_name, + prefix, suffix, organization, birthday, account FROM contacts {where_clause} {"AND" if where_clause else "WHERE"} birthday IS NOT NULL AND ( @@ -155,7 +167,11 @@ def get_upcoming_birthdays(conn, account: str | None, days: int = 7) -> list[dic params + [today.month, today.month, today.day, today.month, today.month, today.day, days], ) - return cur.fetchall() + rows = cur.fetchall() + for row in rows: + if not row.get("full_name"): + row["full_name"] = _build_full_name(row) + return rows def _sanitize_contact(c: dict) -> dict: