nl2sql-engine 0.1.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 (192) hide show
  1. nl2sql/__init__.py +38 -0
  2. nl2sql/adapters/__init__.py +0 -0
  3. nl2sql/adapters/duckdb/__init__.py +0 -0
  4. nl2sql/adapters/duckdb/adapter.py +71 -0
  5. nl2sql/adapters/mssql/__init__.py +0 -0
  6. nl2sql/adapters/mssql/adapter.py +122 -0
  7. nl2sql/adapters/mysql/__init__.py +0 -0
  8. nl2sql/adapters/mysql/adapter.py +123 -0
  9. nl2sql/adapters/postgres/__init__.py +0 -0
  10. nl2sql/adapters/postgres/adapter.py +115 -0
  11. nl2sql/adapters/sqlalchemy_base/__init__.py +17 -0
  12. nl2sql/adapters/sqlalchemy_base/adapter.py +476 -0
  13. nl2sql/adapters/sqlalchemy_base/models.py +36 -0
  14. nl2sql/adapters/sqlite/__init__.py +0 -0
  15. nl2sql/adapters/sqlite/adapter.py +88 -0
  16. nl2sql/aggregation/__init__.py +3 -0
  17. nl2sql/aggregation/aggregator.py +98 -0
  18. nl2sql/aggregation/engines/__init__.py +3 -0
  19. nl2sql/aggregation/engines/polars_duckdb.py +125 -0
  20. nl2sql/api/__init__.py +0 -0
  21. nl2sql/api/auth_api.py +60 -0
  22. nl2sql/api/benchmark_api.py +114 -0
  23. nl2sql/api/datasource_api.py +132 -0
  24. nl2sql/api/indexing_api.py +59 -0
  25. nl2sql/api/llm_api.py +82 -0
  26. nl2sql/api/policy_api.py +135 -0
  27. nl2sql/api/query_api.py +138 -0
  28. nl2sql/api/result_api.py +24 -0
  29. nl2sql/api/settings_api.py +65 -0
  30. nl2sql/auth/__init__.py +8 -0
  31. nl2sql/auth/models.py +36 -0
  32. nl2sql/auth/rbac.py +25 -0
  33. nl2sql/cli/__init__.py +0 -0
  34. nl2sql/cli/checks.py +53 -0
  35. nl2sql/cli/commands/__init__.py +0 -0
  36. nl2sql/cli/commands/benchmark.py +34 -0
  37. nl2sql/cli/commands/doctor.py +49 -0
  38. nl2sql/cli/commands/indexing.py +126 -0
  39. nl2sql/cli/commands/info.py +25 -0
  40. nl2sql/cli/commands/install.py +27 -0
  41. nl2sql/cli/commands/policy.py +57 -0
  42. nl2sql/cli/commands/run.py +166 -0
  43. nl2sql/cli/commands/setup.py +415 -0
  44. nl2sql/cli/commands/visualize.py +34 -0
  45. nl2sql/cli/common/decorators.py +34 -0
  46. nl2sql/cli/config.py +24 -0
  47. nl2sql/cli/console.py +52 -0
  48. nl2sql/cli/demo/__init__.py +1 -0
  49. nl2sql/cli/demo/data.py +87 -0
  50. nl2sql/cli/demo/defaults.py +122 -0
  51. nl2sql/cli/demo/factory.py +289 -0
  52. nl2sql/cli/demo/manager.py +230 -0
  53. nl2sql/cli/demo/schemas.py +336 -0
  54. nl2sql/cli/demo/writers/__init__.py +0 -0
  55. nl2sql/cli/demo/writers/docker.py +182 -0
  56. nl2sql/cli/demo/writers/sqlite.py +88 -0
  57. nl2sql/cli/generators/datasources/__init__.py +3 -0
  58. nl2sql/cli/generators/datasources/generator.py +24 -0
  59. nl2sql/cli/generators/datasources/templates.py +7 -0
  60. nl2sql/cli/generators/env/__init__.py +3 -0
  61. nl2sql/cli/generators/env/generator.py +46 -0
  62. nl2sql/cli/generators/env/templates.py +25 -0
  63. nl2sql/cli/generators/llm/__init__.py +3 -0
  64. nl2sql/cli/generators/llm/generator.py +24 -0
  65. nl2sql/cli/generators/llm/templates.py +4 -0
  66. nl2sql/cli/generators/policies/__init__.py +3 -0
  67. nl2sql/cli/generators/policies/generator.py +20 -0
  68. nl2sql/cli/generators/policies/templates.py +2 -0
  69. nl2sql/cli/main.py +195 -0
  70. nl2sql/cli/reporting.py +878 -0
  71. nl2sql/cli/types.py +13 -0
  72. nl2sql/common/__init__.py +1 -0
  73. nl2sql/common/cancellation.py +25 -0
  74. nl2sql/common/context.py +5 -0
  75. nl2sql/common/errors.py +109 -0
  76. nl2sql/common/event_logger.py +88 -0
  77. nl2sql/common/exceptions.py +3 -0
  78. nl2sql/common/logger.py +119 -0
  79. nl2sql/common/metrics.py +50 -0
  80. nl2sql/common/resilience.py +59 -0
  81. nl2sql/common/settings.py +195 -0
  82. nl2sql/configs/__init__.py +6 -0
  83. nl2sql/configs/datasources.py +10 -0
  84. nl2sql/configs/llm.py +36 -0
  85. nl2sql/configs/manager.py +176 -0
  86. nl2sql/configs/policies.py +14 -0
  87. nl2sql/configs/sample_questions.py +11 -0
  88. nl2sql/configs/secrets.py +11 -0
  89. nl2sql/context.py +106 -0
  90. nl2sql/datasources/__init__.py +21 -0
  91. nl2sql/datasources/discovery.py +28 -0
  92. nl2sql/datasources/models.py +21 -0
  93. nl2sql/datasources/protocols.py +3 -0
  94. nl2sql/datasources/registry.py +172 -0
  95. nl2sql/evaluation/__init__.py +6 -0
  96. nl2sql/evaluation/benchmark_runner.py +320 -0
  97. nl2sql/evaluation/evaluator.py +134 -0
  98. nl2sql/evaluation/types.py +22 -0
  99. nl2sql/execution/__init__.py +4 -0
  100. nl2sql/execution/artifacts/__init__.py +3 -0
  101. nl2sql/execution/artifacts/parquet.py +41 -0
  102. nl2sql/execution/artifacts/store.py +165 -0
  103. nl2sql/execution/contracts.py +57 -0
  104. nl2sql/execution/execution_store.py +25 -0
  105. nl2sql/execution/executor/__init__.py +3 -0
  106. nl2sql/execution/executor/sql_executor.py +116 -0
  107. nl2sql/indexing/__init__.py +7 -0
  108. nl2sql/indexing/chunk_builder.py +227 -0
  109. nl2sql/indexing/embeddings.py +180 -0
  110. nl2sql/indexing/enrichment_service.py +316 -0
  111. nl2sql/indexing/models.py +209 -0
  112. nl2sql/indexing/orchestrator.py +90 -0
  113. nl2sql/indexing/vector_store.py +422 -0
  114. nl2sql/llm/__init__.py +8 -0
  115. nl2sql/llm/models.py +10 -0
  116. nl2sql/llm/registry.py +214 -0
  117. nl2sql/pipeline/__init__.py +1 -0
  118. nl2sql/pipeline/graph.py +73 -0
  119. nl2sql/pipeline/graph_utils.py +141 -0
  120. nl2sql/pipeline/nodes/__init__.py +25 -0
  121. nl2sql/pipeline/nodes/aggregator/__init__.py +4 -0
  122. nl2sql/pipeline/nodes/aggregator/node.py +55 -0
  123. nl2sql/pipeline/nodes/aggregator/prompts.py +20 -0
  124. nl2sql/pipeline/nodes/aggregator/schemas.py +28 -0
  125. nl2sql/pipeline/nodes/answer_synthesizer/__init__.py +4 -0
  126. nl2sql/pipeline/nodes/answer_synthesizer/node.py +98 -0
  127. nl2sql/pipeline/nodes/answer_synthesizer/prompts.py +19 -0
  128. nl2sql/pipeline/nodes/answer_synthesizer/schemas.py +24 -0
  129. nl2sql/pipeline/nodes/ast_planner/__init__.py +4 -0
  130. nl2sql/pipeline/nodes/ast_planner/node.py +104 -0
  131. nl2sql/pipeline/nodes/ast_planner/prompts.py +138 -0
  132. nl2sql/pipeline/nodes/ast_planner/schemas.py +236 -0
  133. nl2sql/pipeline/nodes/datasource_resolver/__init__.py +4 -0
  134. nl2sql/pipeline/nodes/datasource_resolver/node.py +253 -0
  135. nl2sql/pipeline/nodes/datasource_resolver/schemas.py +21 -0
  136. nl2sql/pipeline/nodes/decomposer/__init__.py +3 -0
  137. nl2sql/pipeline/nodes/decomposer/node.py +219 -0
  138. nl2sql/pipeline/nodes/decomposer/prompts.py +96 -0
  139. nl2sql/pipeline/nodes/decomposer/schemas.py +143 -0
  140. nl2sql/pipeline/nodes/executor/__init__.py +3 -0
  141. nl2sql/pipeline/nodes/executor/node.py +107 -0
  142. nl2sql/pipeline/nodes/generator/__init__.py +4 -0
  143. nl2sql/pipeline/nodes/generator/node.py +267 -0
  144. nl2sql/pipeline/nodes/generator/schemas.py +13 -0
  145. nl2sql/pipeline/nodes/global_planner/__init__.py +4 -0
  146. nl2sql/pipeline/nodes/global_planner/node.py +186 -0
  147. nl2sql/pipeline/nodes/global_planner/schemas.py +101 -0
  148. nl2sql/pipeline/nodes/refiner/__init__.py +4 -0
  149. nl2sql/pipeline/nodes/refiner/node.py +132 -0
  150. nl2sql/pipeline/nodes/refiner/prompts.py +28 -0
  151. nl2sql/pipeline/nodes/refiner/schemas.py +13 -0
  152. nl2sql/pipeline/nodes/schema_retriever/__init__.py +3 -0
  153. nl2sql/pipeline/nodes/schema_retriever/node.py +252 -0
  154. nl2sql/pipeline/nodes/schema_retriever/schema.py +27 -0
  155. nl2sql/pipeline/nodes/validator/__init__.py +7 -0
  156. nl2sql/pipeline/nodes/validator/node.py +839 -0
  157. nl2sql/pipeline/nodes/validator/schemas.py +12 -0
  158. nl2sql/pipeline/pipeline_runner.py +72 -0
  159. nl2sql/pipeline/routes.py +72 -0
  160. nl2sql/pipeline/runtime.py +153 -0
  161. nl2sql/pipeline/state.py +92 -0
  162. nl2sql/pipeline/subgraphs/__init__.py +5 -0
  163. nl2sql/pipeline/subgraphs/schemas.py +23 -0
  164. nl2sql/pipeline/subgraphs/sql_agent.py +167 -0
  165. nl2sql/public_api.py +199 -0
  166. nl2sql/schema/__init__.py +37 -0
  167. nl2sql/schema/in_memory_store.py +173 -0
  168. nl2sql/schema/protocol.py +88 -0
  169. nl2sql/schema/sqlite_store.py +233 -0
  170. nl2sql/schema/store.py +29 -0
  171. nl2sql/secrets/__init__.py +14 -0
  172. nl2sql/secrets/factory.py +85 -0
  173. nl2sql/secrets/interfaces.py +16 -0
  174. nl2sql/secrets/manager.py +139 -0
  175. nl2sql/secrets/models.py +56 -0
  176. nl2sql/secrets/providers/aws.py +30 -0
  177. nl2sql/secrets/providers/azure.py +49 -0
  178. nl2sql/secrets/providers/env.py +8 -0
  179. nl2sql/secrets/providers/hashi.py +46 -0
  180. nl2sql/services/__init__.py +0 -0
  181. nl2sql/services/callbacks/__init__.py +0 -0
  182. nl2sql/services/callbacks/monitor.py +84 -0
  183. nl2sql/services/callbacks/node_context.py +7 -0
  184. nl2sql/services/callbacks/node_handlers.py +187 -0
  185. nl2sql/services/callbacks/node_metrics.py +14 -0
  186. nl2sql/services/callbacks/presenter.py +12 -0
  187. nl2sql/services/callbacks/token_handler.py +56 -0
  188. nl2sql_engine-0.1.0.dist-info/METADATA +295 -0
  189. nl2sql_engine-0.1.0.dist-info/RECORD +192 -0
  190. nl2sql_engine-0.1.0.dist-info/WHEEL +5 -0
  191. nl2sql_engine-0.1.0.dist-info/entry_points.txt +9 -0
  192. nl2sql_engine-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,336 @@
