natquery 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. natquery/__init__.py +0 -0
  2. natquery/cli/__init__.py +0 -0
  3. natquery/cli/commands.py +256 -0
  4. natquery/cli/formatter.py +126 -0
  5. natquery/cli/main.py +51 -0
  6. natquery/cli/shell.py +135 -0
  7. natquery/config/__init__.py +0 -0
  8. natquery/config/connection.py +123 -0
  9. natquery/config/settings.py +100 -0
  10. natquery/execution/__init__.py +0 -0
  11. natquery/execution/engine.py +29 -0
  12. natquery/execution/explain.py +51 -0
  13. natquery/llm/__init__.py +0 -0
  14. natquery/llm/client.py +37 -0
  15. natquery/llm/self_corrector.py +84 -0
  16. natquery/ml/__init__.py +0 -0
  17. natquery/observability/__init__.py +0 -0
  18. natquery/observability/cost_analyzer.py +79 -0
  19. natquery/observability/index_recommender.py +58 -0
  20. natquery/observability/logger.py +109 -0
  21. natquery/observability/performance_api.py +58 -0
  22. natquery/orchestration/__init__.py +0 -0
  23. natquery/orchestration/error_classifier.py +29 -0
  24. natquery/orchestration/error_handler.py +81 -0
  25. natquery/orchestration/pipeline.py +192 -0
  26. natquery/orchestration/workspace.py +44 -0
  27. natquery/prompt/__init__.py +0 -0
  28. natquery/prompt/builder.py +27 -0
  29. natquery/schema/__init__.py +0 -0
  30. natquery/schema/extractor.py +80 -0
  31. natquery/schema/formatter.py +52 -0
  32. natquery/security/__init__.py +0 -0
  33. natquery/security/validator.py +20 -0
  34. natquery-1.0.0.dist-info/METADATA +147 -0
  35. natquery-1.0.0.dist-info/RECORD +39 -0
  36. natquery-1.0.0.dist-info/WHEEL +5 -0
  37. natquery-1.0.0.dist-info/entry_points.txt +2 -0
  38. natquery-1.0.0.dist-info/licenses/LICENSE +21 -0
  39. natquery-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,81 @@
