Skip to main content

rdbi/
query.rs

1//! Query builder for rdbi
2
3use crate::error::Result;
4use crate::traits::{ExecuteResult, FromRow, Pool, ToValue};
5use crate::value::Value;
6
7/// A query builder that supports fluent parameter binding.
8///
9/// # Example
10///
11/// ```ignore
12/// use rdbi::{Query, Pool};
13///
14/// async fn find_user(pool: &impl Pool, id: i64) -> rdbi::Result<Option<User>> {
15///     Query::new("SELECT * FROM users WHERE id = ?")
16///         .bind(id)
17///         .fetch_optional(pool)
18///         .await
19/// }
20/// ```
21#[derive(Debug, Clone)]
22pub struct Query<'q> {
23    sql: &'q str,
24    params: Vec<Value>,
25}
26
27impl<'q> Query<'q> {
28    /// Create a new query with the given SQL.
29    pub fn new(sql: &'q str) -> Self {
30        Self {
31            sql,
32            params: Vec::new(),
33        }
34    }
35
36    /// Bind a single value to the query.
37    ///
38    /// Values are bound in order, replacing `?` placeholders.
39    pub fn bind<T: ToValue>(mut self, value: T) -> Self {
40        self.params.push(value.to_value());
41        self
42    }
43
44    /// Bind multiple values to the query.
45    ///
46    /// This is useful for IN clauses or batch operations.
47    pub fn bind_all<T: ToValue>(mut self, values: &[T]) -> Self {
48        for value in values {
49            self.params.push(value.to_value());
50        }
51        self
52    }
53
54    /// Get the SQL string.
55    pub fn sql(&self) -> &str {
56        self.sql
57    }
58
59    /// Get the bound parameters.
60    pub fn params(&self) -> &[Value] {
61        &self.params
62    }
63
64    /// Take ownership of the parameters.
65    pub fn into_params(self) -> Vec<Value> {
66        self.params
67    }
68
69    /// Execute the query and return the result.
70    pub async fn execute<P: Pool>(self, pool: &P) -> Result<ExecuteResult> {
71        pool.execute(self.sql, self.params).await
72    }
73
74    /// Fetch all matching rows.
75    pub async fn fetch_all<T: FromRow + Send, P: Pool>(self, pool: &P) -> Result<Vec<T>> {
76        pool.fetch_all(self.sql, self.params).await
77    }
78
79    /// Fetch a single optional row.
80    pub async fn fetch_optional<T: FromRow + Send, P: Pool>(self, pool: &P) -> Result<Option<T>> {
81        pool.fetch_optional(self.sql, self.params).await
82    }
83
84    /// Fetch exactly one row.
85    pub async fn fetch_one<T: FromRow + Send, P: Pool>(self, pool: &P) -> Result<T> {
86        pool.fetch_one(self.sql, self.params).await
87    }
88
89    /// Fetch a scalar value (first column of first row).
90    pub async fn fetch_scalar<T: crate::FromValue + Send, P: Pool>(self, pool: &P) -> Result<T> {
91        pool.fetch_scalar(self.sql, self.params).await
92    }
93}
94
95/// A dynamic query builder for queries with variable SQL.
96///
97/// Use this when you need to build SQL dynamically at runtime.
98#[derive(Debug, Clone)]
99pub struct DynamicQuery {
100    sql: String,
101    params: Vec<Value>,
102}
103
104impl DynamicQuery {
105    /// Create a new dynamic query with the given SQL.
106    pub fn new(sql: impl Into<String>) -> Self {
107        Self {
108            sql: sql.into(),
109            params: Vec::new(),
110        }
111    }
112
113    /// Bind a single value to the query.
114    pub fn bind<T: ToValue>(mut self, value: T) -> Self {
115        self.params.push(value.to_value());
116        self
117    }
118
119    /// Bind multiple values to the query.
120    pub fn bind_all<T: ToValue>(mut self, values: &[T]) -> Self {
121        for value in values {
122            self.params.push(value.to_value());
123        }
124        self
125    }
126
127    /// Get the SQL string.
128    pub fn sql(&self) -> &str {
129        &self.sql
130    }
131
132    /// Get the bound parameters.
133    pub fn params(&self) -> &[Value] {
134        &self.params
135    }
136
137    /// Execute the query and return the result.
138    pub async fn execute<P: Pool>(self, pool: &P) -> Result<ExecuteResult> {
139        pool.execute(&self.sql, self.params).await
140    }
141
142    /// Fetch all matching rows.
143    pub async fn fetch_all<T: FromRow + Send, P: Pool>(self, pool: &P) -> Result<Vec<T>> {
144        pool.fetch_all(&self.sql, self.params).await
145    }
146
147    /// Fetch a single optional row.
148    pub async fn fetch_optional<T: FromRow + Send, P: Pool>(self, pool: &P) -> Result<Option<T>> {
149        pool.fetch_optional(&self.sql, self.params).await
150    }
151
152    /// Fetch exactly one row.
153    pub async fn fetch_one<T: FromRow + Send, P: Pool>(self, pool: &P) -> Result<T> {
154        pool.fetch_one(&self.sql, self.params).await
155    }
156
157    /// Fetch a scalar value (first column of first row).
158    pub async fn fetch_scalar<T: crate::FromValue + Send, P: Pool>(self, pool: &P) -> Result<T> {
159        pool.fetch_scalar(&self.sql, self.params).await
160    }
161}