Files
llm/scripts/read_1c_object_view.py
T

272 lines
9.1 KiB
Python

#!/usr/bin/env python3
"""Run the full 1C SQL read-view pipeline for one metadata object."""
from __future__ import annotations
import argparse
import base64
import json
import os
import hashlib
import subprocess
import sys
from pathlib import Path
from typing import Any
sys.path.insert(0, str(Path(__file__).resolve().parent))
from build_1c_metadata_from_resolved_object import build_metadata # noqa: E402
from resolve_1c_object import resolve_object # noqa: E402
def load_json(path: Path) -> dict[str, Any]:
return json.loads(path.read_text(encoding="utf-8-sig"))
def find_metadata(summary_path: Path, *, kind: str, name: str) -> Path | None:
summary = load_json(summary_path)
matches = [
row
for row in summary.get("outputs") or []
if str(row.get("kind") or "").casefold() == kind.casefold()
and str(row.get("name") or "").casefold() == name.casefold()
]
if not matches:
return None
if len(matches) > 1:
raise SystemExit(f"Ambiguous metadata object in {summary_path}: {kind}.{name}")
return Path(matches[0]["output"])
def safe_name(value: str) -> str:
keep = []
for char in value:
if char.isascii() and (char.isalnum() or char in ("-", "_")):
keep.append(char)
else:
keep.append(f"u{ord(char):04x}")
result = "".join(keep).strip("-")
digest = hashlib.sha1(value.encode("utf-8")).hexdigest()[:8]
if len(result) > 48:
result = result[:48].rstrip("-_")
return f"{result or 'object'}-{digest}"
def run(command: list[str], *, env: dict[str, str] | None = None) -> None:
printable = " ".join(command)
print(printable, flush=True)
completed = subprocess.run(command, env=env)
if completed.returncode != 0:
raise SystemExit(completed.returncode)
def powershell_exe() -> str:
return os.environ.get("POWERSHELL_EXE") or "powershell"
def main() -> int:
parser = argparse.ArgumentParser(description="Build a 1C SQL read view by kind/name.")
parser.add_argument("--kind")
parser.add_argument("--name")
parser.add_argument("--kind-b64", help="UTF-8 base64 encoded kind.")
parser.add_argument("--name-b64", help="UTF-8 base64 encoded name.")
parser.add_argument("--top", type=int, default=5)
parser.add_argument("--view", choices=["effective", "base", "extension"], default="effective")
parser.add_argument("--extension")
parser.add_argument("--summary", type=Path, required=True)
parser.add_argument("--validation", type=Path, required=True)
parser.add_argument("--route-index", type=Path, required=True)
parser.add_argument("--enum-presentation-map", type=Path)
parser.add_argument("--output-dir", type=Path, required=True)
parser.add_argument("--server", default=os.environ.get("ONEC_SQL_SERVER"))
parser.add_argument("--database", default=os.environ.get("ONEC_SQL_DATABASE"))
parser.add_argument("--user", default=os.environ.get("ONEC_SQL_USER"))
parser.add_argument("--password", default=os.environ.get("ONEC_SQL_PASSWORD"))
args = parser.parse_args()
if args.kind_b64:
args.kind = base64.b64decode(args.kind_b64).decode("utf-8")
if args.name_b64:
args.name = base64.b64decode(args.name_b64).decode("utf-8")
if not args.kind or not args.name:
raise SystemExit("Use --kind/--name or --kind-b64/--name-b64.")
if args.view == "extension" and not args.extension:
raise SystemExit("Use --extension with --view extension.")
missing = [name for name in ("server", "database", "user", "password") if not getattr(args, name)]
if missing:
raise SystemExit(f"Missing SQL connection settings: {', '.join(missing)}")
route_index = load_json(args.route_index)
resolution = resolve_object(route_index, kind=args.kind, name=args.name, limit=50)
canonical = resolution.get("canonical")
if not canonical:
raise SystemExit(f"Object not found: {args.kind}.{args.name}")
args.kind = str(canonical["kind"])
args.name = str(canonical["name"])
prefix = f"{safe_name(args.kind)}-{safe_name(args.name)}"
args.output_dir.mkdir(parents=True, exist_ok=True)
metadata_path = args.output_dir / f"metadata-{prefix}.json"
metadata = build_metadata(route_index, kind=args.kind, name=args.name)
metadata_path.write_text(json.dumps(metadata, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
projection_path = args.output_dir / f"sql-read-projection-{prefix}.json"
read_result_path = args.output_dir / f"sql-read-result-{prefix}.json"
reference_path = args.output_dir / f"sql-reference-resolution-{prefix}.json"
composite_path = args.output_dir / f"sql-composite-reference-resolution-{prefix}.json"
composite_value_path = args.output_dir / f"sql-composite-value-resolution-{prefix}.json"
enum_map_path = args.enum_presentation_map or args.output_dir / "enum-presentation-map.json"
view_path = args.output_dir / f"sql-read-view-{prefix}.json"
python = sys.executable
ps_env = os.environ.copy()
ps_env.update(
{
"ONEC_SQL_SERVER": args.server,
"ONEC_SQL_DATABASE": args.database,
"ONEC_SQL_USER": args.user,
"ONEC_SQL_PASSWORD": args.password,
}
)
run(
[
python,
"plugins/1c/tools/build_sql_read_projection.py",
"--metadata",
str(metadata_path),
"--validation",
str(args.validation),
"--output",
str(projection_path),
"--top",
str(args.top),
"--view",
args.view,
]
+ (["--extension", args.extension] if args.extension else [])
)
run(
[
powershell_exe(),
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"scripts/execute_1c_sql_read_projection.ps1",
"-ProjectionPath",
str(projection_path),
"-OutputPath",
str(read_result_path),
],
env=ps_env,
)
run(
[
powershell_exe(),
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"scripts/resolve_1c_sql_read_references.ps1",
"-ReadResultPath",
str(read_result_path),
"-RouteIndexPath",
str(args.route_index),
"-OutputPath",
str(reference_path),
],
env=ps_env,
)
run(
[
powershell_exe(),
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"scripts/resolve_1c_sql_composite_references.ps1",
"-ReadResultPath",
str(read_result_path),
"-RouteIndexPath",
str(args.route_index),
"-OutputPath",
str(composite_path),
],
env=ps_env,
)
run(
[
python,
"scripts/resolve_1c_sql_composite_values.py",
"--read-result",
str(read_result_path),
"--output",
str(composite_value_path),
]
)
if not enum_map_path.is_file():
run(
[
python,
"scripts/build_1c_enum_presentation_map.py",
"--index",
str(args.route_index),
"--output",
str(enum_map_path),
]
)
run(
[
python,
"scripts/build_1c_sql_read_view.py",
"--read-result",
str(read_result_path),
"--reference-resolution",
str(reference_path),
"--composite-reference-resolution",
str(composite_path),
"--composite-value-resolution",
str(composite_value_path),
"--enum-presentation-map",
str(enum_map_path),
"--output",
str(view_path),
]
)
view = load_json(view_path)
print(
json.dumps(
{
"schema": "onec_sql_read_object_view_run.v1",
"kind": args.kind,
"name": args.name,
"requested_view": args.view,
"extension": args.extension,
"resolution": {
"schema": resolution.get("schema"),
"canonical": canonical,
"summary": resolution.get("summary"),
},
"metadata": str(metadata_path),
"projection": str(projection_path),
"read_result": str(read_result_path),
"reference_resolution": str(reference_path),
"composite_reference_resolution": str(composite_path),
"composite_value_resolution": str(composite_value_path),
"enum_presentation_map": str(enum_map_path),
"view_path": str(view_path),
"summary": view.get("summary"),
},
ensure_ascii=True,
indent=2,
),
flush=True,
)
return 0
if __name__ == "__main__":
raise SystemExit(main())