1use crate::{expr::*, query::*, FunctionCall, ValueTuple, Values};
4use std::{fmt, mem, ops};
5
6#[cfg(feature = "backend-postgres")]
7use crate::extension::postgres::PgBinOper;
8#[cfg(feature = "backend-sqlite")]
9use crate::extension::sqlite::SqliteBinOper;
10#[cfg(not(feature = "thread-safe"))]
11pub use std::rc::Rc as RcOrArc;
12#[cfg(feature = "thread-safe")]
13pub use std::sync::Arc as RcOrArc;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub struct Quote(pub(crate) u8, pub(crate) u8);
17
18macro_rules! iden_trait {
19 ($($bounds:ident),*) => {
20 pub trait Iden where $(Self: $bounds),* {
22 fn prepare(&self, s: &mut dyn fmt::Write, q: Quote) {
23 write!(s, "{}{}{}", q.left(), self.quoted(q), q.right()).unwrap();
24 }
25
26 fn quoted(&self, q: Quote) -> String {
27 let byte = [q.1];
28 let qq: &str = std::str::from_utf8(&byte).unwrap();
29 self.to_string().replace(qq, qq.repeat(2).as_str())
30 }
31
32 fn to_string(&self) -> String {
33 let mut s = String::new();
34 self.unquoted(&mut s);
35 s
36 }
37
38 fn unquoted(&self, s: &mut dyn fmt::Write);
39 }
40
41 pub trait IdenStatic: Iden + Copy + 'static {
43 fn as_str(&self) -> &'static str;
44 }
45 };
46}
47
48#[cfg(feature = "thread-safe")]
49iden_trait!(Send, Sync);
50#[cfg(not(feature = "thread-safe"))]
51iden_trait!();
52
53pub type DynIden = SeaRc<dyn Iden>;
54
55#[derive(Debug)]
56#[repr(transparent)]
57pub struct SeaRc<I>(pub(crate) RcOrArc<I>)
58where
59 I: ?Sized;
60
61impl ops::Deref for SeaRc<dyn Iden> {
62 type Target = dyn Iden;
63
64 fn deref(&self) -> &Self::Target {
65 ops::Deref::deref(&self.0)
66 }
67}
68
69impl Clone for SeaRc<dyn Iden> {
70 fn clone(&self) -> SeaRc<dyn Iden> {
71 SeaRc(RcOrArc::clone(&self.0))
72 }
73}
74
75impl PartialEq for SeaRc<dyn Iden> {
76 fn eq(&self, other: &Self) -> bool {
77 let (self_vtable, other_vtable) = unsafe {
78 let (_, self_vtable) = mem::transmute::<&dyn Iden, (usize, usize)>(&*self.0);
79 let (_, other_vtable) = mem::transmute::<&dyn Iden, (usize, usize)>(&*other.0);
80 (self_vtable, other_vtable)
81 };
82 self_vtable == other_vtable && self.to_string() == other.to_string()
83 }
84}
85
86impl SeaRc<dyn Iden> {
87 pub fn new<I>(i: I) -> SeaRc<dyn Iden>
88 where
89 I: Iden + 'static,
90 {
91 SeaRc(RcOrArc::new(i))
92 }
93}
94
95pub trait IntoIden {
96 fn into_iden(self) -> DynIden;
97}
98
99pub trait IdenList {
100 type IntoIter: Iterator<Item = DynIden>;
101
102 fn into_iter(self) -> Self::IntoIter;
103}
104
105impl fmt::Debug for dyn Iden {
106 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
107 self.unquoted(formatter);
108 Ok(())
109 }
110}
111
112#[derive(Debug, Clone, PartialEq)]
114pub enum ColumnRef {
115 Column(DynIden),
116 TableColumn(DynIden, DynIden),
117 SchemaTableColumn(DynIden, DynIden, DynIden),
118 Asterisk,
119 TableAsterisk(DynIden),
120}
121
122pub trait IntoColumnRef {
123 fn into_column_ref(self) -> ColumnRef;
124}
125
126#[allow(clippy::large_enum_variant)]
128#[derive(Debug, Clone, PartialEq)]
129pub enum TableRef {
130 Table(DynIden),
132 SchemaTable(DynIden, DynIden),
134 DatabaseSchemaTable(DynIden, DynIden, DynIden),
136 TableAlias(DynIden, DynIden),
138 SchemaTableAlias(DynIden, DynIden, DynIden),
140 DatabaseSchemaTableAlias(DynIden, DynIden, DynIden, DynIden),
142 SubQuery(SelectStatement, DynIden),
144 ValuesList(Vec<ValueTuple>, DynIden),
146 FunctionCall(FunctionCall, DynIden),
148}
149
150pub trait IntoTableRef {
151 fn into_table_ref(self) -> TableRef;
152}
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq)]
156pub enum UnOper {
157 Not,
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub enum BinOper {
165 And,
166 Or,
167 Like,
168 NotLike,
169 Is,
170 IsNot,
171 In,
172 NotIn,
173 Between,
174 NotBetween,
175 Equal,
176 NotEqual,
177 SmallerThan,
178 GreaterThan,
179 SmallerThanOrEqual,
180 GreaterThanOrEqual,
181 Add,
182 Sub,
183 Mul,
184 Div,
185 Mod,
186 BitAnd,
187 BitOr,
188 LShift,
189 RShift,
190 As,
191 Escape,
192 Custom(&'static str),
193 #[cfg(feature = "backend-postgres")]
194 PgOperator(PgBinOper),
195 #[cfg(feature = "backend-sqlite")]
196 SqliteOperator(SqliteBinOper),
197}
198
199#[derive(Debug, Clone, PartialEq)]
201pub enum LogicalChainOper {
202 And(SimpleExpr),
203 Or(SimpleExpr),
204}
205
206#[derive(Debug, Clone, Copy, PartialEq, Eq)]
208pub enum JoinType {
209 Join,
210 CrossJoin,
211 InnerJoin,
212 LeftJoin,
213 RightJoin,
214 FullOuterJoin,
215}
216
217#[derive(Debug, Clone, Copy, PartialEq, Eq)]
219pub enum NullOrdering {
220 First,
221 Last,
222}
223
224#[derive(Debug, Clone, PartialEq)]
226pub struct OrderExpr {
227 pub(crate) expr: SimpleExpr,
228 pub(crate) order: Order,
229 pub(crate) nulls: Option<NullOrdering>,
230}
231
232#[derive(Debug, Clone, PartialEq)]
234pub enum JoinOn {
235 Condition(Box<ConditionHolder>),
236 Columns(Vec<SimpleExpr>),
237}
238
239#[derive(Debug, Clone, PartialEq)]
241pub enum Order {
242 Asc,
243 Desc,
244 Field(Values),
245}
246
247#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
249pub struct Alias(String);
250
251#[derive(Default, Debug, Copy, Clone)]
253pub struct NullAlias;
254
255#[derive(Default, Debug, Clone, Copy)]
309pub struct Asterisk;
310
311#[derive(Debug, Clone, PartialEq)]
315pub enum Keyword {
316 Null,
317 CurrentDate,
318 CurrentTime,
319 CurrentTimestamp,
320 Custom(DynIden),
321}
322
323#[derive(Debug, Clone)]
325pub struct LikeExpr {
326 pub(crate) pattern: String,
327 pub(crate) escape: Option<char>,
328}
329
330pub trait IntoLikeExpr {
331 fn into_like_expr(self) -> LikeExpr;
332}
333
334#[derive(Debug, Copy, Clone, PartialEq)]
336pub enum SubQueryOper {
337 Exists,
338 Any,
339 Some,
340 All,
341}
342
343impl Quote {
346 pub fn new(c: u8) -> Self {
347 Self(c, c)
348 }
349
350 pub fn left(&self) -> char {
351 char::from(self.0)
352 }
353
354 pub fn right(&self) -> char {
355 char::from(self.1)
356 }
357}
358
359impl From<char> for Quote {
360 fn from(c: char) -> Self {
361 (c as u8).into()
362 }
363}
364
365impl From<(char, char)> for Quote {
366 fn from((l, r): (char, char)) -> Self {
367 (l as u8, r as u8).into()
368 }
369}
370
371impl From<u8> for Quote {
372 fn from(u8: u8) -> Self {
373 Quote::new(u8)
374 }
375}
376
377impl From<(u8, u8)> for Quote {
378 fn from((l, r): (u8, u8)) -> Self {
379 Quote(l, r)
380 }
381}
382
383impl<T: 'static> IntoIden for T
384where
385 T: Iden,
386{
387 fn into_iden(self) -> DynIden {
388 SeaRc::new(self)
389 }
390}
391
392impl IntoIden for DynIden {
393 fn into_iden(self) -> DynIden {
394 self
395 }
396}
397
398impl<I> IdenList for I
399where
400 I: IntoIden,
401{
402 type IntoIter = std::iter::Once<DynIden>;
403
404 fn into_iter(self) -> Self::IntoIter {
405 std::iter::once(self.into_iden())
406 }
407}
408
409impl<A, B> IdenList for (A, B)
410where
411 A: IntoIden,
412 B: IntoIden,
413{
414 type IntoIter = std::array::IntoIter<DynIden, 2>;
415
416 fn into_iter(self) -> Self::IntoIter {
417 [self.0.into_iden(), self.1.into_iden()].into_iter()
418 }
419}
420
421impl<A, B, C> IdenList for (A, B, C)
422where
423 A: IntoIden,
424 B: IntoIden,
425 C: IntoIden,
426{
427 type IntoIter = std::array::IntoIter<DynIden, 3>;
428
429 fn into_iter(self) -> Self::IntoIter {
430 [self.0.into_iden(), self.1.into_iden(), self.2.into_iden()].into_iter()
431 }
432}
433
434impl IntoColumnRef for ColumnRef {
435 fn into_column_ref(self) -> ColumnRef {
436 self
437 }
438}
439
440impl<T: 'static> IntoColumnRef for T
441where
442 T: IntoIden,
443{
444 fn into_column_ref(self) -> ColumnRef {
445 ColumnRef::Column(self.into_iden())
446 }
447}
448
449impl IntoColumnRef for Asterisk {
450 fn into_column_ref(self) -> ColumnRef {
451 ColumnRef::Asterisk
452 }
453}
454
455impl<S: 'static, T: 'static> IntoColumnRef for (S, T)
456where
457 S: IntoIden,
458 T: IntoIden,
459{
460 fn into_column_ref(self) -> ColumnRef {
461 ColumnRef::TableColumn(self.0.into_iden(), self.1.into_iden())
462 }
463}
464
465impl<T: 'static> IntoColumnRef for (T, Asterisk)
466where
467 T: IntoIden,
468{
469 fn into_column_ref(self) -> ColumnRef {
470 ColumnRef::TableAsterisk(self.0.into_iden())
471 }
472}
473
474impl<S: 'static, T: 'static, U: 'static> IntoColumnRef for (S, T, U)
475where
476 S: IntoIden,
477 T: IntoIden,
478 U: IntoIden,
479{
480 fn into_column_ref(self) -> ColumnRef {
481 ColumnRef::SchemaTableColumn(self.0.into_iden(), self.1.into_iden(), self.2.into_iden())
482 }
483}
484
485impl IntoTableRef for TableRef {
486 fn into_table_ref(self) -> TableRef {
487 self
488 }
489}
490
491impl<T: 'static> IntoTableRef for T
492where
493 T: IntoIden,
494{
495 fn into_table_ref(self) -> TableRef {
496 TableRef::Table(self.into_iden())
497 }
498}
499
500impl<S: 'static, T: 'static> IntoTableRef for (S, T)
501where
502 S: IntoIden,
503 T: IntoIden,
504{
505 fn into_table_ref(self) -> TableRef {
506 TableRef::SchemaTable(self.0.into_iden(), self.1.into_iden())
507 }
508}
509
510impl<S: 'static, T: 'static, U: 'static> IntoTableRef for (S, T, U)
511where
512 S: IntoIden,
513 T: IntoIden,
514 U: IntoIden,
515{
516 fn into_table_ref(self) -> TableRef {
517 TableRef::DatabaseSchemaTable(self.0.into_iden(), self.1.into_iden(), self.2.into_iden())
518 }
519}
520
521impl TableRef {
522 pub fn alias<A>(self, alias: A) -> Self
524 where
525 A: IntoIden,
526 {
527 match self {
528 Self::Table(table) => Self::TableAlias(table, alias.into_iden()),
529 Self::TableAlias(table, _) => Self::TableAlias(table, alias.into_iden()),
530 Self::SchemaTable(schema, table) => {
531 Self::SchemaTableAlias(schema, table, alias.into_iden())
532 }
533 Self::DatabaseSchemaTable(database, schema, table) => {
534 Self::DatabaseSchemaTableAlias(database, schema, table, alias.into_iden())
535 }
536 Self::SchemaTableAlias(schema, table, _) => {
537 Self::SchemaTableAlias(schema, table, alias.into_iden())
538 }
539 Self::DatabaseSchemaTableAlias(database, schema, table, _) => {
540 Self::DatabaseSchemaTableAlias(database, schema, table, alias.into_iden())
541 }
542 Self::SubQuery(statement, _) => Self::SubQuery(statement, alias.into_iden()),
543 Self::ValuesList(values, _) => Self::ValuesList(values, alias.into_iden()),
544 Self::FunctionCall(func, _) => Self::FunctionCall(func, alias.into_iden()),
545 }
546 }
547}
548
549impl Alias {
550 pub fn new<T>(n: T) -> Self
551 where
552 T: Into<String>,
553 {
554 Self(n.into())
555 }
556}
557
558impl Iden for Alias {
559 fn unquoted(&self, s: &mut dyn fmt::Write) {
560 write!(s, "{}", self.0).unwrap();
561 }
562}
563
564impl NullAlias {
565 pub fn new() -> Self {
566 Self
567 }
568}
569
570impl Iden for NullAlias {
571 fn unquoted(&self, _s: &mut dyn fmt::Write) {}
572}
573
574impl LikeExpr {
575 pub fn new<T>(pattern: T) -> Self
576 where
577 T: Into<String>,
578 {
579 Self {
580 pattern: pattern.into(),
581 escape: None,
582 }
583 }
584
585 #[deprecated(since = "0.29.0", note = "Please use the [`LikeExpr::new`] method")]
586 pub fn str<T>(pattern: T) -> Self
587 where
588 T: Into<String>,
589 {
590 Self {
591 pattern: pattern.into(),
592 escape: None,
593 }
594 }
595
596 pub fn escape(self, c: char) -> Self {
597 Self {
598 pattern: self.pattern,
599 escape: Some(c),
600 }
601 }
602}
603
604impl IntoLikeExpr for LikeExpr {
605 fn into_like_expr(self) -> LikeExpr {
606 self
607 }
608}
609
610impl<T> IntoLikeExpr for T
611where
612 T: Into<String>,
613{
614 fn into_like_expr(self) -> LikeExpr {
615 LikeExpr::new(self)
616 }
617}
618
619#[cfg(test)]
620mod tests {
621 pub use crate::{tests_cfg::*, *};
622 use pretty_assertions::assert_eq;
623 pub use Character as CharReexport;
624
625 #[test]
626 fn test_identifier() {
627 let query = Query::select()
628 .column(Alias::new("hello-World_"))
629 .to_owned();
630
631 #[cfg(feature = "backend-mysql")]
632 assert_eq!(query.to_string(MysqlQueryBuilder), r"SELECT `hello-World_`");
633 #[cfg(feature = "backend-postgres")]
634 assert_eq!(
635 query.to_string(PostgresQueryBuilder),
636 r#"SELECT "hello-World_""#
637 );
638 #[cfg(feature = "backend-sqlite")]
639 assert_eq!(
640 query.to_string(SqliteQueryBuilder),
641 r#"SELECT "hello-World_""#
642 );
643 }
644
645 #[test]
646 fn test_quoted_identifier_1() {
647 let query = Query::select().column(Alias::new("hel`lo")).to_owned();
648
649 #[cfg(feature = "backend-mysql")]
650 assert_eq!(query.to_string(MysqlQueryBuilder), r"SELECT `hel``lo`");
651 #[cfg(feature = "backend-sqlite")]
652 assert_eq!(query.to_string(SqliteQueryBuilder), r#"SELECT "hel`lo""#);
653
654 let query = Query::select().column(Alias::new("hel\"lo")).to_owned();
655
656 #[cfg(feature = "backend-postgres")]
657 assert_eq!(query.to_string(PostgresQueryBuilder), r#"SELECT "hel""lo""#);
658 }
659
660 #[test]
661 fn test_quoted_identifier_2() {
662 let query = Query::select().column(Alias::new("hel``lo")).to_owned();
663
664 #[cfg(feature = "backend-mysql")]
665 assert_eq!(query.to_string(MysqlQueryBuilder), r"SELECT `hel````lo`");
666 #[cfg(feature = "backend-sqlite")]
667 assert_eq!(query.to_string(SqliteQueryBuilder), r#"SELECT "hel``lo""#);
668
669 let query = Query::select().column(Alias::new("hel\"\"lo")).to_owned();
670
671 #[cfg(feature = "backend-postgres")]
672 assert_eq!(
673 query.to_string(PostgresQueryBuilder),
674 r#"SELECT "hel""""lo""#
675 );
676 }
677
678 #[test]
679 fn test_cmp_identifier() {
680 type CharLocal = Character;
681
682 assert_eq!(
683 ColumnRef::Column(Character::Id.into_iden()),
684 ColumnRef::Column(Character::Id.into_iden())
685 );
686 assert_eq!(
687 ColumnRef::Column(Character::Id.into_iden()),
688 ColumnRef::Column(Char::Id.into_iden())
689 );
690 assert_eq!(
691 ColumnRef::Column(Character::Id.into_iden()),
692 ColumnRef::Column(CharLocal::Id.into_iden())
693 );
694 assert_eq!(
695 ColumnRef::Column(Character::Id.into_iden()),
696 ColumnRef::Column(CharReexport::Id.into_iden())
697 );
698 assert_eq!(
699 ColumnRef::Column(Alias::new("id").into_iden()),
700 ColumnRef::Column(Alias::new("id").into_iden())
701 );
702 assert_ne!(
703 ColumnRef::Column(Alias::new("id").into_iden()),
704 ColumnRef::Column(Alias::new("id_").into_iden())
705 );
706 assert_ne!(
707 ColumnRef::Column(Character::Id.into_iden()),
708 ColumnRef::Column(Alias::new("id").into_iden())
709 );
710 assert_ne!(
711 ColumnRef::Column(Character::Id.into_iden()),
712 ColumnRef::Column(Character::Table.into_iden())
713 );
714 assert_ne!(
715 ColumnRef::Column(Character::Id.into_iden()),
716 ColumnRef::Column(Font::Id.into_iden())
717 );
718 }
719}