|
65 | 65 | SqlRewriteRule, |
66 | 66 | SqlTranslateParams, |
67 | 67 | SqlTranslateResult, |
| 68 | + WarehouseExploreParams, |
| 69 | + WarehouseExploreTableInfo, |
| 70 | + WarehouseExploreResult, |
68 | 71 | WarehouseInfo, |
69 | 72 | WarehouseListResult, |
70 | 73 | WarehouseTestParams, |
|
212 | 215 | INTERNAL_ERROR = -32603 |
213 | 216 |
|
214 | 217 |
|
| 218 | +# --- Warehouse helpers --- |
| 219 | + |
| 220 | + |
| 221 | +def _resolve_warehouse(warehouse_name: str | None): |
| 222 | + """Resolve warehouse: explicit name > registered connections > dbt profiles.""" |
| 223 | + if warehouse_name: |
| 224 | + return ConnectionRegistry.get(warehouse_name) |
| 225 | + # Try first registered connection |
| 226 | + connections = ConnectionRegistry.list() |
| 227 | + if connections: |
| 228 | + return ConnectionRegistry.get(connections[0]["name"]) |
| 229 | + # Try dbt profiles |
| 230 | + dbt_conns = discover_dbt_connections() |
| 231 | + if dbt_conns: |
| 232 | + first_name = next(iter(dbt_conns)) |
| 233 | + # Register it so ConnectionRegistry.get() works |
| 234 | + ConnectionRegistry.add(first_name, dbt_conns[first_name]) |
| 235 | + return ConnectionRegistry.get(first_name) |
| 236 | + raise ValueError( |
| 237 | + "No warehouse connection found. Configure one or pass warehouse name." |
| 238 | + ) |
| 239 | + |
| 240 | + |
| 241 | +def _parse_table_ref(table_name: str) -> tuple[str | None, str]: |
| 242 | + """Parse 'schema.table' into (schema, table) or (None, table).""" |
| 243 | + parts = table_name.split(".", 1) |
| 244 | + if len(parts) == 2: |
| 245 | + return parts[0], parts[1] |
| 246 | + return None, parts[0] |
| 247 | + |
| 248 | + |
215 | 249 | # Lazily-initialized singletons |
216 | 250 | def _schema_context_to_dict( |
217 | 251 | schema_context: dict[str, list] | None, |
@@ -453,6 +487,28 @@ def dispatch(request: JsonRpcRequest) -> JsonRpcResponse: |
453 | 487 | result = parse_manifest(DbtManifestParams(**params)) |
454 | 488 | elif method == "dbt.lineage": |
455 | 489 | result = dbt_lineage(DbtLineageParams(**params)) |
| 490 | + elif method == "warehouse.explore": |
| 491 | + p = WarehouseExploreParams(**params) |
| 492 | + connector = _resolve_warehouse(p.warehouse) |
| 493 | + connector.connect() |
| 494 | + try: |
| 495 | + tables_info = [] |
| 496 | + for schema in connector.list_schemas(): |
| 497 | + for tbl in connector.list_tables(schema): |
| 498 | + cols = connector.describe_table(schema, tbl["name"]) |
| 499 | + col_names = [c["name"] for c in cols] |
| 500 | + tables_info.append( |
| 501 | + WarehouseExploreTableInfo( |
| 502 | + schema=schema, |
| 503 | + name=tbl["name"], |
| 504 | + columns=col_names, |
| 505 | + ) |
| 506 | + ) |
| 507 | + result = WarehouseExploreResult( |
| 508 | + tables=tables_info, table_count=len(tables_info) |
| 509 | + ) |
| 510 | + finally: |
| 511 | + connector.close() |
456 | 512 | elif method == "warehouse.list": |
457 | 513 | warehouses = [WarehouseInfo(**w) for w in ConnectionRegistry.list()] |
458 | 514 | result = WarehouseListResult(warehouses=warehouses) |
|
0 commit comments