Skip to content

Commit 5d22034

Browse files
authored
query validating script (#264)
1 parent 816da08 commit 5d22034

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ plugins/*/compiled
1717
.cache-loader
1818
static/llms.txt
1919

20+
# Files generated by script validate_queries.py
21+
all_queries.sql
22+
failed_queries.sql
23+
2024
# Misc
2125
.DS_Store
2226
.env.local

scripts/validate_queries.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import re
2+
import requests
3+
from pathlib import Path
4+
import sys
5+
import json
6+
import argparse
7+
8+
parser = argparse.ArgumentParser(
9+
description="Execute all QuestDB demo SQL queries found in Markdown files."
10+
)
11+
parser.add_argument(
12+
"--path",
13+
default=".",
14+
help="Root folder to search for .md and .mdx files (default: current directory)",
15+
)
16+
parser.add_argument(
17+
"--url",
18+
default="http://localhost:9000",
19+
help="QuestDB REST API base URL, e.g. http://localhost:9000 (default: localhost)",
20+
)
21+
args = parser.parse_args()
22+
23+
24+
QUESTDB_REST_URL = f"{args.url.rstrip('/')}/exec"
25+
ROOT_DIR = args.path
26+
ALL_FILE = Path("all_queries.sql")
27+
FAILED_FILE = Path("failed_queries.sql")
28+
TIMEOUT = (3, 5)
29+
MAX_BYTES = 8192
30+
31+
block_re = re.compile(
32+
r"```questdb-sql[^\n]*title=\"([^\"]+)\"[^\n]*\bdemo\b[^\n]*\n(.*?)```",
33+
re.DOTALL,
34+
)
35+
36+
def extract_blocks(root_dir):
37+
root = Path(root_dir)
38+
for ext in ("*.md", "*.mdx"):
39+
for path in root.rglob(ext):
40+
text = path.read_text(encoding="utf-8", errors="ignore")
41+
for match in block_re.finditer(text):
42+
title, sql = match.groups()
43+
yield path, title.strip(), sql.strip()
44+
45+
def execute_query(query):
46+
"""Execute the query via GET, keeping it exactly as-is and parsing 400 bodies."""
47+
try:
48+
with requests.get(
49+
QUESTDB_REST_URL, params={"query": query}, timeout=TIMEOUT, stream=True
50+
) as r:
51+
content = b""
52+
for chunk in r.iter_content(chunk_size=1024):
53+
content += chunk
54+
if len(content) > MAX_BYTES:
55+
break
56+
57+
text = content.decode("utf-8", errors="ignore").strip()
58+
if r.status_code != 200:
59+
try:
60+
js = json.loads(text)
61+
if "error" in js:
62+
return False, js["error"]
63+
except Exception:
64+
pass
65+
return False, f"HTTP {r.status_code} {r.reason}: {text or 'No body'}"
66+
67+
if not text:
68+
return True, None
69+
70+
try:
71+
js = json.loads(text)
72+
if "error" in js:
73+
return False, js["error"]
74+
return True, None
75+
except json.JSONDecodeError:
76+
return True, None
77+
78+
except requests.Timeout:
79+
return False, f"Timeout after {TIMEOUT[1]}s"
80+
except Exception as e:
81+
return False, str(e)
82+
83+
if __name__ == "__main__":
84+
success = 0
85+
failed = 0
86+
failed_list = []
87+
blocks = list(extract_blocks(ROOT_DIR))
88+
total = len(blocks)
89+
90+
print(f"QuestDB REST URL: {QUESTDB_REST_URL}")
91+
print(f"Searching in: {Path(ROOT_DIR).resolve()}")
92+
print(f"Found {total} queries to execute.\n")
93+
94+
with ALL_FILE.open("w", encoding="utf-8") as all_out, FAILED_FILE.open("w", encoding="utf-8") as fail_out:
95+
for i, (file_path, title, sql) in enumerate(blocks, 1):
96+
print(f"[{i}/{total}] Executing: {file_path} [{title}]")
97+
sys.stdout.flush()
98+
99+
ok, err = execute_query(sql)
100+
all_out.write(f"-- {file_path}\n--- {title}\n{sql}\n\n")
101+
102+
if ok:
103+
success += 1
104+
else:
105+
failed += 1
106+
failed_list.append((file_path, title, err))
107+
print(f" ❌ Failed: {err}")
108+
fail_out.write(f"-- {file_path}\n--- {title}\n{sql}\n-- ERROR: {err}\n\n")
109+
110+
print("\n============================")
111+
print(f"Executed {total} queries")
112+
print(f"✅ Succeeded: {success}")
113+
print(f"❌ Failed: {failed}")
114+
print("============================")
115+
116+
if failed_list:
117+
print("\n❌ Failed queries summary:")
118+
for path, title, err in failed_list:
119+
print(f" - {path} [{title}]: {err}")
120+
121+
print("\nResults written to:")
122+
print(f" • {ALL_FILE}")
123+
print(f" • {FAILED_FILE}")

0 commit comments

Comments
 (0)