Skip to main content

Async SQLAlchemy-based implementation of the fastlite API

Project description

DeeBase

Async SQLAlchemy-based database library with an ergonomic, fastlite-inspired API

Python 3.14+ SQLAlchemy 2.0+ Tests License

DeeBase provides a simple, intuitive interface for async database operations in Python. Built on SQLAlchemy, it combines the ergonomics of fastlite with full async/await support and multi-database compatibility.

Features

  • ๐Ÿš€ Async/Await - Built for modern async Python (FastAPI, etc.)
  • ๐Ÿ“ Ergonomic API - Simple, intuitive database operations
  • ๐Ÿ”’ Type Safety - Optional dataclass support with IDE autocomplete
  • ๐ŸŽฏ Multi-Database - SQLite and PostgreSQL support
  • ๐Ÿ› ๏ธ Rich Types - Text, JSON, datetime, Optional support
  • โšก Dynamic Access - Access tables with db.t.tablename
  • ๐Ÿ” Views Support - Read-only database views
  • ๐ŸŽจ Error Handling - 6 specific exception types with rich context
  • ๐Ÿ“ค Code Generation - Export schemas as Python dataclasses

Quick Start

Installation

# Using uv (recommended)
uv add sqlalchemy aiosqlite

# Using pip
pip install sqlalchemy aiosqlite

Basic Example

from deebase import Database
from datetime import datetime

# Connect to database
db = Database("sqlite+aiosqlite:///myapp.db")

# Define schema
class User:
    id: int
    name: str
    email: str
    created_at: datetime

# Create table
users = await db.create(User, pk='id')

# Insert
user = await users.insert({
    "name": "Alice",
    "email": "alice@example.com",
    "created_at": datetime.now()
})
# Returns: {'id': 1, 'name': 'Alice', 'email': 'alice@example.com', ...}

# Query
all_users = await users()  # All records
user = await users[1]       # By primary key
user = await users.lookup(email="alice@example.com")  # By column

# Update
user['name'] = "Alice Smith"
await users.update(user)

# Delete
await users.delete(1)

await db.close()

Type Safety with Dataclasses

# Enable dataclass mode for type-safe operations
UserDC = users.dataclass()

# Now all operations return dataclass instances
user = await users[1]
print(user.name)  # IDE autocomplete works!
print(user.email)

# Insert with dataclass
new_user = await users.insert(UserDC(
    id=None,
    name="Bob",
    email="bob@example.com",
    created_at=datetime.now()
))

Rich Type System

from deebase import Database, Text
from typing import Optional
from datetime import datetime

class Article:
    id: int
    title: str              # VARCHAR (limited)
    content: Text           # TEXT (unlimited)
    metadata: dict          # JSON column
    tags: Optional[list]    # JSON, nullable
    published: bool         # BOOLEAN
    view_count: int         # INTEGER
    created_at: datetime    # TIMESTAMP
    updated_at: Optional[datetime]  # TIMESTAMP, nullable

articles = await db.create(Article, pk='id')

article = await articles.insert({
    "title": "Getting Started",
    "content": "A very long article...",
    "metadata": {"author": "Alice", "category": "tutorial"},
    "tags": ["python", "async"],
    "published": True,
    "view_count": 0,
    "created_at": datetime.now()
})

Error Handling

DeeBase provides specific exception types with rich context:

from deebase import NotFoundError, IntegrityError, ValidationError

try:
    user = await users[999]
except NotFoundError as e:
    print(f"Not found in {e.table_name}")
    print(f"Filters: {e.filters}")

try:
    await users.insert({"email": "duplicate@example.com"})
except IntegrityError as e:
    print(f"Constraint {e.constraint} violated")

try:
    await users.update({"name": "Missing PK"})  # No ID
except ValidationError as e:
    print(f"Invalid {e.field}: {e.value}")

Working with Existing Databases

# Connect to existing database
db = Database("sqlite+aiosqlite:///existing.db")

# Reflect all tables
await db.reflect()

# Access tables
users = db.t.users
posts = db.t.posts

# CRUD operations work normally
user = await users[1]
all_posts = await posts()

Database Views

# Create view
popular_posts = await db.create_view(
    "popular_posts",
    "SELECT * FROM posts WHERE views > 1000"
)

# Query view (read-only)
posts = await popular_posts()

# Access via db.v
view = db.v.popular_posts

Filtering with xtra()

# Create filtered view of table
admin_users = users.xtra(role="admin")
active_admins = admin_users.xtra(active=True)

# All operations respect filters
admins = await active_admins()

# Insert automatically sets filter values
await active_admins.insert({"name": "Eve", "email": "eve@example.com"})
# Automatically sets role='admin' and active=True

Code Generation

Export your database schema as Python dataclasses:

from deebase import create_mod_from_tables

# Connect and reflect
db = Database("sqlite+aiosqlite:///myapp.db")
await db.reflect()

# Export all tables to models.py
create_mod_from_tables(
    "models.py",
    db.t.users,
    db.t.posts,
    db.t.comments,
    overwrite=True
)

# Now you can:
# from models import User, Post, Comment

Examples

Runnable examples are available in the examples/ folder:

Run any example:

uv run examples/complete_example.py

Documentation

Supported Databases

Database Status Driver
SQLite โœ… Fully tested aiosqlite
PostgreSQL ๐Ÿšง Infrastructure ready asyncpg

Supported Python Types

