prax-orm 0.11.0

A next-generation, type-safe ORM for Rust inspired by Prisma
Documentation
---
import DocsLayout from '../../layouts/DocsLayout.astro';
import CodeBlock from '../../components/CodeBlock.astro';

const basicHandling = `use prax_query::{QueryError, ErrorCode};

// Handle specific error types
match result {
    Ok(user) => println!("Found user: {:?}", user),
    Err(e) if e.is_not_found() => {
        println!("User not found");
    }
    Err(e) if e.is_constraint_violation() => {
        println!("Constraint violated: {}", e.message);
    }
    Err(e) if e.is_timeout() => {
        println!("Query timed out");
    }
    Err(e) if e.is_retryable() => {
        println!("Transient error, retrying...");
        // Retry logic
    }
    Err(e) => {
        println!("Error [{}]: {}", e.code, e.message);
    }
}`;

const errorCodes = `// Error codes follow the Pxxxx format

// Query Errors (P1xxx)
ErrorCode::RecordNotFound       // P1001
ErrorCode::NotUnique            // P1002
ErrorCode::InvalidFilter        // P1003
ErrorCode::RequiredFieldMissing // P1005

// Constraint Errors (P2xxx)
ErrorCode::UniqueConstraint     // P2001
ErrorCode::ForeignKeyConstraint // P2002
ErrorCode::NotNullConstraint    // P2004

// Connection Errors (P3xxx)
ErrorCode::ConnectionFailed     // P3001
ErrorCode::PoolExhausted        // P3002
ErrorCode::AuthenticationFailed // P3004

// Transaction Errors (P4xxx)
ErrorCode::Deadlock             // P4002
ErrorCode::SerializationFailure // P4003

// Query Execution (P5xxx)
ErrorCode::QueryTimeout         // P5001
ErrorCode::SqlSyntax            // P5002`;

const actionableErrors = `use prax_query::QueryError;

// Errors include actionable suggestions
let err = QueryError::unique_violation("User", "email");
println!("{}", err.display_full());

// Output:
// Error [P2001]: Unique constraint violated on User.email
//   → Model: User
//   → Field: email
//
// Suggestions:
//   1. A record with this email already exists
//   2. Use upsert() to update if exists, create if not
//      \`\`\`
//      client.user().upsert()
//        .where(user::email::equals(value))
//        .create(...)
//        .update(...)
//        .exec().await
//      \`\`\`
//
// More info: https://prax.rs/docs/errors/P2001`;

const coloredOutput = `use prax_query::QueryError;

// Display with ANSI colors for terminal
let err = QueryError::not_found("User")
    .with_context("Finding user by email")
    .with_suggestion("Verify the user exists");

// Colored output for CLI tools
eprintln!("{}", err.display_colored());

// Plain text for logging
log::error!("{}", err.display_full());`;

const customContext = `use prax_query::{QueryError, ErrorCode, Suggestion};

// Add context to errors
let err = QueryError::not_found("User")
    .with_context("Authenticating user login")
    .with_model("User")
    .with_field("email")
    .with_suggestion("Check the email address is correct")
    .with_code_suggestion(
        "Register the user first",
        "client.user().create(data! { email, password }).exec().await"
    )
    .with_help("Users must be registered before they can log in");

// Access error details
println!("Code: {}", err.code);           // P1001
println!("Message: {}", err.message);
println!("Model: {:?}", err.context.model);
println!("Docs: {}", err.docs_url());`;

const errorChecks = `use prax_query::QueryError;

// Boolean checks for error categories
fn handle_error(err: &QueryError) {
    // Record errors
    if err.is_not_found() { /* ... */ }

    // Constraint violations
    if err.is_constraint_violation() { /* ... */ }

    // Timeout errors (connection or query)
    if err.is_timeout() { /* ... */ }

    // Connection-related errors
    if err.is_connection_error() { /* ... */ }

    // Can this error be retried?
    if err.is_retryable() {
        // Safe to retry: timeouts, deadlocks, pool exhaustion
    }
}`;

const errorMacro = `use prax_query::{query_error, ErrorCode};

// Create custom errors with the macro
let err = query_error!(
    ErrorCode::InvalidParameter,
    "Email format is invalid",
    with_field = "email",
    with_suggestion = "Use a valid email like user@example.com",
    with_help = "Email must contain @ and a domain"
);`;
---

