Initial SQL-only 1C adapter baseline

This commit is contained in:
2026-07-22 03:03:47 +03:00
commit e2503b77e7
545 changed files with 184711 additions and 0 deletions
+213
View File
@@ -0,0 +1,213 @@
from __future__ import annotations
import argparse
import json
from pathlib import Path
from typing import Any
from urllib import request
def rpc(adapter_url: str, method: str, payload: dict[str, Any], *, timeout: int = 240) -> dict[str, Any]:
body = json.dumps({"method": method, "payload": payload}, ensure_ascii=False).encode("utf-8")
req = request.Request(
f"{adapter_url.rstrip('/')}/rpc",
data=body,
headers={"Content-Type": "application/json; charset=utf-8"},
method="POST",
)
with request.urlopen(req, timeout=timeout) as response:
return json.loads(response.read().decode("utf-8", errors="replace"))
def extension_template_payloads(
adapter_url: str,
*,
base_id: str,
extension: str,
query: str,
timeout_seconds: int,
refresh_cache: bool,
) -> tuple[dict[str, Any], list[dict[str, Any]]]:
result = rpc(
adapter_url,
"extension.objects.find",
{
"base_id": base_id,
"extension": extension,
"query": query,
"limit": 500,
"refresh_cache": refresh_cache,
"include_storage": True,
"timeout_seconds": timeout_seconds,
},
timeout=max(240, timeout_seconds + 60),
)
by_guid: dict[str, dict[str, Any]] = {}
for item in result.get("objects") or []:
if not isinstance(item, dict):
continue
name = str(item.get("name") or "")
guid = str(item.get("guid") or "")
if not name or not guid or guid in by_guid:
continue
payload_entry = next(
(
entry
for entry in item.get("manifest_entries") or []
if isinstance(entry, dict)
and (entry.get("suffix") == ".0" or str(entry.get("object_id") or "").endswith(".0"))
and entry.get("cas_key")
),
None,
)
if payload_entry:
by_guid[guid] = {
"name": name,
"metadata_guid": guid,
"payload_file_name": payload_entry.get("cas_key"),
"manifest_entry": payload_entry,
}
return result, sorted(by_guid.values(), key=lambda item: str(item.get("name") or ""))
def profile_payload(
adapter_url: str,
*,
base_id: str,
item: dict[str, Any],
timeout_seconds: int,
refresh_cache: bool,
sample_limit: int,
) -> dict[str, Any]:
payload_file_name = str(item.get("payload_file_name") or "")
result = rpc(
adapter_url,
"templates.read",
{
"base_id": base_id,
"kind": "Template",
"guid": payload_file_name,
"file_name": payload_file_name,
"table": "ConfigCAS",
"sections": "summary,merged_ranges,merges,coordinate_hints,cells,parameters,named_areas,formats,diagnostics",
"view": "structure",
"refresh_cache": refresh_cache,
"max_cells": sample_limit,
"max_merged": sample_limit,
"max_parameters": sample_limit,
"max_named_areas": sample_limit,
"timeout_seconds": timeout_seconds,
},
timeout=max(240, timeout_seconds + 60),
)
templates = result.get("templates") or []
structure = (templates[0].get("structure") if templates and isinstance(templates[0], dict) else {}) or {}
return {
**item,
"status": result.get("status"),
"counts": structure.get("counts") or {},
"capacity_dimensions": structure.get("capacity_dimensions"),
"used_dimensions": structure.get("used_dimensions"),
"format_dimensions": structure.get("format_dimensions"),
"capabilities": structure.get("capabilities"),
"merge_block_counts": [
candidate.get("count")
for candidate in structure.get("merge_record_block_candidates") or []
if isinstance(candidate, dict)
],
"merge_count_hint_counts": [
hint.get("count")
for hint in structure.get("merge_count_hints") or []
if isinstance(hint, dict)
],
"sample_merged_ranges": structure.get("merged_ranges") or [],
"sample_merge_count_hints": structure.get("merge_count_hints") or [],
"sample_merge_record_block_candidates": structure.get("merge_record_block_candidates") or [],
"sample_cell_coordinate_hints": structure.get("cell_coordinate_hints") or [],
"sample_cells": structure.get("cells") or [],
"sample_cell_parameters": structure.get("cell_parameters") or [],
"sample_named_ranges": structure.get("named_range_candidates") or [],
"sample_column_widths": structure.get("column_widths") or [],
"sample_format_table": structure.get("format_table") or [],
"sample_font_table": structure.get("font_table") or [],
"sample_format_style_index_table": structure.get("format_style_index_table") or {},
"sample_cell_format_links": structure.get("cell_format_links") or [],
"cell_format_link_stats": structure.get("cell_format_link_stats") or {},
}
def render_markdown(payload: dict[str, Any]) -> str:
lines = [
"# Extension SQL direct template profiles",
"",
f"- Base: `{payload.get('base_id')}`",
f"- Extension: `{payload.get('extension')}`",
f"- Profiles: `{(payload.get('counts') or {}).get('profiles')}`",
"",
"| Template | Cells | Cell params | Used | Merged ranges | Merge blocks | Merge count hints |",
"| --- | ---: | ---: | --- | ---: | --- | --- |",
]
for item in payload.get("profiles") or []:
counts = item.get("counts") if isinstance(item.get("counts"), dict) else {}
used = item.get("used_dimensions") if isinstance(item.get("used_dimensions"), dict) else {}
lines.append(
f"| `{item.get('name')}` | {counts.get('cells') or 0} | {counts.get('cell_parameters') or 0} | "
f"`{used.get('rows')}x{used.get('columns')}` | {counts.get('merged_ranges') or 0} | `{item.get('merge_block_counts') or []}` | "
f"`{item.get('merge_count_hint_counts') or []}` |"
)
return "\n".join(lines) + "\n"
def main() -> int:
parser = argparse.ArgumentParser(description="Profile extension common template payloads from live SQL ConfigCAS.")
parser.add_argument("--adapter-url", default="http://docker-gpu.cin.su:8011")
parser.add_argument("--base-id", default="upo_test")
parser.add_argument("--extension", required=True)
parser.add_argument("--query", default="t_MOXEL")
parser.add_argument("--timeout-seconds", type=int, default=180)
parser.add_argument("--sample-limit", type=int, default=20)
parser.add_argument("--refresh-cache", action="store_true")
parser.add_argument("--output-json", required=True)
parser.add_argument("--output-markdown", required=True)
args = parser.parse_args()
find_result, payloads = extension_template_payloads(
args.adapter_url,
base_id=args.base_id,
extension=args.extension,
query=args.query,
timeout_seconds=int(args.timeout_seconds or 180),
refresh_cache=bool(args.refresh_cache),
)
profiles = [
profile_payload(
args.adapter_url,
base_id=args.base_id,
item=item,
timeout_seconds=int(args.timeout_seconds or 180),
refresh_cache=bool(args.refresh_cache),
sample_limit=int(args.sample_limit or 20),
)
for item in payloads
]
payload = {
"schema": "onec_extension_template_profiles.v1",
"base_id": args.base_id,
"extension": args.extension,
"query": args.query,
"find_counts": find_result.get("counts"),
"profiles": profiles,
"counts": {"profiles": len(profiles)},
}
output_json = Path(args.output_json)
output_markdown = Path(args.output_markdown)
output_json.parent.mkdir(parents=True, exist_ok=True)
output_markdown.parent.mkdir(parents=True, exist_ok=True)
output_json.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
output_markdown.write_text(render_markdown(payload), encoding="utf-8")
print(json.dumps({"status": "ok", "json": str(output_json), "markdown": str(output_markdown), "counts": payload["counts"]}, ensure_ascii=False, indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())