SQL for everything. Read, write, and delete across any API or database using plain SQL.
SELECT→ executed through DuckDB (fast, in-memory, federated)INSERT/UPDATE/DELETE→ parsed by sqlglot, routed to connector write APIs- Built-in connectors: ServiceNow, CSV, SQLite
- Extensible: implement
BaseConnectorto add any source
| Connector | SELECT | INSERT | UPDATE | DELETE | Filter Pushdown |
|---|---|---|---|---|---|
| ServiceNow | ✅ | ✅ | ✅ | ✅ | ✅ |
| CSV | ✅ | ✅ | ✅ | ✅ | ❌ |
| SQLite | ✅ | ✅ | ✅ | ✅ | ✅ |
| Airtable | ✅ | ✅ | ✅ | ✅ | ✅ |
See ROADMAP.md for phased delivery (Phase 2 current focus).
import sidol
db = sidol.connect()
db.register("incidents", sidol.ServiceNowConnector(instance="myco", table="incident", ...))
db.register("local", sidol.SQLiteConnector(path="./data.db"))
tbl = db.sql("SELECT number, state FROM incidents WHERE priority = 1") # pyarrow.Table
db.sql("UPDATE incidents SET state = 'closed' WHERE number = 'INC001'")uv is a fast Python package manager. Install it once, then:
# Install uv (one-time)
# Windows:
winget install --id=astral-sh.uv -e
# macOS/Linux:
curl -LsSf https://astral.sh/uv/install.sh | sh
# Clone & install all dependencies in ~2 seconds
git clone https://github.com/mitayan0/sidol
cd sidol
uv sync
# Run tests
uv run pytest
# Run linter
uv run ruff check sidol/
# Type-check
uv run mypy sidol/pip install -e .
pip install pytest pytest-asyncio respx mypy ruff
python -m pytestSQL string
│
├─ SELECT ──→ DuckDB (in-memory) ──→ connector.fetch() per table ──→ DataFrame
│
└─ DML ─────→ sqlglot AST ──→ extract table/values/filters ──→ connector.insert/update/delete()
Three layers:
- SQL interface —
sidol.connect(),db.sql(),db.register() - Router —
sidol/router.pyparses and dispatches - Connectors — pluggable
BaseConnectorimplementations
from sidol.connectors.base import BaseConnector
from sidol.types import Schema, Column, Capabilities, WriteResult
class MyConnector(BaseConnector):
def schema(self) -> Schema:
return Schema(tables={"mytable": [Column("id", "int", primary_key=True)]})
def fetch(self, table, columns, filters, limit, offset):
yield {"id": 1, "name": "hello"}
def capabilities(self) -> Capabilities:
return Capabilities(readable=True, insertable=True)
def insert(self, table, rows) -> WriteResult:
...
return WriteResult(affected_rows=len(rows))| Statement | Support |
|---|---|
SELECT |
✅ Full (via DuckDB — JOINs, aggregates, CTEs) |
INSERT INTO t (cols) VALUES (...) |
✅ Literal values only |
UPDATE t SET col=val WHERE ... |
✅ Simple equality filters |
DELETE FROM t WHERE ... |
✅ Simple equality filters |
CREATE TABLE |
❌ Not supported in v1 |
| Subqueries in DML | ❌ Not supported in v1 |
MIT — see LICENSE