sea_query/types/iden/
compound.rs

1//! "Compound" identifiers built on top of `DynIden`.
2
3use crate::{FunctionCall, SelectStatement, ValueTuple};
4use std::{fmt::Debug, iter::Flatten};
5
6use super::*;
7
8pub trait IdenList {
9    type IntoIter: Iterator<Item = DynIden>;
10
11    fn into_iter(self) -> Self::IntoIter;
12}
13
14impl<I> IdenList for I
15where
16    I: IntoIden,
17{
18    type IntoIter = std::iter::Once<DynIden>;
19
20    fn into_iter(self) -> Self::IntoIter {
21        std::iter::once(self.into_iden())
22    }
23}
24
25impl<A, B> IdenList for (A, B)
26where
27    A: IntoIden,
28    B: IntoIden,
29{
30    type IntoIter = std::array::IntoIter<DynIden, 2>;
31
32    fn into_iter(self) -> Self::IntoIter {
33        [self.0.into_iden(), self.1.into_iden()].into_iter()
34    }
35}
36
37impl<A, B, C> IdenList for (A, B, C)
38where
39    A: IntoIden,
40    B: IntoIden,
41    C: IntoIden,
42{
43    type IntoIter = std::array::IntoIter<DynIden, 3>;
44
45    fn into_iter(self) -> Self::IntoIter {
46        [self.0.into_iden(), self.1.into_iden(), self.2.into_iden()].into_iter()
47    }
48}
49
50/// An identifier that represents a database name.
51#[derive(Debug, Clone, PartialEq, Eq, Hash)]
52pub struct DatabaseName(pub DynIden);
53
54impl<T> From<T> for DatabaseName
55where
56    T: IntoIden,
57{
58    fn from(iden: T) -> Self {
59        DatabaseName(iden.into_iden())
60    }
61}
62
63/// A schema name, potentially qualified as `(database.)schema`.
64#[derive(Debug, Clone, PartialEq, Eq, Hash)]
65pub struct SchemaName(pub Option<DatabaseName>, pub DynIden);
66
67/// An SQL type name, potentially qualified as `(database.)(schema.)type`.
68#[derive(Debug, Clone, PartialEq, Eq, Hash)]
69pub struct TypeRef(pub Option<SchemaName>, pub DynIden);
70
71pub trait IntoTypeRef: Into<TypeRef> {
72    fn into_type_ref(self) -> TypeRef;
73}
74
75impl<T> IntoTypeRef for T
76where
77    T: Into<TypeRef>,
78{
79    fn into_type_ref(self) -> TypeRef {
80        self.into()
81    }
82}
83
84/// A table name, potentially qualified as `(database.)(schema.)table`.
85#[derive(Debug, Clone, PartialEq, Eq, Hash)]
86pub struct TableName(pub Option<SchemaName>, pub DynIden);
87
88impl TableName {
89    /// A flat `(db?, schema?, table)` tuple view, for quick pattern matching.
90    ///
91    /// Don't use this if you need exhaustiveness.
92    /// The return type is too lax and allows invalid shapes like `(Some(_), None, _)`.
93    pub(crate) fn as_iden_tuple(&self) -> (Option<&DynIden>, Option<&DynIden>, &DynIden) {
94        let TableName(schema_name, table) = self;
95        match schema_name {
96            None => (None, None, table),
97            Some(SchemaName(db_name, schema)) => match db_name {
98                None => (None, Some(schema), table),
99                Some(DatabaseName(db)) => (Some(db), Some(schema), table),
100            },
101        }
102    }
103}
104
105/// A column name, potentially qualified as `(database.)(schema.)(table.)column`.
106#[derive(Debug, Clone, PartialEq, Eq, Hash)]
107pub struct ColumnName(pub Option<TableName>, pub DynIden);
108
109/// Iteration over `[db?, schema?, table?, column]` identifiers.
110impl IdenList for ColumnName {
111    type IntoIter = Flatten<std::array::IntoIter<Option<DynIden>, 4>>;
112
113    /// Iteration over `[db?, schema?, table?, column]` identifiers.
114    fn into_iter(self) -> Self::IntoIter {
115        let ColumnName(table_name, column) = self;
116        let arr = match table_name {
117            None => [None, None, None, Some(column)],
118            Some(TableName(schema_name, table)) => match schema_name {
119                None => [None, None, Some(table), Some(column)],
120                Some(SchemaName(db_name, schema)) => {
121                    let db = db_name.map(|db| db.0);
122                    [db, Some(schema), Some(table), Some(column)]
123                }
124            },
125        };
126        arr.into_iter().flatten()
127    }
128}
129
130/// Column references.
131#[derive(Debug, Clone, PartialEq)]
132#[non_exhaustive]
133pub enum ColumnRef {
134    /// A column name, potentially qualified as `(database.)(schema.)(table.)column`.
135    Column(ColumnName),
136    /// An `*` expression, potentially qualified as `(database.)(schema.)(table.)*`.
137    Asterisk(Option<TableName>),
138}
139
140impl ColumnRef {
141    #[doc(hidden)]
142    /// Returns the unqualified column name if it's not an asterisk.
143    pub fn column(&self) -> Option<&DynIden> {
144        match self {
145            ColumnRef::Column(ColumnName(_table_ref, column_itself)) => Some(column_itself),
146            ColumnRef::Asterisk(..) => None,
147        }
148    }
149}
150
151impl From<Asterisk> for ColumnRef {
152    fn from(_: Asterisk) -> Self {
153        ColumnRef::Asterisk(None)
154    }
155}
156
157impl<T> From<T> for ColumnRef
158where
159    T: Into<ColumnName>,
160{
161    fn from(value: T) -> Self {
162        ColumnRef::Column(value.into())
163    }
164}
165
166impl<T> From<(T, Asterisk)> for ColumnRef
167where
168    T: IntoIden,
169{
170    fn from(value: (T, Asterisk)) -> Self {
171        ColumnRef::Asterisk(Some(value.0.into_iden().into()))
172    }
173}
174
175pub trait IntoColumnRef: Into<ColumnRef> {
176    fn into_column_ref(self) -> ColumnRef;
177}
178
179impl<T> IntoColumnRef for T
180where
181    T: Into<ColumnRef>,
182{
183    fn into_column_ref(self) -> ColumnRef {
184        self.into()
185    }
186}
187
188/// Table references
189#[derive(Debug, Clone, PartialEq)]
190#[non_exhaustive]
191pub enum TableRef {
192    /// A table identifier with optional Alias. Potentially qualified.
193    Table(TableName, Option<DynIden>),
194    /// Subquery with alias
195    SubQuery(Box<SelectStatement>, DynIden),
196    /// Values list with alias
197    ValuesList(Vec<ValueTuple>, DynIden),
198    /// Function call with alias
199    FunctionCall(FunctionCall, DynIden),
200}
201
202impl TableRef {
203    /// Add or replace the current alias
204    pub fn alias<A>(self, alias: A) -> Self
205    where
206        A: IntoIden,
207    {
208        match self {
209            Self::Table(table, _) => Self::Table(table, Some(alias.into_iden())),
210            Self::SubQuery(statement, _) => Self::SubQuery(statement, alias.into_iden()),
211            Self::ValuesList(values, _) => Self::ValuesList(values, alias.into_iden()),
212            Self::FunctionCall(func, _) => Self::FunctionCall(func, alias.into_iden()),
213        }
214    }
215
216    #[doc(hidden)]
217    pub fn sea_orm_table(&self) -> &DynIden {
218        match self {
219            TableRef::Table(TableName(_, tbl), _)
220            | TableRef::SubQuery(_, tbl)
221            | TableRef::ValuesList(_, tbl)
222            | TableRef::FunctionCall(_, tbl) => tbl,
223        }
224    }
225
226    #[doc(hidden)]
227    pub fn sea_orm_table_alias(&self) -> Option<&DynIden> {
228        match self {
229            TableRef::Table(_, None) | TableRef::SubQuery(_, _) | TableRef::ValuesList(_, _) => {
230                None
231            }
232            TableRef::Table(_, Some(alias)) | TableRef::FunctionCall(_, alias) => Some(alias),
233        }
234    }
235}
236
237impl<T> From<T> for TableRef
238where
239    T: Into<TableName>,
240{
241    fn from(value: T) -> Self {
242        TableRef::Table(value.into(), None)
243    }
244}
245
246pub trait IntoTableRef: Into<TableRef> {
247    fn into_table_ref(self) -> TableRef {
248        self.into()
249    }
250}
251
252impl<T> IntoTableRef for T where T: Into<TableRef> {}