database/writing-queries/SKILL.md
Write SQLAlchemy ORM models and queries following repository patterns, with guidance on when to use raw SQL.
npx skillsauth add 7a336e6e/skills Writing QueriesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
4 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Implement data access using SQLAlchemy ORM for standard CRUD operations and raw SQL for complex reporting queries. Follow the repository pattern to keep database logic isolated from business logic.
Models must match the schema defined in the designing-schemas skill. Use the declarative base and include all constraints.
from datetime import datetime
from sqlalchemy import Column, BigInteger, String, DateTime, func
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False)
password_hash: Mapped[str] = mapped_column(String(128), nullable=False)
display_name: Mapped[str] = mapped_column(String(100), nullable=False)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), nullable=False
)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), nullable=False
)
Encapsulate all database operations in a repository class. This keeps SQL logic out of service and route layers.
from sqlalchemy import select
from sqlalchemy.orm import Session
class UserRepository:
def __init__(self, session: Session):
self.session = session
def get_by_id(self, user_id: int) -> User | None:
return self.session.get(User, user_id)
def get_by_email(self, email: str) -> User | None:
stmt = select(User).where(User.email == email)
return self.session.scalars(stmt).first()
def create(self, email: str, password_hash: str, display_name: str) -> User:
user = User(
email=email,
password_hash=password_hash,
display_name=display_name,
)
self.session.add(user)
self.session.flush()
return user
def update(self, user: User, **kwargs) -> User:
for key, value in kwargs.items():
setattr(user, key, value)
self.session.flush()
return user
def delete(self, user: User) -> None:
self.session.delete(user)
self.session.flush()
Use scoped sessions with explicit commit and rollback boundaries. Never leave sessions open across request boundaries.
from contextlib import contextmanager
from sqlalchemy.orm import sessionmaker, Session
@contextmanager
def get_session(session_factory: sessionmaker) -> Session:
session = session_factory()
try:
yield session
session.commit()
except Exception:
session.rollback()
raise
finally:
session.close()
Use eager loading when you know related data will be accessed. Choose joinedload for single-valued relationships and selectinload for collections.
from sqlalchemy.orm import joinedload, selectinload
# Load user with their profile (one-to-one)
stmt = select(User).options(joinedload(User.profile)).where(User.id == user_id)
# Load project with all tasks (one-to-many)
stmt = select(Project).options(selectinload(Project.tasks)).where(Project.id == project_id)
For reporting, analytics, or queries that are awkward in the ORM, use raw SQL with parameterized queries.
from sqlalchemy import text
stmt = text("""
SELECT u.display_name, COUNT(t.id) AS task_count
FROM users u
JOIN task_assignments ta ON ta.user_id = u.id
JOIN tasks t ON t.id = ta.task_id
WHERE t.status = :status
GROUP BY u.display_name
ORDER BY task_count DESC
LIMIT :limit
""")
result = session.execute(stmt, {"status": "completed", "limit": 10})
rows = result.mappings().all()
| Use Case | Approach | Reason | |------------------------|-----------|-------------------------------------------| | CRUD operations | ORM | Clear, type-safe, easy to maintain | | Simple filters/joins | ORM | Readable and composable | | Complex aggregations | Raw SQL | ORM syntax becomes unwieldy | | Bulk updates/deletes | Raw SQL | ORM loads every row; raw SQL is faster | | Reporting queries | Raw SQL | Multiple joins, CTEs, window functions |
Produce a Python module containing the SQLAlchemy model class, a repository class with CRUD methods, and a session management utility. Include docstrings on all public methods. Add inline comments for non-obvious query logic.
development
Implement features using the Red-Green-Refactor cycle to ensure testability and correctness from the start.
data-ai
Manage the `tasks.md` ledger with strict locking and collision avoidance protocols to allow multiple agents to work in parallel safely.
development
The git-workflow skill defines branching conventions, commit message formats, and pull request standards that all agents must follow for consistent version control.
development
The environment-config skill standardizes how agents manage environment variables, secrets, and application configuration across local development and deployed environments.