#!/usr/bin/env python3 """Summarize DBNames-Ext records by extension inventory and XML match status.""" from __future__ import annotations import argparse import json from collections import Counter from pathlib import Path from typing import Any def load_json(path: Path) -> dict[str, Any]: return json.loads(path.read_text(encoding="utf-8")) def main() -> int: parser = argparse.ArgumentParser(description="Summarize extension DBNames records.") parser.add_argument("--dbnames", type=Path, required=True) parser.add_argument("--compare", type=Path, required=True) parser.add_argument("--inventory", type=Path, required=True) parser.add_argument("--output", type=Path, required=True) args = parser.parse_args() dbnames = load_json(args.dbnames) compare = load_json(args.compare) inventory = load_json(args.inventory) extension_by_file = {} for extension in inventory.get("extensions") or []: file_name = extension.get("dbnames_ext_file_name") if file_name: extension_by_file[file_name] = extension unmatched_guid_set = set(compare.get("unmatched_sql_guids") or []) matched_guid_set = set(compare.get("matched_guids") or []) unmatched_by_guid = {item["guid"]: item for item in compare.get("unmatched_sql") or []} if not unmatched_guid_set: unmatched_guid_set = set(unmatched_by_guid) if not matched_guid_set: matched_guid_set = {item["guid"] for item in compare.get("matches") or []} summaries: dict[str, Any] = {} for dbnames_file in dbnames.get("dbnames") or []: file_name = dbnames_file.get("file_name") if not str(file_name).startswith("DBNames-Ext-"): continue extension = extension_by_file.get(file_name) key = file_name item = summaries.setdefault( key, { "dbnames_ext_file": file_name, "extension_name": extension.get("extension_name") if extension else None, "extension_guid": extension.get("dbnames_ext_guid") if extension else None, "extension_order": extension.get("extension_order") if extension else None, "record_count": 0, "guid_count": 0, "matched_guid_count": 0, "unmatched_guid_count": 0, "storage_role_counts": Counter(), "matched_storage_role_counts": Counter(), "unmatched_storage_role_counts": Counter(), "unmatched_examples": [], }, ) seen_guids = set() for record in dbnames_file.get("records") or []: if record.get("status") != "parsed": continue guid = record.get("guid") role = record.get("storage_role") item["record_count"] += 1 item["storage_role_counts"][role] += 1 if guid not in seen_guids: seen_guids.add(guid) item["guid_count"] += 1 if guid in matched_guid_set: item["matched_guid_count"] += 1 elif guid in unmatched_guid_set: item["unmatched_guid_count"] += 1 if len(item["unmatched_examples"]) < 20: item["unmatched_examples"].append( { "guid": guid, "storage_roles": (unmatched_by_guid.get(guid) or {}).get("storage_roles"), "records": (unmatched_by_guid.get(guid) or {}).get("records", [])[:5], } ) else: item["unmatched_guid_count"] += 1 if guid in matched_guid_set: item["matched_storage_role_counts"][role] += 1 else: item["unmatched_storage_role_counts"][role] += 1 output_items = [] for item in summaries.values(): output_items.append( { **{ key: value for key, value in item.items() if not key.endswith("_counts") and key != "unmatched_examples" }, "storage_role_counts": dict(item["storage_role_counts"].most_common()), "matched_storage_role_counts": dict(item["matched_storage_role_counts"].most_common()), "unmatched_storage_role_counts": dict(item["unmatched_storage_role_counts"].most_common()), "unmatched_examples": item["unmatched_examples"], } ) output_items.sort(key=lambda row: (-row["unmatched_guid_count"], row["dbnames_ext_file"])) result = { "schema": "onec_extension_dbnames_summary.v1", "dbnames": str(args.dbnames), "compare": str(args.compare), "inventory": str(args.inventory), "extension_file_count": len(output_items), "extensions": output_items, } args.output.parent.mkdir(parents=True, exist_ok=True) args.output.write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") print( json.dumps( { "output": str(args.output), "extension_files": len(output_items), "total_unmatched_guids": sum(item["unmatched_guid_count"] for item in output_items), }, ensure_ascii=False, ) ) return 0 if __name__ == "__main__": raise SystemExit(main())