Skip to main content

bottle_orm/
query_builder.rs

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