Skip to main content

drizzle_core/sql/
owned.rs

1use crate::prelude::*;
2use crate::sql::{ColumnRef, ColumnSqlRef, TableRef, TableSqlRef};
3use crate::{OwnedParam, SQL, SQLChunk, SQLParam, ToSQL, Token};
4use smallvec::SmallVec;
5
6/// A [`SQLChunk`] that owns all its data, so it has no lifetime.
7#[derive(Debug, Clone)]
8pub enum OwnedSQLChunk<V: SQLParam> {
9    /// A keyword or punctuation token.
10    Token(Token),
11    /// A quoted identifier.
12    Ident(Box<str>),
13    /// Raw SQL text, written as-is.
14    Raw(Box<str>),
15    /// An unsigned integer literal.
16    Number(usize),
17    /// A placeholder with an optional bound value.
18    Param(OwnedParam<V>),
19    /// A table reference.
20    Table(TableSqlRef),
21    /// A column reference.
22    Column(ColumnSqlRef),
23}
24
25impl<V: SQLParam> OwnedSQLChunk<V> {
26    /// Creates a token chunk.
27    #[inline]
28    #[must_use]
29    pub const fn token(t: Token) -> Self {
30        Self::Token(t)
31    }
32
33    /// Creates a table chunk.
34    #[inline]
35    #[must_use]
36    pub const fn table(table: TableRef) -> Self {
37        Self::Table(TableSqlRef::from_table_ref(table))
38    }
39
40    /// Creates a column chunk.
41    #[inline]
42    #[must_use]
43    pub const fn column(column: ColumnRef) -> Self {
44        Self::Column(ColumnSqlRef::from_column_ref(column))
45    }
46
47    /// Creates a quoted identifier from a runtime string.
48    #[inline]
49    pub fn ident(name: impl Into<Box<str>>) -> Self {
50        Self::Ident(name.into())
51    }
52
53    /// Creates raw SQL text from a runtime string.
54    #[inline]
55    pub fn raw(text: impl Into<Box<str>>) -> Self {
56        Self::Raw(text.into())
57    }
58
59    /// Creates a parameter chunk.
60    #[inline]
61    pub const fn param(value: OwnedParam<V>) -> Self {
62        Self::Param(value)
63    }
64}
65
66impl<'a, V: SQLParam> From<SQLChunk<'a, V>> for OwnedSQLChunk<V> {
67    fn from(value: SQLChunk<'a, V>) -> Self {
68        match value {
69            SQLChunk::Token(token) => Self::Token(token),
70            SQLChunk::Ident(cow) => Self::Ident(cow.into_owned().into_boxed_str()),
71            SQLChunk::Raw(cow) => Self::Raw(cow.into_owned().into_boxed_str()),
72            SQLChunk::Number(value) => Self::Number(value),
73            SQLChunk::Param(param) => Self::Param(param.into()),
74            SQLChunk::Table(t) => Self::Table(t),
75            SQLChunk::Column(c) => Self::Column(c),
76        }
77    }
78}
79
80impl<V: SQLParam> From<OwnedSQLChunk<V>> for SQLChunk<'static, V> {
81    fn from(value: OwnedSQLChunk<V>) -> Self {
82        match value {
83            OwnedSQLChunk::Token(token) => SQLChunk::Token(token),
84            OwnedSQLChunk::Ident(s) => SQLChunk::Ident(Cow::Owned(String::from(s))),
85            OwnedSQLChunk::Raw(s) => SQLChunk::Raw(Cow::Owned(String::from(s))),
86            OwnedSQLChunk::Number(value) => SQLChunk::Number(value),
87            OwnedSQLChunk::Param(param) => SQLChunk::Param(param.into()),
88            OwnedSQLChunk::Table(t) => SQLChunk::Table(t),
89            OwnedSQLChunk::Column(c) => SQLChunk::Column(c),
90        }
91    }
92}
93
94/// A [`SQL`] fragment that owns all its data, so it can be stored without a
95/// lifetime.
96///
97/// Create one with [`SQL::into_owned`]; turn it back with
98/// [`OwnedSQL::into_sql`].
99#[derive(Debug, Clone)]
100pub struct OwnedSQL<V: SQLParam> {
101    /// The fragment's chunks, in order.
102    pub chunks: SmallVec<[OwnedSQLChunk<V>; 8]>,
103}
104
105impl<V: SQLParam> Default for OwnedSQL<V> {
106    fn default() -> Self {
107        Self {
108            chunks: SmallVec::new(),
109        }
110    }
111}
112
113impl<'a, V: SQLParam> From<SQL<'a, V>> for OwnedSQL<V> {
114    fn from(value: SQL<'a, V>) -> Self {
115        Self {
116            chunks: value.chunks.into_iter().map(Into::into).collect(),
117        }
118    }
119}
120
121impl<V: SQLParam> OwnedSQL<V> {
122    /// Creates an empty fragment. Usable in `const` contexts.
123    #[inline]
124    #[must_use]
125    pub const fn empty() -> Self {
126        Self {
127            chunks: SmallVec::new_const(),
128        }
129    }
130
131    /// Creates an empty fragment with room for `capacity` chunks.
132    #[inline]
133    #[must_use]
134    pub fn with_capacity_chunks(capacity: usize) -> Self {
135        Self {
136            chunks: SmallVec::with_capacity(capacity),
137        }
138    }
139
140    /// Copies this fragment into a `SQL<'static, V>`.
141    pub fn to_sql(&self) -> SQL<'static, V> {
142        SQL {
143            chunks: self.chunks.iter().cloned().map(Into::into).collect(),
144        }
145    }
146
147    /// Converts this fragment into a `SQL<'static, V>`.
148    pub fn into_sql(self) -> SQL<'static, V> {
149        SQL {
150            chunks: self.chunks.into_iter().map(Into::into).collect(),
151        }
152    }
153}
154
155impl<V: SQLParam> ToSQL<'static, V> for OwnedSQL<V> {
156    fn to_sql(&self) -> SQL<'static, V> {
157        Self::to_sql(self)
158    }
159
160    fn into_sql(self) -> SQL<'static, V> {
161        self.into_sql()
162    }
163}