Modern async database library with ORM, query builder, and migrations
Project description
PyAsyncDB
Modern asynchronous database library for Python with ORM, query builder, connection pooling, migrations, and more.
✨ Features
- ✅ Async/Await - Full async support for PostgreSQL, MySQL, SQLite
- ✅ ORM - Django-like model definitions with relationships
- ✅ Query Builder - Fluent SQL builder
- ✅ Connection Pooling - Efficient connection management
- ✅ Migrations - Schema version control with CLI
- ✅ Transactions - ACID transactions with nested savepoints
- ✅ Query Logging - Slow query detection and profiling
- ✅ Batch Operations - Bulk insert/update/delete
- ✅ Pydantic Integration - Automatic validation and serialization
- ✅ CLI Tool - Database management from command line
- ✅ Type Hints - Full type annotations
📦 Installation
pip install pyasyncdb
For Pydantic support:
pip install pyasyncdb[pydantic]
For development:
pip install pyasyncdb[dev]
🚀 Quick Start
Basic Usage
import asyncio
from asyncdb import Database
async def main():
db = Database("postgresql://user:pass@localhost/mydb")
async with db:
# Create table
await db.execute("""
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(255) UNIQUE
)
""")
# Insert
await db.execute(
"INSERT INTO users (name, email) VALUES ($1, $2)",
("John", "john@example.com")
)
# Select
users = await db.fetch_all("SELECT * FROM users")
print(users)
asyncio.run(main())
Transactions
from asyncdb import Database
db = Database("postgresql://localhost/mydb")
async with db:
async with db.transaction():
# All queries in transaction
await db.execute("INSERT INTO users (name) VALUES ($1)", ("Alice",))
await db.execute("UPDATE accounts SET balance = balance - 100 WHERE id = $1", (1,))
await db.execute("UPDATE accounts SET balance = balance + 100 WHERE id = $2", (2,))
# Automatically commits on success, rollbacks on error
ORM with Validation
from asyncdb import Database, Model, Field, PydanticModelMixin
db = Database("postgresql://localhost/mydb")
class User(Model, PydanticModelMixin):
__tablename__ = "users"
id = Field(primary_key=True, auto_increment=True)
name = Field(type="VARCHAR", max_length=100, nullable=False)
email = Field(type="VARCHAR", max_length=255, unique=True)
age = Field(type="INTEGER", default=0)
async with db:
await User.create_table(db)
# Create instance
user = User(name="Alice", email="alice@example.com", age=25)
await user.insert(db)
# Query with filters
users = await User.objects().filter(age__gte=18).all(db)
# Generate Pydantic schema
UserSchema = User.pydantic_model()
validated = UserSchema(name="Bob", email="bob@example.com")
Query Builder
from asyncdb import select, insert, update, delete
# SELECT with joins
q = (
select("users")
.columns("id", "name", "email")
.left_join("orders", "users.id = orders.user_id")
.where("age > $1", 18)
.and_where("status = $2", "active")
.order_by("name")
.limit(10)
)
sql, params = q.build()
# INSERT
q = insert("users").columns("name", "email").values("John", "john@example.com")
sql, params = q.build()
# UPDATE
q = update("users").set("email", "new@example.com").where("id = $1", 1)
sql, params = q.build()
# DELETE
q = delete("users").where("id = $1", 1)
sql, params = q.build()
Batch Operations
from asyncdb import Database, Model, Field
db = Database("postgresql://localhost/mydb")
class User(Model):
__tablename__ = "users"
name = Field(type="VARCHAR", max_length=100)
email = Field(type="VARCHAR", max_length=255)
async with db:
# Bulk insert
users = [
User(name="Alice", email="alice@example.com"),
User(name="Bob", email="bob@example.com"),
User(name="Charlie", email="charlie@example.com"),
]
await User.bulk_insert(db, users)
# Bulk update
for u in users:
u.name = u.name.upper()
await User.bulk_update(db, users)
# Bulk delete
await User.bulk_delete(db, [1, 2, 3])
Query Logging & Debugging
from asyncdb import Database
import logging
logging.basicConfig(level=logging.INFO)
# Enable query logging
db = Database("postgresql://localhost/mydb", echo=True, slow_query_threshold=0.5)
async with db:
await db.execute("SELECT * FROM users")
await db.execute("SELECT * FROM orders WHERE amount > 1000") # Slow query
# Get slow queries
slow = db.get_slow_queries()
print(f"Slow queries: {len(slow)}")
# Get all query log
log = db.get_query_log()
for entry in log:
print(f"{entry['duration']:.3f}s - {entry['query']}")
🛠 CLI Commands
# Set database URL
export DATABASE_URL="postgresql://user:pass@localhost/mydb"
# Run migrations
pyasyncdb migrate-up
# Rollback migrations
pyasyncdb migrate-down --steps 2
# Check migration status
pyasyncdb migrate-status
# Create new migration
pyasyncdb migrate-create add_users_table
# Interactive shell
pyasyncdb shell
# Inspect database
pyasyncdb inspect
📊 Database URLs
postgresql://user:pass@host:5432/dbname
mysql://user:pass@host:3306/dbname
sqlite:///path/to/database.db
📖 API Reference
Database
| Method | Description |
|---|---|
connect() |
Establish connection |
disconnect() |
Close connection |
execute(query, params) |
Execute query |
fetch_one(query, params) |
Fetch single row |
fetch_all(query, params) |
Fetch all rows |
fetch_val(query, params) |
Fetch single value |
fetch_col(query, params) |
Fetch single column |
transaction() |
Transaction context |
get_query_log() |
Get query history |
get_slow_queries() |
Get slow queries |
Model
| Method | Description |
|---|---|
create_table(db) |
Create table |
drop_table(db) |
Drop table |
insert(db) |
Insert instance |
update(db) |
Update instance |
delete(db) |
Delete instance |
save(db) |
Insert or update |
bulk_insert(db, instances) |
Bulk insert |
bulk_update(db, instances) |
Bulk update |
bulk_delete(db, ids) |
Bulk delete |
objects() |
Get queryset |
pydantic_model() |
Generate Pydantic schema |
QuerySet
| Method | Description |
|---|---|
filter(**kwargs) |
Add WHERE filters |
exclude(**kwargs) |
Add NOT filters |
order_by(*fields) |
Add ORDER BY |
limit(n) |
Add LIMIT |
offset(n) |
Add OFFSET |
all(db) |
Fetch all |
first(db) |
Fetch first |
count(db) |
Count records |
exists(db) |
Check existence |
📝 License
MIT License - see LICENSE for details.
🤝 Contributing
Contributions welcome! Please read our contributing guidelines first.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📧 Support
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyasyncdb_driver-0.2.0.tar.gz.
File metadata
- Download URL: pyasyncdb_driver-0.2.0.tar.gz
- Upload date:
- Size: 24.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c602e52005f9fa467b0432f83cebdc944b37b48bb2d8465a638779523b17775c
|
|
| MD5 |
2c58e63bbec44d44aa874c95c95c7d00
|
|
| BLAKE2b-256 |
4c5316acfca3c3c1550f66eaf5ea6b9e9ce1d85878965fd54ed30235185fd9f7
|
File details
Details for the file pyasyncdb_driver-0.2.0-py3-none-any.whl.
File metadata
- Download URL: pyasyncdb_driver-0.2.0-py3-none-any.whl
- Upload date:
- Size: 22.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c41682a584b5214b80a82b11931711c163bf5c6c3469642145833456be96ba0b
|
|
| MD5 |
ffd16c79d2ec9addabe5ff72fd49ab6d
|
|
| BLAKE2b-256 |
f15f50019f7d28f5293df683526f4fa79f6c8a981ae8b32f75713949753af371
|