Skip to main content

bottle_orm/
query_builder.rs

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