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 pip
pip install deebase

# Using uv (recommended)
uv add deebase

DeeBase will automatically install its dependencies: SQLAlchemy, aiosqlite, asyncpg, and greenlet.

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

DeeBase supports two approaches for type-safe operations:

Option 1: Start with a plain class, generate dataclass later

# Create table from plain class
class User:
    id: int
    name: str
    email: str
    created_at: datetime

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

# Later, 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()
))

Option 2: Start with @dataclass (recommended for new code)

from dataclasses import dataclass
from datetime import datetime

@dataclass
class User:
    id: int
    name: str
    email: str
    created_at: datetime

# Create table - User is already a dataclass, no need for .dataclass()!
users = await db.create(User, pk='id')

# All operations automatically work with dataclass instances
user = await users[1]  # Returns User instance
print(user.name)       # IDE autocomplete works automatically!

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

# Mix dicts and dataclass instances as needed
await users.insert({"name": "Charlie", "email": "charlie@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

DeeBase documentation follows the Divio documentation system, providing four types of documentation for different needs:

                    DIVIO DOCUMENTATION SYSTEM

        Practical                    Theoretical
           โ”‚                              โ”‚
    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€
           โ”‚                              โ”‚
    TUTORIALS (learning-oriented)  EXPLANATION (understanding-oriented)
           โ”‚                              โ”‚
    โ€ข examples/                    โ€ข how-it-works.md
      - phase1_raw_sql.py          โ€ข migrating_from_fastlite.md
      - phase2_table_creation.py   โ€ข implemented.md
      - phase3_crud_operations.py
      - phase4_dataclass_support.py
      - phase5_reflection.py
      - phase7_views.py
      - phase8_polish_utilities.py
      - complete_example.py
           โ”‚                              โ”‚
    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€
           โ”‚                              โ”‚
    HOW-TO GUIDES (problem-oriented) REFERENCE (information-oriented)
           โ”‚                              โ”‚
    โ€ข best-practices.md            โ€ข api_reference.md
      - Dict vs Dataclass          โ€ข types_reference.md
      - Reflection decisions
      - Error handling patterns
      - Consistency strategies
           โ”‚                              โ”‚

By Type

๐Ÿ“š Tutorials (Learning-oriented - "I want to learn")

  • examples/ - Hands-on runnable examples for each phase

๐Ÿ”ง How-To Guides (Problem-oriented - "I want to solve a problem")

  • Best Practices - Design decisions and patterns (dict vs dataclass, reflection, consistency)

๐Ÿ“– Reference (Information-oriented - "I want to look up details")

๐Ÿ’ก Explanation (Understanding-oriented - "I want to understand")

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.2.0.tar.gz (19.8 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.2.0-py3-none-any.whl (23.3 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for deebase-0.2.0.tar.gz
Algorithm Hash digest
SHA256 f0b9ece0650c6379c8ddebcf7f978b296b5c21d796d8017f5d88fd063c2e4820
MD5 1354e6c4dd11e66580e4ac6274e230ef
BLAKE2b-256 ca66df38858865003f7071225fb1de9018a7a1c072ae732078b8638c019e815d

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for deebase-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 54c091cf61ea0644a6b454386366c735364771f175acc99b73102bf3cd32ddf0
MD5 31363a9bb6644c894032f5c912338543
BLAKE2b-256 d1bf5e4e9b2b13c97190ebcf1d515ba5f3c8c534c0fd873b44f1dc50486bc95c

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