Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Toasty ORM - Development Roadmap

This roadmap outlines potential enhancements and missing features for the Toasty ORM.

Overview

Toasty is an easy-to-use ORM for Rust that supports both SQL and NoSQL databases. This roadmap documents potential future work and feature gaps.

Feature Areas

Composite Keys

Composite Key Support (partial implementation)

  • Composite foreign key optimization in query simplification
  • Composite PK handling in expression rewriting and IN-list operations
  • HasMany/BelongsTo relationships with composite foreign keys referencing composite primary keys
  • Junction table / many-to-many patterns with composite keys
  • DynamoDB driver: batch delete/update with composite keys, composite unique indexes
  • Comprehensive test coverage for all composite key combinations

Query Capabilities

Query Ordering, Limits & Pagination

  • Multi-column ordering convenience method (.then_by())
  • Direct .limit() method for non-paginated queries
  • .last() convenience method

Query Constraints & Filtering

  • String operations: contains, starts with, ends with, LIKE (partial AST support)
  • NOT IN
  • Case-insensitive matching
  • BETWEEN / range queries
  • Relation filtering (filter by associated model fields)
  • Field-to-field comparison
  • Arithmetic operations in queries (add, subtract, multiply, divide, modulo)
  • Aggregate queries and GROUP BY / HAVING

Data Types

Extended Data Types

  • Embedded struct & enum support (partial implementation)
  • Serde-serialized types (JSON/JSONB columns for arbitrary Rust types)
  • Embedded collections (arrays, maps, sets, etc.)

Relationships & Loading

Partial Model Loading

  • Allow models to have fields that are not loaded by default (e.g. a large body column on an Article model)
  • Fields opt-in via a #[deferred] attribute and must be wrapped in a Deferred<T> type
  • By default, queries skip deferred fields; callers opt-in with .include(Article::body) (same API as relation preloading)
  • Accessing a Deferred<T> that was not loaded either returns an error or panics with a clear message
  • Works with primitive types, embedded structs, and embedded enums — just a subset of columns in the same table
    #![allow(unused)]
    fn main() {
    #[toasty::model]
    struct Article {
        #[key]
        #[auto]
        id: u64,
        title: String,
        author: BelongsTo<User>,
        #[deferred]
        body: Deferred<String>,   // not loaded unless explicitly included
    }
    
    // Load metadata only (no body column fetched)
    let articles = Article::all().collect(&db).await?;
    
    // Load with body
    let articles = Article::all().include(Article::body).collect(&db).await?;
    }

Relationships

  • Many-to-many relationships
  • Polymorphic associations
  • Nested preloading (multi-level .include() support)

Query Building

Query Features

  • Subquery improvements
  • Better conditional/dynamic query building ergonomics

Database Function Expressions

  • Allow database-side functions (e.g. NOW(), CURRENT_TIMESTAMP) as expressions in create and update operations
  • User API: field setters accept toasty::stmt helpers like toasty::stmt::now() that resolve to core::stmt::ExprFunc variants
    #![allow(unused)]
    fn main() {
    // Set updated_at to the database's current time instead of a Rust-side value
    user.update()
        .updated_at(toasty::stmt::now())
        .exec(&db)
        .await?;
    
    // Also usable in create operations
    User::create()
        .name("Alice")
        .created_at(toasty::stmt::now())
        .exec(&db)
        .await?;
    }
  • Extend ExprFunc enum in toasty-core with new function variants (e.g. Now)
  • SQL serialization for each function across supported databases (NOW() for PostgreSQL/MySQL, datetime('now') for SQLite)
  • Codegen: update field setter generation to accept both value types and function expressions
  • Future: support additional scalar functions (e.g. COALESCE, LOWER, UPPER, LENGTH)

Raw SQL Support

  • Execute arbitrary SQL statements directly
  • Parameterized queries with type-safe bindings
  • Raw SQL fragments within typed queries (escape hatch for complex expressions)

Data Modification

Upsert

  • Insert-or-update: atomic INSERT ... ON CONFLICT DO UPDATE (PostgreSQL/SQLite), ON DUPLICATE KEY UPDATE (MySQL), MERGE (SQL Server/Oracle)
  • Insert-or-ignore (DO NOTHING / INSERT IGNORE)
  • Conflict target: by column(s), by constraint name, partial indexes (PostgreSQL)
  • Column update control: update all non-key columns, named subset, or raw SQL expression
  • Access to the proposed row via EXCLUDED pseudo-table in the update expression
  • Bulk upsert (multi-row VALUES)
  • DynamoDB: PutItem (unconditional replace) vs. UpdateItem with condition expression