<DocsLayout title="Error Handling - Prax ORM">
  <article class="max-w-4xl mx-auto px-6 py-12">
    <header class="mb-12">
      <h1 class="text-4xl font-bold mb-4">Error Handling</h1>
      <p class="text-xl text-muted">
        Prax provides comprehensive error types with unique error codes, actionable suggestions,
        and helpful context to quickly diagnose and fix issues.
      </p>
    </header>

    <nav class="mb-8 p-4 bg-surface rounded-lg border border-border">
      <h3 class="text-sm font-semibold text-muted mb-2">On this page</h3>
      <ul class="space-y-1 text-sm">
        <li><a href="#handling" class="text-primary-400 hover:text-primary-300">Basic Handling</a></li>
        <li><a href="#codes" class="text-primary-400 hover:text-primary-300">Error Codes</a></li>
        <li><a href="#actionable" class="text-primary-400 hover:text-primary-300">Actionable Messages</a></li>
        <li><a href="#context" class="text-primary-400 hover:text-primary-300">Adding Context</a></li>
        <li><a href="#checks" class="text-primary-400 hover:text-primary-300">Error Checks</a></li>
      </ul>
    </nav>

    <div class="space-y-12">

    <section id="handling" class="mb-12">
      <h2 class="text-2xl font-semibold mb-4">Basic Error Handling</h2>
      <p class="text-muted mb-4">
        Use pattern matching or boolean checks to handle different error types.
      </p>

      <CodeBlock code={basicHandling} lang="rust" filename="Error Handling" />
    </section>

    <section id="codes" class="mb-12">
      <h2 class="text-2xl font-semibold mb-4">Error Codes</h2>
      <p class="text-muted mb-4">
        Every error has a unique code in the <code>Pxxxx</code> format for easy identification and documentation lookup.
      </p>

      <CodeBlock code={errorCodes} lang="rust" filename="Error Code Reference" />

      <div class="mt-6">
        <h4 class="font-semibold mb-3">Error Code Categories</h4>
        <table class="w-full text-sm">
          <thead>
            <tr class="border-b border-border">
              <th class="text-left py-2 text-muted">Range</th>
              <th class="text-left py-2 text-muted">Category</th>
              <th class="text-left py-2 text-muted">Description</th>
            </tr>
          </thead>
          <tbody class="text-muted">
            <tr class="border-b border-border/50">
              <td class="py-2"><code>P1xxx</code></td>
              <td>Query</td>
              <td>Record not found, invalid filters</td>
            </tr>
            <tr class="border-b border-border/50">
              <td class="py-2"><code>P2xxx</code></td>
              <td>Constraint</td>
              <td>Unique, foreign key, not null violations</td>
            </tr>
            <tr class="border-b border-border/50">
              <td class="py-2"><code>P3xxx</code></td>
              <td>Connection</td>
              <td>Connection failures, pool exhausted, auth</td>
            </tr>
            <tr class="border-b border-border/50">
              <td class="py-2"><code>P4xxx</code></td>
              <td>Transaction</td>
              <td>Deadlocks, serialization failures</td>
            </tr>
            <tr class="border-b border-border/50">
              <td class="py-2"><code>P5xxx</code></td>
              <td>Execution</td>
              <td>Timeouts, syntax errors</td>
            </tr>
            <tr class="border-b border-border/50">
              <td class="py-2"><code>P6xxx</code></td>
              <td>Data</td>
              <td>Type mismatches, serialization</td>
            </tr>
            <tr class="border-b border-border/50">
              <td class="py-2"><code>P7xxx</code></td>
              <td>Configuration</td>
              <td>Invalid config, missing settings</td>
            </tr>
            <tr class="border-b border-border/50">
              <td class="py-2"><code>P9xxx</code></td>
              <td>Internal</td>
              <td>Internal errors, bugs</td>
            </tr>
          </tbody>
        </table>
      </div>
    </section>

    <section id="actionable" class="mb-12">
      <h2 class="text-2xl font-semibold mb-4">Actionable Error Messages</h2>
      <p class="text-muted mb-4">
        Errors include suggestions for how to fix the issue, with code examples when applicable.
      </p>

      <CodeBlock code={actionableErrors} lang="rust" filename="Actionable Suggestions" />

      <div class="mt-6">
        <h4 class="font-semibold mb-3">Colored Terminal Output</h4>
        <p class="mb-4 text-muted">
          Use <code>display_colored()</code> for beautiful terminal output with ANSI colors.
        </p>
        <CodeBlock code={coloredOutput} lang="rust" filename="Colored Output" />
      </div>
    </section>

    <section id="context" class="mb-12">
      <h2 class="text-2xl font-semibold mb-4">Adding Context</h2>
      <p class="text-muted mb-4">
        Enrich errors with additional context for better debugging.
      </p>

      <CodeBlock code={customContext} lang="rust" filename="Error Context" />

      <div class="mt-6">
        <h4 class="font-semibold mb-3">Error Macro</h4>
        <p class="mb-4 text-muted">
          Create custom errors quickly with the <code>query_error!</code> macro.
        </p>
        <CodeBlock code={errorMacro} lang="rust" filename="Error Macro" />
      </div>
    </section>

    <section id="checks">
      <h2 class="text-2xl font-semibold mb-4">Error Checks</h2>
      <p class="text-muted mb-4">
        Use boolean methods to check error categories without pattern matching.
      </p>

      <CodeBlock code={errorChecks} lang="rust" filename="Error Checks" />

      <div class="mt-6 p-4 bg-success-500/10 border border-success-500/30 rounded-lg">
        <h4 class="font-semibold text-success-400 mb-2">✓ Retryable Errors</h4>
        <p class="text-sm text-muted">
          The <code class="text-primary-400">is_retryable()</code> check identifies transient errors that
          are safe to retry: connection timeouts, pool exhaustion, deadlocks, and serialization failures.
          Use this with the <code class="text-primary-400">RetryMiddleware</code> for automatic handling.
        </p>
      </div>
    </section>
    </div>
  </article>
</DocsLayout>