Skip to main content

bottle_orm/
query_builder.rs

1//! # Query Builder Module
2//!
3//! This module provides a fluent interface for constructing and executing SQL queries.
4//! It handles SELECT, INSERT, filtering (WHERE), pagination (LIMIT/OFFSET), and ordering operations
5//! with type-safe parameter binding across different database drivers.
6//!
7//! ## Features
8//!
9//! - **Fluent API**: Chainable methods for building complex queries
10//! - **Type-Safe Binding**: Automatic parameter binding with support for multiple types
11//! - **Multi-Driver Support**: Works with PostgreSQL, MySQL, and SQLite
12//! - **UUID Support**: Full support for UUID versions 1-7
13//! - **Pagination**: Built-in LIMIT/OFFSET support with helper methods
14//! - **Custom Filters**: Support for manual SQL construction with closures
15//!
16//! ## Example Usage
17//!
18//! ```rust,ignore
19//! use bottle_orm::{Database, Model};
20//! 
21//!
22//! // Simple query
23//! let users: Vec<User> = db.model::<User>()
24//!     .filter("age", ">=", 18)
25//!     .order("created_at DESC")
26//!     .limit(10)
27//!     .scan()
28//!     .await?;
29//!
30//! // Query with UUID filter
31//! let user_id = Uuid::new_v4();
32//! let user: User = db.model::<User>()
33//!     .filter("id", "=", user_id)
34//!     .first()
35//!     .await?;
36//!
37//! // Insert a new record
38//! let new_user = User {
39//!     id: Uuid::new_v7(uuid::Timestamp::now(uuid::NoContext)),
40//!     username: "john_doe".to_string(),
41//!     age: 25,
42//! };
43//! db.model::<User>().insert(&new_user).await?;
44//! ```
45
46// ============================================================================
47// External Crate Imports
48// ============================================================================
49
50use futures::future::BoxFuture;
51use heck::ToSnakeCase;
52use sqlx::{Any, Arguments, Decode, Encode, Type, any::AnyArguments};
53use std::marker::PhantomData;
54use std::collections::{HashMap, HashSet};
55
56
57// ============================================================================
58// Internal Crate Imports
59// ============================================================================
60
61use crate::{
62    AnyImpl, Error,
63    any_struct::FromAnyRow,
64    database::{Connection, Drivers},
65    model::{ColumnInfo, Model},
66    temporal::{self, is_temporal_type},
67    value_binding::ValueBinder,
68};
69
70// ============================================================================
71// Type Aliases
72// ============================================================================
73
74/// A type alias for filter closures that support manual SQL construction and argument binding.
75///
76/// Filter functions receive the following parameters:
77/// 1. `&mut String` - The SQL query buffer being built
78/// 2. `&mut AnyArguments` - The argument container for binding values
79/// 3. `&Drivers` - The current database driver (determines placeholder syntax)
80/// 4. `&mut usize` - The argument counter (for PostgreSQL `$n` placeholders)
81///
82/// ## Example
83///
84/// ```rust,ignore
85/// let custom_filter: FilterFn = Box::new(|query, args, driver, counter| {
86///     query.push_str(" AND age > ");
87///     match driver {
88///         Drivers::Postgres => {
89///             query.push_str(&format!("${}", counter));
90///             *counter += 1;
91///         }
92///         _ => query.push('?'),
93///     }
94///     args.add(18);
95/// });
96/// });\n/// ```
97pub type FilterFn = Box<dyn Fn(&mut String, &mut AnyArguments<'_>, &Drivers, &mut usize) + Send + Sync>;
98
99// ============================================================================
100// Update Value Traits
101// ============================================================================
102
103/// Trait for types that can be converted to an optional string value for SQL updates.
104///
105/// This trait is used by the `update` method to handle both direct values
106/// (e.g., `update("role", "admin")`) and NULL values (e.g., `update("role", None::<String>)`).
107pub trait ToUpdateValue {
108    /// Converts the value to an `Option<String>` for SQL binding.
109    ///
110    /// # Returns
111    ///
112    /// * `Some(String)` - String representation for a database value
113    /// * `None` - Represents a SQL `NULL`
114    fn to_update_value(self) -> Option<String>;
115}
116
117macro_rules! impl_update_value {
118    ($($t:ty),*) => {
119        $(
120            impl ToUpdateValue for $t {
121                fn to_update_value(self) -> Option<String> {
122                    Some(self.to_string())
123                }
124            }
125            impl ToUpdateValue for Option<$t> {
126                fn to_update_value(self) -> Option<String> {
127                    self.map(|v| v.to_string())
128                }
129            }
130        )*
131    }
132}
133
134impl_update_value!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64, bool, String, &str, uuid::Uuid);
135impl_update_value!(chrono::DateTime<chrono::Utc>, chrono::DateTime<chrono::FixedOffset>, chrono::NaiveDateTime, chrono::NaiveDate, chrono::NaiveTime);
136
137// ============================================================================
138// Comparison Operators Enum
139// ============================================================================
140
141/// Type-safe comparison operators for filter conditions.
142///
143/// Use these instead of string operators for autocomplete support and type safety.
144///
145/// # Example
146///
147/// ```rust,ignore
148/// use bottle_orm::Op;
149///
150/// db.model::<User>()
151///     .filter(user_fields::AGE, Op::Gte, 18)
152///     .filter(user_fields::NAME, Op::Like, "%John%")
153///     .scan()
154///     .await?;
155/// ```
156#[derive(Debug, Clone, Copy, PartialEq, Eq)]
157pub enum Op {
158    /// Equal: `=`
159    Eq,
160    /// Not Equal: `!=` or `<>`
161    Ne,
162    /// Greater Than: `>`
163    Gt,
164    /// Greater Than or Equal: `>=`
165    Gte,
166    /// Less Than: `<`
167    Lt,
168    /// Less Than or Equal: `<=`
169    Lte,
170    /// SQL LIKE pattern matching
171    Like,
172    /// SQL NOT LIKE pattern matching
173    NotLike,
174    /// SQL IN (for arrays/lists)
175    In,
176    /// SQL NOT IN
177    NotIn,
178    /// SQL BETWEEN
179    Between,
180    /// SQL NOT BETWEEN
181    NotBetween,
182}
183
184impl Op {
185    /// Converts the operator to its SQL string representation.
186    pub fn as_sql(&self) -> &'static str {
187        match self {
188            Op::Eq => "=",
189            Op::Ne => "!=",
190            Op::Gt => ">",
191            Op::Gte => ">=",
192            Op::Lt => "<",
193            Op::Lte => "<=",
194            Op::Like => "LIKE",
195            Op::NotLike => "NOT LIKE",
196            Op::In => "IN",
197            Op::NotIn => "NOT IN",
198            Op::Between => "BETWEEN",
199            Op::NotBetween => "NOT BETWEEN",
200        }
201    }
202}
203
204// ============================================================================
205// QueryBuilder Struct
206// ============================================================================
207
208/// A fluent Query Builder for constructing SQL queries.
209///
210/// `QueryBuilder` provides a type-safe, ergonomic interface for building and executing
211/// SQL queries across different database backends. It supports filtering, ordering,
212/// pagination, and both SELECT and INSERT operations.
213///
214/// ## Type Parameter
215///
216/// * `'a` - Lifetime of the database reference (used for PhantomData)
217/// * `T` - The Model type this query operates on
218/// * `E` - The connection type (Database or Transaction)
219///
220/// ## Fields
221///
222/// * `db` - Reference to the database connection pool or transaction
223/// * `table_name` - Static string containing the table name
224/// * `columns_info` - Metadata about each column in the table
225/// * `columns` - List of column names in snake_case format
226/// * `select_columns` - Specific columns to select (empty = SELECT *)
227/// * `where_clauses` - List of filter functions to apply
228/// * `order_clauses` - List of ORDER BY clauses
229/// * `limit` - Maximum number of rows to return
230/// * `offset` - Number of rows to skip (for pagination)
231/// * `_marker` - PhantomData to bind the generic type T
232pub struct QueryBuilder<T, E> {
233    /// Reference to the database connection pool
234    pub(crate) tx: E,
235
236    /// Database driver type
237    pub(crate) driver: Drivers,
238
239    /// Name of the database table (in original case)
240    pub(crate) table_name: &'static str,
241
242    pub(crate) alias: Option<String>,
243
244    /// Metadata information about each column
245    pub(crate) columns_info: Vec<ColumnInfo>,
246
247    /// List of column names (in snake_case)
248    pub(crate) columns: Vec<String>,
249
250    /// Specific columns to select (empty means SELECT *)
251    pub(crate) select_columns: Vec<String>,
252
253    /// Collection of WHERE clause filter functions
254    pub(crate) where_clauses: Vec<FilterFn>,
255
256    /// Collection of ORDER BY clauses
257    pub(crate) order_clauses: Vec<String>,
258
259    /// Collection of JOIN clause to filter entry tables
260    pub(crate) joins_clauses: Vec<FilterFn>,
261
262    /// Collection of relations to eager load
263    pub(crate) with_relations: Vec<String>,
264
265    /// Map of table names to their aliases used in JOINS
266    pub(crate) join_aliases: std::collections::HashMap<String, String>,
267
268    /// Maximum number of rows to return (LIMIT)
269    pub(crate) limit: Option<usize>,
270
271    /// Number of rows to skip (OFFSET)
272    pub(crate) offset: Option<usize>,
273
274    /// Activate debug mode in query
275    pub(crate) debug_mode: bool,
276
277    /// Clauses for GROUP BY
278    pub(crate) group_by_clauses: Vec<String>,
279
280    /// Clauses for HAVING
281    pub(crate) having_clauses: Vec<FilterFn>,
282
283    /// Distinct flag
284    pub(crate) is_distinct: bool,
285
286    /// Columns to omit from the query results (inverse of select_columns)
287    pub(crate) omit_columns: Vec<String>,
288
289    /// Whether to include soft-deleted records in query results
290    pub(crate) with_deleted: bool,
291
292    /// UNION and UNION ALL clauses
293    pub(crate) union_clauses: Vec<(String, FilterFn)>,
294
295    /// PhantomData to bind the generic type T
296    pub(crate) _marker: PhantomData<T>,
297}
298
299// ============================================================================
300// QueryBuilder Implementation
301// ============================================================================
302
303impl<T, E> QueryBuilder<T, E>
304where
305    T: Model + Send + Sync + Unpin + AnyImpl,
306    E: Connection,
307{
308    // ========================================================================
309    // Constructor
310    // ========================================================================
311
312    /// Creates a new QueryBuilder instance.
313    ///
314    /// This constructor is typically called internally via `db.model::<T>()`.
315    /// You rarely need to call this directly.
316    ///
317    /// # Arguments
318    ///
319    /// * `db` - Reference to the database connection
320    /// * `table_name` - Name of the table to query
321    /// * `columns_info` - Metadata about table columns
322    /// * `columns` - List of column names
323    ///
324    /// # Returns
325    ///
326    /// A new `QueryBuilder` instance ready for query construction
327    ///
328    /// # Example
329    ///
330    /// ```rust
331    /// # use bottle_orm::{Database, Model};
332    /// # #[derive(Model, Debug, Clone)]
333    /// # struct User {
334    /// #     #[orm(primary_key)]
335    /// #     id: i32,
336    /// #     username: String,
337    /// # }
338    /// # #[tokio::main]
339    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
340    /// #     let db = Database::connect("sqlite::memory:").await?;
341    /// // Usually called via db.model::<User>()
342    /// let query = db.model::<User>();
343    /// #     Ok(())
344    /// # }
345    /// ```
346    pub fn new(
347        tx: E,
348        driver: Drivers,
349        table_name: &'static str,
350        columns_info: Vec<ColumnInfo>,
351        columns: Vec<String>,
352    ) -> Self {
353        // Pre-populate omit_columns with globally omitted columns (from #[orm(omit)] attribute)
354        let omit_columns: Vec<String> =
355            columns_info.iter().filter(|c| c.omit).map(|c| c.name.to_snake_case()).collect();
356
357        Self {
358            tx,
359            alias: None,
360            driver,
361            table_name,
362            columns_info,
363            columns,
364            debug_mode: false,
365            select_columns: Vec::new(),
366            where_clauses: Vec::new(),
367            order_clauses: Vec::new(),
368            joins_clauses: Vec::new(),
369            join_aliases: std::collections::HashMap::new(),
370            group_by_clauses: Vec::new(),
371            having_clauses: Vec::new(),
372            is_distinct: false,
373            omit_columns,
374            limit: None,
375            offset: None,
376            with_deleted: false,
377            union_clauses: Vec::new(),
378            with_relations: Vec::new(),
379            _marker: PhantomData,
380        }
381    }
382
383    /// Returns the table name or alias if set.
384    pub(crate) fn get_table_identifier(&self) -> String {
385        self.alias.clone().unwrap_or_else(|| self.table_name.to_snake_case())
386    }
387
388    /// Adds a relation to be eager loaded with the query results.
389    ///
390    /// Eager loading allows you to fetch related models in a single operation
391    /// (typically using a second optimized query) to avoid the N+1 query problem.
392    ///
393    /// # Arguments
394    ///
395    /// * `relation` - The name of the relation to load (must match the field name in the model)
396    ///
397    /// # Example
398    ///
399    /// ```rust,ignore
400    /// let users = db.model::<User>()
401    ///     .with("posts")
402    ///     .scan()
403    ///     .await?;
404    ///
405    /// for user in users {
406    ///     println!("User {} has {} posts", user.username, user.posts.len());
407    /// }
408    /// ```
409    pub fn with(mut self, relation: &str) -> Self {
410        self.with_relations.push(relation.to_string());
411        self
412    }
413
414    // ========================================================================
415    // Query Building Methods
416    // ========================================================================
417
418    /// Internal helper to add a WHERE clause with a specific join operator.
419    fn filter_internal<V>(mut self, joiner: &str, col: &'static str, op: Op, value: V) -> Self
420    where
421        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
422    {
423        let op_str = op.as_sql();
424        let table_id = self.get_table_identifier();
425        // Check if the column exists in the main table to avoid ambiguous references in JOINS
426        let is_main_col = self.columns.contains(&col.to_snake_case());
427        let joiner_owned = joiner.to_string();
428        let clause: FilterFn = Box::new(move |query, args, driver, arg_counter| {
429            query.push_str(&joiner_owned);
430            if let Some((table, column)) = col.split_once(".") {
431                // If explicit table prefix is provided, use it
432                query.push_str(&format!("\"{}\".\"{}\"", table, column));
433            } else if is_main_col {
434                // If it's a known column of the main table, apply the table name/alias prefix
435                query.push_str(&format!("\"{}\".\"{}\"", table_id, col));
436            } else {
437                // Otherwise leave it unqualified so the DB can resolve it (or fail if ambiguous)
438                query.push_str(&format!("\"{}\"", col));
439            }
440            query.push(' ');
441            query.push_str(op_str);
442            query.push(' ');
443
444            // Handle different placeholder syntaxes based on database driver
445            match driver {
446                // PostgreSQL uses numbered placeholders: $1, $2, $3, ...
447                Drivers::Postgres => {
448                    query.push_str(&format!("${}", arg_counter));
449                    *arg_counter += 1;
450                }
451                // MySQL and SQLite use question mark placeholders: ?
452                _ => query.push('?'),
453            }
454
455            // Bind the value to the query
456            let _ = args.add(value.clone());
457        });
458
459        self.where_clauses.push(clause);
460        self
461    }
462
463    /// Adds a WHERE IN (SUBQUERY) clause to the query.
464    ///
465    /// This allows for filtering a column based on the results of another query.
466    ///
467    /// # Example
468    /// ```rust,ignore
469    /// let subquery = db.model::<Post>().select("user_id").filter("views", ">", 1000);
470    /// db.model::<User>().filter_subquery("id", Op::In, subquery).scan().await?;
471    /// ```
472    pub fn filter_subquery<S, SE>(mut self, col: &'static str, op: Op, mut subquery: QueryBuilder<S, SE>) -> Self
473    where
474        S: Model + Send + Sync + Unpin + AnyImpl + 'static,
475        SE: Connection + 'static,
476    {
477        subquery.apply_soft_delete_filter();
478        let table_id = self.get_table_identifier();
479        let is_main_col = self.columns.contains(&col.to_snake_case());
480        let op_str = op.as_sql();
481
482        let clause: FilterFn = Box::new(move |query, args, _driver, arg_counter| {
483            query.push_str(" AND ");
484            if let Some((table, column)) = col.split_once(".") {
485                query.push_str(&format!("\"{}\".\"{}\"", table, column));
486            } else if is_main_col {
487                query.push_str(&format!("\"{}\".\"{}\"", table_id, col));
488            } else {
489                query.push_str(&format!("\"{}\"", col));
490            }
491            query.push_str(&format!(" {} (", op_str));
492
493            subquery.write_select_sql::<S>(query, args, arg_counter);
494            query.push_str(")");
495        });
496
497        self.where_clauses.push(clause);
498        self
499    }
500
501    /// Truncates the table associated with this Model.
502    ///
503    /// This method removes all records from the table. It uses `TRUNCATE TABLE`
504    /// for Postgres and MySQL, and `DELETE FROM` with sequence reset for SQLite.
505    ///
506    /// # Returns
507    ///
508    /// * `Ok(())` - Table truncated successfully
509    /// * `Err(sqlx::Error)` - Database error occurred
510    ///
511    /// # Example
512    ///
513    /// ```rust,ignore
514    /// db.model::<Log>().truncate().await?;
515    /// ```
516    pub async fn truncate(self) -> Result<(), sqlx::Error> {
517        let table_name = self.table_name.to_snake_case();
518        let query = match self.driver {
519            Drivers::Postgres | Drivers::MySQL => format!("TRUNCATE TABLE \"{}\"", table_name),
520            Drivers::SQLite => format!("DELETE FROM \"{}\"", table_name),
521        };
522
523        if self.debug_mode {
524            log::debug!("SQL: {}", query);
525        }
526
527        self.tx.execute(&query, AnyArguments::default()).await?;
528        
529        // For SQLite, reset auto-increment if exists
530        if matches!(self.driver, Drivers::SQLite) {
531            let _ = self.tx.execute(&format!("DELETE FROM sqlite_sequence WHERE name='{}'", table_name), AnyArguments::default()).await;
532        }
533
534        Ok(())
535    }
536
537    /// Combines the results of this query with another query using UNION.
538    ///
539    /// This method allows you to combine the result sets of two queries into a single
540    /// result set. Duplicate rows are removed by default.
541    ///
542    /// # Arguments
543    ///
544    /// * `other` - Another QueryBuilder instance to combine with.
545    ///
546    /// # Example
547    ///
548    /// ```rust,ignore
549    /// let q1 = db.model::<User>().filter("age", ">", 18);
550    /// let q2 = db.model::<User>().filter("status", "=", "premium");
551    /// let results = q1.union(q2).scan().await?;
552    /// ```
553    pub fn union(self, other: QueryBuilder<T, E>) -> Self where T: AnyImpl + 'static, E: 'static {
554        self.union_internal("UNION", other)
555    }
556
557    /// Combines the results of this query with another query using UNION ALL.
558    ///
559    /// This method allows you to combine the result sets of two queries into a single
560    /// result set, including all duplicates.
561    ///
562    /// # Arguments
563    ///
564    /// * `other` - Another QueryBuilder instance to combine with.
565    ///
566    /// # Example
567    ///
568    /// ```rust,ignore
569    /// let q1 = db.model::<User>().filter("age", ">", 18);
570    /// let q2 = db.model::<User>().filter("status", "=", "premium");
571    /// let results = q1.union_all(q2).scan().await?;
572    /// ```
573    pub fn union_all(self, other: QueryBuilder<T, E>) -> Self where T: AnyImpl + 'static, E: 'static {
574        self.union_internal("UNION ALL", other)
575    }
576
577    fn union_internal(mut self, op: &str, mut other: QueryBuilder<T, E>) -> Self where T: AnyImpl + 'static, E: 'static {
578        other.apply_soft_delete_filter();
579        let op_owned = op.to_string();
580        
581        self.union_clauses.push((op_owned.clone(), Box::new(move |query: &mut String, args: &mut AnyArguments<'_>, _driver: &Drivers, arg_counter: &mut usize| {
582            query.push_str(" ");
583            query.push_str(&op_owned);
584            query.push_str(" ");
585            other.write_select_sql::<T>(query, args, arg_counter);
586        })));
587        self
588    }
589
590    /// Internal helper to write the SELECT SQL to a string buffer.
591    pub(crate) fn write_select_sql<R: AnyImpl>(
592        &self,
593        query: &mut String,
594        args: &mut AnyArguments,
595        arg_counter: &mut usize,
596    ) {
597        query.push_str("SELECT ");
598
599        if self.is_distinct {
600            query.push_str("DISTINCT ");
601        }
602
603        query.push_str(&self.select_args_sql::<R>().join(", "));
604
605        // Build FROM clause
606        query.push_str(" FROM \"");
607        query.push_str(&self.table_name.to_snake_case());
608        query.push_str("\" ");
609        if let Some(alias) = &self.alias {
610            query.push_str(&format!("\"{}\" ", alias));
611        }
612
613        if !self.joins_clauses.is_empty() {
614            for join_clause in &self.joins_clauses {
615                query.push(' ');
616                join_clause(query, args, &self.driver, arg_counter);
617            }
618        }
619
620        query.push_str(" WHERE 1=1");
621
622        // Apply WHERE clauses
623        for clause in &self.where_clauses {
624            clause(query, args, &self.driver, arg_counter);
625        }
626
627        // Apply GROUP BY
628        if !self.group_by_clauses.is_empty() {
629            query.push_str(&format!(" GROUP BY {}", self.group_by_clauses.join(", ")));
630        }
631
632        // Apply HAVING
633        if !self.having_clauses.is_empty() {
634            query.push_str(" HAVING 1=1");
635            for clause in &self.having_clauses {
636                clause(query, args, &self.driver, arg_counter);
637            }
638        }
639
640        // Apply ORDER BY clauses
641        if !self.order_clauses.is_empty() {
642            query.push_str(&format!(" ORDER BY {}", self.order_clauses.join(", ")));
643        }
644
645        // Apply LIMIT clause
646        if let Some(limit) = self.limit {
647            query.push_str(" LIMIT ");
648            match self.driver {
649                Drivers::Postgres => {
650                    query.push_str(&format!("${}", arg_counter));
651                    *arg_counter += 1;
652                }
653                _ => query.push('?'),
654            }
655            let _ = args.add(limit as i64);
656        }
657
658        // Apply OFFSET clause
659        if let Some(offset) = self.offset {
660            query.push_str(" OFFSET ");
661            match self.driver {
662                Drivers::Postgres => {
663                    query.push_str(&format!("${}", arg_counter));
664                    *arg_counter += 1;
665                }
666                _ => query.push('?'),
667            }
668            let _ = args.add(offset as i64);
669        }
670
671        // Apply UNION clauses
672        for (_op, clause) in &self.union_clauses {
673            clause(query, args, &self.driver, arg_counter);
674        }
675    }
676
677    /// Adds a WHERE clause to the query.
678    ///
679    /// This method adds a filter condition to the query. Multiple filters can be chained
680    /// and will be combined with AND operators. The value is bound as a parameter to
681    /// prevent SQL injection.
682    ///
683    /// # Type Parameters
684    ///
685    /// * `V` - The type of the value to filter by. Must be encodable for SQL queries.
686    ///
687    /// # Arguments
688    ///
689    /// * `col` - The column name to filter on
690    /// * `op` - The comparison operator (e.g., "=", ">", "LIKE", "IN")
691    /// * `value` - The value to compare against
692    ///
693    /// # Example
694    ///
695    /// ```rust
696    /// # use bottle_orm::{Database, Model, Op};
697    /// # #[derive(Model, Debug, Clone)]
698    /// # struct User {
699    /// #     #[orm(primary_key)]
700    /// #     id: i32,
701    /// #     age: i32,
702    /// # }
703    /// # #[tokio::main]
704    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
705    /// #     let db = Database::connect("sqlite::memory:").await?;
706    /// let query = db.model::<User>().filter("age", Op::Gte, 18);
707    /// #     Ok(())
708    /// # }
709    /// ```
710    pub fn filter<V>(self, col: &'static str, op: Op, value: V) -> Self
711    where
712        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
713    {
714        self.filter_internal(" AND ", col, op, value)
715    }
716
717    /// Adds an OR WHERE clause to the query.
718    ///
719    /// # Arguments
720    ///
721    /// * `col` - The column name to filter on
722    /// * `op` - The comparison operator
723    /// * `value` - The value to compare against
724    ///
725    /// # Example
726    ///
727    /// ```rust
728    /// # use bottle_orm::{Database, Model, Op};
729    /// # #[derive(Model, Debug, Clone)]
730    /// # struct User {
731    /// #     #[orm(primary_key)]
732    /// #     id: i32,
733    /// #     age: i32,
734    /// #     active: bool,
735    /// # }
736    /// # #[tokio::main]
737    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
738    /// #     let db = Database::connect("sqlite::memory:").await?;
739    /// let query = db.model::<User>()
740    ///     .filter("age", Op::Lt, 18)
741    ///     .or_filter("active", Op::Eq, false);
742    /// #     Ok(())
743    /// # }
744    /// ```
745    pub fn or_filter<V>(self, col: &'static str, op: Op, value: V) -> Self
746    where
747        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
748    {
749        self.filter_internal(" OR ", col, op, value)
750    }
751
752    /// Adds an AND NOT WHERE clause to the query.
753    ///
754    /// # Arguments
755    ///
756    /// * `col` - The column name to filter on
757    /// * `op` - The comparison operator
758    /// * `value` - The value to compare against
759    ///
760    /// # Example
761    ///
762    /// ```rust
763    /// # use bottle_orm::{Database, Model, Op};
764    /// # #[derive(Model, Debug, Clone)]
765    /// # struct User {
766    /// #     #[orm(primary_key)]
767    /// #     id: i32,
768    /// #     status: String,
769    /// # }
770    /// # #[tokio::main]
771    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
772    /// #     let db = Database::connect("sqlite::memory:").await?;
773    /// let query = db.model::<User>().not_filter("status", Op::Eq, "banned".to_string());
774    /// #     Ok(())
775    /// # }
776    /// ```
777    pub fn not_filter<V>(self, col: &'static str, op: Op, value: V) -> Self
778    where
779        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
780    {
781        self.filter_internal(" AND NOT ", col, op, value)
782    }
783
784    /// Adds an OR NOT WHERE clause to the query.
785    ///
786    /// # Arguments
787    ///
788    /// * `col` - The column name to filter on
789    /// * `op` - The comparison operator
790    /// * `value` - The value to compare against
791    ///
792    /// # Example
793    ///
794    /// ```rust
795    /// # use bottle_orm::{Database, Model, Op};
796    /// # #[derive(Model, Debug, Clone)]
797    /// # struct User {
798    /// #     #[orm(primary_key)]
799    /// #     id: i32,
800    /// #     age: i32,
801    /// #     status: String,
802    /// # }
803    /// # #[tokio::main]
804    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
805    /// #     let db = Database::connect("sqlite::memory:").await?;
806    /// let query = db.model::<User>()
807    ///     .filter("age", Op::Gt, 18)
808    ///     .or_not_filter("status", Op::Eq, "inactive".to_string());
809    /// #     Ok(())
810    /// # }
811    /// ```
812    pub fn or_not_filter<V>(self, col: &'static str, op: Op, value: V) -> Self
813    where
814        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
815    {
816        self.filter_internal(" OR NOT ", col, op, value)
817    }
818
819    /// Adds a BETWEEN clause to the query.
820    ///
821    /// # Arguments
822    ///
823    /// * `col` - The column name
824    /// * `start` - The start value of the range
825    /// * `end` - The end value of the range
826    ///
827    /// # Example
828    ///
829    /// ```rust
830    /// # use bottle_orm::{Database, Model, Op};
831    /// # #[derive(Model, Debug, Clone)]
832    /// # struct User {
833    /// #     #[orm(primary_key)]
834    /// #     id: i32,
835    /// #     age: i32,
836    /// # }
837    /// # #[tokio::main]
838    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
839    /// #     let db = Database::connect("sqlite::memory:").await?;
840    /// let query = db.model::<User>().between("age", 18, 30);
841    /// #     Ok(())
842    /// # }
843    /// ```
844    pub fn between<V>(mut self, col: &'static str, start: V, end: V) -> Self
845    where
846        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
847    {
848        let table_id = self.get_table_identifier();
849        let is_main_col = self.columns.contains(&col.to_snake_case());
850        let clause: FilterFn = Box::new(move |query, args, driver, arg_counter| {
851            query.push_str(" AND ");
852            if let Some((table, column)) = col.split_once(".") {
853                query.push_str(&format!("\"{}\".\"{}\"", table, column));
854            } else if is_main_col {
855                query.push_str(&format!("\"{}\".\"{}\"", table_id, col));
856            } else {
857                query.push_str(&format!("\"{}\"", col));
858            }
859            query.push_str(" BETWEEN ");
860
861            match driver {
862                Drivers::Postgres => {
863                    query.push_str(&format!("${} AND ${}", arg_counter, *arg_counter + 1));
864                    *arg_counter += 2;
865                }
866                _ => query.push_str("? AND ?"),
867            }
868
869            let _ = args.add(start.clone());
870            let _ = args.add(end.clone());
871        });
872        self.where_clauses.push(clause);
873        self
874    }
875
876    /// Adds an OR BETWEEN clause to the query.
877    ///
878    /// # Arguments
879    ///
880    /// * `col` - The column name
881    /// * `start` - The start value of the range
882    /// * `end` - The end value of the range
883    ///
884    /// # Example
885    ///
886    /// ```rust
887    /// # use bottle_orm::{Database, Model, Op};
888    /// # #[derive(Model, Debug, Clone)]
889    /// # struct User {
890    /// #     #[orm(primary_key)]
891    /// #     id: i32,
892    /// #     age: i32,
893    /// #     salary: i32,
894    /// # }
895    /// # #[tokio::main]
896    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
897    /// #     let db = Database::connect("sqlite::memory:").await?;
898    /// let query = db.model::<User>()
899    ///     .between("age", 18, 30)
900    ///     .or_between("salary", 5000, 10000);
901    /// #     Ok(())
902    /// # }
903    /// ```
904    pub fn or_between<V>(mut self, col: &'static str, start: V, end: V) -> Self
905    where
906        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
907    {
908        let table_id = self.get_table_identifier();
909        let is_main_col = self.columns.contains(&col.to_snake_case());
910        let clause: FilterFn = Box::new(move |query, args, driver, arg_counter| {
911            query.push_str(" OR ");
912            if let Some((table, column)) = col.split_once(".") {
913                query.push_str(&format!("\"{}\".\"{}\"", table, column));
914            } else if is_main_col {
915                query.push_str(&format!("\"{}\".\"{}\"", table_id, col));
916            } else {
917                query.push_str(&format!("\"{}\"", col));
918            }
919            query.push_str(" BETWEEN ");
920
921            match driver {
922                Drivers::Postgres => {
923                    query.push_str(&format!("${} AND ${}", arg_counter, *arg_counter + 1));
924                    *arg_counter += 2;
925                }
926                _ => query.push_str("? AND ?"),
927            }
928
929            let _ = args.add(start.clone());
930            let _ = args.add(end.clone());
931        });
932        self.where_clauses.push(clause);
933        self
934    }
935
936    /// Adds an IN list clause to the query.
937    ///
938    /// # Arguments
939    ///
940    /// * `col` - The column name
941    /// * `values` - A vector of values
942    ///
943    /// # Example
944    ///
945    /// ```rust
946    /// # use bottle_orm::{Database, Model, Op};
947    /// # #[derive(Model, Debug, Clone)]
948    /// # struct User {
949    /// #     #[orm(primary_key)]
950    /// #     id: i32,
951    /// #     status: String,
952    /// # }
953    /// # #[tokio::main]
954    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
955    /// #     let db = Database::connect("sqlite::memory:").await?;
956    /// let query = db.model::<User>().in_list("status", vec!["active".to_string(), "pending".to_string()]);
957    /// #     Ok(())
958    /// # }
959    /// ```
960    pub fn in_list<V>(mut self, col: &'static str, values: Vec<V>) -> Self
961    where
962        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
963    {
964        if values.is_empty() {
965            // WHERE 1=0 to ensure empty result
966            let clause: FilterFn = Box::new(|query, _, _, _| {
967                query.push_str(" AND 1=0");
968            });
969            self.where_clauses.push(clause);
970            return self;
971        }
972
973        let table_id = self.get_table_identifier();
974        let is_main_col = self.columns.contains(&col.to_snake_case());
975        let clause: FilterFn = Box::new(move |query, args, driver, arg_counter| {
976            query.push_str(" AND ");
977            if let Some((table, column)) = col.split_once(".") {
978                query.push_str(&format!("\"{}\".\"{}\"", table, column));
979            } else if is_main_col {
980                query.push_str(&format!("\"{}\".\"{}\"", table_id, col));
981            } else {
982                query.push_str(&format!("\"{}\"", col));
983            }
984            query.push_str(" IN (");
985
986            let mut placeholders = Vec::new();
987            for _ in &values {
988                match driver {
989                    Drivers::Postgres => {
990                        placeholders.push(format!("${}", arg_counter));
991                        *arg_counter += 1;
992                    }
993                    _ => placeholders.push("?".to_string()),
994                }
995            }
996            query.push_str(&placeholders.join(", "));
997            query.push(')');
998
999            for val in &values {
1000                let _ = args.add(val.clone());
1001            }
1002        });
1003        self.where_clauses.push(clause);
1004        self
1005    }
1006
1007    /// Adds an OR IN list clause to the query.
1008    ///
1009    /// # Arguments
1010    ///
1011    /// * `col` - The column name
1012    /// * `values` - A vector of values
1013    ///
1014    /// # Example
1015    ///
1016    /// ```rust
1017    /// # use bottle_orm::{Database, Model, Op};
1018    /// # #[derive(Model, Debug, Clone)]
1019    /// # struct User {
1020    /// #     #[orm(primary_key)]
1021    /// #     id: i32,
1022    /// #     status: String,
1023    /// #     role: String,
1024    /// # }
1025    /// # #[tokio::main]
1026    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1027    /// #     let db = Database::connect("sqlite::memory:").await?;
1028    /// let query = db.model::<User>()
1029    ///     .filter("status", Op::Eq, "active".to_string())
1030    ///     .or_in_list("role", vec!["admin".to_string(), "editor".to_string()]);
1031    /// #     Ok(())
1032    /// # }
1033    /// ```
1034    pub fn or_in_list<V>(mut self, col: &'static str, values: Vec<V>) -> Self
1035    where
1036        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
1037    {
1038        if values.is_empty() {
1039            return self;
1040        }
1041
1042        let table_id = self.get_table_identifier();
1043        let is_main_col = self.columns.contains(&col.to_snake_case());
1044        let clause: FilterFn = Box::new(move |query, args, driver, arg_counter| {
1045            query.push_str(" OR ");
1046            if let Some((table, column)) = col.split_once(".") {
1047                query.push_str(&format!("\"{}\".\"{}\"", table, column));
1048            } else if is_main_col {
1049                query.push_str(&format!("\"{}\".\"{}\"", table_id, col));
1050            } else {
1051                query.push_str(&format!("\"{}\"", col));
1052            }
1053            query.push_str(" IN (");
1054
1055            let mut placeholders = Vec::new();
1056            for _ in &values {
1057                match driver {
1058                    Drivers::Postgres => {
1059                        placeholders.push(format!("${}", arg_counter));
1060                        *arg_counter += 1;
1061                    }
1062                    _ => placeholders.push("?".to_string()),
1063                }
1064            }
1065            query.push_str(&placeholders.join(", "));
1066            query.push(')');
1067
1068            for val in &values {
1069                let _ = args.add(val.clone());
1070            }
1071        });
1072        self.where_clauses.push(clause);
1073        self
1074    }
1075
1076    /// Groups filters inside parentheses with an AND operator.
1077    ///
1078    /// This allows for constructing complex WHERE clauses with nested logic.
1079    ///
1080    /// # Arguments
1081    ///
1082    /// * `f` - A closure that receives a `QueryBuilder` and returns it with more filters
1083    ///
1084    /// # Example
1085    ///
1086    /// ```rust,ignore
1087    /// db.model::<User>()
1088    ///     .filter("active", Op::Eq, true)
1089    ///     .group(|q| q.filter("age", Op::Gt, 18).or_filter("role", Op::Eq, "admin"))
1090    ///     .scan()
1091    ///     .await?;
1092    /// // SQL: AND "active" = true AND (1=1 AND ("age" > 18 OR "role" = 'admin'))
1093    /// ```
1094    pub fn group<F>(mut self, f: F) -> Self
1095    where
1096        F: FnOnce(Self) -> Self,
1097    {
1098        let old_clauses = std::mem::take(&mut self.where_clauses);
1099        self = f(self);
1100        let group_clauses = std::mem::take(&mut self.where_clauses);
1101        self.where_clauses = old_clauses;
1102
1103        if !group_clauses.is_empty() {
1104            let clause: FilterFn = Box::new(move |query, args, driver, arg_counter| {
1105                query.push_str(" AND (1=1");
1106                for c in &group_clauses {
1107                    c(query, args, driver, arg_counter);
1108                }
1109                query.push_str(")");
1110            });
1111            self.where_clauses.push(clause);
1112        }
1113        self
1114    }
1115
1116    /// Groups filters inside parentheses with an OR operator.
1117    ///
1118    /// # Arguments
1119    ///
1120    /// * `f` - A closure that receives a `QueryBuilder` and returns it with more filters
1121    ///
1122    /// # Example
1123    ///
1124    /// ```rust,ignore
1125    /// db.model::<User>()
1126    ///     .filter("active", Op::Eq, true)
1127    ///     .or_group(|q| q.filter("role", Op::Eq, "admin").filter("age", Op::Gt, 18))
1128    ///     .scan()
1129    ///     .await?;
1130    /// // SQL: AND "active" = true OR (1=1 AND ("role" = 'admin' AND "age" > 18))
1131    /// ```
1132    pub fn or_group<F>(mut self, f: F) -> Self
1133    where
1134        F: FnOnce(Self) -> Self,
1135    {
1136        let old_clauses = std::mem::take(&mut self.where_clauses);
1137        self = f(self);
1138        let group_clauses = std::mem::take(&mut self.where_clauses);
1139        self.where_clauses = old_clauses;
1140
1141        if !group_clauses.is_empty() {
1142            let clause: FilterFn = Box::new(move |query, args, driver, arg_counter| {
1143                query.push_str(" OR (1=1");
1144                for c in &group_clauses {
1145                    c(query, args, driver, arg_counter);
1146                }
1147                query.push_str(")");
1148            });
1149            self.where_clauses.push(clause);
1150        }
1151        self
1152    }
1153
1154    /// Adds a raw WHERE clause with a placeholder and a single value.
1155    ///
1156    /// This allows writing raw SQL conditions with a `?` placeholder.
1157    /// To use multiple placeholders with different types, chain multiple `where_raw` calls.
1158    ///
1159    /// # Arguments
1160    ///
1161    /// * `sql` - Raw SQL string with one `?` placeholder (e.g., "age > ?")
1162    /// * `value` - Value to bind
1163    ///
1164    /// # Example
1165    ///
1166    /// ```rust,ignore
1167    /// db.model::<User>()
1168    ///     .where_raw("name = ?", "Alice".to_string())
1169    ///     .where_raw("age >= ?", 18)
1170    ///     .scan()
1171    ///     .await?;
1172    /// // SQL: AND name = 'Alice' AND age >= 18
1173    /// ```
1174    pub fn where_raw<V>(mut self, sql: &str, value: V) -> Self
1175    where
1176        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
1177    {
1178        self.where_clauses.push(self.create_raw_clause(" AND ", sql, value));
1179        self
1180    }
1181
1182    /// Adds a raw OR WHERE clause with a placeholder.
1183    ///
1184    /// # Arguments
1185    ///
1186    /// * `sql` - Raw SQL string with one `?` placeholder
1187    /// * `value` - Value to bind
1188    ///
1189    /// # Example
1190    ///
1191    /// ```rust,ignore
1192    /// db.model::<User>()
1193    ///     .filter("active", Op::Eq, true)
1194    ///     .or_where_raw("age > ?", 18)
1195    ///     .scan()
1196    ///     .await?;
1197    /// // SQL: AND "active" = true OR age > 18
1198    /// ```
1199    pub fn or_where_raw<V>(mut self, sql: &str, value: V) -> Self
1200    where
1201        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
1202    {
1203        self.where_clauses.push(self.create_raw_clause(" OR ", sql, value));
1204        self
1205    }
1206
1207    /// Internal helper to create a raw SQL clause with a single value.
1208    fn create_raw_clause<V>(&self, joiner: &'static str, sql: &str, value: V) -> FilterFn
1209    where
1210        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
1211    {
1212        let sql_owned = sql.to_string();
1213        Box::new(move |query, args, driver, arg_counter| {
1214            query.push_str(joiner);
1215            
1216            let mut processed_sql = sql_owned.clone();
1217            
1218            // If no placeholder is found, try to be helpful
1219            if !processed_sql.contains('?') {
1220                let trimmed = processed_sql.trim();
1221                if trimmed.ends_with('=') || trimmed.ends_with('>') || trimmed.ends_with('<') || trimmed.to_uppercase().ends_with(" LIKE") {
1222                    processed_sql.push_str(" ?");
1223                } else if !trimmed.contains(' ') && !trimmed.contains('(') {
1224                    // It looks like just a column name
1225                    processed_sql.push_str(" = ?");
1226                }
1227            }
1228
1229            // Replace '?' with driver-specific placeholders only if needed
1230            if matches!(driver, Drivers::Postgres) {
1231                while let Some(pos) = processed_sql.find('?') {
1232                    let placeholder = format!("${}", arg_counter);
1233                    *arg_counter += 1;
1234                    processed_sql.replace_range(pos..pos + 1, &placeholder);
1235                }
1236            }
1237            
1238            query.push_str(&processed_sql);
1239            let _ = args.add(value.clone());
1240        })
1241    }
1242
1243    /// Adds an equality filter to the query.
1244    ///
1245    /// This is a convenience wrapper around `filter()` for simple equality checks.
1246    /// It is equivalent to calling `filter(col, "=", value)`.
1247    ///
1248    /// # Type Parameters
1249    ///
1250    /// * `V` - The type of the value to compare against.
1251    ///
1252    /// # Arguments
1253    ///
1254    /// * `col` - The column name to filter on.
1255    /// * `value` - The value to match.
1256    ///
1257    /// # Example
1258    ///
1259    /// ```rust,ignore
1260    /// // Equivalent to filter("age", Op::Eq, 18)
1261    /// query.equals("age", 18)
1262    /// ```
1263    pub fn equals<V>(self, col: &'static str, value: V) -> Self
1264    where
1265        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
1266    {
1267        self.filter(col, Op::Eq, value)
1268    }
1269
1270    /// Adds an ORDER BY clause to the query.
1271    ///
1272    /// Specifies the sort order for the query results. Multiple order clauses
1273    /// can be added and will be applied in the order they were added.
1274    ///
1275    /// # Arguments
1276    ///
1277    /// * `order` - The ORDER BY expression (e.g., "created_at DESC", "age ASC, name DESC")
1278    ///
1279    /// # Example
1280    ///
1281    /// ```rust,ignore
1282    /// // Single column ascending (ASC is default)
1283    /// query.order("age")
1284    ///
1285    /// // Single column descending
1286    /// query.order("created_at DESC")
1287    ///
1288    /// // Multiple columns
1289    /// query.order("age DESC, username ASC")
1290    ///
1291    /// // Chain multiple order clauses
1292    /// query
1293    ///     .order("priority DESC")
1294    ///     .order("created_at ASC")
1295    /// ```
1296    pub fn order(mut self, order: &str) -> Self {
1297        self.order_clauses.push(order.to_string());
1298        self
1299    }
1300
1301    /// Defines a SQL alias for the primary table in the query.
1302    ///
1303    /// This method allows you to set a short alias for the model's underlying table.
1304    /// It is highly recommended when writing complex queries with multiple `JOIN` clauses,
1305    /// preventing the need to repeat the full table name in `.filter()`, `.equals()`, or `.select()`.
1306    ///
1307    /// # Arguments
1308    ///
1309    /// * `alias` - A string slice representing the alias to be used (e.g., "u", "rp").
1310    ///
1311    /// # Example
1312    ///
1313    /// ```rust,ignore
1314    /// // Using 'u' as an alias for the User table
1315    /// let results = db.model::<User>()
1316    ///     .alias("u")
1317    ///     .join("role_permissions rp", "rp.role_id = u.role")
1318    ///     .equals("u.id", user_id)
1319    ///     .select("u.username, rp.permission_id")
1320    ///     .scan_as::<UserPermissionDTO>()
1321    ///     .await?;
1322    /// ```
1323    pub fn alias(mut self, alias: &str) -> Self {
1324        self.alias = Some(alias.to_string());
1325        self
1326    }
1327
1328    /// Placeholder for eager loading relationships (preload).
1329    ///
1330    /// This method is reserved for future implementation of relationship preloading.
1331    /// Currently, it returns `self` unchanged to maintain the fluent interface.
1332    ///
1333    /// # Future Implementation
1334    ///
1335    /// Will support eager loading of related models to avoid N+1 query problems:
1336    ///
1337    /// ```rust,ignore
1338    /// // Future usage example
1339    /// query.preload("posts").preload("comments")
1340    /// ```
1341    // pub fn preload(self) -> Self {
1342    //     // TODO: Implement relationship preloading
1343    //     self
1344    // }
1345
1346    /// Activates debug mode for this query.
1347    ///
1348    /// When enabled, the generated SQL query will be logged using the `log` crate
1349    /// at the `DEBUG` level before execution.
1350    ///
1351    /// # Note
1352    ///
1353    /// To see the output, you must initialize a logger in your application (e.g., using `env_logger`)
1354    /// and configure it to display `debug` logs for `bottle_orm`.
1355    ///
1356    /// # Example
1357    ///
1358    /// ```rust,ignore
1359    /// db.model::<User>()
1360    ///     .filter("active", "=", true)
1361    ///     .debug() // Logs SQL: SELECT * FROM "user" WHERE "active" = $1
1362    ///     .scan()
1363    ///     .await?;
1364    /// ```
1365    pub fn debug(mut self) -> Self {
1366        self.debug_mode = true;
1367        self
1368    }
1369
1370    /// Adds an IS NULL filter for the specified column.
1371    ///
1372    /// # Arguments
1373    ///
1374    /// * `col` - The column name to check for NULL
1375    ///
1376    /// # Example
1377    ///
1378    /// ```rust,ignore
1379    /// db.model::<User>()
1380    ///     .is_null("deleted_at")
1381    ///     .scan()
1382    ///     .await?;
1383    /// // SQL: SELECT * FROM "user" WHERE "deleted_at" IS NULL
1384    /// ```
1385    pub fn is_null(mut self, col: &str) -> Self {
1386        let col_owned = col.to_string();
1387        let table_id = self.get_table_identifier();
1388        let is_main_col = self.columns.contains(&col_owned.to_snake_case());
1389        let clause: FilterFn = Box::new(move |query, _args, _driver, _arg_counter| {
1390            query.push_str(" AND ");
1391            if let Some((table, column)) = col_owned.split_once(".") {
1392                query.push_str(&format!("\"{}\".\"{}\"", table, column));
1393            } else if is_main_col {
1394                query.push_str(&format!("\"{}\".\"{}\"", table_id, col_owned));
1395            } else {
1396                query.push_str(&format!("\"{}\"", col_owned));
1397            }
1398            query.push_str(" IS NULL");
1399        });
1400        self.where_clauses.push(clause);
1401        self
1402    }
1403
1404    /// Adds an IS NOT NULL filter for the specified column.
1405    ///
1406    /// # Arguments
1407    ///
1408    /// * `col` - The column name to check for NOT NULL
1409    ///
1410    /// # Example
1411    ///
1412    /// ```rust,ignore
1413    /// db.model::<User>()
1414    ///     .is_not_null("email")
1415    ///     .scan()
1416    ///     .await?;
1417    /// // SQL: SELECT * FROM "user" WHERE "email" IS NOT NULL
1418    /// ```
1419    pub fn is_not_null(mut self, col: &str) -> Self {
1420        let col_owned = col.to_string();
1421        let table_id = self.get_table_identifier();
1422        let is_main_col = self.columns.contains(&col_owned.to_snake_case());
1423        let clause: FilterFn = Box::new(move |query, _args, _driver, _arg_counter| {
1424            query.push_str(" AND ");
1425            if let Some((table, column)) = col_owned.split_once(".") {
1426                query.push_str(&format!("\"{}\".\"{}\"", table, column));
1427            } else if is_main_col {
1428                query.push_str(&format!("\"{}\".\"{}\"", table_id, col_owned));
1429            } else {
1430                query.push_str(&format!("\"{}\"", col_owned));
1431            }
1432            query.push_str(" IS NOT NULL");
1433        });
1434        self.where_clauses.push(clause);
1435        self
1436    }
1437
1438    /// Includes soft-deleted records in query results.
1439    ///
1440    /// By default, queries on models with a `#[orm(soft_delete)]` column exclude
1441    /// records where that column is not NULL. This method disables that filter.
1442    ///
1443    /// # Example
1444    ///
1445    /// ```rust,ignore
1446    /// // Get all users including deleted ones
1447    /// db.model::<User>()
1448    ///     .with_deleted()
1449    ///     .scan()
1450    ///     .await?;
1451    /// ```
1452    pub fn with_deleted(mut self) -> Self {
1453        self.with_deleted = true;
1454        self
1455    }
1456
1457    /// Adds an INNER JOIN clause to the query.
1458    ///
1459    /// # Arguments
1460    ///
1461    /// * `table` - The name of the table to join (with optional alias)
1462    /// * `on` - The join condition (e.g., "users.id = posts.user_id")
1463    ///
1464    /// # Example
1465    ///
1466    /// ```rust,ignore
1467    /// db.model::<User>()
1468    ///     .join("posts p", "u.id = p.user_id")
1469    ///     .scan()
1470    ///     .await?;
1471    /// // SQL: INNER JOIN "posts" p ON u.id = p.user_id
1472    /// ```
1473    pub fn join(self, table: &str, s_query: &str) -> Self {
1474        self.join_generic("", table, s_query)
1475    }
1476
1477    /// Internal helper for specific join types
1478    fn join_generic(mut self, join_type: &str, table: &str, s_query: &str) -> Self {
1479        let table_owned = table.to_string();
1480        let join_type_owned = join_type.to_string();
1481        
1482        let trimmed_value = s_query.replace(" ", "");
1483        let values = trimmed_value.split_once("=");
1484        let mut parsed_query = s_query.to_string();
1485        
1486        if let Some((first, second)) = values {
1487            // Try to parse table.column = table.column
1488            if let Some((t1, c1)) = first.split_once('.') {
1489                if let Some((t2, c2)) = second.split_once('.') {
1490                    parsed_query = format!("\"{}\".\"{}\" = \"{}\".\"{}\"", t1, c1, t2, c2);
1491                }
1492            }
1493        }
1494
1495        if let Some((table_name, alias)) = table.split_once(" ") {
1496            self.join_aliases.insert(table_name.to_snake_case(), alias.to_string());
1497        } else {
1498            self.join_aliases.insert(table.to_snake_case(), table.to_string());
1499        }
1500
1501        self.joins_clauses.push(Box::new(move |query, _args, _driver, _arg_counter| {
1502            if let Some((table_name, alias)) = table_owned.split_once(" ") {
1503                query.push_str(&format!("{} JOIN \"{}\" \"{}\" ON {}", join_type_owned, table_name, alias, parsed_query));
1504            } else {
1505                query.push_str(&format!("{} JOIN \"{}\" ON {}", join_type_owned, table_owned, parsed_query));
1506            }
1507        }));
1508        self
1509    }
1510
1511    /// Adds a JOIN clause with a placeholder and a bound value.
1512    ///
1513    /// # Arguments
1514    ///
1515    /// * `table` - The name of the table to join
1516    /// * `on` - The join condition with a `?` placeholder
1517    /// * `value` - The value to bind
1518    ///
1519    /// # Example
1520    ///
1521    /// ```rust,ignore
1522    /// db.model::<User>()
1523    ///     .join_raw("posts p", "p.user_id = u.id AND p.status = ?", "published")
1524    ///     .scan()
1525    ///     .await?;
1526    /// // SQL: JOIN "posts" p ON p.user_id = u.id AND p.status = 'published'
1527    /// ```
1528    pub fn join_raw<V>(self, table: &str, on: &str, value: V) -> Self
1529    where
1530        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
1531    {
1532        self.join_generic_raw("", table, on, value)
1533    }
1534
1535    /// Adds a raw LEFT JOIN clause with a placeholder and a bound value.
1536    ///
1537    /// # Arguments
1538    ///
1539    /// * `table` - The name of the table to join (with optional alias)
1540    /// * `on` - The join condition with a `?` placeholder
1541    /// * `value` - The value to bind
1542    ///
1543    /// # Example
1544    ///
1545    /// ```rust,ignore
1546    /// query.left_join_raw("posts p", "p.user_id = u.id AND p.status = ?", "published")
1547    /// ```
1548    pub fn left_join_raw<V>(self, table: &str, on: &str, value: V) -> Self
1549    where
1550        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
1551    {
1552        self.join_generic_raw("LEFT", table, on, value)
1553    }
1554
1555    /// Adds a raw RIGHT JOIN clause with a placeholder and a bound value.
1556    ///
1557    /// # Arguments
1558    ///
1559    /// * `table` - The name of the table to join (with optional alias)
1560    /// * `on` - The join condition with a `?` placeholder
1561    /// * `value` - The value to bind
1562    ///
1563    /// # Example
1564    ///
1565    /// ```rust,ignore
1566    /// query.right_join_raw("users u", "u.id = p.user_id AND u.active = ?", true)
1567    /// ```
1568    pub fn right_join_raw<V>(self, table: &str, on: &str, value: V) -> Self
1569    where
1570        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
1571    {
1572        self.join_generic_raw("RIGHT", table, on, value)
1573    }
1574
1575    /// Adds a raw INNER JOIN clause with a placeholder and a bound value.
1576    ///
1577    /// # Arguments
1578    ///
1579    /// * `table` - The name of the table to join (with optional alias)
1580    /// * `on` - The join condition with a `?` placeholder
1581    /// * `value` - The value to bind
1582    ///
1583    /// # Example
1584    ///
1585    /// ```rust,ignore
1586    /// query.inner_join_raw("accounts a", "a.user_id = u.id AND a.type = ?", "checking")
1587    /// ```
1588    pub fn inner_join_raw<V>(self, table: &str, on: &str, value: V) -> Self
1589    where
1590        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
1591    {
1592        self.join_generic_raw("INNER", table, on, value)
1593    }
1594
1595    /// Adds a raw FULL JOIN clause with a placeholder and a bound value.
1596    ///
1597    /// # Arguments
1598    ///
1599    /// * `table` - The name of the table to join (with optional alias)
1600    /// * `on` - The join condition with a `?` placeholder
1601    /// * `value` - The value to bind
1602    ///
1603    /// # Example
1604    ///
1605    /// ```rust,ignore
1606    /// query.full_join_raw("profiles pr", "pr.user_id = u.id AND pr.verified = ?", true)
1607    /// ```
1608    pub fn full_join_raw<V>(self, table: &str, on: &str, value: V) -> Self
1609    where
1610        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
1611    {
1612        self.join_generic_raw("FULL", table, on, value)
1613    }
1614
1615    /// Internal helper for raw join types
1616    fn join_generic_raw<V>(mut self, join_type: &str, table: &str, on: &str, value: V) -> Self
1617    where
1618        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
1619    {
1620        let table_owned = table.to_string();
1621        let on_owned = on.to_string();
1622        let join_type_owned = join_type.to_string();
1623        
1624        if let Some((table_name, alias)) = table.split_once(" ") {
1625            self.join_aliases.insert(table_name.to_snake_case(), alias.to_string());
1626        } else {
1627            self.join_aliases.insert(table.to_snake_case(), table.to_string());
1628        }
1629
1630        self.joins_clauses.push(Box::new(move |query, args, driver, arg_counter| {
1631            if let Some((table_name, alias)) = table_owned.split_once(" ") {
1632                query.push_str(&format!("{} JOIN \"{}\" {} ON ", join_type_owned, table_name, alias));
1633            } else {
1634                query.push_str(&format!("{} JOIN \"{}\" ON ", join_type_owned, table_owned));
1635            }
1636
1637            let mut processed_on = on_owned.clone();
1638            if let Some(pos) = processed_on.find('?') {
1639                let placeholder = match driver {
1640                    Drivers::Postgres => {
1641                        let p = format!("${}", arg_counter);
1642                        *arg_counter += 1;
1643                        p
1644                    }
1645                    _ => "?".to_string(),
1646                };
1647                processed_on.replace_range(pos..pos + 1, &placeholder);
1648            }
1649            
1650            query.push_str(&processed_on);
1651            let _ = args.add(value.clone());
1652        }));
1653        self
1654    }
1655
1656    /// Adds a LEFT JOIN clause.
1657    ///
1658    /// # Arguments
1659    ///
1660    /// * `table` - The name of the table to join with
1661    /// * `on` - The join condition (e.g., "users.id = posts.user_id")
1662    ///
1663    /// # Example
1664    ///
1665    /// ```rust,ignore
1666    /// // Get all users and their posts (if any)
1667    /// let users_with_posts = db.model::<User>()
1668    ///     .left_join("posts p", "u.id = p.user_id")
1669    ///     .scan()
1670    ///     .await?;
1671    /// // SQL: LEFT JOIN "posts" p ON u.id = p.user_id
1672    /// ```
1673    pub fn left_join(self, table: &str, on: &str) -> Self {
1674        self.join_generic("LEFT", table, on)
1675    }
1676
1677    /// Adds a RIGHT JOIN clause.
1678    ///
1679    /// # Arguments
1680    ///
1681    /// * `table` - The name of the table to join with
1682    /// * `on` - The join condition
1683    ///
1684    /// # Example
1685    ///
1686    /// ```rust,ignore
1687    /// db.model::<Post>()
1688    ///     .right_join("users u", "p.user_id = u.id")
1689    ///     .scan()
1690    ///     .await?;
1691    /// // SQL: RIGHT JOIN "users" u ON p.user_id = u.id
1692    /// ```
1693    pub fn right_join(self, table: &str, on: &str) -> Self {
1694        self.join_generic("RIGHT", table, on)
1695    }
1696
1697    /// Adds an INNER JOIN clause.
1698    ///
1699    /// # Arguments
1700    ///
1701    /// * `table` - The name of the table to join with
1702    /// * `on` - The join condition
1703    ///
1704    /// # Example
1705    ///
1706    /// ```rust,ignore
1707    /// // Get only users who have posts
1708    /// let active_users = db.model::<User>()
1709    ///     .inner_join("posts p", "u.id = p.user_id")
1710    ///     .scan()
1711    ///     .await?;
1712    /// // SQL: INNER JOIN "posts" p ON u.id = p.user_id
1713    /// ```
1714    pub fn inner_join(self, table: &str, on: &str) -> Self {
1715        self.join_generic("INNER", table, on)
1716    }
1717
1718    /// Adds a FULL JOIN clause.
1719    ///
1720    /// # Arguments
1721    ///
1722    /// * `table` - The name of the table to join with
1723    /// * `on` - The join condition
1724    ///
1725    /// # Example
1726    ///
1727    /// ```rust,ignore
1728    /// query.full_join("profiles pr", "u.id = pr.user_id")
1729    /// // SQL: FULL JOIN "profiles" pr ON u.id = pr.user_id
1730    /// ```
1731    pub fn full_join(self, table: &str, on: &str) -> Self {
1732        self.join_generic("FULL", table, on)
1733    }
1734
1735    /// Marks the query to return DISTINCT results.
1736    ///
1737    /// Adds the `DISTINCT` keyword to the SELECT statement, ensuring that unique
1738    /// rows are returned.
1739    ///
1740    /// # Example
1741    ///
1742    /// ```rust,ignore
1743    /// // Get unique ages of users
1744    /// let unique_ages: Vec<i32> = db.model::<User>()
1745    ///     .select("age")
1746    ///     .distinct()
1747    ///     .scan()
1748    ///     .await?;
1749    /// ```
1750    pub fn distinct(mut self) -> Self {
1751        self.is_distinct = true;
1752        self
1753    }
1754
1755    /// Adds a GROUP BY clause to the query.
1756    ///
1757    /// Groups rows that have the same values into summary rows. Often used with
1758    /// aggregate functions (COUNT, MAX, MIN, SUM, AVG).
1759    ///
1760    /// # Arguments
1761    ///
1762    /// * `columns` - Comma-separated list of columns to group by
1763    ///
1764    /// # Example
1765    ///
1766    /// ```rust,ignore
1767    /// // Count users by age group
1768    /// let stats: Vec<(i32, i64)> = db.model::<User>()
1769    ///     .select("age, COUNT(*)")
1770    ///     .group_by("age")
1771    ///     .scan()
1772    ///     .await?;
1773    /// ```
1774    pub fn group_by(mut self, columns: &str) -> Self {
1775        self.group_by_clauses.push(columns.to_string());
1776        self
1777    }
1778
1779    /// Adds a HAVING clause to the query.
1780    ///
1781    /// Used to filter groups created by `group_by`. Similar to `filter` (WHERE),
1782    /// but operates on grouped records and aggregate functions.
1783    ///
1784    /// # Arguments
1785    ///
1786    /// * `col` - The column or aggregate function to filter on
1787    /// * `op` - Comparison operator
1788    /// * `value` - Value to compare against
1789    ///
1790    /// # Example
1791    ///
1792    /// ```rust,ignore
1793    /// // Get ages with more than 5 users
1794    /// let popular_ages = db.model::<User>()
1795    ///     .select("age, COUNT(*)")
1796    ///     .group_by("age")
1797    ///     .having("COUNT(*)", Op::Gt, 5)
1798    ///     .scan()
1799    ///     .await?;
1800    /// ```
1801    pub fn having<V>(mut self, col: &'static str, op: Op, value: V) -> Self
1802    where
1803        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
1804    {
1805        let op_str = op.as_sql();
1806        let clause: FilterFn = Box::new(move |query, args, driver, arg_counter| {
1807            query.push_str(" AND ");
1808            query.push_str(col);
1809            query.push(' ');
1810            query.push_str(op_str);
1811            query.push(' ');
1812
1813            match driver {
1814                Drivers::Postgres => {
1815                    query.push_str(&format!("${}", arg_counter));
1816                    *arg_counter += 1;
1817                }
1818                _ => query.push('?'),
1819            }
1820            let _ = args.add(value.clone());
1821        });
1822
1823        self.having_clauses.push(clause);
1824        self
1825    }
1826
1827    /// Returns the COUNT of rows matching the query.
1828    ///
1829    /// A convenience method that automatically sets `SELECT COUNT(*)` and returns
1830    /// the result as an `i64`.
1831    ///
1832    /// # Returns
1833    ///
1834    /// * `Ok(i64)` - The count of rows
1835    /// * `Err(sqlx::Error)` - Database error
1836    ///
1837    /// # Example
1838    ///
1839    /// ```rust,ignore
1840    /// let user_count = db.model::<User>().count().await?;
1841    /// ```
1842    pub async fn count(mut self) -> Result<i64, sqlx::Error> {
1843        self.select_columns = vec!["COUNT(*)".to_string()];
1844        self.scalar::<i64>().await
1845    }
1846
1847    /// Returns the SUM of the specified column.
1848    ///
1849    /// Calculates the sum of a numeric column.
1850    ///
1851    /// # Arguments
1852    ///
1853    /// * `column` - The column to sum
1854    ///
1855    /// # Example
1856    ///
1857    /// ```rust,ignore
1858    /// let total_age: i64 = db.model::<User>().sum("age").await?;
1859    /// ```
1860    pub async fn sum<N>(mut self, column: &str) -> Result<N, sqlx::Error>
1861    where
1862        N: FromAnyRow + AnyImpl + for<'r> Decode<'r, Any> + Type<Any> + Send + Unpin,
1863    {
1864        let quoted_col = if column.contains('.') {
1865            let parts: Vec<&str> = column.split('.').collect();
1866            format!("\"{}\".\"{}\"", parts[0].trim_matches('"'), parts[1].trim_matches('"'))
1867        } else {
1868            format!("\"{}\"", column.trim_matches('"'))
1869        };
1870        self.select_columns = vec![format!("SUM({})", quoted_col)];
1871        self.scalar::<N>().await
1872    }
1873
1874    /// Returns the AVG of the specified column.
1875    ///
1876    /// Calculates the average value of a numeric column.
1877    ///
1878    /// # Arguments
1879    ///
1880    /// * `column` - The column to average
1881    ///
1882    /// # Example
1883    ///
1884    /// ```rust,ignore
1885    /// let avg_age: f64 = db.model::<User>().avg("age").await?;
1886    /// ```
1887    pub async fn avg<N>(mut self, column: &str) -> Result<N, sqlx::Error>
1888    where
1889        N: FromAnyRow + AnyImpl + for<'r> Decode<'r, Any> + Type<Any> + Send + Unpin,
1890    {
1891        let quoted_col = if column.contains('.') {
1892            let parts: Vec<&str> = column.split('.').collect();
1893            format!("\"{}\".\"{}\"", parts[0].trim_matches('"'), parts[1].trim_matches('"'))
1894        } else {
1895            format!("\"{}\"", column.trim_matches('"'))
1896        };
1897        self.select_columns = vec![format!("AVG({})", quoted_col)];
1898        self.scalar::<N>().await
1899    }
1900
1901    /// Returns the MIN of the specified column.
1902    ///
1903    /// Finds the minimum value in a column.
1904    ///
1905    /// # Arguments
1906    ///
1907    /// * `column` - The column to check
1908    ///
1909    /// # Example
1910    ///
1911    /// ```rust,ignore
1912    /// let min_age: i32 = db.model::<User>().min("age").await?;
1913    /// ```
1914    pub async fn min<N>(mut self, column: &str) -> Result<N, sqlx::Error>
1915    where
1916        N: FromAnyRow + AnyImpl + for<'r> Decode<'r, Any> + Type<Any> + Send + Unpin,
1917    {
1918        let quoted_col = if column.contains('.') {
1919            let parts: Vec<&str> = column.split('.').collect();
1920            format!("\"{}\".\"{}\"", parts[0].trim_matches('"'), parts[1].trim_matches('"'))
1921        } else {
1922            format!("\"{}\"", column.trim_matches('"'))
1923        };
1924        self.select_columns = vec![format!("MIN({})", quoted_col)];
1925        self.scalar::<N>().await
1926    }
1927
1928    /// Returns the MAX of the specified column.
1929    ///
1930    /// Finds the maximum value in a column.
1931    ///
1932    /// # Arguments
1933    ///
1934    /// * `column` - The column to check
1935    ///
1936    /// # Example
1937    ///
1938    /// ```rust,ignore
1939    /// let max_age: i32 = db.model::<User>().max("age").await?;
1940    /// ```
1941    pub async fn max<N>(mut self, column: &str) -> Result<N, sqlx::Error>
1942    where
1943        N: FromAnyRow + AnyImpl + for<'r> Decode<'r, Any> + Type<Any> + Send + Unpin,
1944    {
1945        let quoted_col = if column.contains('.') {
1946            let parts: Vec<&str> = column.split('.').collect();
1947            format!("\"{}\".\"{}\"", parts[0].trim_matches('"'), parts[1].trim_matches('"'))
1948        } else {
1949            format!("\"{}\"", column.trim_matches('"'))
1950        };
1951        self.select_columns = vec![format!("MAX({})", quoted_col)];
1952        self.scalar::<N>().await
1953    }
1954
1955    /// Applies pagination with validation and limits.
1956    ///
1957    /// This is a convenience method that combines `limit()` and `offset()` with
1958    /// built-in validation and maximum value enforcement for safer pagination.
1959    ///
1960    /// # Arguments
1961    ///
1962    /// * `max_value` - Maximum allowed items per page
1963    /// * `default` - Default value if `value` exceeds `max_value`
1964    /// * `page` - Zero-based page number
1965    /// * `value` - Requested items per page
1966    ///
1967    /// # Returns
1968    ///
1969    /// * `Ok(Self)` - The updated QueryBuilder with pagination applied
1970    /// * `Err(Error)` - If `value` is negative
1971    ///
1972    /// # Pagination Logic
1973    ///
1974    /// 1. Validates that `value` is non-negative
1975    /// 2. If `value` > `max_value`, uses `default` instead
1976    /// 3. Calculates offset as: `value * page`
1977    /// 4. Sets limit to `value`
1978    ///
1979    /// # Example
1980    ///
1981    /// ```rust,ignore
1982    /// // Page 0 with 10 items (page 1 in 1-indexed systems)
1983    /// query.pagination(100, 20, 0, 10)?  // LIMIT 10 OFFSET 0
1984    ///
1985    /// // Page 2 with 25 items (page 3 in 1-indexed systems)
1986    /// query.pagination(100, 20, 2, 25)?  // LIMIT 25 OFFSET 50
1987    ///
1988    /// // Request too many items, falls back to default
1989    /// query.pagination(100, 20, 0, 150)? // LIMIT 20 OFFSET 0 (150 > 100)
1990    ///
1991    /// // Error: negative value
1992    /// query.pagination(100, 20, 0, -10)? // Returns Error
1993    /// ```
1994    pub fn pagination(mut self, max_value: usize, default: usize, page: usize, value: isize) -> Result<Self, Error> {
1995        // Validate that value is non-negative
1996        if value < 0 {
1997            return Err(Error::InvalidArgument("value cannot be negative".into()));
1998        }
1999
2000        let mut f_value = value as usize;
2001
2002        // Enforce maximum value limit
2003        if f_value > max_value {
2004            f_value = default;
2005        }
2006
2007        // Apply offset and limit
2008        self = self.offset(f_value * page);
2009        self = self.limit(f_value);
2010
2011        Ok(self)
2012    }
2013
2014    /// Selects specific columns to return.
2015    ///
2016    /// By default, queries use `SELECT *` to return all columns. This method
2017    /// allows you to specify exactly which columns should be returned.
2018    ///
2019    /// **Note:** Columns are pushed exactly as provided, without automatic
2020    /// snake_case conversion, allowing for aliases and raw SQL fragments.
2021    ///
2022    /// # Arguments
2023    ///
2024    /// * `columns` - Comma-separated list of column names to select
2025    ///
2026    /// # Example
2027    ///
2028    /// ```rust,ignore
2029    /// // Select single column
2030    /// query.select("id")
2031    ///
2032    /// // Select multiple columns
2033    /// query.select("id, username, email")
2034    ///
2035    /// // Select with SQL functions and aliases (now supported)
2036    /// query.select("COUNT(*) as total_count")
2037    /// ```
2038    pub fn select(mut self, columns: &str) -> Self {
2039        self.select_columns.push(columns.to_string());
2040        self
2041    }
2042
2043    /// Excludes specific columns from the query results.
2044    ///
2045    /// This is the inverse of `select()`. Instead of specifying which columns to include,
2046    /// you specify which columns to exclude. All other columns will be returned.
2047    ///
2048    /// # Arguments
2049    ///
2050    /// * `columns` - Comma-separated list of column names to exclude
2051    ///
2052    /// # Priority
2053    ///
2054    /// If both `select()` and `omit()` are used, `select()` takes priority.
2055    ///
2056    /// # Example
2057    ///
2058    /// ```rust,ignore
2059    /// // Exclude password from results
2060    /// let user = db.model::<User>()
2061    ///     .omit("password")
2062    ///     .first()
2063    ///     .await?;
2064    ///
2065    /// // Exclude multiple fields
2066    /// let user = db.model::<User>()
2067    ///     .omit("password, secret_token")
2068    ///     .first()
2069    ///     .await?;
2070    ///
2071    /// // Using with generated field constants (autocomplete support)
2072    /// let user = db.model::<User>()
2073    ///     .omit(user_fields::PASSWORD)
2074    ///     .first()
2075    ///     .await?;
2076    /// ```
2077    pub fn omit(mut self, columns: &str) -> Self {
2078        for col in columns.split(',') {
2079            self.omit_columns.push(col.trim().to_snake_case());
2080        }
2081        self
2082    }
2083
2084    /// Sets the query offset (pagination).
2085    ///
2086    /// Specifies the number of rows to skip before starting to return rows.
2087    /// Commonly used in combination with `limit()` for pagination.
2088    ///
2089    /// # Arguments
2090    ///
2091    /// * `offset` - Number of rows to skip
2092    ///
2093    /// # Example
2094    ///
2095    /// ```rust,ignore
2096    /// // Skip first 20 rows
2097    /// query.offset(20)
2098    ///
2099    /// // Pagination: page 3 with 10 items per page
2100    /// query.limit(10).offset(20)  // Skip 2 pages = 20 items
2101    /// ```
2102    pub fn offset(mut self, offset: usize) -> Self {
2103        self.offset = Some(offset);
2104        self
2105    }
2106
2107    /// Sets the maximum number of records to return.
2108    ///
2109    /// Limits the number of rows returned by the query. Essential for pagination
2110    /// and preventing accidentally fetching large result sets.
2111    ///
2112    /// # Arguments
2113    ///
2114    /// * `limit` - Maximum number of rows to return
2115    ///
2116    /// # Example
2117    ///
2118    /// ```rust,ignore
2119    /// // Return at most 10 rows
2120    /// query.limit(10)
2121    ///
2122    /// // Pagination: 50 items per page
2123    /// query.limit(50).offset(page * 50)
2124    /// ```
2125    pub fn limit(mut self, limit: usize) -> Self {
2126        self.limit = Some(limit);
2127        self
2128    }
2129
2130    // ========================================================================
2131    // Insert Operation
2132    // ========================================================================
2133
2134    /// Inserts a new record into the database based on the model instance.
2135    ///
2136    /// This method serializes the model into a SQL INSERT statement with proper
2137    /// type handling for primitives, dates, UUIDs, and other supported types.
2138    ///
2139    /// # Type Binding Strategy
2140    ///
2141    /// The method uses string parsing as a temporary solution for type binding.
2142    /// Values are converted to strings via the model's `to_map()` method, then
2143    /// parsed back to their original types for proper SQL binding.
2144    ///
2145    /// # Supported Types for Insert
2146    ///
2147    /// - **Integers**: `i32`, `i64` (INTEGER, BIGINT)
2148    /// - **Boolean**: `bool` (BOOLEAN)
2149    /// - **Float**: `f64` (DOUBLE PRECISION)
2150    /// - **Text**: `String` (TEXT, VARCHAR)
2151    /// - **UUID**: `Uuid` (UUID) - All versions 1-7 supported
2152    /// - **DateTime**: `DateTime<Utc>` (TIMESTAMPTZ)
2153    /// - **NaiveDateTime**: (TIMESTAMP)
2154    /// - **NaiveDate**: (DATE)
2155    /// - **NaiveTime**: (TIME)
2156    ///
2157    /// # Arguments
2158    ///
2159    /// * `model` - Reference to the model instance to insert
2160    ///
2161    /// # Returns
2162    ///
2163    /// * `Ok(&Self)` - Reference to self for method chaining
2164    /// * `Err(sqlx::Error)` - Database error during insertion
2165    ///
2166    /// # Example
2167    ///
2168    /// ```rust,ignore
2169    /// 
2170    /// use chrono::Utc;
2171    ///
2172    /// let new_user = User {
2173    ///     id: Uuid::new_v4(),
2174    ///     username: "john_doe".to_string(),
2175    ///     email: "john@example.com".to_string(),
2176    ///     age: 25,
2177    ///     active: true,
2178    ///     created_at: Utc::now(),
2179    /// };
2180    ///
2181    /// db.model::<User>().insert(&new_user).await?;
2182    /// ```
2183    pub fn insert<'b>(&'b mut self, model: &'b T) -> BoxFuture<'b, Result<(), sqlx::Error>> {
2184        Box::pin(async move {
2185            // Serialize model to a HashMap of column_name -> string_value
2186            let data_map = Model::to_map(model);
2187
2188            // Early return if no data to insert
2189            if data_map.is_empty() {
2190                return Ok(());
2191            }
2192
2193            let table_name = self.table_name.to_snake_case();
2194            let columns_info = <T as Model>::columns();
2195
2196            let mut target_columns = Vec::new();
2197            let mut bindings: Vec<(Option<String>, &str)> = Vec::new();
2198
2199            // Build column list and collect values with their SQL types
2200            for (col_name, value) in data_map {
2201                // Strip the "r#" prefix if present (for Rust keywords used as field names)
2202                let col_name_clean = col_name.strip_prefix("r#").unwrap_or(&col_name).to_snake_case();
2203                target_columns.push(format!("\"{}\"", col_name_clean));
2204
2205                // Find the SQL type for this column
2206                let sql_type = columns_info.iter().find(|c| c.name == col_name).map(|c| c.sql_type).unwrap_or("TEXT");
2207
2208                bindings.push((value, sql_type));
2209            }
2210
2211            // Generate placeholders with proper type casting for PostgreSQL
2212            let placeholders: Vec<String> = bindings
2213                .iter()
2214                .enumerate()
2215                .map(|(i, (_, sql_type))| match self.driver {
2216                    Drivers::Postgres => {
2217                        let idx = i + 1;
2218                        // PostgreSQL requires explicit type casting for some types
2219                        if temporal::is_temporal_type(sql_type) {
2220                            // Use temporal module for type casting
2221                            format!("${}{}", idx, temporal::get_postgres_type_cast(sql_type))
2222                        } else {
2223                            match *sql_type {
2224                                "UUID" => format!("${}::UUID", idx),
2225                                "JSONB" | "jsonb" => format!("${}::JSONB", idx),
2226                                s if s.ends_with("[]") => format!("${}::{}", idx, s),
2227                                _ => format!("${}", idx),
2228                            }
2229                        }
2230                    }
2231                    // MySQL and SQLite use simple ? placeholders
2232                    _ => "?".to_string(),
2233                })
2234                .collect();
2235
2236            // Construct the INSERT query
2237            let query_str = format!(
2238                "INSERT INTO \"{}\" ({}) VALUES ({})",
2239                table_name,
2240                target_columns.join(", "),
2241                placeholders.join(", ")
2242            );
2243
2244            if self.debug_mode {
2245                log::debug!("SQL: {}", query_str);
2246            }
2247
2248            let mut args = AnyArguments::default();
2249
2250            // Bind values using the optimized value_binding module
2251            for (val_opt, sql_type) in bindings {
2252                if let Some(val_str) = val_opt {
2253                    if args.bind_value(&val_str, sql_type, &self.driver).is_err() {
2254                        let _ = args.add(val_str);
2255                    }
2256                } else {
2257                    let _ = args.add(None::<String>);
2258                }
2259            }
2260
2261            // Execute the INSERT query
2262            self.tx.execute(&query_str, args).await?;
2263            Ok(())
2264        })
2265    }
2266
2267    /// Inserts multiple records into the database in a single batch operation.
2268    ///
2269    /// This is significantly faster than performing individual inserts in a loop
2270    /// as it generates a single SQL statement with multiple VALUES groups.
2271    ///
2272    /// # Type Binding Strategy
2273    ///
2274    /// Similar to the single record `insert`, this method uses string parsing for
2275    /// type binding. It ensures that all columns defined in the model are included
2276    /// in the insert statement, providing NULL for any missing optional values.
2277    ///
2278    /// # Arguments
2279    ///
2280    /// * `models` - A slice of model instances to insert
2281    ///
2282    /// # Returns
2283    ///
2284    /// * `Ok(())` - Successfully inserted all records
2285    /// * `Err(sqlx::Error)` - Database error during insertion
2286    ///
2287    /// # Example
2288    ///
2289    /// ```rust,ignore
2290    /// let users = vec![
2291    ///     User { username: "alice".to_string(), ... },
2292    ///     User { username: "bob".to_string(), ... },
2293    /// ];
2294    ///
2295    /// db.model::<User>().batch_insert(&users).await?;
2296    /// ```
2297    pub fn batch_insert<'b>(&'b mut self, models: &'b [T]) -> BoxFuture<'b, Result<(), sqlx::Error>> {
2298        Box::pin(async move {
2299            if models.is_empty() {
2300                return Ok(());
2301            }
2302
2303            let table_name = self.table_name.to_snake_case();
2304            let columns_info = <T as Model>::columns();
2305
2306            // Collect all column names for the INSERT statement
2307            // We use all columns defined in the model to ensure consistency across the batch
2308            let target_columns: Vec<String> = columns_info
2309                .iter()
2310                .map(|c| {
2311                    let col_name_clean = c.name.strip_prefix("r#").unwrap_or(c.name).to_snake_case();
2312                    format!("\"{}\"", col_name_clean)
2313                })
2314                .collect();
2315
2316            let mut value_groups = Vec::new();
2317            let mut bind_index = 1;
2318
2319            // Generate placeholders for all models
2320            for _ in models {
2321                let mut placeholders = Vec::new();
2322                for col in &columns_info {
2323                    match self.driver {
2324                        Drivers::Postgres => {
2325                            let p = if temporal::is_temporal_type(col.sql_type) {
2326                                format!("${}{}", bind_index, temporal::get_postgres_type_cast(col.sql_type))
2327                            } else {
2328                                match col.sql_type {
2329                                    "UUID" => format!("${}::UUID", bind_index),
2330                                    "JSONB" | "jsonb" => format!("${}::JSONB", bind_index),
2331                                    _ => format!("${}", bind_index),
2332                                }
2333                            };
2334                            placeholders.push(p);
2335                            bind_index += 1;
2336                        }
2337                        _ => {
2338                            placeholders.push("?".to_string());
2339                        }
2340                    }
2341                }
2342                value_groups.push(format!("({})", placeholders.join(", ")));
2343            }
2344
2345            let query_str = format!(
2346                "INSERT INTO \"{}\" ({}) VALUES {}",
2347                table_name,
2348                target_columns.join(", "),
2349                value_groups.join(", ")
2350            );
2351
2352            if self.debug_mode {
2353                log::debug!("SQL Batch: {}", query_str);
2354            }
2355
2356            let mut args = AnyArguments::default();
2357
2358            for model in models {
2359                let data_map = Model::to_map(model);
2360                for col in &columns_info {
2361                    let val_opt = data_map.get(col.name);
2362                    let sql_type = col.sql_type;
2363
2364                    if let Some(Some(val_str)) = val_opt {
2365                        if args.bind_value(val_str, sql_type, &self.driver).is_err() {
2366                            let _ = args.add(val_str.clone());
2367                        }
2368                    } else {
2369                        // Bind NULL for missing or None values
2370                        let _ = args.add(None::<String>);
2371                    }
2372                }
2373            }
2374
2375            // Execute the batch INSERT query
2376            self.tx.execute(&query_str, args).await?;
2377            Ok(())
2378        })
2379    }
2380
2381    /// Inserts a record or updates it if a conflict occurs (UPSERT).
2382    ///
2383    /// This method provides a cross-database way to perform "Insert or Update" operations.
2384    /// It uses `ON CONFLICT` for PostgreSQL and SQLite, and `ON DUPLICATE KEY UPDATE` for MySQL.
2385    ///
2386    /// # Arguments
2387    ///
2388    /// * `model` - The model instance to insert or update
2389    /// * `conflict_columns` - Columns that trigger the conflict (e.g., primary key or unique columns)
2390    /// * `update_columns` - Columns to update when a conflict occurs
2391    ///
2392    /// # Returns
2393    ///
2394    /// * `Ok(u64)` - The number of rows affected
2395    /// * `Err(sqlx::Error)` - Database error
2396    ///
2397    /// # Example
2398    ///
2399    /// ```rust,ignore
2400    /// let user = User { id: 1, username: "alice".to_string(), age: 25 };
2401    ///
2402    /// // If id 1 exists, update username and age
2403    /// db.model::<User>().upsert(&user, &["id"], &["username", "age"]).await?;
2404    /// ```
2405    pub fn upsert<'b>(
2406        &'b mut self,
2407        model: &'b T,
2408        conflict_columns: &'b [&'b str],
2409        update_columns: &'b [&'b str],
2410    ) -> BoxFuture<'b, Result<u64, sqlx::Error>> {
2411        Box::pin(async move {
2412            let data_map = Model::to_map(model);
2413            if data_map.is_empty() {
2414                return Ok(0);
2415            }
2416
2417            let table_name = self.table_name.to_snake_case();
2418            let columns_info = <T as Model>::columns();
2419
2420            let mut target_columns = Vec::new();
2421            let mut bindings: Vec<(Option<String>, &str)> = Vec::new();
2422
2423            // Build INSERT part
2424            for (col_name, value) in &data_map {
2425                let col_name_clean = col_name.strip_prefix("r#").unwrap_or(col_name).to_snake_case();
2426                target_columns.push(format!("\"{}\"", col_name_clean));
2427
2428                let sql_type = columns_info.iter().find(|c| {
2429                    let c_clean = c.name.strip_prefix("r#").unwrap_or(c.name);
2430                    c_clean == *col_name || c_clean.to_snake_case() == col_name_clean
2431                }).map(|c| c.sql_type).unwrap_or("TEXT");
2432                bindings.push((value.clone(), sql_type));
2433            }
2434
2435            let mut arg_counter = 1;
2436            let mut placeholders = Vec::new();
2437            for (_, sql_type) in &bindings {
2438                match self.driver {
2439                    Drivers::Postgres => {
2440                        let p = if temporal::is_temporal_type(sql_type) {
2441                            format!("${}{}", arg_counter, temporal::get_postgres_type_cast(sql_type))
2442                        } else {
2443                            match *sql_type {
2444                                "UUID" => format!("${}::UUID", arg_counter),
2445                                "JSONB" | "jsonb" => format!("${}::JSONB", arg_counter),
2446                                _ => format!("${}", arg_counter),
2447                            }
2448                        };
2449                        placeholders.push(p);
2450                        arg_counter += 1;
2451                    }
2452                    _ => {
2453                        placeholders.push("?".to_string());
2454                    }
2455                }
2456            }
2457
2458            let mut query_str = format!(
2459                "INSERT INTO \"{}\" ({}) VALUES ({})",
2460                table_name,
2461                target_columns.join(", "),
2462                placeholders.join(", ")
2463            );
2464
2465            // Build Conflict/Update part
2466            match self.driver {
2467                Drivers::Postgres | Drivers::SQLite => {
2468                    let conflict_cols_str = conflict_columns
2469                        .iter()
2470                        .map(|c| format!("\"{}\"", c.to_snake_case()))
2471                        .collect::<Vec<_>>()
2472                        .join(", ");
2473                    
2474                    query_str.push_str(&format!(" ON CONFLICT ({}) DO UPDATE SET ", conflict_cols_str));
2475                    
2476                    let mut update_clauses = Vec::new();
2477                    let mut update_bindings = Vec::new();
2478
2479                    for col in update_columns {
2480                        let col_snake = col.to_snake_case();
2481                        if let Some((_key, val_opt)) = data_map.iter().find(|(k, _)| {
2482                            let k_clean = k.strip_prefix("r#").unwrap_or(*k);
2483                            k_clean == *col || k_clean.to_snake_case() == col_snake
2484                        }) {
2485                            let sql_type_opt = columns_info.iter().find(|c| {
2486                                let c_clean = c.name.strip_prefix("r#").unwrap_or(c.name);
2487                                c_clean == *col || c_clean.to_snake_case() == col_snake
2488                            }).map(|c| c.sql_type);
2489                            
2490                            let sql_type = match sql_type_opt {
2491                                Some(t) => t,
2492                                None => continue,
2493                            };
2494                            
2495                            let placeholder = match self.driver {
2496                                Drivers::Postgres => {
2497                                    let p = if temporal::is_temporal_type(sql_type) {
2498                                        format!("${}{}", arg_counter, temporal::get_postgres_type_cast(sql_type))
2499                                    } else {
2500                                        match sql_type {
2501                                            "UUID" => format!("${}::UUID", arg_counter),
2502                                            "JSONB" | "jsonb" => format!("${}::JSONB", arg_counter),
2503                                            _ => format!("${}", arg_counter),
2504                                        }
2505                                    };
2506                                    arg_counter += 1;
2507                                    p
2508                                }
2509                                _ => "?".to_string(),
2510                            };
2511                            update_clauses.push(format!("\"{}\" = {}", col_snake, placeholder));
2512                            update_bindings.push((val_opt.clone(), sql_type));
2513                        }
2514                    }
2515                    if update_clauses.is_empty() {
2516                        query_str.push_str(" NOTHING");
2517                    } else {
2518                        query_str.push_str(&update_clauses.join(", "));
2519                    }
2520                    bindings.extend(update_bindings);
2521                }
2522                Drivers::MySQL => {
2523                    query_str.push_str(" ON DUPLICATE KEY UPDATE ");
2524                    let mut update_clauses = Vec::new();
2525                    for col in update_columns {
2526                        let col_snake = col.to_snake_case();
2527                        update_clauses.push(format!("\"{}\" = VALUES(\"{}\")", col_snake, col_snake));
2528                    }
2529                    query_str.push_str(&update_clauses.join(", "));
2530                }
2531            }
2532
2533            if self.debug_mode {
2534                log::debug!("SQL Upsert: {}", query_str);
2535            }
2536
2537            let mut args = AnyArguments::default();
2538            for (val_opt, sql_type) in bindings {
2539                if let Some(val_str) = val_opt {
2540                    if args.bind_value(&val_str, sql_type, &self.driver).is_err() {
2541                        let _ = args.add(val_str);
2542                    }
2543                } else {
2544                    let _ = args.add(None::<String>);
2545                }
2546            }
2547
2548            let result = self.tx.execute(&query_str, args).await?;
2549            Ok(result.rows_affected())
2550        })
2551    }
2552
2553    // ========================================================================
2554    // Query Execution Methods
2555    // ========================================================================
2556
2557    /// Returns the generated SQL string for debugging purposes.
2558    ///
2559    /// This method constructs the SQL query string without executing it.
2560    /// Useful for debugging and logging query construction. Note that this
2561    /// shows placeholders (?, $1, etc.) rather than actual bound values.
2562    ///
2563    /// # Returns
2564    ///
2565    /// A `String` containing the SQL query that would be executed
2566    ///
2567    /// # Example
2568    ///
2569    /// ```rust,ignore
2570    /// let query = db.model::<User>()
2571    ///     .filter("age", ">=", 18)
2572    ///     .order("created_at DESC")
2573    ///     .limit(10);
2574    ///
2575    /// println!("SQL: {}", query.to_sql());
2576    /// // Output: SELECT * FROM "user" WHERE 1=1 AND "age" >= $1 ORDER BY created_at DESC
2577    /// ```
2578    pub fn to_sql(&self) -> String {
2579        let mut query = String::new();
2580        let mut args = AnyArguments::default();
2581        let mut arg_counter = 1;
2582
2583        self.write_select_sql::<T>(&mut query, &mut args, &mut arg_counter);
2584        query
2585    }
2586
2587    /// Generates the list of column selection SQL arguments.
2588    ///
2589    /// This helper function constructs the column list for the SELECT statement.
2590    /// It handles:
2591    /// 1. Mapping specific columns if `select_columns` is set.
2592    /// 2. Defaulting to all columns from the struct `R` if no columns are specified.
2593    /// 3. applying `to_json(...)` casting for temporal types when using `AnyImpl` structs,
2594    ///    ensuring compatibility with the `FromAnyRow` deserialization logic.
2595    fn select_args_sql<R: AnyImpl>(&self) -> Vec<String> {
2596        let struct_cols = R::columns();
2597        let table_id = self.get_table_identifier();
2598        let main_table_snake = self.table_name.to_snake_case();
2599        
2600        if struct_cols.is_empty() {
2601            if self.select_columns.is_empty() { return vec!["*".to_string()]; }
2602            
2603            // If result type is a tuple or primitive (struct_cols is empty),
2604            // we still need to handle temporal types for Postgres.
2605            if matches!(self.driver, Drivers::Postgres) {
2606                let mut args = Vec::new();
2607                for s in &self.select_columns {
2608                    for sub in s.split(',') {
2609                        let s_trim = sub.trim();
2610                        if s_trim.contains(' ') || s_trim.contains('(') {
2611                            args.push(s_trim.to_string());
2612                            continue;
2613                        }
2614
2615                        let (t, c) = if let Some((t, c)) = s_trim.split_once('.') {
2616                            (t.trim().trim_matches('"'), c.trim().trim_matches('"'))
2617                        } else {
2618                            (table_id.as_str(), s_trim.trim_matches('"'))
2619                        };
2620
2621                        let c_snake = c.to_snake_case();
2622                        let mut is_temporal = false;
2623                        
2624                        // Check if this column is known to be temporal
2625                        if let Some(info) = self.columns_info.iter().find(|info| {
2626                            info.name.to_snake_case() == c_snake
2627                        }) {
2628                            if is_temporal_type(info.sql_type) {
2629                                is_temporal = true;
2630                            }
2631                        }
2632
2633                        if is_temporal {
2634                            args.push(format!("to_json(\"{}\".\"{}\") #>> '{{}}' AS \"{}\"", t, c, c));
2635                        } else {
2636                            args.push(format!("\"{}\".\"{}\"", t, c));
2637                        }
2638                    }
2639                }
2640                return args;
2641            }
2642            
2643            return self.select_columns.clone();
2644        }
2645        let mut flat_selects = Vec::new();
2646        for s in &self.select_columns {
2647            for sub in s.split(',') { flat_selects.push(sub.trim().to_string()); }
2648        }
2649        let mut expanded_tables = HashSet::new();
2650        for s in &flat_selects {
2651            if s == "*" { expanded_tables.insert(table_id.clone()); expanded_tables.insert(main_table_snake.clone()); }
2652            else if let Some(t) = s.strip_suffix(".*") { let t_clean = t.trim().trim_matches('"'); expanded_tables.insert(t_clean.to_string()); expanded_tables.insert(t_clean.to_snake_case()); }
2653        }
2654        let mut col_counts = HashMap::new();
2655        for col_info in &struct_cols {
2656            let col_snake = col_info.column.strip_prefix("r#").unwrap_or(col_info.column).to_snake_case();
2657            *col_counts.entry(col_snake).or_insert(0) += 1;
2658        }
2659        let is_tuple = format!("{:?}", std::any::type_name::<R>()).contains('(');
2660        let mut matched_s_indices = HashSet::new();
2661        let mut manual_field_map = HashMap::new();
2662
2663        for (f_idx, s) in flat_selects.iter().enumerate() {
2664            if s == "*" || s.ends_with(".*") { continue; }
2665            let s_lower = s.to_lowercase();
2666            for (s_idx, col_info) in struct_cols.iter().enumerate() {
2667                if matched_s_indices.contains(&s_idx) { continue; }
2668                let col_snake = col_info.column.strip_prefix("r#").unwrap_or(col_info.column).to_snake_case();
2669                let mut m = false;
2670                if let Some((_, alias)) = s_lower.split_once(" as ") {
2671                    let ca = alias.trim().trim_matches('"').trim_matches('\'');
2672                    if ca == col_info.column || ca == &col_snake { m = true; }
2673                } else if s == col_info.column || s == &col_snake || s.ends_with(&format!(".{}", col_info.column)) || s.ends_with(&format!(".{}", col_snake)) {
2674                    m = true;
2675                }
2676                if m { manual_field_map.insert(f_idx, s_idx); matched_s_indices.insert(s_idx); break; }
2677            }
2678        }
2679
2680        let mut args = Vec::new();
2681        if self.select_columns.is_empty() {
2682            for (s_idx, col_info) in struct_cols.iter().enumerate() {
2683                let mut t_use = table_id.clone();
2684                if !col_info.table.is_empty() {
2685                    let c_snake = col_info.table.to_snake_case();
2686                    if c_snake == main_table_snake { t_use = table_id.clone(); }
2687                    else if let Some(alias) = self.join_aliases.get(&c_snake) { t_use = alias.clone(); }
2688                    else if self.join_aliases.values().any(|a| a == &col_info.table) { t_use = col_info.table.to_string(); }
2689                }
2690                args.push(self.format_select_field::<R>(s_idx, &t_use, &main_table_snake, &col_counts, is_tuple));
2691            }
2692        } else {
2693            for (f_idx, s) in flat_selects.iter().enumerate() {
2694                let s_trim = s.trim();
2695                if s_trim == "*" || s_trim.ends_with(".*") {
2696                    let mut t_exp = if s_trim == "*" { String::new() } else { s_trim.strip_suffix(".*").unwrap().trim().trim_matches('"').to_string() };
2697                    if !t_exp.is_empty() && (t_exp.to_snake_case() == main_table_snake || t_exp == table_id) { t_exp = table_id.clone(); }
2698                    for (s_idx, col_info) in struct_cols.iter().enumerate() {
2699                        if matched_s_indices.contains(&s_idx) { continue; }
2700                        let mut t_col = table_id.clone(); let mut known = false;
2701                        if !col_info.table.is_empty() {
2702                            let c_snake = col_info.table.to_snake_case();
2703                            if c_snake == main_table_snake { t_col = table_id.clone(); known = true; }
2704                            else if let Some(alias) = self.join_aliases.get(&c_snake) { t_col = alias.clone(); known = true; }
2705                            else if self.join_aliases.values().any(|a| a == &col_info.table) { t_col = col_info.table.to_string(); known = true; }
2706                        }
2707                        if !known && !t_exp.is_empty() && flat_selects.iter().filter(|x| x.ends_with(".*") || *x == "*").count() == 1 { t_col = t_exp.clone(); known = true; }
2708                        if (t_exp.is_empty() && known) || (!t_exp.is_empty() && t_col == t_exp) {
2709                            args.push(self.format_select_field::<R>(s_idx, &t_col, &main_table_snake, &col_counts, is_tuple));
2710                            matched_s_indices.insert(s_idx);
2711                        }
2712                    }
2713                } else if let Some(s_idx) = manual_field_map.get(&f_idx) {
2714                    if s.to_lowercase().contains(" as ") { args.push(s_trim.to_string()); }
2715                    else {
2716                        let mut t = table_id.clone();
2717                        if let Some((prefix, _)) = s_trim.split_once('.') { t = prefix.trim().trim_matches('"').to_string(); }
2718                        args.push(self.format_select_field::<R>(*s_idx, &t, &main_table_snake, &col_counts, is_tuple));
2719                    }
2720                } else {
2721                    if !s_trim.contains(' ') && !s_trim.contains('(') {
2722                        if let Some((t, c)) = s_trim.split_once('.') { args.push(format!("\"{}\".\"{}\"", t.trim().trim_matches('"'), c.trim().trim_matches('"'))); }
2723                        else { args.push(format!("\"{}\"", s_trim.trim_matches('"'))); }
2724                    } else { args.push(s_trim.to_string()); }
2725                }
2726            }
2727        }
2728        if args.is_empty() { vec!["*".to_string()] } else { args }
2729    }
2730
2731    fn format_select_field<R: AnyImpl>(&self, s_idx: usize, table_to_use: &str, main_table_snake: &str, col_counts: &HashMap<String, usize>, is_tuple: bool) -> String {
2732        let col_info = &R::columns()[s_idx];
2733        let col_snake = col_info.column.strip_prefix("r#").unwrap_or(col_info.column).to_snake_case();
2734        let has_collision = *col_counts.get(&col_snake).unwrap_or(&0) > 1;
2735        let alias = if is_tuple || has_collision {
2736            let t_alias = if !col_info.table.is_empty() { col_info.table.to_snake_case() } else { main_table_snake.to_string() };
2737            format!("{}__{}", t_alias.to_lowercase(), col_snake.to_lowercase())
2738        } else { col_snake.to_lowercase() };
2739        if is_temporal_type(col_info.sql_type) && matches!(self.driver, Drivers::Postgres) {
2740            format!("to_json(\"{}\".\"{}\") #>> '{{}}' AS \"{}\"", table_to_use, col_snake, alias)
2741        } else {
2742            format!("\"{}\".\"{}\" AS \"{}\"", table_to_use, col_snake, alias)
2743        }
2744    }
2745
2746    /// Executes the query and returns a list of results.
2747    ///
2748    /// This method builds and executes a SELECT query with all accumulated filters,
2749    /// ordering, and pagination settings. It returns all matching rows as a vector.
2750    ///
2751    /// # Type Parameters
2752    ///
2753    /// * `R` - The result type. Must implement `FromAnyRow` and `AnyImpl`.
2754    ///
2755    /// # Returns
2756    ///
2757    /// * `Ok(Vec<R>)` - Vector of results (empty if no matches)
2758    /// * `Err(sqlx::Error)` - Database error during query execution
2759    ///
2760    /// # Example
2761    ///
2762    /// ```rust,ignore
2763    /// let users: Vec<User> = db.model::<User>()
2764    ///     .filter("age", Op::Gte, 18)
2765    ///     .scan()
2766    ///     .await?;
2767    /// // SQL: SELECT * FROM "user" WHERE "age" >= 18
2768    /// ```
2769    pub async fn scan<R>(mut self) -> Result<Vec<R>, sqlx::Error>
2770    where
2771        R: FromAnyRow + AnyImpl + Send + Unpin,
2772    {
2773        self.apply_soft_delete_filter();
2774        let mut query = String::new();
2775        let mut args = AnyArguments::default();
2776        let mut arg_counter = 1;
2777
2778        self.write_select_sql::<R>(&mut query, &mut args, &mut arg_counter);
2779
2780        if self.debug_mode {
2781            log::debug!("SQL: {}", query);
2782        }
2783
2784        let rows = self.tx.fetch_all(&query, args).await?;
2785        let mut result = Vec::with_capacity(rows.len());
2786        for row in rows {
2787            result.push(R::from_any_row(&row)?);
2788        }
2789        Ok(result)
2790    }
2791
2792    /// Executes the query and eager loads the requested relationships.
2793    ///
2794    /// This method is specifically for cases where you want to load relations
2795    /// into models. It requires the return type to implement the `Model` trait.
2796    pub async fn scan_with(mut self) -> Result<Vec<T>, sqlx::Error>
2797    where
2798        T: FromAnyRow + AnyImpl + crate::model::Model + Send + Unpin + 'static,
2799        E: Clone,
2800    {
2801        let with_relations = std::mem::take(&mut self.with_relations);
2802        let tx = self.tx.clone();
2803        let mut results: Vec<T> = self.scan::<T>().await?;
2804
2805        if !results.is_empty() && !with_relations.is_empty() {
2806            for relation in with_relations {
2807                T::load_relations(&relation, &mut results, &tx).await?;
2808            }
2809        }
2810
2811        Ok(results)
2812    }
2813
2814    /// Executes the query and maps the result to a custom DTO.
2815    ///
2816    /// Useful for queries that return only a subset of columns or join multiple tables.
2817    ///
2818    /// # Type Parameters
2819    ///
2820    /// * `R` - The DTO type. Must implement `FromAnyRow` and `AnyImpl`.
2821    ///
2822    /// # Returns
2823    ///
2824    /// * `Ok(Vec<R>)` - Vector of results
2825    /// * `Err(sqlx::Error)` - Database error
2826    ///
2827    /// # Example
2828    ///
2829    /// ```rust,ignore
2830    /// let dtos: Vec<UserStats> = db.model::<User>()
2831    ///     .select("username, age")
2832    ///     .scan_as::<UserStats>()
2833    ///     .await?;
2834    /// // SQL: SELECT "username", "age" FROM "user"
2835    /// ```
2836    pub async fn scan_as<R>(mut self) -> Result<Vec<R>, sqlx::Error>
2837    where
2838        R: FromAnyRow + AnyImpl + Send + Unpin,
2839    {
2840        self.apply_soft_delete_filter();
2841        let mut query = String::new();
2842        let mut args = AnyArguments::default();
2843        let mut arg_counter = 1;
2844
2845        self.write_select_sql::<R>(&mut query, &mut args, &mut arg_counter);
2846
2847        if self.debug_mode {
2848            log::debug!("SQL: {}", query);
2849        }
2850
2851        let rows = self.tx.fetch_all(&query, args).await?;
2852        let mut result = Vec::with_capacity(rows.len());
2853        for row in rows {
2854            result.push(R::from_any_row(&row)?);
2855        }
2856        Ok(result)
2857    }
2858
2859    /// Executes the query and returns only the first result.
2860    ///
2861    /// Automatically applies `LIMIT 1` if no limit is set.
2862    ///
2863    /// # Type Parameters
2864    ///
2865    /// * `R` - The result type. Must implement `FromAnyRow` and `AnyImpl`.
2866    ///
2867    /// # Returns
2868    ///
2869    /// * `Ok(R)` - The first matching record
2870    /// * `Err(sqlx::Error::RowNotFound)` - If no records match
2871    ///
2872    /// # Example
2873    ///
2874    /// ```rust,ignore
2875    /// let user: User = db.model::<User>()
2876    ///     .filter("id", Op::Eq, 1)
2877    ///     .first()
2878    ///     .await?;
2879    /// // SQL: SELECT * FROM "user" WHERE "id" = 1 LIMIT 1
2880    /// ```
2881    pub async fn first<R>(mut self) -> Result<R, sqlx::Error>
2882    where
2883        R: FromAnyRow + AnyImpl + Send + Unpin,
2884    {
2885        self.apply_soft_delete_filter();
2886        let mut query = String::new();
2887        let mut args = AnyArguments::default();
2888        let mut arg_counter = 1;
2889
2890        // Force limit 1 if not set
2891        if self.limit.is_none() {
2892            self.limit = Some(1);
2893        }
2894
2895        // Apply PK ordering fallback if no order is set
2896        if self.order_clauses.is_empty() {
2897            let table_id = self.get_table_identifier();
2898            let pk_columns: Vec<String> = <T as Model>::columns()
2899                .iter()
2900                .filter(|c| c.is_primary_key)
2901                .map(|c| format!("\"{}\".\"{}\"", table_id, c.name.strip_prefix("r#").unwrap_or(c.name).to_snake_case()))
2902                .collect();
2903            
2904            if !pk_columns.is_empty() {
2905                self.order_clauses.push(pk_columns.iter().map(|col| format!("{} ASC", col)).collect::<Vec<_>>().join(", "));
2906            }
2907        }
2908
2909        self.write_select_sql::<R>(&mut query, &mut args, &mut arg_counter);
2910
2911        if self.debug_mode {
2912            log::debug!("SQL: {}", query);
2913        }
2914
2915        let row = self.tx.fetch_one(&query, args).await?;
2916        R::from_any_row(&row)
2917    }
2918
2919    /// Executes the query and returns a single scalar value.
2920    ///
2921    /// This method is useful for fetching single values like counts, max/min values,
2922    /// or specific columns without mapping to a struct or tuple.
2923    ///
2924    /// # Type Parameters
2925    ///
2926    /// * `O` - The output type. Must implement `FromAnyRow`, `AnyImpl`, `Send` and `Unpin`.
2927    ///
2928    /// # Example
2929    ///
2930    /// ```rust,ignore
2931    /// // Get count of users
2932    /// let count: i64 = db.model::<User>()
2933    ///     .select("count(*)")
2934    ///     .scalar()
2935    ///     .await?;
2936    ///
2937    /// // Get specific field
2938    /// let username: String = db.model::<User>()
2939    ///     .filter("id", "=", 1)
2940    ///     .select("username")
2941    ///     .scalar()
2942    ///     .await?;
2943    /// ```
2944    pub async fn scalar<O>(mut self) -> Result<O, sqlx::Error>
2945    where
2946        O: FromAnyRow + AnyImpl + Send + Unpin,
2947    {
2948        self.apply_soft_delete_filter();
2949        let mut query = String::new();
2950        let mut args = AnyArguments::default();
2951        let mut arg_counter = 1;
2952
2953        // Force limit 1 if not set
2954        if self.limit.is_none() {
2955            self.limit = Some(1);
2956        }
2957
2958        self.write_select_sql::<O>(&mut query, &mut args, &mut arg_counter);
2959
2960        if self.debug_mode {
2961            log::debug!("SQL: {}", query);
2962        }
2963
2964        let row = self.tx.fetch_one(&query, args).await?;
2965        O::from_any_row(&row)
2966    }
2967
2968    /// Updates a single column in the database for all rows matching the filters.
2969    ///
2970    /// # Arguments
2971    ///
2972    /// * `col` - The column name to update
2973    /// * `value` - The new value (supports primitive types and Option for NULL)
2974    ///
2975    /// # Returns
2976    ///
2977    /// * `Ok(u64)` - The number of rows affected
2978    ///
2979    /// # Example
2980    ///
2981    /// ```rust,ignore
2982    /// db.model::<User>()
2983    ///     .filter("id", Op::Eq, 1)
2984    ///     .update("active", false)
2985    ///     .await?;
2986    /// ```
2987    pub fn update<'b, V>(&'b mut self, col: &str, value: V) -> BoxFuture<'b, Result<u64, sqlx::Error>>
2988    where
2989        V: ToUpdateValue + Send + Sync,
2990    {
2991        let mut map = std::collections::HashMap::new();
2992        map.insert(col.to_string(), value.to_update_value());
2993        self.execute_update(map)
2994    }
2995
2996    /// Updates columns based on a model instance for all rows matching the filters.
2997    ///
2998    /// This method updates the table with values from the provided model.
2999    /// Note: It updates ALL columns present in the model's `to_map()`.
3000    ///
3001    /// # Arguments
3002    ///
3003    /// * `model` - The model instance containing new values
3004    ///
3005    /// # Returns
3006    ///
3007    /// * `Ok(u64)` - The number of rows affected
3008    ///
3009    /// # Example
3010    ///
3011    /// ```rust,ignore
3012    /// let user = User { id: 1, username: "new_name".to_string(), ... };
3013    /// db.model::<User>()
3014    ///     .filter("id", Op::Eq, 1)
3015    ///     .updates(&user)
3016    ///     .await?;
3017    /// ```
3018    pub fn updates<'b>(&'b mut self, model: &T) -> BoxFuture<'b, Result<u64, sqlx::Error>> {
3019        self.execute_update(Model::to_map(model))
3020    }
3021
3022    /// Updates columns based on a partial model (struct implementing AnyImpl).
3023    ///
3024    /// This allows updating a subset of columns using a custom struct.
3025    /// The struct must implement `AnyImpl` (usually via `#[derive(FromAnyRow)]`).
3026    ///
3027    /// # Arguments
3028    ///
3029    /// * `partial` - The partial model containing new values
3030    ///
3031    /// # Returns
3032    ///
3033    /// * `Ok(u64)` - The number of rows affected
3034    ///
3035    /// # Example
3036    ///
3037    /// ```rust,ignore
3038    /// #[derive(AnyRow)]
3039    /// struct UserUpdate {
3040    ///     username: String,
3041    ///     active: bool,
3042    /// }
3043    ///
3044    /// let partial = UserUpdate { username: "updated".into(), active: true };
3045    /// db.model::<User>()
3046    ///     .filter("id", Op::Eq, 1)
3047    ///     .update_partial(&partial)
3048    ///     .await?;
3049    /// ```
3050    pub fn update_partial<'b, P: AnyImpl>(&'b mut self, partial: &P) -> BoxFuture<'b, Result<u64, sqlx::Error>> {
3051        self.execute_update(AnyImpl::to_map(partial))
3052    }
3053
3054    /// Updates a column using a raw SQL expression.
3055    ///
3056    /// This allows for complex updates like incrementing values or using database functions.
3057    /// You can use a `?` placeholder in the expression and provide a value to bind.
3058    ///
3059    /// # Arguments
3060    ///
3061    /// * `col` - The column name to update
3062    /// * `expr` - The raw SQL expression (e.g., "age + 1" or "age + ?")
3063    /// * `value` - The value to bind for the placeholder
3064    ///
3065    /// # Example
3066    ///
3067    /// ```rust,ignore
3068    /// // Increment age by 1
3069    /// db.model::<User>()
3070    ///     .filter("id", "=", 1)
3071    ///     .update_raw("age", "age + 1", 0)
3072    ///     .await?;
3073    ///
3074    /// // Increment age by a variable
3075    /// db.model::<User>()
3076    ///     .filter("id", "=", 1)
3077    ///     .update_raw("age", "age + ?", 5)
3078    ///     .await?;
3079    /// ```
3080    pub fn update_raw<'b, V>(
3081        &'b mut self,
3082        col: &str,
3083        expr: &str,
3084        value: V,
3085    ) -> BoxFuture<'b, Result<u64, sqlx::Error>>
3086    where
3087        V: 'static + for<'q> Encode<'q, Any> + Type<Any> + Send + Sync + Clone,
3088    {
3089        self.apply_soft_delete_filter();
3090
3091        let col_name_clean = col.strip_prefix("r#").unwrap_or(col).to_snake_case();
3092        let expr_owned = expr.to_string();
3093        let value_owned = value.clone();
3094
3095        Box::pin(async move {
3096            let table_name = self.table_name.to_snake_case();
3097            let mut query = format!("UPDATE \"{}\" ", table_name);
3098            if let Some(alias) = &self.alias {
3099                query.push_str(&format!("AS {} ", alias));
3100            }
3101            query.push_str("SET ");
3102
3103            let mut arg_counter = 1;
3104            let mut args = AnyArguments::default();
3105
3106            let mut processed_expr = expr_owned.clone();
3107            let mut has_placeholder = false;
3108
3109            if processed_expr.contains('?') {
3110                has_placeholder = true;
3111                if matches!(self.driver, Drivers::Postgres) {
3112                    while let Some(pos) = processed_expr.find('?') {
3113                        let placeholder = format!("${}", arg_counter);
3114                        arg_counter += 1;
3115                        processed_expr.replace_range(pos..pos + 1, &placeholder);
3116                    }
3117                }
3118            }
3119
3120            if has_placeholder {
3121                let _ = args.add(value_owned);
3122            }
3123
3124            query.push_str(&format!("\"{}\" = {}", col_name_clean, processed_expr));
3125            query.push_str(" WHERE 1=1");
3126
3127            for clause in &self.where_clauses {
3128                clause(&mut query, &mut args, &self.driver, &mut arg_counter);
3129            }
3130
3131            if self.debug_mode {
3132                log::debug!("SQL: {}", query);
3133            }
3134
3135            let result = self.tx.execute(&query, args).await?;
3136            Ok(result.rows_affected())
3137        })
3138    }
3139
3140    /// Internal helper to apply soft delete filter to where clauses if necessary.
3141    fn apply_soft_delete_filter(&mut self) {
3142        if !self.with_deleted {
3143            if let Some(soft_delete_col) = self.columns_info.iter().find(|c| c.soft_delete).map(|c| c.name) {
3144                let col_owned = soft_delete_col.to_string();
3145                let clause: FilterFn = Box::new(move |query, _args, _driver, _arg_counter| {
3146                    query.push_str(" AND ");
3147                    query.push_str(&format!("\"{}\"", col_owned));
3148                    query.push_str(" IS NULL");
3149                });
3150                self.where_clauses.push(clause);
3151            }
3152        }
3153    }
3154
3155    /// Internal helper to execute an UPDATE query from a map of values.
3156    fn execute_update<'b>(
3157        &'b mut self,
3158        data_map: std::collections::HashMap<String, Option<String>>,
3159    ) -> BoxFuture<'b, Result<u64, sqlx::Error>> {
3160        self.apply_soft_delete_filter();
3161
3162        Box::pin(async move {
3163            let table_name = self.table_name.to_snake_case();
3164            let mut query = format!("UPDATE \"{}\" ", table_name);
3165            if let Some(alias) = &self.alias {
3166                query.push_str(&format!("{} ", alias));
3167            }
3168            query.push_str("SET ");
3169
3170            let mut bindings: Vec<(Option<String>, &str)> = Vec::new();
3171            let mut set_clauses = Vec::new();
3172
3173            // Maintain argument counter for PostgreSQL ($1, $2, ...)
3174            let mut arg_counter = 1;
3175
3176            // Build SET clause
3177            for (col_name, value) in data_map {
3178                // Strip the "r#" prefix if present
3179                let col_name_clean = col_name.strip_prefix("r#").unwrap_or(&col_name).to_snake_case();
3180
3181                // Find the SQL type for this column from the Model metadata
3182                let sql_type_opt = self
3183                    .columns_info
3184                    .iter()
3185                    .find(|c| c.name == col_name || c.name == col_name_clean)
3186                    .map(|c| c.sql_type);
3187                    
3188                let sql_type = match sql_type_opt {
3189                    Some(t) => t,
3190                    None => continue,
3191                };
3192
3193                // Generate placeholder
3194                let placeholder = match self.driver {
3195                    Drivers::Postgres => {
3196                        let idx = arg_counter;
3197                        arg_counter += 1;
3198
3199                        if temporal::is_temporal_type(sql_type) {
3200                            format!("${}{}", idx, temporal::get_postgres_type_cast(sql_type))
3201                        } else {
3202                            match sql_type {
3203                                "UUID" => format!("${}::UUID", idx),
3204                                "JSONB" | "jsonb" => format!("${}::JSONB", idx),
3205                                s if s.ends_with("[]") => format!("${}::{}", idx, s),
3206                                _ => format!("${}", idx),
3207                            }
3208                        }
3209                    }
3210                    _ => "?".to_string(),
3211                };
3212
3213                set_clauses.push(format!("\"{}\" = {}", col_name_clean, placeholder));
3214                bindings.push((value, sql_type));
3215            }
3216
3217            // If no fields to update, return 0
3218            if set_clauses.is_empty() {
3219                return Ok(0);
3220            }
3221
3222            query.push_str(&set_clauses.join(", "));
3223
3224            // Build WHERE clause
3225            query.push_str(" WHERE 1=1");
3226
3227            let mut args = AnyArguments::default();
3228
3229            // Bind SET values
3230            for (val_opt, sql_type) in bindings {
3231                if let Some(val_str) = val_opt {
3232                    if args.bind_value(&val_str, sql_type, &self.driver).is_err() {
3233                        let _ = args.add(val_str);
3234                    }
3235                } else {
3236                    let _ = args.add(None::<String>);
3237                }
3238            }
3239
3240            // Apply WHERE clauses (appending to args and query)
3241            for clause in &self.where_clauses {
3242                clause(&mut query, &mut args, &self.driver, &mut arg_counter);
3243            }
3244
3245            // Print SQL query to logs if debug mode is active
3246            if self.debug_mode {
3247                log::debug!("SQL: {}", query);
3248            }
3249
3250            // Execute the UPDATE query
3251            let result = self.tx.execute(&query, args).await?;
3252
3253            Ok(result.rows_affected())
3254        })
3255    }
3256
3257    /// Executes a DELETE query based on the current filters.
3258    ///
3259    /// Performs a soft delete if the model has a soft delete column,
3260    /// otherwise performs a permanent hard delete.
3261    ///
3262    /// # Returns
3263    ///
3264    /// * `Ok(u64)` - The number of rows deleted (or soft-deleted)
3265    /// * `Err(sqlx::Error)` - Database error
3266    ///
3267    /// # Example
3268    ///
3269    /// ```rust,ignore
3270    /// db.model::<User>()
3271    ///     .filter("id", Op::Eq, 1)
3272    ///     .delete()
3273    ///     .await?;
3274    /// // SQL (Soft): UPDATE "user" SET "deleted_at" = NOW() WHERE "id" = 1
3275    /// // SQL (Hard): DELETE FROM "user" WHERE "id" = 1
3276    /// ```
3277    pub async fn delete(self) -> Result<u64, sqlx::Error> {
3278        // Check for soft delete column
3279        let soft_delete_col = self.columns_info.iter().find(|c| c.soft_delete).map(|c| c.name);
3280
3281        if let Some(col) = soft_delete_col {
3282            // Soft Delete: Update the column to current timestamp
3283            let table_name = self.table_name.to_snake_case();
3284            let mut query = format!("UPDATE \"{}\" ", table_name);
3285            if let Some(alias) = &self.alias {
3286                query.push_str(&format!("{} ", alias));
3287            }
3288            query.push_str(&format!("SET \"{}\" = ", col));
3289
3290            match self.driver {
3291                Drivers::Postgres => query.push_str("NOW()"),
3292                Drivers::SQLite => query.push_str("strftime('%Y-%m-%dT%H:%M:%SZ', 'now')"),
3293                Drivers::MySQL => query.push_str("NOW()"),
3294            }
3295
3296            query.push_str(" WHERE 1=1");
3297
3298            let mut args = AnyArguments::default();
3299            let mut arg_counter = 1;
3300
3301            // Apply filters
3302            for clause in &self.where_clauses {
3303                clause(&mut query, &mut args, &self.driver, &mut arg_counter);
3304            }
3305
3306            // Print SQL query to logs if debug mode is active
3307            if self.debug_mode {
3308                log::debug!("SQL: {}", query);
3309            }
3310
3311            let result = self.tx.execute(&query, args).await?;
3312            Ok(result.rows_affected())
3313        } else {
3314            // Standard Delete (no soft delete column)
3315            let mut query = String::from("DELETE FROM \"");
3316            query.push_str(&self.table_name.to_snake_case());
3317            query.push_str("\" WHERE 1=1");
3318
3319            let mut args = AnyArguments::default();
3320            let mut arg_counter = 1;
3321
3322            for clause in &self.where_clauses {
3323                clause(&mut query, &mut args, &self.driver, &mut arg_counter);
3324            }
3325
3326            // Print SQL query to logs if debug mode is active
3327            if self.debug_mode {
3328                log::debug!("SQL: {}", query);
3329            }
3330
3331            let result = self.tx.execute(&query, args).await?;
3332            Ok(result.rows_affected())
3333        }
3334    }
3335
3336    /// Permanently removes records from the database.
3337    ///
3338    /// # Returns
3339    ///
3340    /// * `Ok(u64)` - The number of rows deleted
3341    /// * `Err(sqlx::Error)` - Database error
3342    ///
3343    /// # Example
3344    ///
3345    /// ```rust,ignore
3346    /// db.model::<User>()
3347    ///     .filter("id", Op::Eq, 1)
3348    ///     .hard_delete()
3349    ///     .await?;
3350    /// // SQL: DELETE FROM "user" WHERE "id" = 1
3351    /// ```
3352    pub async fn hard_delete(self) -> Result<u64, sqlx::Error> {
3353        let mut query = String::from("DELETE FROM \"");
3354        query.push_str(&self.table_name.to_snake_case());
3355        query.push_str("\" WHERE 1=1");
3356
3357        let mut args = AnyArguments::default();
3358        let mut arg_counter = 1;
3359
3360        for clause in &self.where_clauses {
3361            clause(&mut query, &mut args, &self.driver, &mut arg_counter);
3362        }
3363
3364        // Print SQL query to logs if debug mode is active
3365        if self.debug_mode {
3366            log::debug!("SQL: {}", query);
3367        }
3368
3369        let result = self.tx.execute(&query, args).await?;
3370        Ok(result.rows_affected())
3371    }
3372}