1
+
2
+ # Templates for Demo Environment Generation
3
+
4
+ REF_SQL_POSTGRES = """
5
+ CREATE TABLE factories (
6
+ id SERIAL PRIMARY KEY,
7
+ name TEXT,
8
+ region TEXT,
9
+ capacity INTEGER
10
+ );
11
+ CREATE TABLE machine_types (
12
+ id SERIAL PRIMARY KEY,
13
+ model TEXT,
14
+ producer TEXT,
15
+ maintenance_interval_days INTEGER
16
+ );
17
+ CREATE TABLE shifts (
18
+ id SERIAL PRIMARY KEY,
19
+ name TEXT,
20
+ start_time TEXT,
21
+ end_time TEXT
22
+ );
23
+ CREATE TABLE departments (
24
+ id SERIAL PRIMARY KEY,
25
+ name TEXT
26
+ );
27
+ CREATE TABLE employee_roles (
28
+ id SERIAL PRIMARY KEY,
29
+ title TEXT,
30
+ department_id INTEGER
31
+ );
32
+ CREATE TABLE customer_segments (
33
+ id SERIAL PRIMARY KEY,
34
+ name TEXT
35
+ );
36
+ """
37
+
38
+ REF_SQL_SQLITE = """
39
+ CREATE TABLE factories (
40
+ id INTEGER PRIMARY KEY,
41
+ name TEXT,
42
+ region TEXT,
43
+ capacity INTEGER
44
+ );
45
+ CREATE TABLE machine_types (
46
+ id INTEGER PRIMARY KEY,
47
+ model TEXT,
48
+ producer TEXT,
49
+ maintenance_interval_days INTEGER
50
+ );
51
+ CREATE TABLE shifts (
52
+ id INTEGER PRIMARY KEY,
53
+ name TEXT,
54
+ start_time TEXT,
55
+ end_time TEXT
56
+ );
57
+ CREATE TABLE departments (
58
+ id INTEGER PRIMARY KEY,
59
+ name TEXT
60
+ );
61
+ CREATE TABLE employee_roles (
62
+ id INTEGER PRIMARY KEY,
63
+ title TEXT,
64
+ department_id INTEGER
65
+ );
66
+ CREATE TABLE customer_segments (
67
+ id INTEGER PRIMARY KEY,
68
+ name TEXT
69
+ );
70
+ """
71
+
72
+ OPS_SQL_POSTGRES = """
73
+ CREATE TABLE employees (
74
+ id SERIAL PRIMARY KEY,
75
+ name TEXT,
76
+ factory_id INTEGER,
77
+ shift_id INTEGER,
78
+ hire_date DATE,
79
+ role_id INTEGER,
80
+ department_id INTEGER,
81
+ status TEXT
82
+ );
83
+ CREATE TABLE machines (
84
+ id SERIAL PRIMARY KEY,
85
+ factory_id INTEGER,
86
+ type_id INTEGER,
87
+ status TEXT DEFAULT 'Active',
88
+ installation_date DATE,
89
+ last_maintenance_date DATE
90
+ );
91
+ CREATE TABLE maintenance_logs (
92
+ id SERIAL PRIMARY KEY,
93
+ machine_id INTEGER,
94
+ date DATE,
95
+ description TEXT,
96
+ technician_id INTEGER,
97
+ severity TEXT,
98
+ downtime_hours INTEGER
99
+ );
100
+ """
101
+
102
+ OPS_SQL_SQLITE = """
103
+ CREATE TABLE employees (
104
+ id INTEGER PRIMARY KEY,
105
+ name TEXT,
106
+ factory_id INTEGER,
107
+ shift_id INTEGER,
108
+ hire_date DATE,
109
+ role_id INTEGER,
110
+ department_id INTEGER,
111
+ status TEXT
112
+ );
113
+ CREATE TABLE machines (
114
+ id INTEGER PRIMARY KEY,
115
+ factory_id INTEGER,
116
+ type_id INTEGER,
117
+ status TEXT,
118
+ installation_date DATE,
119
+ last_maintenance_date DATE
120
+ );
121
+ CREATE TABLE maintenance_logs (
122
+ id INTEGER PRIMARY KEY,
123
+ machine_id INTEGER,
124
+ date DATE,
125
+ description TEXT,
126
+ technician_id INTEGER,
127
+ severity TEXT,
128
+ downtime_hours INTEGER
129
+ );
130
+ """
131
+
132
+ SUPPLY_SQL_MYSQL = """
133
+ CREATE TABLE products (
134
+ id INT AUTO_INCREMENT PRIMARY KEY,
135
+ sku VARCHAR(255),
136
+ name TEXT,
137
+ base_cost DECIMAL(10,2),
138
+ category VARCHAR(100)
139
+ );
140
+ CREATE TABLE suppliers (
141
+ id INT AUTO_INCREMENT PRIMARY KEY,
142
+ name TEXT,
143
+ country VARCHAR(100)
144
+ );
145
+ CREATE TABLE inventory (
146
+ product_id INT,
147
+ factory_id INT,
148
+ quantity INT,
149
+ last_updated DATE,
150
+ PRIMARY KEY (product_id, factory_id)
151
+ );
152
+ CREATE TABLE supplier_products (
153
+ supplier_id INT,
154
+ product_id INT,
155
+ PRIMARY KEY (supplier_id, product_id)
156
+ );
157
+ """
158
+
159
+ SUPPLY_SQL_SQLITE = """
160
+ CREATE TABLE products (
161
+ id INTEGER PRIMARY KEY,
162
+ sku TEXT,
163
+ name TEXT,
164
+ base_cost REAL,
165
+ category TEXT
166
+ );
167
+ CREATE TABLE suppliers (
168
+ id INTEGER PRIMARY KEY,
169
+ name TEXT,
170
+ country TEXT
171
+ );
172
+ CREATE TABLE inventory (
173
+ product_id INTEGER,
174
+ factory_id INTEGER,
175
+ quantity INTEGER,
176
+ last_updated DATE,
177
+ PRIMARY KEY (product_id, factory_id)
178
+ );
179
+ CREATE TABLE supplier_products (
180
+ supplier_id INTEGER,
181
+ product_id INTEGER,
182
+ PRIMARY KEY (supplier_id, product_id)
183
+ );
184
+ """
185
+
186
+ HISTORY_SQL_MSSQL = """
187
+ CREATE TABLE sales_orders (
188
+ id INT IDENTITY(1,1) PRIMARY KEY,
189
+ customer_name NVARCHAR(255),
190
+ order_date DATE,
191
+ total_amount DECIMAL(12,2),
192
+ status NVARCHAR(50),
193
+ customer_segment_id INT,
194
+ factory_id INT
195
+ );
196
+ CREATE TABLE sales_items (
197
+ id INT IDENTITY(1,1) PRIMARY KEY,
198
+ order_id INT,
199
+ product_id INT,
200
+ quantity INT,
201
+ unit_price DECIMAL(10,2),
202
+ discount_pct DECIMAL(5,2)
203
+ );
204
+ CREATE TABLE production_runs (
205
+ id INT IDENTITY(1,1) PRIMARY KEY,
206
+ factory_id INT,
207
+ date DATE,
208
+ output_quantity INT,
209
+ shift_id INT,
210
+ status NVARCHAR(50)
211
+ );
212
+ """
213
+
214
+ HISTORY_SQL_SQLITE = """
215
+ CREATE TABLE sales_orders (
216
+ id INTEGER PRIMARY KEY,
217
+ customer_name TEXT,
218
+ order_date DATE,
219
+ total_amount REAL,
220
+ status TEXT,
221
+ customer_segment_id INTEGER,
222
+ factory_id INTEGER
223
+ );
224
+ CREATE TABLE sales_items (
225
+ id INTEGER PRIMARY KEY,
226
+ order_id INTEGER,
227
+ product_id INTEGER,
228
+ quantity INTEGER,
229
+ unit_price REAL,
230
+ discount_pct REAL
231
+ );
232
+ CREATE TABLE production_runs (
233
+ id INTEGER PRIMARY KEY,
234
+ factory_id INTEGER,
235
+ date DATE,
236
+ output_quantity INTEGER,
237
+ shift_id INTEGER,
238
+ status TEXT
239
+ );
240
+ """
241
+
242
+ DOCKER_COMPOSE_TEMPLATE = """version: '3.8'
243
+
244
+ services:
245
+ manufacturing_ref:
246
+ image: postgres:15
247
+ container_name: manufacturing_ref
248
+ ports:
249
+ - "5433:5432"
250
+ environment:
251
+ POSTGRES_USER: ${DEMO_POSTGRES_USER}
252
+ POSTGRES_PASSWORD: ${DEMO_POSTGRES_PASSWORD}
253
+ POSTGRES_DB: manufacturing_ref
254
+ # Env vars for Init Scripts
255
+ DEMO_REF_USER: ${DEMO_REF_USER}
256
+ DEMO_REF_PASSWORD: ${DEMO_REF_PASSWORD}
257
+ volumes:
258
+ - ./init_ref.sql:/docker-entrypoint-initdb.d/init.sql
259
+ healthcheck:
260
+ test: ["CMD-SHELL", "pg_isready -U ${DEMO_POSTGRES_USER}"]
261
+ interval: 5s
262
+ retries: 5
263
+
264
+ manufacturing_ops:
265
+ image: postgres:15
266
+ container_name: manufacturing_ops
267
+ ports:
268
+ - "5434:5432"
269
+ environment:
270
+ POSTGRES_USER: ${DEMO_POSTGRES_USER}
271
+ POSTGRES_PASSWORD: ${DEMO_POSTGRES_PASSWORD}
272
+ POSTGRES_DB: manufacturing_ops
273
+ # Env vars for Init Scripts
274
+ DEMO_OPS_USER: ${DEMO_OPS_USER}
275
+ DEMO_OPS_PASSWORD: ${DEMO_OPS_PASSWORD}
276
+ volumes:
277
+ - ./init_ops.sql:/docker-entrypoint-initdb.d/init.sql
278
+ healthcheck:
279
+ test: ["CMD-SHELL", "pg_isready -U ${DEMO_POSTGRES_USER}"]
280
+ interval: 5s
281
+ retries: 5
282
+
283
+ manufacturing_supply:
284
+ image: mysql:8
285
+ container_name: manufacturing_supply
286
+ ports:
287
+ - "3307:3306"
288
+ environment:
289
+ MYSQL_ROOT_PASSWORD: ${DEMO_MYSQL_ROOT_PASSWORD}
290
+ MYSQL_USER: ${DEMO_SUPPLY_USER}
291
+ MYSQL_PASSWORD: ${DEMO_SUPPLY_PASSWORD}
292
+ MYSQL_DATABASE: manufacturing_supply
293
+ volumes:
294
+ - ./init_supply.sql:/docker-entrypoint-initdb.d/init.sql
295
+ healthcheck:
296
+ test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
297
+ interval: 5s
298
+ retries: 5
299
+
300
+ # Opt-in: `docker compose --profile mssql up`. The image is a ~1.6 GB pull, so
301
+ # the default stack leaves it out. Nothing outside this profile depends on it.
302
+ manufacturing_history:
303
+ image: mcr.microsoft.com/mssql/server:2022-latest
304
+ container_name: manufacturing_history
305
+ profiles: ["mssql"]
306
+ ports:
307
+ - "1434:1433"
308
+ environment:
309
+ ACCEPT_EULA: "Y"
310
+ MSSQL_SA_PASSWORD: "${DEMO_MSSQL_SA_PASSWORD}"
311
+ MSSQL_PID: "Express"
312
+ user: root # Needed to run the init script wrapper if we mount it
313
+ command: /bin/bash -c "/opt/mssql/bin/sqlservr & sleep 20 && /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P '${DEMO_MSSQL_SA_PASSWORD}' -i /init.sql -v HISTORY_USER='${DEMO_HISTORY_USER}' HISTORY_PASS='${DEMO_HISTORY_PASSWORD}' && wait"
314
+ volumes:
315
+ - ./init_history.sql:/init.sql
316
+
317
+ app:
318
+ build:
319
+ context: ..
320
+ dockerfile: packages/api/Dockerfile
321
+ container_name: nl2sql_app
322
+ ports:
323
+ - "8000:8000"
324
+ env_file:
325
+ - ../.env.demo
326
+ volumes:
327
+ - ../configs:/app/configs
328
+ - ../data:/app/data
329
+ depends_on:
330
+ manufacturing_ref:
331
+ condition: service_healthy
332
+ manufacturing_ops:
333
+ condition: service_healthy
334
+ manufacturing_supply:
335
+ condition: service_healthy
336
+ """
File without changes
@@ -0,0 +1,182 @@
1
+
2
+ import pathlib
3
+ from typing import List, Dict, Any
4
+ from ..schemas import (
5
+ REF_SQL_POSTGRES,
6
+ OPS_SQL_POSTGRES,
7
+ SUPPLY_SQL_MYSQL,
8
+ HISTORY_SQL_MSSQL,
9
+ DOCKER_COMPOSE_TEMPLATE
10
+ )
11
+
12
+ class DockerWriter:
13
+ """Writes Demo Artifacts (SQL, .env, docker-compose) for Docker environment."""
14
+
15
+ @staticmethod
16
+ def write_docker(output_dir: pathlib.Path,
17
+ secrets: Dict[str, str],
18
+ ref_data: tuple,
19
+ ops_data: tuple,
20
+ supply_data: tuple,
21
+ history_data: tuple):
22
+ """Main entry point."""
23
+ output_dir.mkdir(parents=True, exist_ok=True)
24
+
25
+ # Unpack
26
+ factories, mtypes, shifts, departments, roles, segments = ref_data
27
+ employees, machines, logs = ops_data
28
+ products, suppliers, inventory, supplier_products = supply_data
29
+ orders, items, runs = history_data
30
+
31
+ # 1. SQL Scripts
32
+ DockerWriter._write_sql(output_dir / "init_ref.sql", REF_SQL_POSTGRES, secrets["DEMO_REF_PASSWORD"], "ref_admin", "manufacturing_ref", {
33
+ "factories": factories,
34
+ "machine_types": mtypes,
35
+ "shifts": shifts,
36
+ "departments": departments,
37
+ "employee_roles": roles,
38
+ "customer_segments": segments
39
+ })
40
+
41
+ DockerWriter._write_sql(output_dir / "init_ops.sql", OPS_SQL_POSTGRES, secrets["DEMO_OPS_PASSWORD"], "ops_admin", "manufacturing_ops", {
42
+ "employees": employees, "machines": machines, "maintenance_logs": logs
43
+ })
44
+
45
+ DockerWriter._write_mysql(output_dir / "init_supply.sql", SUPPLY_SQL_MYSQL, {
46
+ "products": products, "suppliers": suppliers, "inventory": inventory, "supplier_products": supplier_products
47
+ })
48
+
49
+ DockerWriter._write_mssql(output_dir / "init_history.sql", HISTORY_SQL_MSSQL, secrets, {
50
+ "sales_orders": orders, "sales_items": items, "production_runs": runs
51
+ })
52
+
53
+ # 2. .env
54
+ DockerWriter._write_env(output_dir / ".env", secrets)
55
+
56
+ # 3. docker-compose
57
+ (output_dir / "docker-compose.demo.yml").write_text(DOCKER_COMPOSE_TEMPLATE, encoding="utf-8")
58
+
59
+ @staticmethod
60
+ def _to_insert(table: str, rows: List[Dict]) -> str:
61
+ if not rows:
62
+ return ""
63
+
64
+ columns = ", ".join(rows[0].keys())
65
+ values_list = []
66
+ for r in rows:
67
+ vals = []
68
+ for v in r.values():
69
+ if isinstance(v, str):
70
+ clean = v.replace("'", "''") # Basic HTML escape for SQL
71
+ vals.append(f"'{clean}'")
72
+ else:
73
+ vals.append(str(v))
74
+ values_list.append(f"({', '.join(vals)})")
75
+
76
+ # Bulk Insert
77
+ # Postgres supports multi-value INSERT
78
+ return f"INSERT INTO {table} ({columns}) VALUES\n" + ",\n".join(values_list) + ";"
79
+
80
+ @staticmethod
81
+ def _write_sql(path: pathlib.Path, schema: str, password: str, user: str, db: str, data: Dict[str, List[Dict]]):
82
+ inserts = []
83
+ for tbl, rows in data.items():
84
+ inserts.append(DockerWriter._to_insert(tbl, rows))
85
+
86
+ inserts_str = "\n\n".join(inserts)
87
+
88
+ script = f"""
89
+ -- Create User and Database
90
+ CREATE USER {user} WITH PASSWORD '{password}';
91
+ CREATE DATABASE {db} OWNER {user};
92
+
93
+ -- Connect and Populate
94
+ \\c {db};
95
+
96
+ {schema}
97
+
98
+ {inserts_str}
99
+
100
+ -- Grant Ownership
101
+ GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO {user};
102
+ """
103
+ path.write_text(script, encoding="utf-8")
104
+
105
+ @staticmethod
106
+ def _write_mysql(path: pathlib.Path, schema: str, data: Dict[str, List[Dict]]):
107
+ inserts = []
108
+ for tbl, rows in data.items():
109
+ inserts.append(DockerWriter._to_insert(tbl, rows))
110
+
111
+ inserts_str = "\n\n".join(inserts)
112
+
113
+ script = f"""
114
+ CREATE DATABASE IF NOT EXISTS manufacturing_supply;
115
+ USE manufacturing_supply;
116
+
117
+ {schema}
118
+
119
+ {inserts_str}
120
+ """
121
+ path.write_text(script, encoding="utf-8")
122
+
123
+ @staticmethod
124
+ def _write_mssql(path: pathlib.Path, schema: str, secrets: Dict[str, str], data: Dict[str, List[Dict]]):
125
+ inserts = []
126
+ for tbl, rows in data.items():
127
+ inserts.append(DockerWriter._to_insert(tbl, rows))
128
+
129
+ inserts_str = "\nGO\n".join(inserts)
130
+
131
+ script = f"""
132
+ IF NOT EXISTS(SELECT * FROM sys.databases WHERE name = 'manufacturing_history')
133
+ BEGIN
134
+ CREATE DATABASE manufacturing_history
135
+ END
136
+ GO
137
+ USE manufacturing_history;
138
+ GO
139
+
140
+ -- Create User (Passed via sqlcmd -v vars)
141
+ CREATE LOGIN [$(HISTORY_USER)] WITH PASSWORD = '$(HISTORY_PASS)';
142
+ CREATE USER [$(HISTORY_USER)] FOR LOGIN [$(HISTORY_USER)];
143
+ ALTER ROLE [db_owner] ADD MEMBER [$(HISTORY_USER)];
144
+ GO
145
+
146
+ {schema}
147
+ GO
148
+
149
+ {inserts_str}
150
+ GO
151
+ """
152
+ path.write_text(script, encoding="utf-8")
153
+
154
+ @staticmethod
155
+ def _write_env(path: pathlib.Path, secrets: Dict[str, str]):
156
+ # Matches the template we removed
157
+ content = f"""# NL2SQL Demo Environment Secrets
158
+ # Generated automatically. DO NOT COMMIT TO VERSION CONTROL.
159
+
160
+ # 1. Manufacturing Ref (Postgres)
161
+ DEMO_REF_USER=ref_admin
162
+ DEMO_REF_PASSWORD={secrets["DEMO_REF_PASSWORD"]}
163
+
164
+ # 2. Manufacturing Ops (Postgres)
165
+ DEMO_OPS_USER=ops_admin
166
+ DEMO_OPS_PASSWORD={secrets["DEMO_OPS_PASSWORD"]}
167
+
168
+ # Postgres Superuser (Container Root)
169
+ DEMO_POSTGRES_USER=postgres
170
+ DEMO_POSTGRES_PASSWORD={secrets["DEMO_POSTGRES_PASSWORD"]}
171
+
172
+ # 3. Manufacturing Supply (MySQL)
173
+ DEMO_SUPPLY_USER=supply_admin
174
+ DEMO_SUPPLY_PASSWORD={secrets["DEMO_SUPPLY_PASSWORD"]}
175
+ DEMO_MYSQL_ROOT_PASSWORD={secrets["DEMO_MYSQL_ROOT_PASSWORD"]}
176
+
177
+ # 4. Manufacturing History (MSSQL)
178
+ DEMO_HISTORY_USER=history_admin
179
+ DEMO_HISTORY_PASSWORD={secrets["DEMO_HISTORY_PASSWORD"]}
180
+ DEMO_MSSQL_SA_PASSWORD={secrets["DEMO_MSSQL_SA_PASSWORD"]}
181
+ """
182
+ path.write_text(content, encoding="utf-8")
@@ -0,0 +1,88 @@
1
+
2
+ import sqlite3
3
+ import pathlib
4
+ from typing import List, Dict
5
+ from ..schemas import (
6
+ REF_SQL_SQLITE,
7
+ OPS_SQL_SQLITE,
8
+ SUPPLY_SQL_SQLITE,
9
+ HISTORY_SQL_SQLITE
10
+ )
11
+
12
+ class SQLiteWriter:
13
+ """Writes Demo Data to SQLite databases."""
14
+
15
+ @staticmethod
16
+ def write_lite(output_dir: pathlib.Path,
17
+ ref_data: tuple,
18
+ ops_data: tuple,
19
+ supply_data: tuple,
20
+ history_data: tuple):
21
+ """Main entry point to write all 4 databases."""
22
+ output_dir.mkdir(parents=True, exist_ok=True)
23
+
24
+ # Unpack Data
25
+ factories, mtypes, shifts, departments, roles, segments = ref_data
26
+ employees, machines, logs = ops_data
27
+ products, suppliers, inventory, supplier_products = supply_data
28
+ orders, items, runs = history_data
29
+
30
+ # 1. Ref
31
+ SQLiteWriter._create_db(output_dir / "manufacturing_ref.db", REF_SQL_SQLITE, {
32
+ "factories": factories,
33
+ "machine_types": mtypes,
34
+ "shifts": shifts,
35
+ "departments": departments,
36
+ "employee_roles": roles,
37
+ "customer_segments": segments
38
+ })
39
+
40
+ # 2. Ops
41
+ SQLiteWriter._create_db(output_dir / "manufacturing_ops.db", OPS_SQL_SQLITE, {
42
+ "employees": employees,
43
+ "machines": machines,
44
+ "maintenance_logs": logs
45
+ })
46
+
47
+ # 3. Supply
48
+ SQLiteWriter._create_db(output_dir / "manufacturing_supply.db", SUPPLY_SQL_SQLITE, {
49
+ "products": products,
50
+ "suppliers": suppliers,
51
+ "inventory": inventory,
52
+ "supplier_products": supplier_products
53
+ })
54
+
55
+ # 4. History
56
+ SQLiteWriter._create_db(output_dir / "manufacturing_history.db", HISTORY_SQL_SQLITE, {
57
+ "sales_orders": orders,
58
+ "sales_items": items,
59
+ "production_runs": runs
60
+ })
61
+
62
+ @staticmethod
63
+ def _create_db(path: pathlib.Path, schema_sql: str, data_map: Dict[str, List[Dict]]):
64
+ """Creates a DB, runs schema, and inserts data."""
65
+ if path.exists():
66
+ path.unlink()
67
+
68
+ conn = sqlite3.connect(str(path))
69
+ cursor = conn.cursor()
70
+
71
+ # 1. Schema
72
+ cursor.executescript(schema_sql)
73
+
74
+ # 2. Data
75
+ for table_name, rows in data_map.items():
76
+ if not rows:
77
+ continue
78
+
79
+ # Assume all rows have same keys
80
+ keys = list(rows[0].keys())
81
+ cols = ", ".join(keys)
82
+ placeholders = ", ".join(f":{k}" for k in keys)
83
+ sql = f"INSERT INTO {table_name} ({cols}) VALUES ({placeholders})"
84
+
85
+ cursor.executemany(sql, rows)
86
+
87
+ conn.commit()
88
+ conn.close()
@@ -0,0 +1,3 @@
1
+ from .generator import DatasourceGenerator
2
+
3
+ __all__ = ["DatasourceGenerator"]
@@ -0,0 +1,24 @@
1
+ import yaml
2
+ from nl2sql.configs import DatasourceFileConfig
3
+
4
+ class DatasourceGenerator:
5
+ """Generates the content for datasources.yaml."""
6
+
7
+ HEADER = "# NL2SQL Datasource Configuration\n\n"
8
+
9
+ @staticmethod
10
+ def generate(config: DatasourceFileConfig) -> str:
11
+ """
12
+ Generates YAML content for Datasource configuration.
13
+
14
+ Args:
15
+ config: DatasourceFileConfig object (Envelope).
16
+
17
+ Returns:
18
+ Formatted YAML string.
19
+ """
20
+ dumped_config = config.model_dump(exclude_none=True)
21
+
22
+ yaml_block = yaml.safe_dump(dumped_config, sort_keys=False)
23
+
24
+ return DatasourceGenerator.HEADER + yaml_block
@@ -0,0 +1,7 @@
1
+
2
+ # Valid placeholders for injection: {version}, {datasources_yaml_block}
3
+ DATASOURCE_TEMPLATE = """version: {version}
4
+
5
+ datasources:
6
+ {datasources_yaml_block}
7
+ """
@@ -0,0 +1,3 @@
1
+ from .generator import EnvFileGenerator
2
+
3
+ __all__ = ["EnvFileGenerator"]
@@ -0,0 +1,46 @@
1
+ from typing import Dict, Optional
2
+ from .templates import ENV_FILE_TEMPLATE, ENV_SECRETS_HEADER, ENV_SPECIFIC_SETTINGS
3
+
4
+ class EnvFileGenerator:
5
+ """Standard generator for .env files complying with Universal Environment Protocol."""
6
+
7
+ @staticmethod
8
+ def generate(env: str, secrets: Optional[Dict[str, str]] = None) -> str:
9
+ """Generates the content for a .env.<env> file.
10
+
11
+ This method constructs the standard configuration paths based on the
12
+ environment name and optionally appends provided secrets.
13
+
14
+ Args:
15
+ env: The environment name (e.g., 'dev', 'demo', 'prod').
16
+ secrets: Optional dictionary of secret key-values to append.
17
+
18
+ Returns:
19
+ The formatted string content for the .env file.
20
+ """
21
+ suffix = f".{env}" if env != "dev" else ""
22
+
23
+ # Populate template
24
+ content = ENV_FILE_TEMPLATE.format(env=env, suffix=suffix)
25
+ content += ENV_SPECIFIC_SETTINGS.get(env, "")
26
+ content += ENV_SECRETS_HEADER
27
+
28
+ used_keys = set()
29
+
30
+ if secrets:
31
+ for key, value in secrets.items():
32
+ content += f"{key}={value}\n"
33
+ used_keys.add(key)
34
+
35
+ critical_placeholders = ["OPENAI_API_KEY"]
36
+ appended_placeholders = False
37
+
38
+ for ph in critical_placeholders:
39
+ if ph not in used_keys:
40
+ content += f"{ph}=\n"
41
+ appended_placeholders = True
42
+
43
+ if appended_placeholders and not secrets:
44
+ content += "# Please fill in the required secrets above.\n"
45
+
46
+ return content