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