Skip to content

feat(db): Cloudflare D1 + 범용 SQLAlchemy explorer + 자동 라우팅 팩토리#229

Merged
seyoung4503 merged 2 commits into
masterfrom
feat/db-explorer-adapters
May 30, 2026
Merged

feat(db): Cloudflare D1 + 범용 SQLAlchemy explorer + 자동 라우팅 팩토리#229
seyoung4503 merged 2 commits into
masterfrom
feat/db-explorer-adapters

Conversation

@seyoung4503
Copy link
Copy Markdown
Collaborator

무엇

V1의 PG stub explorer 자리를 진짜 외부 DB와 연결되는 어댑터 레이어로 채움. D1은 자체 HTTP 어댑터, 나머지는 SQLAlchemy 하나로 다 커버. `build_explorer(DSN)` 팩토리가 scheme으로 자동 라우팅.

  • 회사에서 쓰는 DB가 다양함(Postgres/MySQL/Snowflake/BigQuery/DuckDB/D1...). 어댑터 N개 짜는 대신 SQLAlchemy 범용 1개로 통일 → "연결이 쉽다".
  • D1은 Workers 전용이라 Python에선 HTTP API로만 가능 → 별도 어댑터.

포함

  • `adapters/db/d1_explorer.py` — Cloudflare D1 `ExplorerPort` (HTTP Query API, urllib/stdlib). SQLite라 `sqlite_master`/`PRAGMA`로 introspection. transport 주입 가능 → 네트워크 없이 unit-test. 식별자 검증으로 인젝션 차단.
  • `adapters/db/sqlalchemy_explorer.py` — 범용 `ExplorerPort`. SQLAlchemy URL만 바꾸면 Postgres/BigQuery/Snowflake/MySQL/DuckDB 등 다 커버. engine lazy 생성(드라이버 미설치여도 라우팅 가능), blocking 호출은 `asyncio.to_thread`.
  • `adapters/db/factory.py` — `build_explorer(conn)` (`d1://` → D1, 그 외 → SQLAlchemy) + `explorer_from_env()` (`LANG2SQL_DB_URL` > Cloudflare D1 env > stub fallback).
  • `tenancy/concierge.py` — 기본 explorer를 env 기반 자동 선택.
  • `pyproject.toml` — sqlalchemy core dep + `[postgres]/[bigquery]/[snowflake]/[mysql]/[duckdb]/[all-db]` extra. 드라이버는 옵셔널.
  • `.env.example` — 연결 옵션 문서화.

사용성 (이게 목표)

연결이 DSN 한 줄로 끝남:
```bash
LANG2SQL_DB_URL="snowflake://user:pass@account/db?warehouse=wh"
uv sync --extra snowflake # 필요한 드라이버만
```
새 DB 추가 = `pip install <드라이버>` + DSN. 어댑터 코드는 안 건드림.

검증

  • 93개 테스트 통과 (84 + 9 신규)
  • factory 라우팅 3종 (D1/SQLAlchemy/stub fallback) 검증
  • SqlAlchemyExplorer 실 sqlite introspection/execute 검증
  • D1Explorer mock HTTP transport로 list/describe/execute/error/식별자 검증
  • 라이브: 실제 DuckDB 파일 만들어서 봇 띄우고 `explore_schema`/`run_sql` 진짜 동작 확인

🤖 Generated with Claude Code

회사 DB 연결을 쉽게 — DSN 하나로 라우팅되는 explorer 어댑터 레이어.

- adapters/db/d1_explorer.py: Cloudflare D1 ExplorerPort (HTTP Query API,
  urllib/stdlib). SQLite라 sqlite_master/PRAGMA로 introspection. transport
  주입 가능 → 네트워크 없이 테스트. 식별자 검증으로 인젝션 차단.
- adapters/db/sqlalchemy_explorer.py: 범용 ExplorerPort. SQLAlchemy URL만
  바꾸면 Postgres/BigQuery/Snowflake/MySQL/DuckDB 등 커버. engine lazy
  생성(드라이버 미설치여도 라우팅 가능), blocking 호출은 to_thread.
- adapters/db/factory.py: build_explorer(conn) — d1:// → D1, 그 외 → SQLAlchemy.
  explorer_from_env(): LANG2SQL_DB_URL > Cloudflare D1 env > stub fallback.
- concierge: 기본 explorer를 explorer_from_env()로(없으면 stub).
- pyproject: sqlalchemy core dep + postgres/bigquery/snowflake/mysql/duckdb/
  all-db extra. .env.example에 연결 옵션 문서화.
- tests/test_db_adapters.py: factory 라우팅, SQLAlchemy 실 sqlite introspection
  /execute, D1 mock transport(list/describe/execute/error/식별자검증).

검증: 93 테스트 통과(84+9), concierge env 라우팅 3종(SQLAlchemy/stub/D1) 확인.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@seyoung4503 seyoung4503 changed the base branch from feat/v1-discord-agent to master May 30, 2026 03:16
@seyoung4503 seyoung4503 merged commit c76918f into master May 30, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant