1use crate::{FunctionCall, ValueTuple, Values, expr::*, query::*};
4use std::{borrow::Cow, fmt::Debug, iter::Flatten};
5
6#[cfg(feature = "backend-postgres")]
7use crate::extension::postgres::PgBinOper;
8#[cfg(feature = "backend-sqlite")]
9use crate::extension::sqlite::SqliteBinOper;
10
11mod qualification;
12
13pub use qualification::{MaybeQualifiedOnce, MaybeQualifiedTwice};
14
15#[cfg(not(feature = "thread-safe"))]
20pub type RcOrArc<T> = std::rc::Rc<T>;
21#[cfg(feature = "thread-safe")]
26pub type RcOrArc<T> = std::sync::Arc<T>;
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub struct Quote(pub(crate) u8, pub(crate) u8);
30
31pub trait Iden {
33 fn quoted(&self) -> Cow<'static, str> {
46 Cow::Owned(self.to_string())
47 }
48
49 fn to_string(&self) -> String {
57 self.unquoted().to_owned()
58 }
59
60 fn unquoted(&self) -> &str;
65}
66
67pub trait IdenStatic: Iden + Copy + 'static {
69 fn as_str(&self) -> &'static str;
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Hash)]
80pub struct DynIden(pub(crate) Cow<'static, str>);
81
82impl DynIden {
83 pub fn inner(&self) -> Cow<'static, str> {
84 self.0.clone()
85 }
86}
87
88#[derive(Debug)]
96pub struct SeaRc;
97
98impl SeaRc {
99 #[allow(clippy::new_ret_no_self)]
107 pub fn new<I>(i: I) -> DynIden
108 where
109 I: Iden,
110 {
111 DynIden(i.quoted())
112 }
113
114 pub fn clone(iden: &DynIden) -> DynIden {
115 iden.clone()
116 }
117}
118
119impl std::fmt::Display for DynIden {
120 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
121 f.write_str(&self.0)
122 }
123}
124
125pub trait IntoIden: Into<DynIden> {
126 fn into_iden(self) -> DynIden;
127}
128
129impl<T> IntoIden for T
130where
131 T: Into<DynIden>,
132{
133 fn into_iden(self) -> DynIden {
134 self.into()
135 }
136}
137
138pub trait IdenList {
139 type IntoIter: Iterator<Item = DynIden>;
140
141 fn into_iter(self) -> Self::IntoIter;
142}
143
144#[derive(Debug, Clone, PartialEq, Eq, Hash)]
146pub struct DatabaseName(pub DynIden);
147
148#[derive(Debug, Clone, PartialEq, Eq, Hash)]
150pub struct SchemaName(pub Option<DatabaseName>, pub DynIden);
151
152#[derive(Debug, Clone, PartialEq, Eq, Hash)]
154pub struct TypeRef(pub Option<SchemaName>, pub DynIden);
155
156pub trait IntoTypeRef: Into<TypeRef> {
157 fn into_type_ref(self) -> TypeRef;
158}
159
160impl<T> IntoTypeRef for T
161where
162 T: Into<TypeRef>,
163{
164 fn into_type_ref(self) -> TypeRef {
165 self.into()
166 }
167}
168
169#[derive(Debug, Clone, PartialEq, Eq, Hash)]
171pub struct TableName(pub Option<SchemaName>, pub DynIden);
172
173impl TableName {
174 pub(crate) fn as_iden_tuple(&self) -> (Option<&DynIden>, Option<&DynIden>, &DynIden) {
179 let TableName(schema_name, table) = self;
180 match schema_name {
181 None => (None, None, table),
182 Some(SchemaName(db_name, schema)) => match db_name {
183 None => (None, Some(schema), table),
184 Some(DatabaseName(db)) => (Some(db), Some(schema), table),
185 },
186 }
187 }
188}
189
190#[derive(Debug, Clone, PartialEq, Eq, Hash)]
192pub struct ColumnName(pub Option<TableName>, pub DynIden);
193
194impl IdenList for ColumnName {
196 type IntoIter = Flatten<std::array::IntoIter<Option<DynIden>, 4>>;
197
198 fn into_iter(self) -> Self::IntoIter {
200 let ColumnName(table_name, column) = self;
201 let arr = match table_name {
202 None => [None, None, None, Some(column)],
203 Some(TableName(schema_name, table)) => match schema_name {
204 None => [None, None, Some(table), Some(column)],
205 Some(SchemaName(db_name, schema)) => {
206 let db = db_name.map(|db| db.0);
207 [db, Some(schema), Some(table), Some(column)]
208 }
209 },
210 };
211 arr.into_iter().flatten()
212 }
213}
214
215#[derive(Debug, Clone, PartialEq)]
217#[non_exhaustive]
218pub enum ColumnRef {
219 Column(ColumnName),
221 Asterisk(Option<TableName>),
223}
224
225impl ColumnRef {
226 #[doc(hidden)]
227 pub fn column(&self) -> Option<&DynIden> {
229 match self {
230 ColumnRef::Column(ColumnName(_table_ref, column_itself)) => Some(column_itself),
231 ColumnRef::Asterisk(..) => None,
232 }
233 }
234}
235
236pub trait IntoColumnRef: Into<ColumnRef> {
237 fn into_column_ref(self) -> ColumnRef;
238}
239
240impl<T> IntoColumnRef for T
241where
242 T: Into<ColumnRef>,
243{
244 fn into_column_ref(self) -> ColumnRef {
245 self.into()
246 }
247}
248
249impl<T> From<T> for ColumnRef
250where
251 T: Into<ColumnName>,
252{
253 fn from(value: T) -> Self {
254 ColumnRef::Column(value.into())
255 }
256}
257
258impl From<Asterisk> for ColumnRef {
259 fn from(_: Asterisk) -> Self {
260 ColumnRef::Asterisk(None)
261 }
262}
263
264impl<T> From<(T, Asterisk)> for ColumnRef
265where
266 T: IntoIden,
267{
268 fn from(value: (T, Asterisk)) -> Self {
269 ColumnRef::Asterisk(Some(value.0.into_iden().into()))
270 }
271}
272
273#[derive(Debug, Clone, PartialEq)]
275#[non_exhaustive]
276pub enum TableRef {
277 Table(TableName, Option<DynIden>),
279 SubQuery(Box<SelectStatement>, DynIden),
281 ValuesList(Vec<ValueTuple>, DynIden),
283 FunctionCall(FunctionCall, DynIden),
285}
286
287impl TableRef {
288 #[doc(hidden)]
289 pub fn sea_orm_table(&self) -> &DynIden {
290 match self {
291 TableRef::Table(TableName(_, tbl), _)
292 | TableRef::SubQuery(_, tbl)
293 | TableRef::ValuesList(_, tbl)
294 | TableRef::FunctionCall(_, tbl) => tbl,
295 }
296 }
297
298 #[doc(hidden)]
299 pub fn sea_orm_table_alias(&self) -> Option<&DynIden> {
300 match self {
301 TableRef::Table(_, None) | TableRef::SubQuery(_, _) | TableRef::ValuesList(_, _) => {
302 None
303 }
304 TableRef::Table(_, Some(alias)) | TableRef::FunctionCall(_, alias) => Some(alias),
305 }
306 }
307}
308
309pub trait IntoTableRef: Into<TableRef> {
310 fn into_table_ref(self) -> TableRef {
311 self.into()
312 }
313}
314
315impl<T> IntoTableRef for T where T: Into<TableRef> {}
316
317impl<T> From<T> for TableRef
318where
319 T: Into<TableName>,
320{
321 fn from(value: T) -> Self {
322 TableRef::Table(value.into(), None)
323 }
324}
325
326#[derive(Debug, Clone, Copy, PartialEq, Eq)]
328#[non_exhaustive]
329pub enum UnOper {
330 Not,
331}
332
333#[derive(Debug, Clone, Copy, PartialEq, Eq)]
337#[non_exhaustive]
338pub enum BinOper {
339 And,
340 Or,
341 Like,
342 NotLike,
343 Is,
344 IsNot,
345 In,
346 NotIn,
347 Between,
348 NotBetween,
349 Equal,
350 NotEqual,
351 SmallerThan,
352 GreaterThan,
353 SmallerThanOrEqual,
354 GreaterThanOrEqual,
355 Add,
356 Sub,
357 Mul,
358 Div,
359 Mod,
360 BitAnd,
361 BitOr,
362 LShift,
363 RShift,
364 As,
365 Escape,
366 Custom(&'static str),
367 #[cfg(feature = "backend-postgres")]
368 PgOperator(PgBinOper),
369 #[cfg(feature = "backend-sqlite")]
370 SqliteOperator(SqliteBinOper),
371}
372
373#[derive(Debug, Clone, PartialEq)]
375pub enum LogicalChainOper {
376 And(Expr),
377 Or(Expr),
378}
379
380#[derive(Debug, Clone, Copy, PartialEq, Eq)]
382pub enum JoinType {
383 Join,
384 CrossJoin,
385 InnerJoin,
386 LeftJoin,
387 RightJoin,
388 FullOuterJoin,
389}
390
391#[derive(Debug, Clone, Copy, PartialEq, Eq)]
393pub enum NullOrdering {
394 First,
395 Last,
396}
397
398#[derive(Debug, Clone, PartialEq)]
400pub struct OrderExpr {
401 pub(crate) expr: Expr,
402 pub(crate) order: Order,
403 pub(crate) nulls: Option<NullOrdering>,
404}
405
406#[derive(Debug, Clone, PartialEq)]
408#[non_exhaustive]
409pub enum JoinOn {
410 Condition(Box<ConditionHolder>),
411 Columns(Vec<Expr>),
412}
413
414#[derive(Debug, Clone, PartialEq)]
416#[non_exhaustive]
417pub enum Order {
418 Asc,
419 Desc,
420 Field(Values),
421}
422
423#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
427pub struct Alias(pub String);
428
429#[derive(Default, Debug, Copy, Clone)]
431pub struct NullAlias;
432
433#[derive(Default, Debug, Clone, Copy)]
487pub struct Asterisk;
488
489#[derive(Debug, Clone, PartialEq)]
493#[non_exhaustive]
494pub enum Keyword {
495 Null,
496 CurrentDate,
497 CurrentTime,
498 CurrentTimestamp,
499 Default,
500 Custom(DynIden),
501}
502
503#[derive(Debug, Clone)]
505pub struct LikeExpr {
506 pub(crate) pattern: String,
507 pub(crate) escape: Option<char>,
508}
509
510pub trait IntoLikeExpr: Into<LikeExpr> {
511 fn into_like_expr(self) -> LikeExpr;
512}
513
514impl<T> IntoLikeExpr for T
515where
516 T: Into<LikeExpr>,
517{
518 fn into_like_expr(self) -> LikeExpr {
519 self.into()
520 }
521}
522
523#[derive(Debug, Copy, Clone, PartialEq)]
525#[non_exhaustive]
526pub enum SubQueryOper {
527 Exists,
528 Any,
529 Some,
530 All,
531}
532
533impl Quote {
536 pub fn new(c: u8) -> Self {
537 Self(c, c)
538 }
539
540 pub fn left(&self) -> char {
541 char::from(self.0)
542 }
543
544 pub fn right(&self) -> char {
545 char::from(self.1)
546 }
547}
548
549impl From<char> for Quote {
550 fn from(c: char) -> Self {
551 (c as u8).into()
552 }
553}
554
555impl From<(char, char)> for Quote {
556 fn from((l, r): (char, char)) -> Self {
557 (l as u8, r as u8).into()
558 }
559}
560
561impl From<u8> for Quote {
562 fn from(u8: u8) -> Self {
563 Quote::new(u8)
564 }
565}
566
567impl From<(u8, u8)> for Quote {
568 fn from((l, r): (u8, u8)) -> Self {
569 Quote(l, r)
570 }
571}
572
573impl<T> From<T> for DynIden
574where
575 T: Iden,
576{
577 fn from(iden: T) -> Self {
578 DynIden(iden.quoted())
579 }
580}
581
582impl<I> IdenList for I
583where
584 I: IntoIden,
585{
586 type IntoIter = std::iter::Once<DynIden>;
587
588 fn into_iter(self) -> Self::IntoIter {
589 std::iter::once(self.into_iden())
590 }
591}
592
593impl<A, B> IdenList for (A, B)
594where
595 A: IntoIden,
596 B: IntoIden,
597{
598 type IntoIter = std::array::IntoIter<DynIden, 2>;
599
600 fn into_iter(self) -> Self::IntoIter {
601 [self.0.into_iden(), self.1.into_iden()].into_iter()
602 }
603}
604
605impl<A, B, C> IdenList for (A, B, C)
606where
607 A: IntoIden,
608 B: IntoIden,
609 C: IntoIden,
610{
611 type IntoIter = std::array::IntoIter<DynIden, 3>;
612
613 fn into_iter(self) -> Self::IntoIter {
614 [self.0.into_iden(), self.1.into_iden(), self.2.into_iden()].into_iter()
615 }
616}
617
618impl<T> From<T> for DatabaseName
619where
620 T: IntoIden,
621{
622 fn from(iden: T) -> Self {
623 DatabaseName(iden.into_iden())
624 }
625}
626
627impl TableRef {
628 pub fn alias<A>(self, alias: A) -> Self
630 where
631 A: IntoIden,
632 {
633 match self {
634 Self::Table(table, _) => Self::Table(table, Some(alias.into_iden())),
635 Self::SubQuery(statement, _) => Self::SubQuery(statement, alias.into_iden()),
636 Self::ValuesList(values, _) => Self::ValuesList(values, alias.into_iden()),
637 Self::FunctionCall(func, _) => Self::FunctionCall(func, alias.into_iden()),
638 }
639 }
640}
641
642impl Alias {
643 pub fn new<T>(n: T) -> Self
644 where
645 T: Into<String>,
646 {
647 Self(n.into())
648 }
649}
650
651impl Iden for Alias {
652 fn quoted(&self) -> Cow<'static, str> {
653 Cow::Owned(self.0.clone())
654 }
655
656 fn unquoted(&self) -> &str {
657 &self.0
658 }
659}
660
661impl From<String> for DynIden {
662 fn from(value: String) -> Self {
663 DynIden(Cow::Owned(value))
664 }
665}
666
667impl Iden for &'static str {
668 fn quoted(&self) -> Cow<'static, str> {
669 if is_static_iden(self) {
670 Cow::Borrowed(self)
671 } else {
672 Cow::Owned(String::from(*self))
673 }
674 }
675
676 fn unquoted(&self) -> &str {
677 self
678 }
679}
680
681pub const fn is_static_iden(string: &str) -> bool {
697 let bytes = string.as_bytes();
698 if bytes.is_empty() {
699 return true;
700 }
701
702 if bytes[0] == b'_' || (bytes[0] as char).is_ascii_alphabetic() {
704 } else {
706 return false;
707 }
708
709 let mut i = 1;
710 while i < bytes.len() {
711 if bytes[i] == b'_' || (bytes[i] as char).is_ascii_alphanumeric() {
712 } else {
714 return false;
715 }
716 i += 1;
717 }
718
719 true
720}
721
722impl NullAlias {
723 pub fn new() -> Self {
724 Self
725 }
726}
727
728impl Iden for NullAlias {
729 fn unquoted(&self) -> &str {
730 ""
731 }
732}
733
734impl LikeExpr {
735 pub fn new<T>(pattern: T) -> Self
736 where
737 T: Into<String>,
738 {
739 Self {
740 pattern: pattern.into(),
741 escape: None,
742 }
743 }
744
745 #[deprecated(since = "0.29.0", note = "Please use the [`LikeExpr::new`] method")]
746 pub fn str<T>(pattern: T) -> Self
747 where
748 T: Into<String>,
749 {
750 Self {
751 pattern: pattern.into(),
752 escape: None,
753 }
754 }
755
756 pub fn escape(self, c: char) -> Self {
757 Self {
758 pattern: self.pattern,
759 escape: Some(c),
760 }
761 }
762}
763
764impl<T> From<T> for LikeExpr
765where
766 T: Into<String>,
767{
768 fn from(value: T) -> Self {
769 LikeExpr::new(value)
770 }
771}
772
773#[cfg(test)]
774mod tests {
775 pub use crate::{tests_cfg::*, *};
776 pub use Character as CharReexport;
777 use pretty_assertions::assert_eq;
778
779 #[test]
780 fn test_identifier() {
781 let query = Query::select().column("hello-World_").to_owned();
782
783 #[cfg(feature = "backend-mysql")]
784 assert_eq!(query.to_string(MysqlQueryBuilder), r"SELECT `hello-World_`");
785 #[cfg(feature = "backend-postgres")]
786 assert_eq!(
787 query.to_string(PostgresQueryBuilder),
788 r#"SELECT "hello-World_""#
789 );
790 #[cfg(feature = "backend-sqlite")]
791 assert_eq!(
792 query.to_string(SqliteQueryBuilder),
793 r#"SELECT "hello-World_""#
794 );
795 }
796
797 #[test]
798 fn test_quoted_identifier_1() {
799 let query = Query::select().column("hel`lo").to_owned();
800
801 #[cfg(feature = "backend-mysql")]
802 assert_eq!(query.to_string(MysqlQueryBuilder), r"SELECT `hel``lo`");
803 #[cfg(feature = "backend-sqlite")]
804 assert_eq!(query.to_string(SqliteQueryBuilder), r#"SELECT "hel`lo""#);
805
806 let query = Query::select().column("hel\"lo").to_owned();
807
808 #[cfg(feature = "backend-postgres")]
809 assert_eq!(query.to_string(PostgresQueryBuilder), r#"SELECT "hel""lo""#);
810 }
811
812 #[test]
813 fn test_quoted_identifier_2() {
814 let query = Query::select().column("hel``lo").to_owned();
815
816 #[cfg(feature = "backend-mysql")]
817 assert_eq!(query.to_string(MysqlQueryBuilder), r"SELECT `hel````lo`");
818 #[cfg(feature = "backend-sqlite")]
819 assert_eq!(query.to_string(SqliteQueryBuilder), r#"SELECT "hel``lo""#);
820
821 let query = Query::select().column("hel\"\"lo").to_owned();
822
823 #[cfg(feature = "backend-postgres")]
824 assert_eq!(
825 query.to_string(PostgresQueryBuilder),
826 r#"SELECT "hel""""lo""#
827 );
828 }
829
830 #[test]
831 fn test_cmp_identifier() {
832 type CharLocal = Character;
833
834 assert_eq!(
835 ColumnRef::Column(Character::Id.into()),
836 ColumnRef::Column(Character::Id.into())
837 );
838 assert_eq!(
839 ColumnRef::Column(Character::Id.into()),
840 ColumnRef::Column(Char::Id.into())
841 );
842 assert_eq!(
843 ColumnRef::Column(Character::Id.into()),
844 ColumnRef::Column(CharLocal::Id.into())
845 );
846 assert_eq!(
847 ColumnRef::Column(Character::Id.into()),
848 ColumnRef::Column(CharReexport::Id.into())
849 );
850 assert_eq!(
851 ColumnRef::Column("id".into()),
852 ColumnRef::Column("id".into())
853 );
854 assert_ne!(
855 ColumnRef::Column("id".into()),
856 ColumnRef::Column("id_".into())
857 );
858 assert_eq!(
859 ColumnRef::Column(Character::Id.into()),
860 ColumnRef::Column("id".into())
861 );
862 assert_ne!(
863 ColumnRef::Column(Character::Id.into()),
864 ColumnRef::Column(Character::Table.into())
865 );
866 assert_eq!(
867 ColumnRef::Column(Character::Id.into()),
868 ColumnRef::Column(Font::Id.into())
869 );
870 }
871}