Skip to main content

drizzle_core/
placeholder.rs

1use crate::expr::{Expr, NonNull, Scalar};
2use crate::traits::{SQLParam, ToSQL};
3use crate::types::Any;
4use crate::{Param, SQL};
5use core::fmt;
6
7/// A SQL parameter placeholder.
8///
9/// Placeholders store a semantic name for parameter binding. The actual SQL syntax
10/// (`$1`, `?`, `:name`) is determined by the `Dialect` at render time.
11///
12/// # Examples
13/// ```ignore
14/// // Named placeholder - rendered based on dialect
15/// let placeholder = Placeholder::named("user_id");
16///
17/// // Anonymous placeholder - for positional parameters
18/// let anon = Placeholder::anonymous();
19/// ```
20#[derive(Default, Debug, Clone, Hash, Copy, PartialEq, Eq)]
21pub struct Placeholder {
22    /// The semantic name of the parameter (used for binding by name).
23    pub name: Option<&'static str>,
24}
25
26impl Placeholder {
27    /// Creates a named placeholder.
28    ///
29    /// The name is used for binding; rendering is dialect-specific:
30    /// - PostgreSQL: `$1`, `$2`, ... (positional, name ignored in SQL)
31    /// - SQLite: `:name` for named placeholders
32    /// - MySQL: `?` (positional, name ignored in SQL)
33    pub const fn named(name: &'static str) -> Self {
34        Placeholder { name: Some(name) }
35    }
36
37    /// Creates an anonymous placeholder (no name).
38    ///
39    /// Used for positional parameters where no name binding is needed.
40    pub const fn anonymous() -> Self {
41        Placeholder { name: None }
42    }
43}
44
45// Placeholder as a SQL expression — uses `Any` type so it's compatible with all SQL types.
46impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for Placeholder {
47    fn to_sql(&self) -> SQL<'a, V> {
48        SQL {
49            chunks: smallvec::smallvec![crate::SQLChunk::Param(Param {
50                value: None,
51                placeholder: *self,
52            })],
53        }
54    }
55}
56
57impl<'a, V: SQLParam + 'a> Expr<'a, V> for Placeholder {
58    type SQLType = Any;
59    type Nullable = NonNull;
60    type Aggregate = Scalar;
61}
62
63impl fmt::Display for Placeholder {
64    /// Debug display: `?` for anonymous or `:name` for named.
65    /// Note: actual SQL rendering uses dialect-specific placeholders via `SQL::write_to`.
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        match self.name {
68            Some(name) => write!(f, ":{}", name),
69            None => write!(f, "?"),
70        }
71    }
72}