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