Python Type Database Type Notes
int INTEGER
str VARCHAR Limited length
Text TEXT Unlimited length
float REAL/FLOAT
bool BOOLEAN 0/1 in SQLite
bytes BLOB/BYTEA
dict JSON Auto-serialized in SQLite
datetime TIMESTAMP
date DATE
time TIME
Optional[T] NULL-able Any type can be nullable

Exception Types

Exception When Raised Attributes
NotFoundError Record not found table_name, filters
IntegrityError Constraint violation constraint, table_name
ValidationError Invalid input field, value
SchemaError Schema error table_name, column_name
ConnectionError Connection failed database_url
InvalidOperationError Invalid operation operation, target

FastAPI Integration

from fastapi import FastAPI, Depends, HTTPException
from deebase import Database, NotFoundError

app = FastAPI()

def get_db():
    return Database("sqlite+aiosqlite:///myapp.db")

@app.get("/users")
async def list_users(db: Database = Depends(get_db)):
    users = db.t.users
    return await users()

@app.get("/users/{user_id}")
async def get_user(user_id: int, db: Database = Depends(get_db)):
    try:
        users = db.t.users
        return await users[user_id]
    except NotFoundError:
        raise HTTPException(status_code=404, detail="User not found")

Comparison with fastlite

DeeBase replicates the fastlite API with async support:

Feature fastlite DeeBase
Syntax Synchronous Async (requires await)
Backend sqlite-utils SQLAlchemy
Databases SQLite only SQLite + PostgreSQL
Type Safety Optional dataclasses Optional dataclasses
CRUD Operations Yes Yes
Views Yes Yes
Dynamic Access db.t.tablename db.t.tablename (after reflection)
Error Handling Basic 6 specific exception types
Code Generation No Yes (create_mod())

See the Migration Guide for detailed comparison.

Development

Running Tests

# Run all tests
uv run pytest

# Run with coverage
uv run pytest --cov=src/deebase --cov-report=html

# Run specific test file
uv run pytest tests/test_crud.py -v

All 161 tests passing โœ…

Project Structure

deebase/
โ”œโ”€โ”€ src/deebase/
โ”‚   โ”œโ”€โ”€ __init__.py           # Public API
โ”‚   โ”œโ”€โ”€ database.py           # Database class
โ”‚   โ”œโ”€โ”€ table.py              # Table operations
โ”‚   โ”œโ”€โ”€ view.py               # View support
โ”‚   โ”œโ”€โ”€ column.py             # Column access
โ”‚   โ”œโ”€โ”€ types.py              # Type mapping
โ”‚   โ”œโ”€โ”€ dataclass_utils.py    # Dataclass utilities
โ”‚   โ””โ”€โ”€ exceptions.py         # Exception classes
โ”œโ”€โ”€ tests/                     # 161 passing tests
โ”œโ”€โ”€ examples/                  # Runnable examples
โ”œโ”€โ”€ docs/                      # Documentation
โ””โ”€โ”€ README.md                  # This file

Requirements

  • Python 3.14+
  • sqlalchemy 2.0.45+
  • aiosqlite 0.22.0+
  • greenlet 3.3.0+ (for SQLAlchemy async)

Design Philosophy

DeeBase follows these principles:

  1. Start Simple - Begin with dicts, opt-in to dataclasses for type safety
  2. Async First - All operations are async for modern frameworks
  3. Database Agnostic - Write once, run on SQLite or PostgreSQL
  4. No Magic - Transparent SQLAlchemy usage with escape hatches
  5. Production Ready - Comprehensive error handling and testing

Status

All 8 development phases complete! Ready for production use.

  • โœ… Phase 1: Core Infrastructure
  • โœ… Phase 2: Table Creation & Schema
  • โœ… Phase 3: CRUD Operations
  • โœ… Phase 4: Dataclass Support
  • โœ… Phase 5: Dynamic Access & Reflection
  • โœ… Phase 6: xtra() Filtering
  • โœ… Phase 7: Views Support
  • โœ… Phase 8: Polish & Utilities

See Implementation Plan for details.

Contributing

This project follows an 8-phase development plan (now complete). See docs/implementation_plan.md for the roadmap.

License

TBD

Acknowledgments


Made with โค๏ธ for the async Python community

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

deebase-0.1.0.tar.gz (18.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

deebase-0.1.0-py3-none-any.whl (21.9 kB view details)

Uploaded Python 3

File details

Details for the file deebase-0.1.0.tar.gz.

File metadata

  • Download URL: deebase-0.1.0.tar.gz
  • Upload date:
  • Size: 18.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.8

File hashes

Hashes for deebase-0.1.0.tar.gz
Algorithm Hash digest
SHA256 87afed5b92e9bbdf57408a252c956d7948bfc253d3b36976ff616b65a96f307e
MD5 444cba031e78acf5cddb63a19c6db29c
BLAKE2b-256 18d986fd4b65c6839cd91c607c17f6b8accccb82d34987ca42787498060da7f2

See more details on using hashes here.

File details

Details for the file deebase-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: deebase-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 21.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.8

File hashes

Hashes for deebase-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e3e2a77a477332e31344b6df47b0e3e4fefb60554204242bce3c5f9a2c6aa621
MD5 d32fa465663e8f54984093c53f48c0a8
BLAKE2b-256 ebbb2b63ea7bfe9df70278ff863992ac87ce418e96de698496ed009b1f4f2c41

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page