From compound-engineering-feat-python
Async SQLAlchemy 2.0 patterns with FastAPI and Alembic migration management. Use when working on FastAPI projects with sqlalchemy in their dependencies.
npx claudepluginhub weorbitant/compound-engineering-feat-python-plugin --plugin compound-engineering-feat-pythonThis skill uses the workspace's default tool permissions.
Patterns for building FastAPI applications with async SQLAlchemy 2.0 and Alembic migrations.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Designs, implements, and audits WCAG 2.2 AA accessible UIs for Web (ARIA/HTML5), iOS (SwiftUI traits), and Android (Compose semantics). Audits code for compliance gaps.
Patterns for building FastAPI applications with async SQLAlchemy 2.0 and Alembic migrations. Covers session management, repository pattern, relationship loading, transaction handling, and zero-downtime migration strategies.
create_async_engine and async_sessionmaker for non-blocking I/Oselect() style instead of legacy Query APIsqlalchemy in its dependencies (check pyproject.toml or requirements.txt)from datetime import datetime
from sqlalchemy import String, func
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
email: Mapped[str] = mapped_column(String(255), unique=True, index=True)
name: Mapped[str] = mapped_column(String(100))
is_active: Mapped[bool] = mapped_column(default=True)
created_at: Mapped[datetime] = mapped_column(server_default=func.now())
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
engine = create_async_engine(
"postgresql+asyncpg://user:pass@localhost/dbname",
pool_size=20,
max_overflow=10,
pool_recycle=3600,
)
async_session_factory = async_sessionmaker(engine, expire_on_commit=False)
from collections.abc import AsyncGenerator
from fastapi import Depends
async def get_session() -> AsyncGenerator[AsyncSession, None]:
async with async_session_factory() as session:
yield session
@app.get("/users/{user_id}")
async def get_user(
user_id: int,
session: AsyncSession = Depends(get_session),
) -> User | None:
result = await session.execute(select(User).where(User.id == user_id))
return result.scalar_one_or_none()
Use | None instead of Optional for all type annotations:
def find_by_email(self, email: str) -> User | None:
...
async def list_users(
self, limit: int = 20, offset: int = 0
) -> list[User]:
...
Use emojis as prefixes in log messages:
logger.info("✅ User %s created successfully", user.id)
logger.warning("⚠️ Slow query detected: %dms for %s", duration_ms, query_name)
logger.error("❌ Database connection failed: %s", exc)
| Scenario | Approach |
|---|---|
| Simple CRUD endpoint | Session dependency + inline query |
| Complex query logic | Repository class method |
| Multiple writes in one request | Explicit transaction block |
| Eager load related data | selectinload for collections, joinedload for scalars |
| Add a column | Alembic migration with op.add_column |
| Rename a column safely | Three-step: add new, backfill, drop old |
| Bulk insert thousands of rows | session.execute(insert(Model), list_of_dicts) |
| Read-only reporting queries | Separate read replica engine |