Toasty is an ORM for Rust that supports both SQL and NoSQL databases. The project is in incubating status - not production-ready, with evolving APIs and limited documentation.
When working on Toasty, follow this decision tree to efficiently navigate the codebase and make changes:
First, understand what type of change you're making:
- Is it a new feature? → Check docs/CHANGE_GUIDE.md for similar patterns
- Is it a bug fix? → Read relevant component CONTEXT.md files
- Is it a refactor? → Review docs/ARCHITECTURE.md for design principles
Use the architecture layers to find where changes belong:
User-facing API changes → crates/toasty/
Code generation changes → crates/toasty-codegen/
Core types/schemas → crates/toasty-core/
SQL generation → crates/toasty-sql/
Database-specific → crates/toasty-driver-*/
Most changes cascade through layers in this order:
- Define in toasty-core (types, schemas, statements)
- Generate in toasty-codegen (user API)
- Process in toasty/engine (simplify → plan → execute)
- Serialize in toasty-sql (if SQL databases)
- Execute in drivers (database-specific)
Start: docs/CHANGE_GUIDE.md § "Adding a New Primitive Type"
Read: toasty-core/CONTEXT.md § "Adding a New Primitive Type"
Follow: The 7-step process with example commits
Start: docs/CHANGE_GUIDE.md § "Adding a Query Feature"
Read: toasty/CONTEXT.md § "Query Execution Pipeline"
Check: toasty-sql/CONTEXT.md for SQL generation
Start: toasty-driver-sqlite/CONTEXT.md (template for all drivers)
Read: docs/ARCHITECTURE.md § "Driver Layer"
Reference: Existing driver implementations
Start: toasty/CONTEXT.md § "Simplification"
Read: Recent commits for simplification patterns
Focus: engine/simplify/ directory
Before making changes, trace the impact:
- Read the component's CONTEXT.md to understand responsibilities
- Check docs/ARCHITECTURE.md for layer dependencies
- Review docs/CHANGE_GUIDE.md for similar past changes
- Look for Visit/VisitMut traits that need updating (for AST changes)
Testing Guidelines:
- No unit tests: Avoid
#[test]or#[cfg(test)]in source code unless explicitly requested - Test public APIs only: Focus on testing the user-facing interface, not internal implementation
- Full-stack database tests: Go in the workspace
tests/crate (uses actual databases) - Non-database tests: Go in individual crate's
tests/directory (e.g., testing stmt types)
Based on change type:
- Core types: Unit tests in module
- Codegen: UI tests for compile errors
- Engine: Integration tests across all drivers
- Drivers: Database-specific integration tests
Test placement examples:
- Database integration tests →
tests/tests/my_feature.rs - Statement parsing tests →
crates/toasty-core/tests/stmt_tests.rs
From recent development:
- Use specific imports, not glob imports
- Generate minimal code with fully qualified paths (#toasty::)
- Implement Visit/VisitMut for new AST nodes
- Handle NULL in value conversions
- Test with all database drivers
Debugging approach:
- Check what layer the issue is in
- Read that component's CONTEXT.md
- Find similar code in recent commits (docs/CHANGE_GUIDE.md has examples)
- Trace through the execution pipeline
- Use debug assertions and dbg!() macros
Keep these in mind:
- Zero-cost abstractions (no runtime overhead)
- Type safety (catch errors at compile time)
- Driver abstraction (work uniformly across databases)
- Stream processing (avoid loading everything into memory)
- Index awareness (use indexes when available)
- toasty-core: Defines all types and interfaces (no implementation)
- toasty-codegen: Generates user-facing API from macros
- toasty: Runtime engine that executes queries
- toasty-sql: Converts statements to SQL strings
- toasty-driver-*: Database-specific implementations
# Basic commands
cargo build
cargo test
cargo check
# Test specific database backends
cargo test --features sqlite
cargo test --features postgresql
cargo test --features mysql
cargo test --features dynamodb
# Run/check examples
./scripts/gen-examples run # Run all examples
./scripts/gen-examples # Check all examples
# Run a single test
cargo test test_name -- --nocaptureWhen working on Toasty engine changes, follow this established pattern:
-
Clarify Before Implementing
- Ask follow-up questions to understand the full scope
- Identify edge cases and potential issues
- Understand how the change fits into Toasty's architecture
-
Design and Sketch First
- Present a design sketch or plan before writing code
- Break complex changes into phases
- Get feedback on the approach
- Use TodoWrite to track multi-phase implementations
-
Consult Documentation
- Review
docs/ARCHITECTURE.mdfor system design - Check existing similar code for patterns
- Review
-
Implement Incrementally
- Make changes in small, compilable increments
- Test each phase before moving to the next
- Document learnings as you go
-
Always create an implementation plan before starting work - break changes into small, manageable steps
-
Bias toward small increments - prefer multiple small changes over large ones
-
Report unexpected fallout immediately - do not power through compilation errors or test failures
-
Unexpected issues indicate faulty assumptions - stop and reassess implementation strategy
-
Validate each step - ensure each increment compiles and existing tests pass before proceeding
-
PAUSE AND ASK when encountering architectural decisions - If you need to:
- Make private APIs public
- Add new dependencies
- Duplicate existing code
- Work around architectural constraints
Stop and ask: "I need to [describe need]. The current code [describe constraint]. Should I [option A] or [option B]?"
- The codebase uses async/await throughout - all database operations are async
- Error handling uses
anyhow::Result<T>- comprehensive error handling is still being developed - When modifying drivers, ensure changes work across all database backends
- Schema changes require updates to both app and db schema representations
- New model features need implementation in toasty-macros and toasty-codegen
- IMPORTANT: Before modifying code in
crates/toasty/src/engine, consultdocs/ARCHITECTURE.mdfor detailed engine architecture documentation - Test infrastructure: Multi-database test infrastructure in
tests/crate - Tests run against all enabled database backends via feature flags
- Test macros:
tests!()andmodels!()for multi-database testing - Connection strings:
"sqlite::memory:","postgres://..."
- docs/ARCHITECTURE.md: System design and component relationships
- docs/CHANGE_GUIDE.md: How to make common changes with examples
- docs/CONTEXT.md: Writing style guidelines for documentation (load when editing docs/)
- Component CONTEXT.md files: Deep dive into each component
- This file (CLAUDE.md): Navigation guide for using the documentation
When editing files in certain directories, load the corresponding CONTEXT.md:
- docs/: Load
docs/CONTEXT.mdfor documentation writing guidelines
The codebase follows predictable patterns. Most changes you'll make have been done before in similar ways. Use the commit history and documentation to find these patterns and follow them.