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}