milvusql
A PEP 249 DBAPI (sync + async) for Milvus — parses/generates MilvusQL via sqlglot-milvus and executes the resulting AST against pymilvus.
Why a DBAPI, not a client wrapper?
| Feature | milvusql | raw pymilvus |
|---|---|---|
| Query surface | SQL (MilvusQL) | Python method calls |
| Parameterized queries | ✅ :name binds |
⚠️ manual dict-building |
Standard Connection/Cursor (PEP 249) |
✅ | ❌ |
| Sync + async, same dispatch table | ✅ | ⚠️ separate MilvusClient/AsyncMilvusClient |
| Drop-in for SQLAlchemy / Django | ✅ milvusql-sqlalchemy, milvusql-django |
❌ |
Auto-LOAD on first use, cached per connection |
✅ | manual load_collection() |
| Consistency-level fallback (per-connection default, per-query override) | ✅ | manual per-call |
Writing MilvusQL instead of chaining pymilvus calls means the same SELECT ... ORDER BY embedding <=> :q LIMIT n string works whether it's typed by hand, generated by an ORM, or built by an LLM tool call — and it works the same way from cursor.execute() or await acursor.execute(), off one shared parser and dispatch table (translate.ast_to_pymilvus).
Installation
pip install milvusql
Quick start
import milvusql
conn = milvusql.connect(uri="./items.db") # Milvus Lite, or a real server's URI
cur = conn.cursor()
cur.execute(
"""
CREATE TABLE items (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
embedding VECTOR(8),
category VARCHAR(64)
) WITH (shards=1, consistency_level='Strong')
"""
)
cur.execute(
"CREATE INDEX idx_embedding ON items (embedding) USING HNSW WITH (metric_type='COSINE')"
)
cur.executemany(
"INSERT INTO items (embedding, category) VALUES (:embedding, :category)",
[{"embedding": [0.1] * 8, "category": "book"}],
)
cur.execute("SELECT id FROM items WHERE category = :cat LIMIT 10", {"cat": "book"})
print(cur.fetchall())
cur.execute(
"SELECT id FROM items ORDER BY embedding <=> :q LIMIT 5",
{"q": [0.1] * 8},
)
print(cur.fetchall())
The same program, asyncio-native, over milvusql.aio (built on pymilvus.AsyncMilvusClient):
from milvusql import aio
conn = aio.connect(uri="./items.db")
cur = conn.cursor()
await cur.execute("SELECT id FROM items WHERE category = :cat", {"cat": "book"})
async for row in cur:
print(row)
await conn.close()
API
milvusql.connect()
milvusql.connect(
uri="http://localhost:19530", # or a Milvus Lite file path
token="", # "user:password", or a full token string
db_name="",
consistency_level=None, # per-connection default; a query's own CONSISTENCY LEVEL wins
**kwargs, # passed straight through to pymilvus.MilvusClient
) -> Connection
Connection |
Description |
|---|---|
.cursor() |
Returns a new Cursor bound to this connection |
.commit() |
No-op — every statement is already applied when it returns |
.rollback() |
Raises NotSupportedError — Milvus has no multi-statement rollback; catch and compensate instead |
.close() |
Closes the underlying MilvusClient |
| Context manager | with milvusql.connect(...) as conn: ... |
Cursor |
Description |
|---|---|
.execute(operation, parameters=None) |
Runs one statement; parameters binds :name placeholders |
.executemany(operation, seq_of_parameters) |
Batched INSERT in one round trip where the statement allows it; falls back to one call per parameter set otherwise |
.fetchone() / .fetchmany(size) / .fetchall() |
Read back result rows |
.description, .rowcount, .lastrowid, .arraysize |
Standard PEP 249 attributes |
| Iteration | for row in cursor: ... |
milvusql.aio.connect()/AsyncConnection/AsyncCursor mirror the same shape, async/await throughout — deliberately not PEP 249 itself (execute() as a coroutine can't be), but built on the same parser, dispatch table, and error hierarchy as the sync path.
Errors
Standard PEP 249 hierarchy, importable from milvusql:
Warning
Error
├── InterfaceError
└── DatabaseError
├── DataError
├── OperationalError
├── IntegrityError
├── InternalError
├── ProgrammingError
└── NotSupportedError
Every pymilvus exception and gRPC error raised while executing a statement is translated into one of these before it reaches your code.
Packages
This is the core of a uv workspace. Two packages build on milvusql's DBAPI:
| Package | Description |
|---|---|
milvusql-sqlalchemy |
SQLAlchemy 2.0 dialect — VECTOR/SPARSEVEC column types, hybrid_search(), Alembic support |
milvusql-django |
Django database backend — VectorField, ORM CRUD/filtering through the normal compiler |
Each is installed and versioned separately; both depend on this package as their DBAPI layer.
Examples
| Example | Shows |
|---|---|
examples/basic_walkthrough |
A guided, top-to-bottom tour of the DBAPI: connect, CREATE TABLE/CREATE INDEX, insert, filter SELECT, vector search, UPDATE/DELETE — sync and async |
examples/temporal_worker |
A Temporal workflow/activity that inserts rows into Milvus as a durable, retry-safe ingestion pipeline |
See also milvusql-sqlalchemy's own examples (a FastAPI image-search service, a pydantic-ai agent).
Development
Requires Python 3.12+, uv, task.
task install # uv sync --all-groups --all-packages
task lint # ruff + ty + bandit for core + all packages
task tests # all tests (core + sqlalchemy + django) -- integration tests need Docker (testcontainers)
Individual package tasks:
task core:lint task core:test
task sqlalchemy:lint task sqlalchemy:test
task django:lint task django:test
License
MIT
Release files for milvusql 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| milvusql-0.1.4.tar.gz | 30.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| milvusql-0.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 66.3 kB
Release files / milvusql-0.1.4.tar.gz
| Download URL | milvusql-0.1.4.tar.gz |
|---|---|
| Size | 30.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bcefcf7da06385dfc1c01faf2d294e377aad1ea62507b556646b0c2398eebd35
|
|
BLAKE2b-256 checksum How to use checksums |
bb0d65d966dfa31bd513616ebc447f133c87f59fcaab146d178c33dfd627b7bb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / milvusql-0.1.4-py3-none-any.whl
| Download URL | milvusql-0.1.4-py3-none-any.whl |
|---|---|
| Size | 35.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b19b02e9b65ac9ab75fa93b8a0eb21a21a5c0d44f679f2f02f0b9dd2f5f59a03
|
|
BLAKE2b-256 checksum How to use checksums |
81bd39806e51ca3fa0dac9c77d6c661c4974bcebffce7a3970f4bcb9a45a8154
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|