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