drizzle_core/
placeholder.rs1use crate::bind::{BindValue, NullableBindValue};
2use crate::expr::{Expr, NonNull, Null, Nullability, Scalar};
3use crate::param::ParamBind;
4use crate::traits::{SQLParam, ToSQL};
5use crate::types::DataType;
6use crate::{Param, SQL};
7use core::fmt;
8use core::marker::PhantomData;
9
10#[derive(Default, Debug, Clone, Hash, Copy, PartialEq, Eq)]
15pub struct Placeholder {
16 pub name: Option<&'static str>,
18}
19
20#[derive(Default, Debug, Clone, Hash, Copy, PartialEq, Eq)]
22pub struct TypedPlaceholder<T: DataType, N: Nullability = NonNull> {
23 inner: Placeholder,
24 _marker: PhantomData<fn() -> (T, N)>,
25}
26
27impl Placeholder {
28 #[must_use]
35 pub const fn named(name: &'static str) -> Self {
36 Self { name: Some(name) }
37 }
38
39 #[must_use]
41 pub const fn anonymous() -> Self {
42 Self { name: None }
43 }
44
45 #[must_use]
47 pub const fn typed<T: DataType>(name: &'static str) -> TypedPlaceholder<T, NonNull> {
48 TypedPlaceholder {
49 inner: Self::named(name),
50 _marker: PhantomData,
51 }
52 }
53
54 #[must_use]
56 pub const fn typed_nullable<T: DataType>(name: &'static str) -> TypedPlaceholder<T, Null> {
57 TypedPlaceholder {
58 inner: Self::named(name),
59 _marker: PhantomData,
60 }
61 }
62}
63
64impl<T: DataType, N: Nullability> TypedPlaceholder<T, N> {
65 #[must_use]
67 pub const fn named(name: &'static str) -> Self {
68 Self {
69 inner: Placeholder::named(name),
70 _marker: PhantomData,
71 }
72 }
73
74 pub fn bind<'a, V, R>(self, value: R) -> ParamBind<'a, V>
76 where
77 V: SQLParam,
78 R: BindValue<'a, V, T>,
79 {
80 ParamBind {
81 name: self.inner.name.unwrap_or(""),
82 value: value.into_bind_value(),
83 }
84 }
85
86 #[must_use]
88 pub const fn name(self) -> Option<&'static str> {
89 self.inner.name
90 }
91
92 #[must_use]
94 pub const fn into_placeholder(self) -> Placeholder {
95 self.inner
96 }
97}
98
99impl<T: DataType> TypedPlaceholder<T, Null> {
100 pub fn bind_opt<'a, V, R>(self, value: Option<R>) -> ParamBind<'a, V>
102 where
103 V: SQLParam,
104 Option<R>: NullableBindValue<'a, V, T>,
105 {
106 ParamBind {
107 name: self.inner.name.unwrap_or(""),
108 value: value.into_nullable_bind_value(),
109 }
110 }
111}
112
113impl<T: DataType, N: Nullability> From<TypedPlaceholder<T, N>> for Placeholder {
114 fn from(value: TypedPlaceholder<T, N>) -> Self {
115 value.inner
116 }
117}
118
119impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for Placeholder {
120 fn to_sql(&self) -> SQL<'a, V> {
121 SQL {
122 chunks: smallvec::smallvec![crate::SQLChunk::Param(Param {
123 value: None,
124 placeholder: *self,
125 })],
126 }
127 }
128}
129
130impl<'a, V: SQLParam + 'a> Expr<'a, V> for Placeholder {
131 type SQLType = crate::types::Placeholder;
132 type Nullable = NonNull;
133 type Aggregate = Scalar;
134}
135
136impl<'a, V: SQLParam + 'a, T: DataType, N: Nullability> ToSQL<'a, V> for TypedPlaceholder<T, N> {
137 fn to_sql(&self) -> SQL<'a, V> {
138 self.inner.to_sql()
139 }
140}
141
142impl<'a, V: SQLParam + 'a, T: DataType, N: Nullability> Expr<'a, V> for TypedPlaceholder<T, N> {
143 type SQLType = T;
144 type Nullable = N;
145 type Aggregate = Scalar;
146}
147
148impl fmt::Display for Placeholder {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 match self.name {
153 Some(name) => write!(f, ":{name}"),
154 None => write!(f, "?"),
155 }
156 }
157}