Metadata-Version: 2.4
Name: sqlxtralite
Version: 0.1.0
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Database
Classifier: Intended Audience :: Developers
Summary: Python (DB-API 2.0) binding for SQLXtraLite — a from-scratch SQL engine in Rust
Keywords: sql,database,embedded,sqlite,rust
Author-email: Barış Akın <barisakin@gmail.com>
License: AGPL-3.0-only
Requires-Python: >=3.8
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://github.com/parisxmas/SQLXtraLite
Project-URL: Repository, https://github.com/parisxmas/SQLXtraLite

# SQLXtraLite — Python binding (PyO3, DB-API 2.0)

A native CPython extension built with [PyO3](https://pyo3.rs) that calls the Rust
engine directly (no C-ABI round-trip) and exposes a small **DB-API 2.0** surface.
Values come back as **native Python types** (`int`, `float`, `str`, `bytes`,
`None`).

> There's also a zero-dependency `ctypes` binding in `../python/` — no build tools,
> but it returns string values. This PyO3 binding is the idiomatic, pip-installable
> one. The engine crate itself stays dependency-free; PyO3 lives only here.

## Build & install

```sh
# from this directory (bindings/pyo3)
pip install maturin

maturin develop --release      # build + install into the current venv
# or build a redistributable wheel:
maturin build --release        # -> target/wheels/sqlxtralite-*.whl
pip install target/wheels/sqlxtralite-*.whl
```

A plain `cargo build --release` also links a loadable module here (via
`.cargo/config.toml`); rename `target/release/libsqlxtralite.dylib` → `sqlxtralite.so`
(`.so` on Linux) on your `PYTHONPATH` to import it without maturin.

## Use

```python
import sqlxtralite

con = sqlxtralite.connect("shop.db")
cur = con.cursor()
cur.execute("CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT, price REAL)")

cur.executemany("INSERT INTO items VALUES (?, ?, ?)",
                [(1, "basil", 2.95), (2, "mint", None)])

cur.execute("SELECT * FROM items WHERE price > ?", (1.0,))
print(cur.description)     # [('id', None, …), ('name', …), ('price', …)]
print(cur.fetchall())      # [(1, 'basil', 2.95)]   ← native int / str / float
print(cur.lastrowid, cur.rowcount)
con.close()
```

## API (DB-API 2.0 subset)

Module: `connect(path)`, `apilevel = "2.0"`, `threadsafety = 1`,
`paramstyle = "qmark"`, `Error`.

| Object | Methods / attrs |
|---|---|
| `Connection` | `cursor()`, `execute(sql, params=None)`, `commit()`, `rollback()`, `close()`, context manager |
| `Cursor` | `execute(sql, params=None)`, `executemany(sql, seq)`, `fetchone()`, `fetchmany(size=1)`, `fetchall()`, `description`, `rowcount`, `lastrowid`, `close()` |

Parameters use **qmark** style (`?`), positional; `None`→NULL, `int`/`float`/`str`/
`bytes` bind directly. Prepared statements are used automatically when you pass
params (and for `executemany`), giving the engine's fast bind path.

## Run the test

```sh
maturin develop --release
python3 test_dbapi.py
# OK — PyO3 DB-API binding works
```

## Notes

- `Connection`/`Cursor` are `unsendable` — use one connection per thread (the
  engine is single-writer; the GIL serializes calls anyway).
- SQLXtraLite auto-commits each statement, so `commit()`/`rollback()` are no-ops
  provided for DB-API shape; use explicit `BEGIN`/`COMMIT` SQL for multi-statement
  transactions.

