Skip to main content

bottle_orm/
query_builder.rs

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