Skip to main content

bottle_orm/
database.rs

1//! # Database Module
2//!
3//! This module provides the core database connection and management functionality for Bottle ORM.
4//! It handles connection pooling, driver detection, table creation, and foreign key management
5//! across multiple database backends.
6//!
7//! ## Supported Database Drivers
8//!
9//! - **PostgreSQL**: Full support with advanced features like UUID, JSONB, arrays
10//! - **MySQL**: Complete support for standard MySQL/MariaDB features
11//! - **SQLite**: In-memory and file-based SQLite databases
12//!
13//! ## Features
14//!
15//! - **Connection Pooling**: Automatic connection pool management via sqlx
16//! - **Driver Detection**: Automatic database driver detection from connection URL
17//! - **Schema Management**: Table creation with indexes, constraints, and foreign keys
18//! - **Type Safety**: Type-safe operations across different database backends
19//!
20//! ## Example Usage
21//!
22//! ```rust,ignore
23//! use bottle_orm::Database;
24//!
25//! // Connect to PostgreSQL
26//! let db = Database::connect("postgres://user:pass@localhost/mydb").await?;
27//!
28//! // Connect to SQLite
29//! let db = Database::connect("sqlite::memory:").await?;
30//!
31//! // Connect to MySQL
32//! let db = Database::connect("mysql://user:pass@localhost/mydb").await?;
33//!
34//! // Create table for a model
35//! db.create_table::<User>().await?;
36//!
37//! // Assign foreign keys
38//! db.assign_foreign_keys::<Post>().await?;
39//!
40//! // Start building queries
41//! let users = db.model::<User>().scan().await?;
42//! ```
43
44// ============================================================================
45// External Crate Imports
46// ============================================================================
47
48use heck::ToSnakeCase;
49use sqlx::{
50    any::{AnyArguments, AnyPoolOptions},
51    AnyPool, Arguments, Error, Row,
52};
53use std::time::Duration;
54
55// ============================================================================
56// Internal Crate Imports
57// ============================================================================
58
59use crate::{migration::Migrator, model::Model, query_builder::QueryBuilder, Transaction};
60
61// ============================================================================
62// Database Driver Enumeration
63// ============================================================================
64
65/// Supported database driver types.
66///
67/// This enum represents the different database backends that Bottle ORM can work with.
68/// The driver type is automatically detected from the connection URL and used to
69/// generate appropriate SQL syntax for each database system.
70///
71/// # Variants
72///
73/// * `Postgres` - PostgreSQL database (9.5+)
74/// * `SQLite` - SQLite database (3.x)
75/// * `MySQL` - MySQL or MariaDB database (5.7+/10.2+)
76///
77/// # SQL Dialect Differences
78///
79/// Different drivers use different SQL syntax:
80///
81/// - **Placeholders**:
82///   - PostgreSQL: `$1, $2, $3` (numbered)
83///   - SQLite/MySQL: `?, ?, ?` (positional)
84///
85/// - **Type Casting**:
86///   - PostgreSQL: `$1::UUID`, `$2::TIMESTAMPTZ`
87///   - SQLite/MySQL: Automatic type inference
88///
89/// - **Schema Queries**:
90///   - PostgreSQL: `information_schema` tables
91///   - SQLite: `sqlite_master` system table
92///   - MySQL: `information_schema` tables
93///
94/// # Example
95///
96/// ```rust,ignore
97/// match db.driver {
98///     Drivers::Postgres => println!("Using PostgreSQL"),
99///     Drivers::SQLite => println!("Using SQLite"),
100///     Drivers::MySQL => println!("Using MySQL"),
101/// }
102/// ```
103#[derive(Clone, Debug, Copy)]
104pub enum Drivers {
105    /// PostgreSQL driver.
106    ///
107    /// Used for PostgreSQL databases. Supports advanced features like:
108    /// - UUID native type
109    /// - JSONB for JSON data
110    /// - Array types
111    /// - Full-text search
112    /// - Advanced indexing (GiST, GIN, etc.)
113    Postgres,
114
115    /// SQLite driver.
116    ///
117    /// Used for SQLite databases (both in-memory and file-based). Characteristics:
118    /// - Lightweight and embedded
119    /// - Single-file database
120    /// - Limited concurrent write support
121    /// - Good for development and small applications
122    SQLite,
123
124    /// MySQL driver.
125    ///
126    /// Used for MySQL and MariaDB databases. Features:
127    /// - Wide compatibility
128    /// - Good performance for read-heavy workloads
129    /// - Mature ecosystem
130    /// - ACID compliance (with InnoDB)
131    MySQL,
132}
133
134// ============================================================================
135// Database Builder
136// ============================================================================
137
138/// A builder for creating a `Database` connection with custom options.
139///
140/// Allows configuration of connection pool settings such as maximum connections,
141/// timeouts, and lifetimes.
142///
143/// # Example
144///
145/// ```rust,ignore
146/// let db = Database::builder()
147///     .max_connections(10)
148///     .min_connections(2)
149///     .acquire_timeout(std::time::Duration::from_secs(5))
150///     .connect("postgres://...")
151///     .await?;
152/// ```
153#[derive(Debug)]
154pub struct DatabaseBuilder {
155    options: AnyPoolOptions,
156}
157
158impl DatabaseBuilder {
159    /// Sets the maximum number of connections that this pool should maintain.
160    pub fn max_connections(mut self, max: u32) -> Self {
161        self.options = self.options.max_connections(max);
162        self
163    }
164
165    /// Sets the minimum number of connections that this pool should maintain.
166    pub fn min_connections(mut self, min: u32) -> Self {
167        self.options = self.options.min_connections(min);
168        self
169    }
170
171    /// Sets the maximum amount of time to spend waiting for a connection.
172    pub fn acquire_timeout(mut self, timeout: Duration) -> Self {
173        self.options = self.options.acquire_timeout(timeout);
174        self
175    }
176
177    /// Sets the maximum amount of time a connection may be idle.
178    pub fn idle_timeout(mut self, timeout: Duration) -> Self {
179        self.options = self.options.idle_timeout(Some(timeout));
180        self
181    }
182
183    /// Sets the maximum lifetime of a connection.
184    pub fn max_lifetime(mut self, lifetime: Duration) -> Self {
185        self.options = self.options.max_lifetime(Some(lifetime));
186        self
187    }
188
189    /// Connects to the database using the configured options.
190    pub async fn connect(self, url: &str) -> Result<Database, Error> {
191        // Install default drivers for sqlx::Any
192        sqlx::any::install_default_drivers();
193
194        let pool = self.options.connect(url).await?;
195
196        // Detect driver type from URL scheme
197        let (driver_str, _) = url.split_once(':').unwrap_or(("sqlite", ""));
198        let driver = match driver_str {
199            "postgresql" | "postgres" => Drivers::Postgres,
200            "mysql" => Drivers::MySQL,
201            _ => Drivers::SQLite,
202        };
203
204        Ok(Database { pool, driver })
205    }
206}
207
208// ============================================================================
209// Database Connection and Management
210// ============================================================================
211
212/// The main entry point for database connection and management.
213///
214/// `Database` handles connection pooling, driver detection, and provides methods
215/// for schema operations and query building. It uses sqlx's `AnyPool` to support
216/// multiple database backends with a unified interface.
217///
218/// # Fields
219///
220/// * `pool` - The sqlx connection pool for executing queries
221/// * `driver` - The detected database driver type
222///
223/// # Thread Safety
224///
225/// `Database` implements `Clone` and can be safely shared across threads.
226/// The underlying connection pool is thread-safe and handles connection
227/// distribution automatically.
228///
229/// # Example
230///
231/// ```rust,ignore
232/// use bottle_orm::Database;
233///
234/// #[tokio::main]
235/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
236///     // Connect to database
237///     let db = Database::connect("postgres://localhost/mydb").await?;
238///
239///     // Create migrator
240///     let migrator = db.migrator();
241///
242///     // Build queries
243///     let query = db.model::<User>();
244///
245///     // Database can be cloned and shared
246///     let db_clone = db.clone();
247///     tokio::spawn(async move {
248///         let users = db_clone.model::<User>().scan().await;
249///     });
250///
251///     Ok(())
252/// }
253/// ```
254#[derive(Debug, Clone)]
255pub struct Database {
256    /// The sqlx connection pool for executing database queries.
257    ///
258    /// This pool manages a set of database connections that can be reused
259    /// across multiple queries, improving performance by avoiding the overhead
260    /// of creating new connections for each operation.
261    pub(crate) pool: AnyPool,
262
263    /// The detected database driver type.
264    ///
265    /// Used to generate driver-specific SQL syntax (e.g., placeholders,
266    /// type casting, schema queries).
267    pub(crate) driver: Drivers,
268}
269
270// ============================================================================
271// Database Implementation
272// ============================================================================
273
274impl Database {
275    // ========================================================================
276    // Connection Management
277    // ========================================================================
278
279    /// Creates a builder to configure the database connection options.
280    ///
281    /// Returns a `DatabaseBuilder` which allows setting pool options like
282    /// `max_connections`, timeouts, etc.
283    ///
284    /// # Example
285    ///
286    /// ```rust,ignore
287    /// let db = Database::builder()
288    ///     .max_connections(20)
289    ///     .connect("postgres://...")
290    ///     .await?;
291    /// ```
292    pub fn builder() -> DatabaseBuilder {
293        DatabaseBuilder { options: AnyPoolOptions::new() }
294    }
295
296    /// Connects to the database using a connection string (Database URL).
297    ///
298    /// This method establishes a connection pool to the specified database and
299    /// automatically detects the driver type based on the URL scheme. The connection
300    /// pool is configured with a default maximum of 5 connections.
301    ///
302    /// # Arguments
303    ///
304    /// * `url` - The database connection string with the format:
305    ///   `<scheme>://<user>:<password>@<host>:<port>/<database>`
306    ///
307    /// # Supported URL Schemes
308    ///
309    /// - **PostgreSQL**: `postgres://` or `postgresql://`
310    /// - **MySQL**: `mysql://`
311    /// - **SQLite**: `sqlite://` or `sqlite::memory:` (for in-memory databases)
312    ///
313    /// # Connection Pool Configuration
314    ///
315    /// - Maximum connections: 5
316    /// - Connection timeout: Default (30 seconds)
317    /// - Idle timeout: Default (10 minutes)
318    ///
319    /// # Returns
320    ///
321    /// * `Ok(Database)` - Successfully connected database instance
322    /// * `Err(sqlx::Error)` - Connection error (invalid URL, authentication failure, etc.)
323    ///
324    /// # Examples
325    ///
326    /// ```rust,ignore
327    /// // PostgreSQL connection
328    /// let db = Database::connect("postgres://user:password@localhost:5432/mydb").await?;
329    ///
330    /// // PostgreSQL with SSL
331    /// let db = Database::connect("postgres://user:password@localhost/mydb?sslmode=require").await?;
332    ///
333    /// // SQLite in-memory database (great for testing)
334    /// let db = Database::connect("sqlite::memory:").await?;
335    ///
336    /// // SQLite file-based database
337    /// let db = Database::connect("sqlite://./database.db").await?;
338    ///
339    /// // MySQL connection
340    /// let db = Database::connect("mysql://user:password@localhost:3306/mydb").await?;
341    /// ```
342    ///
343    /// # Error Handling
344    ///
345    /// ```rust,ignore
346    /// match Database::connect("postgres://localhost/mydb").await {
347    ///     Ok(db) => println!("Connected successfully"),
348    ///     Err(e) => eprintln!("Connection failed: {}", e),
349    /// }
350    /// ```
351    pub async fn connect(url: &str) -> Result<Self, Error> {
352        Self::builder().max_connections(5).connect(url).await
353    }
354
355    // ========================================================================
356    // Schema Management
357    // ========================================================================
358
359    /// Creates a `Migrator` instance to manage schema migrations.
360    ///
361    /// The migrator allows you to register multiple models and execute
362    /// all necessary schema changes (table creation, foreign keys) in the
363    /// correct order.
364    ///
365    /// # Returns
366    ///
367    /// A new `Migrator` instance associated with this database connection
368    ///
369    /// # Example
370    ///
371    /// ```rust,ignore
372    /// let db = Database::connect("sqlite::memory:").await?;
373    ///
374    /// db.migrator()
375    ///     .register::<User>()
376    ///     .register::<Post>()
377    ///     .register::<Comment>()
378    ///     .run()
379    ///     .await?;
380    /// ```
381    ///
382    /// # See Also
383    ///
384    /// * [`Migrator`] - For detailed migration documentation
385    /// * [`Migrator::register()`] - For registering models
386    /// * [`Migrator::run()`] - For executing migrations
387    pub fn migrator(&self) -> Migrator<'_> {
388        Migrator::new(self)
389    }
390
391    // ========================================================================
392    // Query Building
393    // ========================================================================
394
395    /// Starts building a query for a specific Model.
396    ///
397    /// This method creates a new `QueryBuilder` instance configured for the
398    /// specified model type. The query builder provides a fluent interface
399    /// for constructing SELECT and INSERT queries.
400    ///
401    /// # Type Parameters
402    ///
403    /// * `T` - The Model type to query. Must implement `Model + Send + Sync + Unpin`
404    ///
405    /// # Returns
406    ///
407    /// A new `QueryBuilder` instance ready for query construction
408    ///
409    /// # Example
410    ///
411    /// ```rust,ignore
412    /// // Simple query
413    /// let users: Vec<User> = db.model::<User>().scan().await?;
414    ///
415    /// // Filtered query
416    /// let adults: Vec<User> = db.model::<User>()
417    ///     .filter("age", ">=", 18)
418    ///     .scan()
419    ///     .await?;
420    ///
421    /// // Insert operation
422    /// let new_user = User { /* ... */ };
423    /// db.model::<User>().insert(&new_user).await?;
424    /// ```
425    ///
426    /// # See Also
427    ///
428    /// * [`QueryBuilder`] - For detailed query building documentation
429    /// * [`QueryBuilder::filter()`] - For adding WHERE clauses
430    /// * [`QueryBuilder::scan()`] - For executing SELECT queries
431    /// * [`QueryBuilder::insert()`] - For INSERT operations
432    pub fn model<T: Model + Send + Sync + Unpin>(&self) -> QueryBuilder<'_, T, Self> {
433        // Get active column names from the model
434        let active_columns = T::active_columns();
435        let mut columns: Vec<String> = Vec::with_capacity(active_columns.capacity());
436
437        // Convert column names to snake_case and strip 'r#' prefix if present
438        for col in active_columns {
439            columns.push(col.strip_prefix("r#").unwrap_or(col).to_snake_case());
440        }
441
442        // Create and return the query builder
443        QueryBuilder::new(self.clone(), self.driver, T::table_name(), T::columns(), columns)
444    }
445
446    /// Creates a raw SQL query builder.
447    ///
448    /// This provides a "safety hatch" to execute raw SQL queries when the fluent
449    /// QueryBuilder is not sufficient (e.g., complex joins, CTEs, specific DB features).
450    ///
451    /// # Arguments
452    ///
453    /// * `sql` - The raw SQL query string (use `$1`, `?`, etc. for placeholders based on driver)
454    ///
455    /// # Returns
456    ///
457    /// A `RawQuery` builder that allows binding parameters and executing the query.
458    ///
459    /// # Example
460    ///
461    /// ```rust,ignore
462    /// // Fetching complex data
463    /// let users: Vec<User> = db.raw("SELECT * FROM users WHERE age > $1")
464    ///     .bind(18)
465    ///     .fetch_all()
466    ///     .await?;
467    ///
468    /// // Executing an update
469    /// let affected = db.raw("UPDATE users SET active = $1 WHERE last_login < $2")
470    ///     .bind(false)
471    ///     .bind(one_year_ago)
472    ///     .execute()
473    ///     .await?;
474    /// ```
475    pub fn raw<'a>(&'a self, sql: &'a str) -> RawQuery<'a, Self> {
476        RawQuery::new(self.clone(), sql)
477    }
478
479    // ========================================================================
480    // Table Creation
481    // ========================================================================
482
483    /// Creates the table for model `T` if it does not exist.
484    ///
485    /// This method generates and executes SQL to create a table based on the
486    /// model's structure. It handles column definitions, primary keys, unique
487    /// constraints, default values, and indexes.
488    ///
489    /// # Type Parameters
490    ///
491    /// * `T` - The Model type representing the table
492    ///
493    /// # Returns
494    ///
495    /// * `Ok(&Self)` - Reference to self for method chaining
496    /// * `Err(sqlx::Error)` - Database error during table creation
497    ///
498    /// # Generated SQL Features
499    ///
500    /// - **Primary Keys**: Automatically marked with `PRIMARY KEY`
501    /// - **NOT NULL**: Non-nullable fields get `NOT NULL` constraint
502    /// - **UNIQUE**: Fields marked with `#[orm(unique)]` get `UNIQUE` constraint
503    /// - **DEFAULT**: Fields marked with `#[orm(create_time)]` get `DEFAULT CURRENT_TIMESTAMP`
504    /// - **Indexes**: Fields marked with `#[orm(index)]` get database indexes
505    ///
506    /// # Example
507    ///
508    /// ```rust,ignore
509    /// use bottle_orm::Model;
510    /// use uuid::Uuid;
511    /// use chrono::{DateTime, Utc};
512    ///
513    /// #[derive(Model)]
514    /// struct User {
515    ///     #[orm(primary_key)]
516    ///     id: Uuid,
517    ///     #[orm(size = 50, unique)]
518    ///     username: String,
519    ///     #[orm(index)]
520    ///     email: String,
521    ///     age: i32,
522    ///     #[orm(create_time)]
523    ///     created_at: DateTime<Utc>,
524    /// }
525    ///
526    /// // Creates table with:
527    /// // - UUID primary key
528    /// // - Unique username constraint
529    /// // - Index on email
530    /// // - created_at with DEFAULT CURRENT_TIMESTAMP
531    /// db.create_table::<User>().await?;
532    /// ```
533    ///
534    /// # Generated SQL Example (PostgreSQL)
535    ///
536    /// ```sql
537    /// CREATE TABLE IF NOT EXISTS "user" (
538    ///     "id" UUID PRIMARY KEY,
539    ///     "username" VARCHAR(50) NOT NULL UNIQUE,
540    ///     "email" TEXT NOT NULL,
541    ///     "age" INTEGER NOT NULL,
542    ///     "created_at" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
543    /// );
544    /// CREATE INDEX IF NOT EXISTS "idx_user_email" ON "user" ("email");
545    /// ```
546    pub async fn create_table<T: Model>(&self) -> Result<&Self, Error> {
547        // Get table name in snake_case format
548        let table_name = T::table_name().to_snake_case();
549        let columns = T::columns();
550
551        let mut column_defs = Vec::new();
552        let mut index_statements = Vec::new();
553
554        // Build column definitions
555        for col in &columns {
556            // Strip 'r#' prefix if present (for Rust keywords used as column names)
557            let col_name = col.name.strip_prefix("r#").unwrap_or(col.name).to_snake_case();
558            let mut def = format!("\"{}\" {}", col_name, col.sql_type);
559
560            // Add PRIMARY KEY constraint
561            if col.is_primary_key {
562                def.push_str(" PRIMARY KEY");
563            }
564
565            // Add NOT NULL constraint (except for primary keys, which are implicitly NOT NULL)
566            if !col.is_nullable && !col.is_primary_key {
567                def.push_str(" NOT NULL");
568            }
569
570            // Add DEFAULT CURRENT_TIMESTAMP for create_time fields
571            if col.create_time {
572                def.push_str(" DEFAULT CURRENT_TIMESTAMP");
573            }
574
575            // Add UNIQUE constraint
576            if col.unique {
577                def.push_str(" UNIQUE");
578            }
579
580            column_defs.push(def);
581
582            // Generate index creation statement if needed
583            if col.index {
584                let index_type = if col.unique { "UNIQUE INDEX" } else { "INDEX" };
585                let index_name = format!("idx_{}_{}", table_name, col_name);
586
587                let index_query = format!(
588                    "CREATE {} IF NOT EXISTS \"{}\" ON \"{}\" (\"{}\")",
589                    index_type, index_name, table_name, col_name,
590                );
591
592                index_statements.push(index_query);
593            }
594        }
595
596        // Add SQLite Foreign Keys inline (SQLite doesn't support ADD CONSTRAINT)
597        if let Drivers::SQLite = self.driver {
598            for col in &columns {
599                if let (Some(f_table), Some(f_key)) = (col.foreign_table, col.foreign_key) {
600                    let col_name = col.name.strip_prefix("r#").unwrap_or(col.name).to_snake_case();
601                    let f_table_clean = f_table.to_snake_case();
602                    let f_key_clean = f_key.to_snake_case();
603
604                    let fk_def = format!(
605                        "FOREIGN KEY (\"{}\") REFERENCES \"{}\" (\"{}\")",
606                        col_name, f_table_clean, f_key_clean
607                    );
608                    column_defs.push(fk_def);
609                }
610            }
611        }
612
613        // Build and execute CREATE TABLE statement
614        let create_table_query =
615            format!("CREATE TABLE IF NOT EXISTS \"{}\" ({})", table_name.to_snake_case(), column_defs.join(", "));
616        log::info!("{}", create_table_query);
617
618        sqlx::query(&create_table_query).execute(&self.pool).await?;
619
620        // Create indexes
621        for idx_stmt in index_statements {
622            sqlx::query(&idx_stmt).execute(&self.pool).await?;
623        }
624
625        Ok(self)
626    }
627
628    /// Starts a new database transaction.
629    ///
630    /// Returns a `Transaction` wrapper that can be used to execute multiple
631    /// queries atomically. The transaction must be explicitly committed
632    /// using `commit()`, otherwise it will be rolled back when dropped.
633    ///
634    /// # Returns
635    ///
636    /// * `Ok(Transaction)` - A new transaction instance
637    /// * `Err(sqlx::Error)` - Database error starting transaction
638    ///
639    /// # Example
640    ///
641    /// ```rust,ignore
642    /// let mut tx = db.begin().await?;
643    /// // ... perform operations ...
644    /// tx.commit().await?;
645    /// ```
646    pub async fn begin<'a>(&self) -> Result<Transaction<'a>, sqlx::Error> {
647        let tx = self.pool.begin().await?;
648        Ok(Transaction { tx, driver: self.driver })
649    }
650
651    // ========================================================================
652    // Foreign Key Management
653    // ========================================================================
654
655    /// Checks for and assigns Foreign Keys for model `T`.
656    ///
657    /// This method examines all columns marked with `#[orm(foreign_key = "Table::Column")]`
658    /// and creates the appropriate foreign key constraints. It verifies that constraints
659    /// don't already exist before attempting to create them, preventing duplication errors.
660    ///
661    /// # Type Parameters
662    ///
663    /// * `T` - The Model type to process for foreign keys
664    ///
665    /// # Returns
666    ///
667    /// * `Ok(&Self)` - Reference to self for method chaining
668    /// * `Err(sqlx::Error)` - Database error during foreign key creation
669    ///
670    /// # Constraint Naming
671    ///
672    /// Foreign key constraints are named using the pattern:
673    /// `fk_{table_name}_{column_name}`
674    ///
675    /// # Example
676    ///
677    /// ```rust,ignore
678    /// use bottle_orm::Model;
679    /// use uuid::Uuid;
680    ///
681    /// #[derive(Model)]
682    /// struct User {
683    ///     #[orm(primary_key)]
684    ///     id: Uuid,
685    ///     username: String,
686    /// }
687    ///
688    /// #[derive(Model)]
689    /// struct Post {
690    ///     #[orm(primary_key)]
691    ///     id: Uuid,
692    ///     #[orm(foreign_key = "User::id")]
693    ///     user_id: Uuid,
694    ///     title: String,
695    /// }
696    ///
697    /// // Create tables first
698    /// db.create_table::<User>().await?;
699    /// db.create_table::<Post>().await?;
700    ///
701    /// // Then assign foreign keys
702    /// db.assign_foreign_keys::<Post>().await?;
703    /// ```
704    ///
705    /// # Generated SQL Example
706    ///
707    /// ```sql
708    /// ALTER TABLE "post"
709    /// ADD CONSTRAINT "fk_post_user_id"
710    /// FOREIGN KEY ("user_id")
711    /// REFERENCES "user" ("id");
712    /// ```
713    ///
714    /// # Important Notes
715    ///
716    /// - Foreign key assignment should be done **after** all tables are created
717    /// - The referenced table and column must exist before creating the foreign key
718    /// - Use the `Migrator` to handle the correct order automatically
719    /// - Currently optimized for PostgreSQL (uses `information_schema`)
720    ///
721    /// # See Also
722    ///
723    /// * [`Migrator`] - For automatic migration order management
724    pub async fn assign_foreign_keys<T: Model>(&self) -> Result<&Self, Error> {
725        // SQLite handles FKs in create_table, so we skip here
726        if let Drivers::SQLite = self.driver {
727            return Ok(self);
728        }
729
730        // Get table name in snake_case format
731        let table_name = T::table_name().to_snake_case();
732        let columns = T::columns();
733
734        // Process each column that has a foreign key definition
735        for col in columns {
736            if let (Some(f_table), Some(f_key)) = (col.foreign_table, col.foreign_key) {
737                // Clean up column and reference names
738                let col_name = col.name.strip_prefix("r#").unwrap_or(col.name).to_snake_case();
739                let f_table_clean = f_table.to_snake_case();
740                let f_key_clean = f_key.to_snake_case();
741
742                // Generate constraint name
743                let constraint_name = format!("fk_{}_{}", table_name, col_name);
744
745                // Check if constraint already exists
746                let count: i64 = match self.driver {
747                    Drivers::Postgres => {
748                        let check_query =
749                            "SELECT count(*) FROM information_schema.table_constraints WHERE constraint_name = $1";
750                        let row = sqlx::query(check_query).bind(&constraint_name).fetch_one(&self.pool).await?;
751                        row.try_get(0).unwrap_or(0)
752                    }
753                    Drivers::MySQL => {
754                        let check_query = "SELECT count(*) FROM information_schema.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME = ? AND TABLE_SCHEMA = DATABASE()";
755                        let row = sqlx::query(check_query).bind(&constraint_name).fetch_one(&self.pool).await?;
756                        row.try_get(0).unwrap_or(0)
757                    }
758                    Drivers::SQLite => 0, // Unreachable
759                };
760
761                // Skip if constraint already exists
762                if count > 0 {
763                    continue;
764                }
765
766                // Create foreign key constraint
767                let alter_query = format!(
768                    "ALTER TABLE \"{}\" ADD CONSTRAINT \"{}\" FOREIGN KEY (\"{}\") REFERENCES \"{}\" (\"{}\")",
769                    table_name, constraint_name, col_name, f_table_clean, f_key_clean
770                );
771
772                sqlx::query(&alter_query).execute(&self.pool).await?;
773            }
774        }
775
776        Ok(self)
777    }
778}
779
780/// A trait representing a database connection or transaction.
781///
782/// This trait abstracts over `Database` (pool) and `Transaction` types, allowing
783/// the `QueryBuilder` to work seamlessly with both. It uses Generic Associated Types (GATs)
784/// to handle the lifetimes of the executor references correctly.
785pub trait Connection {
786    /// The type of the executor returned by this connection.
787    ///
788    /// This uses GATs to bind the lifetime of the executor (`'c`) to the lifetime
789    /// of the borrow of the connection (`&'c mut self`).
790    type Exec<'c>: sqlx::Executor<'c, Database = sqlx::Any>
791    where
792        Self: 'c;
793
794    /// Returns a mutable reference to the SQLx executor.
795    ///
796    /// # Returns
797    ///
798    /// An executor capable of running SQL queries (either a Pool or a Transaction).
799    fn executor<'c>(&'c mut self) -> Self::Exec<'c>;
800}
801
802/// Implementation of Connection for the main Database struct.
803///
804/// Uses the internal connection pool to execute queries.
805impl Connection for Database {
806    type Exec<'c> = &'c sqlx::Pool<sqlx::Any>;
807
808    fn executor<'c>(&'c mut self) -> Self::Exec<'c> {
809        &self.pool
810    }
811}
812
813/// Implementation of Connection for a mutable reference to Database.
814impl<'a> Connection for &'a mut Database {
815    type Exec<'c>
816        = &'c sqlx::Pool<sqlx::Any>
817    where
818        Self: 'c;
819
820    fn executor<'c>(&'c mut self) -> Self::Exec<'c> {
821        &self.pool
822    }
823}
824
825/// Implementation of Connection for a mutable reference to sqlx::Transaction.
826impl<'a> Connection for &mut sqlx::Transaction<'a, sqlx::Any> {
827    type Exec<'c>
828        = &'c mut sqlx::AnyConnection
829    where
830        Self: 'c;
831
832    fn executor<'c>(&'c mut self) -> Self::Exec<'c> {
833        &mut **self
834    }
835}
836
837// ============================================================================
838// Raw SQL Query Builder
839// ============================================================================
840/// A builder for executing raw SQL queries with parameter binding.
841///
842/// Returned by `Database::raw()` or `Transaction::raw()`. Allows constructing safe, parameterized
843/// SQL queries that can bypass the standard model-based QueryBuilder when
844/// complex SQL features (CTEs, Window Functions, etc.) are needed.
845pub struct RawQuery<'a, C> {
846    conn: C,
847    sql: &'a str,
848    args: AnyArguments<'a>,
849}
850
851impl<'a, C> RawQuery<'a, C>
852where
853    C: Connection + Send,
854{
855    /// Creates a new RawQuery instance.
856    pub(crate) fn new(conn: C, sql: &'a str) -> Self {
857        Self { conn, sql, args: AnyArguments::default() }
858    }
859
860    /// Binds a parameter to the query.
861    ///
862    /// # Arguments
863    ///
864    /// * `value` - The value to bind. Must implement `sqlx::Encode` and `sqlx::Type`.
865    pub fn bind<T>(mut self, value: T) -> Self
866    where
867        T: 'a + sqlx::Encode<'a, sqlx::Any> + sqlx::Type<sqlx::Any> + Send + Sync,
868    {
869        let _ = self.args.add(value);
870        self
871    }
872
873    /// Executes the query and returns all matching rows mapped to type `T`.
874    pub async fn fetch_all<T>(mut self) -> Result<Vec<T>, Error>
875    where
876        T: for<'r> sqlx::FromRow<'r, sqlx::any::AnyRow> + Send + Unpin,
877    {
878        sqlx::query_as_with::<_, T, _>(self.sql, self.args).fetch_all(self.conn.executor()).await
879    }
880
881    /// Executes the query and returns the first matching row mapped to type `T`.
882    pub async fn fetch_one<T>(mut self) -> Result<T, Error>
883    where
884        T: for<'r> sqlx::FromRow<'r, sqlx::any::AnyRow> + Send + Unpin,
885    {
886        sqlx::query_as_with::<_, T, _>(self.sql, self.args).fetch_one(self.conn.executor()).await
887    }
888
889    /// Executes the query and returns the first matching row, or None if not found.
890    pub async fn fetch_optional<T>(mut self) -> Result<Option<T>, Error>
891    where
892        T: for<'r> sqlx::FromRow<'r, sqlx::any::AnyRow> + Send + Unpin,
893    {
894        sqlx::query_as_with::<_, T, _>(self.sql, self.args).fetch_optional(self.conn.executor()).await
895    }
896
897    /// Executes the query and returns a single scalar value.
898    ///
899    /// Useful for queries like `SELECT count(*) ...` or `SELECT id ...`.
900    pub async fn fetch_scalar<O>(mut self) -> Result<O, Error>
901    where
902        O: for<'r> sqlx::Decode<'r, sqlx::Any> + sqlx::Type<sqlx::Any> + Send + Unpin,
903    {
904        sqlx::query_scalar_with::<_, O, _>(self.sql, self.args).fetch_one(self.conn.executor()).await
905    }
906
907    /// Executes the query and returns a single scalar value, or None if not found.
908    pub async fn fetch_scalar_optional<O>(mut self) -> Result<Option<O>, Error>
909    where
910        O: for<'r> sqlx::Decode<'r, sqlx::Any> + sqlx::Type<sqlx::Any> + Send + Unpin,
911    {
912        sqlx::query_scalar_with::<_, O, _>(self.sql, self.args).fetch_optional(self.conn.executor()).await
913    }
914
915    /// Executes the query (INSERT, UPDATE, DELETE) and returns the number of affected rows.
916    pub async fn execute(mut self) -> Result<u64, Error> {
917        let result = sqlx::query_with(self.sql, self.args).execute(self.conn.executor()).await?;
918
919        Ok(result.rows_affected())
920    }
921}