Skip to content

Commit 4c1d0d6

Browse files
committed
feat: update docs
1 parent 43264c9 commit 4c1d0d6

50 files changed

Lines changed: 1027 additions & 1938 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 0 additions & 111 deletions
This file was deleted.

docs/adapters/development.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Building Adapters
2+
3+
The **Adapter SDK** (`nl2sql-adapter-sdk`) allows you to extend the platform to support new databases or APIs.
4+
5+
## Implementing an Adapter
6+
7+
You must implement the `DatasourceAdapter` interface.
8+
9+
### Mandatory Properties
10+
11+
* `datasource_id`: Unique identifier (e.g. "postgres_prod").
12+
* `row_limit`: **Safety Breaker**. Must return `1000` (or config value) to prevent massive result sets.
13+
* `max_bytes`: **Safety Breaker**. limit result size at the network/driver level if possible.
14+
15+
### Mandatory Methods
16+
17+
* `fetch_schema()`: Must return `SchemaMetadata` with `tables`, `columns`, `pks`, `fks`. *Crucially, it should also populate `col.statistics` (samples, min/max) for Indexing.*
18+
* `execute(sql)`: Returns `QueryResult`.
19+
* `dry_run(sql)`: Returns validity checks.
20+
21+
### Optional Optimization
22+
23+
* `explain(sql)`: Returns query plan.
24+
* `cost_estimate(sql)`: Returns estimated rows/time. used by PhysicalValidator.
25+
26+
::: nl2sql_adapter_sdk.interfaces.DatasourceAdapter
27+
28+
## Compliance Testing
29+
30+
The SDK provides a compliance test suite. **All Adapters MUST pass this suite.**
31+
32+
It verifies:
33+
34+
* Schema Introspection (PKs/FKs detected?)
35+
* Type Mapping (Date -> Python Date, Numeric -> Python Float)
36+
* Error Handling (Bad SQL -> AdapterError)
37+
38+
```python
39+
# tests/test_my_adapter.py
40+
from nl2sql_adapter_sdk.testing import BaseAdapterTest
41+
from my_adapter import MyAdapter
42+
43+
class TestMyAdapter(BaseAdapterTest):
44+
@pytest.fixture
45+
def adapter(self):
46+
return MyAdapter(...)
47+
```
48+
49+
## Choosing a Base Class
50+
51+
The platform provides two ways to build adapters. Choose the one that fits your target datasource.
52+
53+
| Feature | `DatasourceAdapter` (Base Interface) | `BaseSQLAlchemyAdapter` (Helper Class) |
54+
| :--- | :--- | :--- |
55+
| **Package** | `nl2sql-adapter-sdk` | `nl2sql-adapter-sqlalchemy` |
56+
| **Best For** | REST APIs, NoSQL, GraphQL, Manual SQL Drivers. | SQL Databases with SQLAlchemy dialects (Postgres, Oracle, Snowflake). |
57+
| **Schema Fetching** | **Manual Implementation Required**. You must map metadata to `SchemaMetadata`. | **Automatic**. Uses `sqlalchemy.inspect` to reflect tables/FKs. |
58+
| **Execution** | **Manual Implementation Required**. You handle connections, cursors, and types. | **Automatic**. Handles pooling, transactions, and result formatting. |
59+
| **Stats Gathering** | **Manual**. You write queries to fetch min/max/nulls. | **Automatic**. Runs optimized generic queries for stats. |
60+
| **Dry Run** | **Manual**. | **Automatic**. Uses transaction rollback pattern. |
61+
62+
### When to use `DatasourceAdapter`?
63+
64+
Use the raw interface when:
65+
66+
1. You are connecting to a non-SQL source (e.g., Elasticsearch, HubSpot API).
67+
2. You are using a customized internal SQL driver that is not compatible with SQLAlchemy.
68+
3. You need complete control over the execution lifecycle (e.g. async-only drivers).
69+
70+
### When to use `BaseSQLAlchemyAdapter`?
71+
72+
Use this helper class when:
73+
74+
1. There is an existing SQLAlchemy dialect for your database (this covers 95% of SQL databases).
75+
2. You want to save time on boilerplate (connection pooling, schema reflection).
76+
3. You want consistent behavior with the core supported adapters.
77+
78+
## Building SQL Adapters (The Fast Way)
79+
80+
For SQL databases supported by SQLAlchemy, you should use the `nl2sql-adapter-sqlalchemy` package as described in the comparison above.
81+
82+
### `BaseSQLAlchemyAdapter` Features
83+
84+
This base class implements ~90% of the required functionality for you:
85+
86+
* **Automatic Schema Fetching**: Uses `sqlalchemy.inspect` to get tables, columns, PKs.
87+
* **Automatic Statistics**: Runs optimized queries to fetch `min/max`, `null_percentage`, `distinct_count`, and `sample_values` for text columns.
88+
* **Generic Execution**: Handles connection pooling and result formatting.
89+
* **Safety**: Built-in generic `dry_run` using transaction rollbacks.
90+
91+
### Example Implementation
92+
93+
See `packages/adapters/postgres` for a reference implementation.
94+
95+
```python
96+
from nl2sql_sqlalchemy_adapter import BaseSQLAlchemyAdapter
97+
98+
class PostgresAdapter(BaseSQLAlchemyAdapter):
99+
def construct_uri(self, args: Dict[str, Any]) -> str:
100+
return f"postgresql://{args.get('user')}:{args.get('password')}@{args.get('host')}/{args.get('database')}"
101+
102+
# Optional: Override dry_run for better performance using EXPLAIN
103+
def dry_run(self, sql: str):
104+
self.execute(f"EXPLAIN {sql}")
105+
return DryRunResult(is_valid=True)
106+
```
107+
108+
## Reference Adapters
109+
110+
For detailed usage configurations of our supported adapters, please see the **[Supported Adapters](index.md)** section.
111+
112+
Explore the `packages/adapters/` directory for examples:
113+
114+
* `postgres`: Standard implementation using `sqlalchemy`.
115+
* `sqlite`: Simple, file-based.
116+
* `mssql` / `mysql`: Standard enterprise drivers.
117+
118+
## Next Steps
119+
120+
Check out the [Postgres Adapter Source Code](https://github.com/nadeem4/nl2sql/tree/main/packages/adapters/postgres) for a complete, production-grade example.

docs/adapters/index.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Supported Adapters
2+
3+
The NL2SQL Platform supports a variety of datasources through specialized adapters. Each adapter is designed to handle the specific idiosyncrasies of its underlying database engine, from connection strings to specialized `EXPLAIN` plans.
4+
5+
## SQL Adapters
6+
7+
We provide first-class support for the following SQL databases via SQLAlchemy.
8+
9+
| Adapter | Description | Status |
10+
| :--- | :--- | :--- |
11+
| **[PostgreSQL](postgres.md)** | Full support including `EXPLAIN`, JSONB, and SSL. | 🟢 Stable |
12+
| **[MySQL](mysql.md)** | Support for 5.7+ and 8.0. Includes `MAX_EXECUTION_TIME` management. | 🟢 Stable |
13+
| **[Microsoft SQL Server](mssql.md)** | Enterprise support via `pyodbc` and `T-SQL` dialect. | 🟡 Beta |
14+
| **[SQLite](sqlite.md)** | File-based local development. | 🟢 Stable |
15+
16+
## Missing your database?
17+
18+
Can't find what you need? Check out the **[Building Adapters](development.md)** guide to see how to implement your own.
19+
20+
## Configuration
21+
22+
All adapters are configured in your `configs/datasources.yaml` file.
23+
24+
```yaml
25+
version: 1
26+
datasources:
27+
- id: "sales_db"
28+
connection:
29+
type: "postgres"
30+
host: "${env:DB_HOST}"
31+
port: 5432
32+
# ... see specific adapter docs for full reference
33+
```

docs/adapters/mssql.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Microsoft SQL Server (MSSQL) Adapter
2+
3+
Support for SQL Server 2017+ and Azure SQL.
4+
5+
!!! info "Implementation"
6+
This adapter extends `BaseSQLAlchemyAdapter` but provides specialized `dry_run` logic using `SET NOEXEC ON` to safely validate T-SQL.
7+
8+
## Configuration
9+
10+
**Type**: `mssql`
11+
12+
```yaml
13+
14+
connection:
15+
type: "mssql"
16+
host: "localhost"
17+
port: 1433
18+
user: "sa"
19+
password: "${env:DB_PASS}"
20+
database: "my_db"
21+
driver: "ODBC Driver 17 for SQL Server" # Default
22+
trusted_connection: false
23+
```
24+
25+
### Connection Details
26+
27+
* **Driver**: `pyodbc`. **Requires system ODBC headers installed.**
28+
* **URI Constructed**: `mssql+pyodbc://{user}:{pass}@{host}:{port}/{db}?driver={driver}`
29+
30+
## Features
31+
32+
| Feature | Implementation | Note |
33+
| :--- | :--- | :--- |
34+
| **Timeout** | Not strictly enforced by driver | Rely on global statement timeout. |
35+
| **Dry Run** | `SET NOEXEC ON` | Validates syntax without execution. |
36+
| **Costing** | `SET SHOWPLAN_XML ON` | Parses XML for `StatementSubTreeCost`. |
37+
38+
## Requirements
39+
40+
You must have the MS ODBC Driver installed in your Docker image or local environment.
41+
42+
[Download ODBC Driver for SQL Server](https://learn.microsoft.com/en-us/sql/connect/odbc/download-odbc-driver-for-sql-server)
43+
44+
```bash
45+
# Debian / Ubuntu
46+
sudo apt-get install unixodbc-dev
47+
```

docs/adapters/mysql.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# MySQL Adapter
2+
3+
Support for MySQL 5.7+ and 8.0+.
4+
5+
!!! info "Implementation"
6+
This adapter extends `BaseSQLAlchemyAdapter`. It overrides `connect()` to handle `MAX_EXECUTION_TIME` session variables.
7+
8+
## Configuration
9+
10+
**Type**: `mysql`
11+
12+
```yaml
13+
14+
connection:
15+
type: "mysql"
16+
host: "localhost"
17+
port: 3306
18+
user: "root"
19+
password: "${env:DB_PASS}"
20+
database: "my_db"
21+
options:
22+
charset: "utf8mb4"
23+
```
24+
25+
### Connection Details
26+
27+
* **Driver**: `pymysql` (Pure Python).
28+
* **URI Constructed**: `mysql+pymysql://{user}:{pass}@{host}:{port}/{db}?{options}`
29+
30+
## Features
31+
32+
| Feature | Implementation | Note |
33+
| :--- | :--- | :--- |
34+
| **Timeout** | `SET MAX_EXECUTION_TIME={ms}` | Session-level enforcement. |
35+
| **Dry Run** | Transaction Rollback | Starts transaction, runs SQL, rolls back. |
36+
| **Costing** | `EXPLAIN FORMAT=JSON` | Extracts `query_cost`. |
37+
| **Stats** | `SELECT count(*), min(), max()` | Standard aggregation. |
38+
39+
## Limitations
40+
41+
* **Row Estimation**: MySQL's `EXPLAIN` does not always provide a reliable "Total Rows" estimate for complex joins compared to Postgres.

0 commit comments

Comments
 (0)