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