Skip to content

feat: DSL API, ProviderConfig, hexagonal architecture improvements (0.2.0rc8)#31

Merged
luiscarbonel1991 merged 3 commits into
mainfrom
feat/dsl-api-provider-config-hexagonal-ports
Mar 23, 2026
Merged

feat: DSL API, ProviderConfig, hexagonal architecture improvements (0.2.0rc8)#31
luiscarbonel1991 merged 3 commits into
mainfrom
feat/dsl-api-provider-config-hexagonal-ports

Conversation

@luiscarbonel1991

Copy link
Copy Markdown
Owner

Summary

Major architecture improvement: adds a Pythonic DSL API (connect / ask), unified ProviderConfig, 3 new hexagonal ports, unified storage with per-database isolation, and PostgreSQL integration tests.

New Features

  • DSL API: nlp2sql.connect(url, provider=ProviderConfig(...)) returns NLP2SQL client with .ask(), .validate(), .explain(), .suggest() methods. Replaces verbose create_and_initialize_service() for common use cases
  • ProviderConfig: Single object for all AI provider settings (provider, api_key, model, temperature, max_tokens). Includes resolved_model property that returns the effective model per provider
  • ExampleRepositoryPort: Hexagonal port for few-shot examples. ExampleStore (FAISS) is now an adapter. Pass examples=[{...}] to connect() for automatic setup
  • QueryValidatorPort + RegexQueryValidator: Deterministic SQL validation (syntax check, keyword detection) without LLM calls
  • QuerySafetyPort: SQL safety checks extracted from repositories to core/sql_safety.py (pure Python, no external deps)
  • QueryResult: Typed dataclass with .sql, .confidence, .is_valid, .explanation — replaces raw dict access

Architecture Improvements

  • Unified storage: get_data_directory() in utils/storage.py with fallback chain (NLP2SQL_DATA_DIR > ./embeddings > ~/.nlp2sql/data). Both SchemaEmbeddingManager and ExampleStore share the same base directory
  • Per-database FAISS isolation: Indexes stored under <db_hash>/embeddings/ and <db_hash>/examples/ preventing cross-contamination between databases
  • Dimension validation: ExampleStore validates FAISS index dimensions match the embedding provider on load (same pattern as SchemaEmbeddingManager)
  • Service depends on ports: QueryGenerationService uses ExampleRepositoryPort, not ExampleStore directly
  • Core extraction: sql_safety.py (safety checks) and sql_keywords.py (SQL keyword set) extracted from query_service.py to core/

AI Provider Updates

  • Updated default models: gpt-4o-mini (OpenAI), claude-sonnet-4-20250514 (Anthropic), gemini-2.0-flash (Gemini)
  • ProviderConfig wiring: All 3 adapters + all 3 factories accept ProviderConfig. Backward-compatible — legacy ai_provider + api_key + model params still work

Tests

Suite Count Requires Command
Unit tests 195 Nothing uv run pytest -m "not integration and not llm"
PostgreSQL integration 17 Docker postgres uv run pytest -m "integration and not llm"
LLM smoke tests 3 Docker + API key OPENAI_API_KEY=... uv run pytest -m llm
Redshift integration 6 (skipped) LocalStack uv run pytest -m integration
Total 212 passed, 9 skipped uv run pytest -m "not llm"

New test files:

  • tests/conftest.py: MockAIProvider, MockEmbeddingProvider, postgres_available fixture with Docker auto-detection, customizable via NLP2SQL_TEST_POSTGRES_PORT
  • tests/test_postgres_integration.py (7 tests): Repository connect, column discovery, view exclusion, safe query check, schema filters (include/exclude), embedding search with real schema
  • tests/test_dsl_integration.py (13 tests): connect() factory (5), ask() pipeline (3), validate() (2), LLM end-to-end with FAISS isolation via tmp_path (3)

Documentation

  • README.md: New Quick Start with DSL API examples, ProviderConfig usage
  • API.md: Full DSL API reference (connect, ask, validate, explain, suggest), ProviderConfig, QueryResult
  • ARCHITECTURE.md: Updated component diagram, 9 ports listed, storage layout documented

Files Changed

  • 25 files modified, 14 new files
  • +833 lines, -780 lines

Hexagonal Ports (9 total)

Port Adapter(s) Status
AIProviderPort OpenAI, Anthropic, Gemini Active
SchemaRepositoryPort PostgreSQL, Redshift Active
EmbeddingProviderPort Local, OpenAI Active
ExampleRepositoryPort ExampleStore (FAISS) New
QueryValidatorPort RegexQueryValidator New
QuerySafetyPort core/sql_safety.py New
SchemaStrategyPort SchemaAnalyzer Active
CachePort (no implementation) Defined
QueryOptimizerPort (no implementation) Defined

…gration tests

- Add Pythonic DSL: nlp2sql.connect() -> .ask() / .validate() / .explain() / .suggest()
- Add ProviderConfig: unified AI provider config (provider, api_key, model, temperature, max_tokens)
- Add ExampleRepositoryPort: hexagonal port for few-shot examples (ExampleStore implements it)
- Add QueryValidatorPort + RegexQueryValidator: deterministic SQL validation without LLM
- Add QuerySafetyPort: extracted SQL safety checks from repositories to core
- Extract sql_safety.py and sql_keywords.py from query_service.py to core/
- Unify storage: get_data_directory() with fallback chain (env > ./embeddings > ~/.nlp2sql/data)
- Add per-database FAISS isolation: schema + examples indexes under <db_hash>/
- Add dimension validation to ExampleStore (prevents mock/real provider mismatch)
- Update default models: gpt-4o-mini, claude-sonnet-4-20250514, gemini-2.0-flash
- Wire ProviderConfig through factories (backward-compatible)
- Add QueryResult dataclass with typed access (.sql, .confidence, .is_valid, .explanation)
- Add conftest.py, 17 integration tests, 3 LLM smoke tests, llm pytest marker
- Update README, API.md, ARCHITECTURE.md
- Bump version to 0.2.0rc8
- Bump nlp2sql version from 0.2.0rc7 to 0.2.0rc8 in uv.lock.
- Introduce a new CI workflow in .github/workflows/ci.yml for automated testing and linting on push and pull request events.
@luiscarbonel1991
luiscarbonel1991 merged commit d90ecfd into main Mar 23, 2026
1 check passed
@luiscarbonel1991
luiscarbonel1991 deleted the feat/dsl-api-provider-config-hexagonal-ports branch March 23, 2026 03:38
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