"""Google Sheets response shapes. Plain dicts only — no DB, no Depends.""" from __future__ import annotations import uuid from datetime import datetime from g_sheet.enums import FORM_DATA_FIELDS def serialize_metadata(payload: dict) -> dict: """spreadsheets.get response -> the spreadsheet header the UI renders.""" properties = payload.get("properties") or {} return { "spreadsheet_id": payload.get("spreadsheetId"), "title": properties.get("title"), "locale": properties.get("locale"), "time_zone": properties.get("timeZone"), "url": payload.get("spreadsheetUrl"), "tabs": [serialize_tab(sheet) for sheet in payload.get("sheets") or []], } def serialize_tab(sheet: dict) -> dict: """One entry of spreadsheets.get -> tab name plus its grid size.""" properties = sheet.get("properties") or {} grid = properties.get("gridProperties") or {} return { "title": properties.get("title"), "sheet_id": properties.get("sheetId"), "index": properties.get("index"), "row_count": grid.get("rowCount"), "column_count": grid.get("columnCount"), } def serialize_values(tab: str, cell_range: str | None, rows: list[list[str]]) -> dict: """Raw rows -> the read_range envelope.""" return { "tab": tab, "range": cell_range, "rows": rows, "row_count": len(rows), } def serialize_records(tab: str, records: list[dict]) -> dict: """Header-mapped rows -> the read_records envelope.""" return { "tab": tab, "records": records, "total": len(records), "headers": list(records[0].keys()) if records else [], } def serialize_append(tab: str, payload: dict) -> dict: """values.append response -> what was written and where.""" updates = payload.get("updates") or {} return { "tab": tab, "spreadsheet_id": payload.get("spreadsheetId"), "updated_range": updates.get("updatedRange"), "updated_rows": updates.get("updatedRows", 0), "updated_columns": updates.get("updatedColumns", 0), "updated_cells": updates.get("updatedCells", 0), } def serialize_update(tab: str, payload: dict) -> dict: """values.update response -> the same shape as an append result.""" return { "tab": tab, "spreadsheet_id": payload.get("spreadsheetId"), "updated_range": payload.get("updatedRange"), "updated_rows": payload.get("updatedRows", 0), "updated_columns": payload.get("updatedColumns", 0), "updated_cells": payload.get("updatedCells", 0), } def serialize_clear(tab: str, payload: dict) -> dict: """values.clear response -> the cleared range.""" return { "tab": tab, "spreadsheet_id": payload.get("spreadsheetId"), "cleared_range": payload.get("clearedRange"), } def serialize_health(ok: bool, detail: str, tabs: list[str] | None = None) -> dict: """health_check result. Returned on failure too — this one never raises.""" return { "status": "ok" if ok else "error", "detail": detail, "tabs": tabs or [], "tab_count": len(tabs or []), } def _iso(value): return value.isoformat() if value is not None else None def serialize_form_data(row) -> dict: """FormData ORM row → API dict, including raw_record.""" out = {} for key in FORM_DATA_FIELDS: value = getattr(row, key) if isinstance(value, datetime): out[key] = _iso(value) elif isinstance(value, uuid.UUID): out[key] = str(value) elif key == "suggested_job_post_ids": out[key] = [str(v) for v in (value or []) if v not in (None, "")] else: out[key] = value return out def serialize_import(report: dict) -> dict: """Per-tab import report.""" return { "tab": report.get("tab"), "rows_read": report.get("rows_read", 0), "inserted": report.get("inserted", 0), "deleted": report.get("deleted", 0), "dates_parsed": report.get("dates_parsed", 0), "dates_unparsed": report.get("dates_unparsed", 0), "ages_parsed": report.get("ages_parsed", 0), "salaries_parsed": report.get("salaries_parsed", 0), "unmapped_headers": report.get("unmapped_headers") or [], "extracted": report.get("extracted", 0), "extract_failed": report.get("extract_failed", 0), "error": report.get("error"), } def serialize_import_all(reports: list[dict]) -> dict: """Aggregate of per-tab reports from import_all.""" ok=[r for r in reports if not r.get("error")] failed=[r for r in reports if r.get("error")] return { "tabs": len(reports), "succeeded": len(ok), "failed": len(failed), "inserted": sum(r.get("inserted", 0) for r in ok), "deleted": sum(r.get("deleted", 0) for r in ok), "extracted": sum(r.get("extracted", 0) for r in ok), "extract_failed": sum(r.get("extract_failed", 0) for r in reports), "reports": [serialize_import(r) for r in reports], } def serialize_sheet_summary(sheets: list[str]) -> dict: return {"sheets": sheets, "total": len(sheets)} def serialize_import_run(row) -> dict: return { "id": str(row.id), "status": row.status, "task_id": row.task_id, "created_by": str(row.created_by) if row.created_by else None, "tab": row.tab, "report": row.report, "error": row.error, "created_at": _iso(row.created_at), "started_at": _iso(row.started_at), "finished_at": _iso(row.finished_at), }