Mutation Result Information

  • Return affected row counts from update operations (how many records were updated)
  • Return affected row counts from delete operations (how many records were deleted)
  • Better result types that provide operation metadata
  • Distinguish between “no rows matched” vs “rows matched but no changes needed”

Transactions

Atomic Batch Operations

  • Cross-database atomic batch API
  • Supported across SQL and NoSQL databases
  • Type-safe operation batching
  • All-or-nothing semantics

SQL Transaction API

  • Manual transaction control for SQL databases
  • BEGIN/COMMIT/ROLLBACK support
  • Savepoints and nested transactions
  • Isolation level configuration

Schema Management

Migrations

  • Schema migration system
  • Migration generation
  • Rollback support
  • Schema versioning
  • CLI tools for schema management

Toasty Runtime Improvements

Concurrent Task Execution

  • Replace the current ad-hoc background task with a proper in-flight task manager
  • Execute independent parts of an execution plan concurrently
  • Track and coordinate multiple in-flight tasks within a single query execution

Cancellation & Cleanup

  • Detect when the caller drops the future representing query completion
  • Perform clean cancellation on drop (rollback any incomplete transactions)
  • Ensure no resource leaks or orphaned database state on cancellation

Internal Instrumentation & Metrics

  • Instrument time spent in each execution phase (planning, simplification, execution, serialization)
  • Track CPU time consumed by query planning to detect expensive plans
  • Provide internal metrics for diagnosing performance bottlenecks

Performance

Query Engine Optimization

  • Dedicated post-lowering optimization pass for expensive predicate analysis (run once, not per-node)
  • Equivalence classes for transitive constraint reasoning (a = b AND b = 5 implies a = 5)
  • Structured constraint representation (constant bindings, range bounds, exclusion sets)
  • Targeted predicate normalization without full DNF conversion

Stored Procedures (Pre-Compiled Query Plans)

  • Compile query plans once and execute them many times with different parameter values
  • Skip the full compilation pipeline (simplification, lowering, HIR/MIR planning) on repeated calls
  • Parameterized statement AST with Param slots for value substitution at execution time
  • Pairs with database-level prepared statements for end-to-end optimization

Optimization Features

  • Bulk inserts/updates
  • Query caching
  • Connection pooling improvements

Developer Experience

Ergonomic Macros

  • toasty::query!() - Succinct query syntax that translates to builder DSL
    #![allow(unused)]
    fn main() {
    // Instead of: User::all().filter(...).order_by(...).collect(&db).await
    toasty::query!(User, filter: ..., order_by: ...).collect(&db).await
    }
  • toasty::create!() - Concise record creation syntax
    #![allow(unused)]
    fn main() {
    // Instead of: User::create().name("Alice").age(30).exec(&db).await
    toasty::create!(User, name: "Alice", age: 30).exec(&db).await
    }
  • toasty::update!() - Simplified update syntax
    #![allow(unused)]
    fn main() {
    // Instead of: user.update().name("Bob").age(31).exec(&db).await
    toasty::update!(user, name: "Bob", age: 31).exec(&db).await
    }

Tooling & Debugging

  • Query logging

Safety & Security

Sensitive Value Flagging

  • Flag sensitive fields (e.g. passwords, tokens, secrets) so they are automatically redacted in logs and debug output
  • Attribute-based opt-in: #[sensitive] on model fields marks values that must never appear in plaintext outside the database
  • All logging, query tracing, and error messages strip or mask flagged values
  • Prevents accidental credential leakage in application logs, query dumps, and diagnostics

Trusted vs Untrusted Input

  • Distinguish between values originating from untrusted user input and values produced internally by the query engine (e.g. literal numbers, generated keys)
  • Engine-produced values can skip escaping/parameterization since they are known-safe, reducing unnecessary overhead
  • Untrusted input continues to be parameterized or escaped to prevent SQL injection
  • Enables more efficient SQL generation without weakening safety guarantees for external data

Notes

The roadmap documents describe potential enhancements and missing features. For information about what’s currently implemented, refer to the user guide or test the API directly.