From 1c502328f179d7331fc2de08786971f79f504924 Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Fri, 17 Apr 2026 08:21:29 +0900 Subject: [PATCH] =?UTF-8?q?fix(scripts):=20calibrate=5Fask.py=20None=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EC=B6=94=EB=A1=A0=20=EC=8B=A4=ED=8C=A8=20=ED=95=B4=EC=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit asyncpg 이 $N IS NULL 비교에서 Python None 의 타입 추론 실패 (AmbiguousParameterError: could not determine data type of parameter). None 인 조건은 WHERE 에서 아예 제외 — clauses 동적 조립. 부수 효과: 조건 0개일 때 "TRUE" 반환으로 quiet fallback. Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/calibrate_ask.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/scripts/calibrate_ask.py b/scripts/calibrate_ask.py index 6ca8582..dba167a 100644 --- a/scripts/calibrate_ask.py +++ b/scripts/calibrate_ask.py @@ -104,21 +104,23 @@ def build_filters(args: argparse.Namespace) -> tuple[str, dict[str, Any]]: """공통 WHERE 절 SQL + 바인딩 파라미터. 조건 4가지: source, prompt_version, since, until. - None 인 항목은 IS NULL 로 무력화 (SQL CASE 회피, 단순 OR 패턴). + None 인 항목은 WHERE 에 포함하지 않음 (asyncpg 이 None param 의 타입 추론 실패 회피). """ - clauses = [ - "(:source IS NULL OR source = :source)", - "(:prompt_version IS NULL OR prompt_version = :prompt_version)", - "(:since IS NULL OR created_at >= CAST(:since AS TIMESTAMPTZ))", - "(:until IS NULL OR created_at < CAST(:until AS TIMESTAMPTZ))", - ] - params: dict[str, Any] = { - "source": args.source, - "prompt_version": args.prompt_version, - "since": args.since, - "until": args.until, - } - return " AND ".join(clauses), params + clauses: list[str] = [] + params: dict[str, Any] = {} + if args.source is not None: + clauses.append("source = :source") + params["source"] = args.source + if args.prompt_version is not None: + clauses.append("prompt_version = :prompt_version") + params["prompt_version"] = args.prompt_version + if args.since is not None: + clauses.append("created_at >= CAST(:since AS TIMESTAMPTZ)") + params["since"] = args.since + if args.until is not None: + clauses.append("created_at < CAST(:until AS TIMESTAMPTZ)") + params["until"] = args.until + return (" AND ".join(clauses) if clauses else "TRUE"), params # ─── eval split (id 해시) ────────────────────────────────