1
+ from natquery.llm.self_corrector import correct_sql
2
+ from natquery.security.validator import validate_sql
3
+ from natquery.observability.logger import NatQueryLogger
4
+ from natquery.orchestration.error_classifier import classify_error
5
+
6
+
7
+ def handle_query_error(
8
+ user_query: str,
9
+ sql: str,
10
+ error: Exception,
11
+ conv_id: str,
12
+ db_name: str,
13
+ max_retries: int = 3,
14
+ ):
15
+ """
16
+ Retry mechanism with intelligent self-correction.
17
+ """
18
+
19
+ current_sql = sql
20
+ last_error = error
21
+ corrected_sql = None
22
+
23
+ for attempt in range(1, max_retries + 1):
24
+
25
+ error_type = classify_error(str(last_error))
26
+
27
+ try:
28
+ corrected_sql = correct_sql(
29
+ user_query,
30
+ current_sql,
31
+ str(last_error),
32
+ )
33
+
34
+ if not corrected_sql or len(corrected_sql.strip()) == 0:
35
+ raise ValueError("Empty SQL from self-corrector")
36
+
37
+ NatQueryLogger.log_event(
38
+ level="INFO",
39
+ event="sql_correction_attempt",
40
+ db_name=db_name,
41
+ conv_id=conv_id,
42
+ details={
43
+ "attempt": attempt,
44
+ "error_type": error_type,
45
+ "previous_sql": current_sql,
46
+ "corrected_sql": corrected_sql,
47
+ },
48
+ )
49
+
50
+ # Validate corrected SQL
51
+ validate_sql(corrected_sql)
52
+
53
+ return corrected_sql # success
54
+
55
+ except Exception as e:
56
+
57
+ NatQueryLogger.log_event(
58
+ level="WARNING",
59
+ event="sql_correction_failed",
60
+ db_name=db_name,
61
+ conv_id=conv_id,
62
+ details={
63
+ "attempt": attempt,
64
+ "error_type": error_type,
65
+ "error": str(e),
66
+ "previous_sql": current_sql,
67
+ },
68
+ )
69
+
70
+ current_sql = corrected_sql if corrected_sql else current_sql
71
+ last_error = e
72
+
73
+ NatQueryLogger.log_event(
74
+ level="ERROR",
75
+ event="self_correction_exhausted",
76
+ db_name=db_name,
77
+ conv_id=conv_id,
78
+ details={"final_error": str(last_error)},
79
+ )
80
+
81
+ raise RuntimeError("Max retries reached. Query failed after corrections.")
@@ -0,0 +1,192 @@
1
+ import time
2
+ from natquery.llm.client import generate_sql
3
+ from natquery.execution.engine import execute_sql
4
+ from natquery.config.settings import Settings
5
+ from natquery.security.validator import validate_sql
6
+ from natquery.observability.logger import NatQueryLogger
7
+ from natquery.orchestration.error_handler import handle_query_error
8
+ from natquery.execution.explain import run_explain_analyze
9
+ from natquery.observability.cost_analyzer import analyze_cost
10
+ from natquery.observability.index_recommender import suggest_indexes
11
+
12
+
13
+ def run_query(user_query: str):
14
+
15
+ conv_id = NatQueryLogger.generate_conv_id()
16
+ db_name = Settings.get_db_config()["dbname"]
17
+
18
+ # -------- LOG INPUT --------
19
+ NatQueryLogger.log_event(
20
+ level="INFO",
21
+ event="query_received",
22
+ db_name=db_name,
23
+ conv_id=conv_id,
24
+ details={"user_query": user_query},
25
+ )
26
+
27
+ # -------- LLM STEP --------
28
+ try:
29
+ sql = generate_sql(user_query)
30
+
31
+ if not sql or len(sql.strip()) == 0:
32
+ raise ValueError("Empty SQL generated by LLM")
33
+
34
+ NatQueryLogger.log_event(
35
+ level="INFO",
36
+ event="llm_sql_generated",
37
+ db_name=db_name,
38
+ conv_id=conv_id,
39
+ details={"generated_sql": sql},
40
+ )
41
+
42
+ except Exception as e:
43
+ NatQueryLogger.log_event(
44
+ level="ERROR",
45
+ event="llm_generation_failed",
46
+ db_name=db_name,
47
+ conv_id=conv_id,
48
+ details={"error": str(e)},
49
+ )
50
+ raise
51
+
52
+ # -------- VALIDATION --------
53
+ try:
54
+ validate_sql(sql)
55
+
56
+ except Exception as e:
57
+
58
+ NatQueryLogger.log_event(
59
+ level="ERROR",
60
+ event="sql_validation_failed",
61
+ db_name=db_name,
62
+ conv_id=conv_id,
63
+ details={
64
+ "error": str(e),
65
+ "generated_sql": sql,
66
+ },
67
+ )
68
+
69
+ # Attempt correction EVEN on validation failure
70
+ sql = handle_query_error(
71
+ user_query,
72
+ sql,
73
+ e,
74
+ conv_id,
75
+ db_name,
76
+ )
77
+
78
+ # -------- EXECUTION --------
79
+ start_time = time.time()
80
+
81
+ try:
82
+ result = execute_sql(sql)
83
+
84
+ except Exception as e:
85
+
86
+ NatQueryLogger.log_event(
87
+ level="ERROR",
88
+ event="db_execution_failed",
89
+ db_name=db_name,
90
+ conv_id=conv_id,
91
+ details={
92
+ "error": str(e),
93
+ "generated_sql": sql,
94
+ },
95
+ )
96
+
97
+ # Self-correction loop
98
+ sql = handle_query_error(
99
+ user_query,
100
+ sql,
101
+ e,
102
+ conv_id,
103
+ db_name,
104
+ )
105
+
106
+ # Retry execution once corrected
107
+ try:
108
+ result = execute_sql(sql)
109
+ except Exception as retry_error:
110
+ NatQueryLogger.log_event(
111
+ level="ERROR",
112
+ event="db_execution_failed_after_correction",
113
+ db_name=db_name,
114
+ conv_id=conv_id,
115
+ details={
116
+ "error": str(retry_error),
117
+ "corrected_sql": sql,
118
+ },
119
+ )
120
+ raise retry_error
121
+
122
+ # -------- SUCCESS LOGGING --------
123
+ execution_time_ms = (time.time() - start_time) * 1000
124
+ rows_returned = len(result)
125
+
126
+ NatQueryLogger.log_event(
127
+ level="INFO",
128
+ event="db_execution_completed",
129
+ db_name=db_name,
130
+ conv_id=conv_id,
131
+ details={
132
+ "rows_returned": rows_returned,
133
+ "execution_time_ms": execution_time_ms,
134
+ },
135
+ )
136
+
137
+ NatQueryLogger.log_conversation(
138
+ db_name=db_name,
139
+ conv_id=conv_id,
140
+ user_query=user_query,
141
+ generated_sql=sql,
142
+ rows_returned=rows_returned,
143
+ execution_time_ms=execution_time_ms,
144
+ )
145
+
146
+ # -------- PERFORMANCE ANALYSIS --------
147
+ summary = None
148
+ suggestions = None
149
+
150
+ try:
151
+ plan_json = run_explain_analyze(sql)
152
+
153
+ analysis = analyze_cost(plan_json)
154
+ suggestions = suggest_indexes(analysis)
155
+
156
+ summary = analysis["summary"]
157
+
158
+ # Store performance history
159
+ NatQueryLogger.log_performance(
160
+ db_name=db_name,
161
+ conv_id=conv_id,
162
+ sql=sql,
163
+ summary=summary,
164
+ suggestions=suggestions,
165
+ )
166
+
167
+ # Existing log
168
+ NatQueryLogger.log_event(
169
+ level="INFO",
170
+ event="performance_analysis",
171
+ db_name=db_name,
172
+ conv_id=conv_id,
173
+ details={
174
+ "summary": summary,
175
+ "suggestions": suggestions,
176
+ },
177
+ )
178
+
179
+ except Exception as e:
180
+ NatQueryLogger.log_event(
181
+ level="ERROR",
182
+ event="performance_analysis_failed",
183
+ db_name=db_name,
184
+ conv_id=conv_id,
185
+ details={"error": str(e)},
186
+ )
187
+
188
+ return {
189
+ "result": result,
190
+ "summary": summary,
191
+ "suggestions": suggestions,
192
+ }
@@ -0,0 +1,44 @@
1
+ from pathlib import Path
2
+ import json
3
+ from natquery.config.connection import get_connection, close_connection
4
+ from natquery.schema.extractor import extract_schema
5
+ from natquery.observability.logger import NatQueryLogger
6
+ from natquery.config.settings import Settings
7
+
8
+
9
+ def initialize_workspace():
10
+ """
11
+ Ensures schema is extracted and saved under:
12
+ ~/.natquery/<db_name>/schema.json
13
+ """
14
+
15
+ db_config = Settings.get_db_config()
16
+ db_name = db_config["dbname"]
17
+
18
+ base_dir = Path.home() / ".natquery"
19
+ workspace_dir = base_dir / db_name
20
+ workspace_dir.mkdir(parents=True, exist_ok=True)
21
+
22
+ schema_file = workspace_dir / "schema.json"
23
+
24
+ # Skip if already extracted
25
+ if schema_file.exists():
26
+ print("Schema already exists. Skipping extraction.")
27
+ return
28
+
29
+ conn = get_connection()
30
+ schema = extract_schema(conn)
31
+ close_connection(conn)
32
+
33
+ with open(schema_file, "w") as f:
34
+ json.dump(schema, f, indent=2)
35
+
36
+ NatQueryLogger.log_event(
37
+ level="INFO",
38
+ event="schema_extracted",
39
+ db_name=db_name,
40
+ conv_id=None,
41
+ details={"schema_path": str(schema_file)},
42
+ )
43
+
44
+ print(f"Schema saved to {schema_file}")
File without changes
@@ -0,0 +1,27 @@
1
+ def build_prompt(user_query: str, schema_text: str) -> list:
2
+ """
3
+ Build structured messages for LLM.
4
+ Returns messages list (for chat APIs).
5
+ """
6
+
7
+ system_prompt = f"""
8
+ You are a PostgreSQL expert.
9
+
10
+ STRICT RULES:
11
+ - Generate ONLY valid PostgreSQL SQL.
12
+ - DO NOT include explanations.
13
+ - DO NOT use INSERT, UPDATE, DELETE, DROP.
14
+ - Use only tables and columns from the schema.
15
+ - Prefer explicit JOINs using foreign keys.
16
+ - If query is ambiguous, choose the most relevant interpretation.
17
+
18
+ DATABASE SCHEMA:
19
+ {schema_text}
20
+ """
21
+
22
+ messages = [
23
+ {"role": "system", "content": system_prompt.strip()},
24
+ {"role": "user", "content": user_query.strip()},
25
+ ]
26
+
27
+ return messages
File without changes
@@ -0,0 +1,80 @@
1
+ def extract_schema(conn):
2
+ """
3
+ Extract full schema:
4
+ - tables
5
+ - columns + types
6
+ - primary keys
7
+ - foreign keys
8
+ """
9
+
10
+ cursor = conn.cursor()
11
+
12
+ schema = {"tables": {}}
13
+
14
+ # Get tables
15
+ cursor.execute(
16
+ """
17
+ SELECT table_name
18
+ FROM information_schema.tables
19
+ WHERE table_schema = 'public';
20
+ """
21
+ )
22
+
23
+ tables = [row[0] for row in cursor.fetchall()]
24
+
25
+ for table in tables:
26
+ schema["tables"][table] = {"columns": {}, "primary_key": [], "foreign_keys": []}
27
+
28
+ # Columns and types
29
+ cursor.execute(
30
+ """
31
+ SELECT column_name, data_type
32
+ FROM information_schema.columns
33
+ WHERE table_name = %s;
34
+ """,
35
+ (table,),
36
+ )
37
+
38
+ for col, dtype in cursor.fetchall():
39
+ schema["tables"][table]["columns"][col] = dtype
40
+
41
+ # Primary keys
42
+ cursor.execute(
43
+ """
44
+ SELECT kcu.column_name
45
+ FROM information_schema.table_constraints tc
46
+ JOIN information_schema.key_column_usage kcu
47
+ ON tc.constraint_name = kcu.constraint_name
48
+ WHERE tc.table_name = %s
49
+ AND tc.constraint_type = 'PRIMARY KEY';
50
+ """,
51
+ (table,),
52
+ )
53
+
54
+ schema["tables"][table]["primary_key"] = [row[0] for row in cursor.fetchall()]
55
+
56
+ # Foreign keys
57
+ cursor.execute(
58
+ """
59
+ SELECT
60
+ kcu.column_name,
61
+ ccu.table_name AS foreign_table,
62
+ ccu.column_name AS foreign_column
63
+ FROM information_schema.table_constraints tc
64
+ JOIN information_schema.key_column_usage kcu
65
+ ON tc.constraint_name = kcu.constraint_name
66
+ JOIN information_schema.constraint_column_usage ccu
67
+ ON ccu.constraint_name = tc.constraint_name
68
+ WHERE tc.constraint_type = 'FOREIGN KEY'
69
+ AND tc.table_name = %s;
70
+ """,
71
+ (table,),
72
+ )
73
+
74
+ for col, ref_table, ref_col in cursor.fetchall():
75
+ schema["tables"][table]["foreign_keys"].append(
76
+ {"column": col, "references": {"table": ref_table, "column": ref_col}}
77
+ )
78
+
79
+ cursor.close()
80
+ return schema
@@ -0,0 +1,52 @@
1
+ def format_schema(schema: dict) -> str:
2
+ """
3
+ Convert schema JSON → compact SQL-like text for LLM.
4
+
5
+ RAG-ready:
6
+ - Works with full schema OR filtered schema
7
+ """
8
+
9
+ if not schema or "tables" not in schema:
10
+ return ""
11
+
12
+ lines = []
13
+
14
+ tables = schema["tables"]
15
+
16
+ # Ensure deterministic ordering
17
+ for table_name in sorted(tables.keys()):
18
+ table = tables[table_name]
19
+
20
+ columns = table.get("columns", {})
21
+ pk = set(table.get("primary_key", []))
22
+
23
+ col_lines = []
24
+
25
+ for col_name in columns:
26
+ col_type = columns[col_name].upper()
27
+
28
+ if col_name in pk:
29
+ col_lines.append(f" {col_name} {col_type} PRIMARY KEY")
30
+ else:
31
+ col_lines.append(f" {col_name} {col_type}")
32
+
33
+ table_block = f"TABLE {table_name} (\n" + ",\n".join(col_lines) + "\n)"
34
+ lines.append(table_block)
35
+
36
+ # Relationships (FKs)
37
+ relationships = []
38
+
39
+ for table_name in sorted(tables.keys()):
40
+ fks = tables[table_name].get("foreign_keys", [])
41
+
42
+ for fk in fks:
43
+ relationships.append(
44
+ f"{table_name}.{fk['column']} → "
45
+ f"{fk['references']['table']}.{fk['references']['column']}"
46
+ )
47
+
48
+ if relationships:
49
+ lines.append("\nRELATIONSHIPS:")
50
+ lines.extend(relationships)
51
+
52
+ return "\n\n".join(lines)
File without changes
@@ -0,0 +1,20 @@
1
+ import re
2
+
3
+
4
+ def validate_sql(sql: str):
5
+ """
6
+ Ensure SQL is safe (SELECT only).
7
+ """
8
+
9
+ sql_clean = sql.strip().lower()
10
+
11
+ if not sql_clean.startswith("select"):
12
+ raise ValueError("Only SELECT queries are allowed.")
13
+
14
+ forbidden = ["insert", "update", "delete", "drop", "alter", "truncate"]
15
+
16
+ for word in forbidden:
17
+ if re.search(rf"\b{word}\b", sql_clean):
18
+ raise ValueError(f"Forbidden keyword detected: {word}")
19
+
20
+ return True
@@ -0,0 +1,147 @@
1
+ Metadata-Version: 2.4
2
+ Name: natquery
3
+ Version: 1.0.0
4
+ Summary: Interact with PostgreSQL databases using natural language via a secure, performance-aware CLI
5
+ Author-email: Tanmai Raghava <tanmairaghava@kgpian.iitkgp.ac.in>, Krishna Chaitanya <krish89@kgpian.iitkgp.ac.in>, Thania Joshi <thaniavjoshi@kgpian.iitkgp.ac.in>, Lokeswara Reddy <lokeswarareddy2006@gmail.com>, Manasa Vankam <vankammanasa45@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/N-T-Raghava/NatQuery
8
+ Project-URL: Documentation, https://github.com/N-T-Raghava/NatQuery#readme
9
+ Project-URL: Repository, https://github.com/N-T-Raghava/NatQuery
10
+ Project-URL: Issues, https://github.com/N-T-Raghava/NatQuery/issues
11
+ Keywords: nlp,database,postgres,natural-language,cli,llm
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: System Administrators
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Natural Language :: English
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Database
24
+ Classifier: Topic :: Utilities
25
+ Requires-Python: >=3.10
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: psycopg2-binary>=2.9.0
29
+ Requires-Dist: groq>=0.4.0
30
+ Requires-Dist: rich>=13.0.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
33
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
34
+ Requires-Dist: black==25.1.0; extra == "dev"
35
+ Requires-Dist: ruff==0.15.6; extra == "dev"
36
+ Requires-Dist: build>=1.0.0; extra == "dev"
37
+ Requires-Dist: twine>=4.0.0; extra == "dev"
38
+ Dynamic: license-file
39
+
40
+ # NatQuery
41
+ natquery is a Python package that enables users to interact with relational databases using natural language via a secure, performance-aware command-line interface along with database driven machine learning analytics.
42
+
43
+ ```
44
+ natquery/
45
+ │
46
+ ├── pyproject.toml
47
+ ├── README.md
48
+ ├── requirements.txt
49
+ │── src/
50
+ ├ ├── natquery/
51
+ │ ├── __init__.py
52
+ │
53
+ │ # =========================
54
+ │ # 1. CLI LAYER
55
+ │ # =========================
56
+ │ ├── cli/
57
+ │ │ ├── __init__.py
58
+ │ │ ├── main.py # Entry point
59
+ │ │ ├── shell.py # Interactive REPL
60
+ │ │ ├── commands.py # CLI command registry
61
+ │
62
+ │ # =========================
63
+ │ # 2. CONFIG LAYER
64
+ │ # =========================
65
+ │ ├── config/
66
+ │ │ ├── __init__.py
67
+ │ │ ├── settings.py # API keys, DB config
68
+ │ │ ├── connection.py # PostgreSQL connection manager
69
+ │
70
+ │ # =========================
71
+ │ # 3. ORCHESTRATION LAYER
72
+ │ # =========================
73
+ │ ├── orchestration/
74
+ │ │ ├── __init__.py
75
+ │ │ ├── pipeline.py # End-to-end coordinator
76
+ │ │ ├── error_handler.py
77
+ │
78
+ │ # =========================
79
+ │ # 4. SCHEMA MODULE
80
+ │ # =========================
81
+ │ ├── schema/
82
+ │ │ ├── __init__.py
83
+ │ │ ├── extractor.py # Dynamic schema extraction
84
+ │ │ ├── formatter.py # Convert schema to prompt-friendly text
85
+ │
86
+ │ # =========================
87
+ │ # 5. PROMPT BUILDER
88
+ │ # =========================
89
+ │ ├── prompt/
90
+ │ │ ├── __init__.py
91
+ │ │ ├── builder.py # Structured prompt construction
92
+ │
93
+ │ # =========================
94
+ │ # 6. LLM CLIENT
95
+ │ # =========================
96
+ │ ├── llm/
97
+ │ │ ├── __init__.py
98
+ │ │ ├── client.py # LLM API calls
99
+ │ │ ├── self_corrector.py # Retry & correction mechanism
100
+ │
101
+ │ # =========================
102
+ │ # 7. SECURITY + VALIDATION
103
+ │ # =========================
104
+ │ ├── security/
105
+ │ │ ├── __init__.py
106
+ │ │ ├── validator.py # SELECT-only enforcement
107
+ │ │ ├── limiter.py # LIMIT enforcement
108
+ │
109
+ │ # =========================
110
+ │ # 8. EXECUTION ENGINE
111
+ │ # =========================
112
+ │ ├── execution/
113
+ │ │ ├── __init__.py
114
+ │ │ ├── engine.py # SQL execution
115
+ │ │ ├── explain.py # EXPLAIN / ANALYZE
116
+ │
117
+ │ # =========================
118
+ │ # 9. MACHINE LEARNING
119
+ │ # =========================
120
+ │ ├── ml/
121
+ │ │ ├── __init__.py
122
+ │ │ ├── preprocessing.py
123
+ │ │ ├── trainer.py
124
+ │ │ ├── inference.py
125
+ │ │
126
+ │ # =========================
127
+ │ # 10. PERFORMANCE + LOGGING
128
+ │ # =========================
129
+ │ ├── observability/
130
+ │ ├── __init__.py
131
+ │ ├── logger.py
132
+ │ ├── cost_analyzer.py
133
+ │ ├── index_recommender.py
134
+ │
135
+ │
136
+ ├── database/
137
+ │ ├── schema.sql
138
+ │ ├── seed.py
139
+ │ ├── synthetic_data.py
140
+ │
141
+ ├── tests/
142
+ │ ├── test_pipeline.py
143
+ │ ├── test_security.py
144
+ │ ├── test_ml.py
145
+ │
146
+ └── benchmarks/
147
+ ├── nl_queries.json
@@ -0,0 +1,39 @@
1
+ natquery/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ natquery/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ natquery/cli/commands.py,sha256=tzTKTRT3yiL_LsgGV6rOj7JXYoWnp40oLb-x3-BBJ3I,7103
4
+ natquery/cli/formatter.py,sha256=qK2B9ANzNbFbcCT6QAEdM8rm0AZbWezCL333_Jf7sPM,2981
5
+ natquery/cli/main.py,sha256=FJAllKEqrqARZfH-qArt8UbWgk3GlAZ56LnaOKmGSRM,1189
6
+ natquery/cli/shell.py,sha256=Lq5UHDENCFXKugcUvzn7PfIgbKdH99xHaT-U6JPWdTc,5159
7
+ natquery/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ natquery/config/connection.py,sha256=7t-Ia4PWkXT6I3tZKFrUOB78aLGJjNNY8wrZSFVl9Cc,3212
9
+ natquery/config/settings.py,sha256=ZtwGLI3kGyPpaKUsPkIaKvOh47OKjUKGzQ1mCc9sEq0,2723
10
+ natquery/execution/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ natquery/execution/engine.py,sha256=eviZj8QE4CtrLPIzluTntb1KuCDpMWiu7WJ14VjGC6E,750
12
+ natquery/execution/explain.py,sha256=aEcuYDnjxruKrmlQlMkeJCvmGyZxElVMCQ42EjC3vvs,1207
13
+ natquery/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ natquery/llm/client.py,sha256=ui6AGI7ApT1YBCceXEtQzl13Gb3hJiLZ8DwJZhb4Jjw,995
15
+ natquery/llm/self_corrector.py,sha256=kOn1_pcBEVc7eW6L-Y-IL1xiRh7GhvF6eGx6WdCcH8U,2211
16
+ natquery/ml/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ natquery/observability/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ natquery/observability/cost_analyzer.py,sha256=zVZoDuYYvmPMkkM-PZ6mXbGQjjBb5ICIeZKw904jzyY,2063
19
+ natquery/observability/index_recommender.py,sha256=nOZCL69m06LL0rnELRgH6sdDGPqhLC1D3TsVwq_QY4g,1910
20
+ natquery/observability/logger.py,sha256=uIRfeSBQA5lrq0k3YGydVjUihMcGllOn-hLYSxn--L4,2756
21
+ natquery/observability/performance_api.py,sha256=5cNJ8fowM_WWljN7wEUf_1Yhqimsi1Mmvh8LiS0vQcc,1257
22
+ natquery/orchestration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ natquery/orchestration/error_classifier.py,sha256=ok0e2TQRZaTN9mvfe7pgiPFd0iWxrq8PhYjXpjzqNsQ,711
24
+ natquery/orchestration/error_handler.py,sha256=TB_uwYp9Crg0p1-JV23OvIzFKIHLIapAvL_003Od-og,2299
25
+ natquery/orchestration/pipeline.py,sha256=Y_D4RTrbR0sy3eISYgUxUplAX4smlKqMzrxeLn1Ibu4,5012
26
+ natquery/orchestration/workspace.py,sha256=FMyt-iVZGfYaRF0slO7HlFH3BzmtAr8uItXfi83jQkY,1203
27
+ natquery/prompt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ natquery/prompt/builder.py,sha256=K3KMgvfHyE5kxKD1tsFGNsw4aTwQy0H5DN94EPYlIHc,698
29
+ natquery/schema/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ natquery/schema/extractor.py,sha256=PMlGI7d_0QvDz8vo8EsU23pol1kO91mx2ZFfcBvWGZA,2271
31
+ natquery/schema/formatter.py,sha256=xSduYN37k0Zp1PrTS0iiMXJm_HsdwuQzz5-BPvXln_U,1388
32
+ natquery/security/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
+ natquery/security/validator.py,sha256=GOOnfzpTrIX8tMQ8RWkSsuzgbYqErOeh5xfpDhUBNnA,475
34
+ natquery-1.0.0.dist-info/licenses/LICENSE,sha256=k8l1DTpell6239gvuFh5bHDfMl7VH49BTGNmMYC8fkA,1071
35
+ natquery-1.0.0.dist-info/METADATA,sha256=QTMNp06Sks0xdh-uEgFhixCHv87qCNzh887GeJb0X6U,5634
36
+ natquery-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
37
+ natquery-1.0.0.dist-info/entry_points.txt,sha256=B0v2hqxmh3gfiYPmhEp-o8DSOt1YTXOAnjNffMLQCCU,52
38
+ natquery-1.0.0.dist-info/top_level.txt,sha256=eX578Cs4V48pAKXMICMKMMU0L_UFz_KLV1FHvLxZEP8,9
39
+ natquery-1.0.0.dist-info/RECORD,,