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)]
162pub enum BinOper {
163 And,
164 Or,
165 Like,
166 NotLike,
167 Is,
168 IsNot,
169 In,
170 NotIn,
171 Between,
172 NotBetween,
173 Equal,
174 NotEqual,
175 SmallerThan,
176 GreaterThan,
177 SmallerThanOrEqual,
178 GreaterThanOrEqual,
179 Add,
180 Sub,
181 Mul,
182 Div,
183 Mod,
184 BitAnd,
185 BitOr,
186 LShift,
187 RShift,
188 As,
189 Escape,
190 Custom(&'static str),
191 #[cfg(feature = "backend-postgres")]
192 PgOperator(PgBinOper),
193 #[cfg(feature = "backend-sqlite")]
194 SqliteOperator(SqliteBinOper),
195}
196
197#[derive(Debug, Clone, PartialEq)]
199pub enum LogicalChainOper {
200 And(SimpleExpr),
201 Or(SimpleExpr),
202}
203
204#[derive(Debug, Clone, Copy, PartialEq, Eq)]
206pub enum JoinType {
207 Join,
208 CrossJoin,
209 InnerJoin,
210 LeftJoin,
211 RightJoin,
212 FullOuterJoin,
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
217pub enum NullOrdering {
218 First,
219 Last,
220}
221
222#[derive(Debug, Clone, PartialEq)]
224pub struct OrderExpr {
225 pub(crate) expr: SimpleExpr,
226 pub(crate) order: Order,
227 pub(crate) nulls: Option<NullOrdering>,
228}
229
230#[derive(Debug, Clone, PartialEq)]
232pub enum JoinOn {
233 Condition(Box<ConditionHolder>),
234 Columns(Vec<SimpleExpr>),
235}
236
237#[derive(Debug, Clone, PartialEq)]
239pub enum Order {
240 Asc,
241 Desc,
242 Field(Values),
243}
244
245#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
247pub struct Alias(String);
248
249#[derive(Default, Debug, Copy, Clone)]
251pub struct NullAlias;
252
253#[derive(Default, Debug, Clone, Copy)]
307pub struct Asterisk;
308
309#[derive(Debug, Clone, PartialEq)]
311pub enum Keyword {
312 Null,
313 CurrentDate,
314 CurrentTime,
315 CurrentTimestamp,
316 Custom(DynIden),
317}
318
319#[derive(Debug, Clone)]
321pub struct LikeExpr {
322 pub(crate) pattern: String,
323 pub(crate) escape: Option<char>,
324}
325
326pub trait IntoLikeExpr {
327 fn into_like_expr(self) -> LikeExpr;
328}
329
330#[derive(Debug, Copy, Clone, PartialEq)]
332pub enum SubQueryOper {
333 Exists,
334 Any,
335 Some,
336 All,
337}
338
339impl Quote {
342 pub fn new(c: u8) -> Self {
343 Self(c, c)
344 }
345
346 pub fn left(&self) -> char {
347 char::from(self.0)
348 }
349
350 pub fn right(&self) -> char {
351 char::from(self.1)
352 }
353}
354
355impl From<char> for Quote {
356 fn from(c: char) -> Self {
357 (c as u8).into()
358 }
359}
360
361impl From<(char, char)> for Quote {
362 fn from((l, r): (char, char)) -> Self {
363 (l as u8, r as u8).into()
364 }
365}
366
367impl From<u8> for Quote {
368 fn from(u8: u8) -> Self {
369 Quote::new(u8)
370 }
371}
372
373impl From<(u8, u8)> for Quote {
374 fn from((l, r): (u8, u8)) -> Self {
375 Quote(l, r)
376 }
377}
378
379impl<T: 'static> IntoIden for T
380where
381 T: Iden,
382{
383 fn into_iden(self) -> DynIden {
384 SeaRc::new(self)
385 }
386}
387
388impl IntoIden for DynIden {
389 fn into_iden(self) -> DynIden {
390 self
391 }
392}
393
394impl<I> IdenList for I
395where
396 I: IntoIden,
397{
398 type IntoIter = std::iter::Once<DynIden>;
399
400 fn into_iter(self) -> Self::IntoIter {
401 std::iter::once(self.into_iden())
402 }
403}
404
405impl<A, B> IdenList for (A, B)
406where
407 A: IntoIden,
408 B: IntoIden,
409{
410 type IntoIter = std::array::IntoIter<DynIden, 2>;
411
412 fn into_iter(self) -> Self::IntoIter {
413 [self.0.into_iden(), self.1.into_iden()].into_iter()
414 }
415}
416
417impl<A, B, C> IdenList for (A, B, C)
418where
419 A: IntoIden,
420 B: IntoIden,
421 C: IntoIden,
422{
423 type IntoIter = std::array::IntoIter<DynIden, 3>;
424
425 fn into_iter(self) -> Self::IntoIter {
426 [self.0.into_iden(), self.1.into_iden(), self.2.into_iden()].into_iter()
427 }
428}
429
430impl IntoColumnRef for ColumnRef {
431 fn into_column_ref(self) -> ColumnRef {
432 self
433 }
434}
435
436impl<T: 'static> IntoColumnRef for T
437where
438 T: IntoIden,
439{
440 fn into_column_ref(self) -> ColumnRef {
441 ColumnRef::Column(self.into_iden())
442 }
443}
444
445impl IntoColumnRef for Asterisk {
446 fn into_column_ref(self) -> ColumnRef {
447 ColumnRef::Asterisk
448 }
449}
450
451impl<S: 'static, T: 'static> IntoColumnRef for (S, T)
452where
453 S: IntoIden,
454 T: IntoIden,
455{
456 fn into_column_ref(self) -> ColumnRef {
457 ColumnRef::TableColumn(self.0.into_iden(), self.1.into_iden())
458 }
459}
460
461impl<T: 'static> IntoColumnRef for (T, Asterisk)
462where
463 T: IntoIden,
464{
465 fn into_column_ref(self) -> ColumnRef {
466 ColumnRef::TableAsterisk(self.0.into_iden())
467 }
468}
469
470impl<S: 'static, T: 'static, U: 'static> IntoColumnRef for (S, T, U)
471where
472 S: IntoIden,
473 T: IntoIden,
474 U: IntoIden,
475{
476 fn into_column_ref(self) -> ColumnRef {
477 ColumnRef::SchemaTableColumn(self.0.into_iden(), self.1.into_iden(), self.2.into_iden())
478 }
479}
480
481impl IntoTableRef for TableRef {
482 fn into_table_ref(self) -> TableRef {
483 self
484 }
485}
486
487impl<T: 'static> IntoTableRef for T
488where
489 T: IntoIden,
490{
491 fn into_table_ref(self) -> TableRef {
492 TableRef::Table(self.into_iden())
493 }
494}
495
496impl<S: 'static, T: 'static> IntoTableRef for (S, T)
497where
498 S: IntoIden,
499 T: IntoIden,
500{
501 fn into_table_ref(self) -> TableRef {
502 TableRef::SchemaTable(self.0.into_iden(), self.1.into_iden())
503 }
504}
505
506impl<S: 'static, T: 'static, U: 'static> IntoTableRef for (S, T, U)
507where
508 S: IntoIden,
509 T: IntoIden,
510 U: IntoIden,
511{
512 fn into_table_ref(self) -> TableRef {
513 TableRef::DatabaseSchemaTable(self.0.into_iden(), self.1.into_iden(), self.2.into_iden())
514 }
515}
516
517impl TableRef {
518 pub fn alias<A>(self, alias: A) -> Self
520 where
521 A: IntoIden,
522 {
523 match self {
524 Self::Table(table) => Self::TableAlias(table, alias.into_iden()),
525 Self::TableAlias(table, _) => Self::TableAlias(table, alias.into_iden()),
526 Self::SchemaTable(schema, table) => {
527 Self::SchemaTableAlias(schema, table, alias.into_iden())
528 }
529 Self::DatabaseSchemaTable(database, schema, table) => {
530 Self::DatabaseSchemaTableAlias(database, schema, table, alias.into_iden())
531 }
532 Self::SchemaTableAlias(schema, table, _) => {
533 Self::SchemaTableAlias(schema, table, alias.into_iden())
534 }
535 Self::DatabaseSchemaTableAlias(database, schema, table, _) => {
536 Self::DatabaseSchemaTableAlias(database, schema, table, alias.into_iden())
537 }
538 Self::SubQuery(statement, _) => Self::SubQuery(statement, alias.into_iden()),
539 Self::ValuesList(values, _) => Self::ValuesList(values, alias.into_iden()),
540 Self::FunctionCall(func, _) => Self::FunctionCall(func, alias.into_iden()),
541 }
542 }
543}
544
545impl Alias {
546 pub fn new<T>(n: T) -> Self
547 where
548 T: Into<String>,
549 {
550 Self(n.into())
551 }
552}
553
554impl Iden for Alias {
555 fn unquoted(&self, s: &mut dyn fmt::Write) {
556 write!(s, "{}", self.0).unwrap();
557 }
558}
559
560impl NullAlias {
561 pub fn new() -> Self {
562 Self
563 }
564}
565
566impl Iden for NullAlias {
567 fn unquoted(&self, _s: &mut dyn fmt::Write) {}
568}
569
570impl LikeExpr {
571 pub fn new<T>(pattern: T) -> Self
572 where
573 T: Into<String>,
574 {
575 Self {
576 pattern: pattern.into(),
577 escape: None,
578 }
579 }
580
581 #[deprecated(since = "0.29.0", note = "Please use the [`LikeExpr::new`] method")]
582 pub fn str<T>(pattern: T) -> Self
583 where
584 T: Into<String>,
585 {
586 Self {
587 pattern: pattern.into(),
588 escape: None,
589 }
590 }
591
592 pub fn escape(self, c: char) -> Self {
593 Self {
594 pattern: self.pattern,
595 escape: Some(c),
596 }
597 }
598}
599
600impl IntoLikeExpr for LikeExpr {
601 fn into_like_expr(self) -> LikeExpr {
602 self
603 }
604}
605
606impl<T> IntoLikeExpr for T
607where
608 T: Into<String>,
609{
610 fn into_like_expr(self) -> LikeExpr {
611 LikeExpr::new(self)
612 }
613}
614
615#[cfg(test)]
616mod tests {
617 pub use crate::{tests_cfg::*, *};
618 use pretty_assertions::assert_eq;
619 pub use Character as CharReexport;
620
621 #[test]
622 fn test_identifier() {
623 let query = Query::select()
624 .column(Alias::new("hello-World_"))
625 .to_owned();
626
627 #[cfg(feature = "backend-mysql")]
628 assert_eq!(query.to_string(MysqlQueryBuilder), r"SELECT `hello-World_`");
629 #[cfg(feature = "backend-postgres")]
630 assert_eq!(
631 query.to_string(PostgresQueryBuilder),
632 r#"SELECT "hello-World_""#
633 );
634 #[cfg(feature = "backend-sqlite")]
635 assert_eq!(
636 query.to_string(SqliteQueryBuilder),
637 r#"SELECT "hello-World_""#
638 );
639 }
640
641 #[test]
642 fn test_quoted_identifier_1() {
643 let query = Query::select().column(Alias::new("hel`lo")).to_owned();
644
645 #[cfg(feature = "backend-mysql")]
646 assert_eq!(query.to_string(MysqlQueryBuilder), r"SELECT `hel``lo`");
647 #[cfg(feature = "backend-sqlite")]
648 assert_eq!(query.to_string(SqliteQueryBuilder), r#"SELECT "hel`lo""#);
649
650 let query = Query::select().column(Alias::new("hel\"lo")).to_owned();
651
652 #[cfg(feature = "backend-postgres")]
653 assert_eq!(query.to_string(PostgresQueryBuilder), r#"SELECT "hel""lo""#);
654 }
655
656 #[test]
657 fn test_quoted_identifier_2() {
658 let query = Query::select().column(Alias::new("hel``lo")).to_owned();
659
660 #[cfg(feature = "backend-mysql")]
661 assert_eq!(query.to_string(MysqlQueryBuilder), r"SELECT `hel````lo`");
662 #[cfg(feature = "backend-sqlite")]
663 assert_eq!(query.to_string(SqliteQueryBuilder), r#"SELECT "hel``lo""#);
664
665 let query = Query::select().column(Alias::new("hel\"\"lo")).to_owned();
666
667 #[cfg(feature = "backend-postgres")]
668 assert_eq!(
669 query.to_string(PostgresQueryBuilder),
670 r#"SELECT "hel""""lo""#
671 );
672 }
673
674 #[test]
675 fn test_cmp_identifier() {
676 type CharLocal = Character;
677
678 assert_eq!(
679 ColumnRef::Column(Character::Id.into_iden()),
680 ColumnRef::Column(Character::Id.into_iden())
681 );
682 assert_eq!(
683 ColumnRef::Column(Character::Id.into_iden()),
684 ColumnRef::Column(Char::Id.into_iden())
685 );
686 assert_eq!(
687 ColumnRef::Column(Character::Id.into_iden()),
688 ColumnRef::Column(CharLocal::Id.into_iden())
689 );
690 assert_eq!(
691 ColumnRef::Column(Character::Id.into_iden()),
692 ColumnRef::Column(CharReexport::Id.into_iden())
693 );
694 assert_eq!(
695 ColumnRef::Column(Alias::new("id").into_iden()),
696 ColumnRef::Column(Alias::new("id").into_iden())
697 );
698 assert_ne!(
699 ColumnRef::Column(Alias::new("id").into_iden()),
700 ColumnRef::Column(Alias::new("id_").into_iden())
701 );
702 assert_ne!(
703 ColumnRef::Column(Character::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(Character::Table.into_iden())
709 );
710 assert_ne!(
711 ColumnRef::Column(Character::Id.into_iden()),
712 ColumnRef::Column(Font::Id.into_iden())
713 );
714 }
715}