Initial SQL-only 1C adapter baseline
This commit is contained in:
@@ -0,0 +1,271 @@
|
||||
#!/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())
|
||||
Reference in New Issue
Block a user