1use std::{borrow::Cow, fmt::Write, marker::PhantomData};
4
5use crate::{
6 BigInt, FromRow, LowerCompatible, Qrafting,
7 builder::{Insert, Insertable},
8 cte::{Cte, IntoCtes},
9 dialect::HasDialect,
10 emitter::{Directive, Emitter},
11 expression::{Operator, Scalar, prepare_sqlite_glob, random},
12 insert_into,
13 instr::RpnInstr,
14 lower::{Data, Instructions, LowerCtx},
15 param::Param,
16 query::{
17 JoinKind, LowerFilter, LowerFrom, LowerGroupBy, LowerHaving, LowerJoin, LowerOrderBy,
18 LowerProject,
19 },
20 span::TextSource,
21 ty::TypeMeta,
22};
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub(crate) enum SetOperator {
26 Union,
27 UnionAll,
28}
29
30#[derive(Debug, Clone)]
31pub(crate) struct CompoundQuery {
32 pub operator: SetOperator,
33 pub right: Box<Query>,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub(crate) enum LockClause {
38 ForUpdate { skip_locked: bool, nowait: bool },
39 Shared { skip_locked: bool, nowait: bool },
40}
41
42#[derive(Debug, Clone)]
47pub struct Query {
48 pub(crate) project: Vec<RpnInstr>,
49 pub(crate) distinct: bool,
50
51 pub(crate) from: Vec<RpnInstr>,
53
54 pub(crate) filters: Vec<RpnInstr>,
55
56 pub(crate) havings: Vec<RpnInstr>,
57 pub(crate) group_by: Vec<RpnInstr>,
58 pub(crate) order_by: Vec<RpnInstr>,
59
60 pub(crate) limit: Vec<RpnInstr>,
62 pub(crate) offset: Vec<RpnInstr>,
63 pub(crate) lock: Option<LockClause>,
64 pub(crate) ctes: Vec<Cte>,
65 pub(crate) compound: Option<CompoundQuery>,
66
67 pub(crate) params: Vec<Param>,
68 pub(crate) data: Vec<u8>,
69}
70
71#[derive(Debug)]
76pub struct QueryOf<M> {
77 pub(crate) query: Query,
78 pub(crate) marker: PhantomData<M>,
79}
80
81#[derive(Debug, Clone)]
83pub struct LockedQuery {
84 pub(crate) query: Query,
85}
86
87#[derive(Debug)]
89pub struct LockedQueryOf<M> {
90 pub(crate) query: Query,
91 pub(crate) marker: PhantomData<M>,
92}
93
94impl<M> From<QueryOf<M>> for Query {
95 fn from(value: QueryOf<M>) -> Self {
96 value.query
97 }
98}
99
100impl From<LockedQuery> for Query {
101 fn from(value: LockedQuery) -> Self {
102 value.query
103 }
104}
105
106impl<M> From<LockedQueryOf<M>> for Query {
107 fn from(value: LockedQueryOf<M>) -> Self {
108 value.query
109 }
110}
111
112impl<M: FromRow> From<Query> for QueryOf<M> {
113 fn from(value: Query) -> Self {
114 Self::new(value)
115 }
116}
117
118impl<M: FromRow> From<LockedQuery> for LockedQueryOf<M> {
119 fn from(value: LockedQuery) -> Self {
120 Self::new(value.query)
121 }
122}
123
124impl<M> QueryOf<M>
125where
126 M: FromRow,
127{
128 pub fn new(query: Query) -> Self {
130 Self {
131 query,
132 marker: PhantomData,
133 }
134 }
135
136 pub fn select<S>(self, s: S) -> Self
141 where
142 S: LowerProject,
143 {
144 self.query.select(s).typed()
145 }
146
147 pub fn left_join<J>(self, join: J) -> Self
149 where
150 J: LowerJoin,
151 {
152 self.query.left_join(join).typed()
153 }
154
155 pub fn right_join<J>(self, join: J) -> Self
157 where
158 J: LowerJoin,
159 {
160 self.query.right_join(join).typed()
161 }
162
163 pub fn inner_join<J>(self, join: J) -> Self
165 where
166 J: LowerJoin,
167 {
168 self.query.inner_join(join).typed()
169 }
170
171 pub fn filter<E>(self, e: E) -> Self
173 where
174 E: LowerFilter,
175 {
176 self.query.filter(e).typed()
177 }
178
179 pub fn or_filter<E>(self, e: E) -> Self
181 where
182 E: LowerFilter,
183 {
184 self.query.or_filter(e).typed()
185 }
186
187 pub fn order_by<T>(self, by: T) -> Self
189 where
190 T: LowerOrderBy,
191 {
192 self.query.order_by(by).typed()
193 }
194
195 pub fn order_by_random(self) -> Self {
197 self.order_by(random())
198 }
199
200 pub fn limit<E>(self, e: E) -> Self
202 where
203 E: LowerCompatible<BigInt>,
204 {
205 self.query.limit(e).typed()
206 }
207
208 pub fn reset_limit(&mut self) {
210 self.query.reset_limit();
211 }
212
213 pub fn offset<E>(self, e: E) -> Self
215 where
216 E: LowerCompatible<BigInt>,
217 {
218 self.query.offset(e).typed()
219 }
220
221 pub fn reset_offset(&mut self) {
223 self.query.reset_offset();
224 }
225
226 pub fn distinct(self) -> Self {
228 self.query.distinct().typed()
229 }
230
231 pub fn not_distinct(self) -> Self {
233 self.query.not_distinct().typed()
234 }
235
236 pub fn lock_for_update(self) -> LockedQueryOf<M> {
238 self.query.lock_for_update().typed()
239 }
240
241 pub fn shared_lock(self) -> LockedQueryOf<M> {
243 self.query.shared_lock().typed()
244 }
245
246 pub fn with<C>(self, ctes: C) -> Self
248 where
249 C: IntoCtes,
250 {
251 self.query.with(ctes).typed()
252 }
253
254 pub fn with_recursive<C>(self, ctes: C) -> Self
256 where
257 C: IntoCtes,
258 {
259 self.query.with_recursive(ctes).typed()
260 }
261
262 pub fn untyped(self) -> Query {
264 self.query
265 }
266
267 pub fn typed<N>(self) -> QueryOf<N>
269 where
270 N: FromRow,
271 {
272 self.query.typed()
273 }
274
275 pub fn scalar<T: TypeMeta>(self) -> Scalar<T> {
277 self.query.scalar::<T>()
278 }
279
280 pub fn union(self, other: impl Into<Query>) -> Self {
282 self.query.union(other).typed()
283 }
284
285 pub fn union_all(self, other: impl Into<Query>) -> Self {
287 self.query.union_all(other).typed()
288 }
289
290 #[allow(clippy::wrong_self_convention)]
292 pub fn to_sql<D: HasDialect>(&mut self) -> String {
293 self.query.to_sql::<D>()
294 }
295
296 #[allow(clippy::wrong_self_convention)]
298 pub fn to_debug_sql<D: HasDialect>(&mut self) -> String {
299 self.query.to_debug_sql::<D>()
300 }
301
302 pub fn into_compiled<D: HasDialect>(self) -> TypedCompiled<M> {
304 let c = self.query.into_compiled::<D>();
305 TypedCompiled {
306 sql: c.sql,
307 params: c.params,
308 data: c.data,
309 marker: PhantomData,
310 }
311 }
312}
313
314impl<M> QueryOf<M>
315where
316 M: FromRow + Qrafting,
317{
318 pub fn create<V>(self, values: V) -> Insert<M>
323 where
324 V: Insertable<M>,
325 {
326 insert_into(crate::query::Table::new(M::TABLE)).values(values)
327 }
328}
329
330impl<M> LockedQueryOf<M>
331where
332 M: FromRow,
333{
334 pub fn new(query: Query) -> Self {
335 Self {
336 query,
337 marker: PhantomData,
338 }
339 }
340
341 pub fn filter<E>(self, e: E) -> Self
342 where
343 E: LowerFilter,
344 {
345 Self::new(self.query.filter(e))
346 }
347
348 pub fn or_filter<E>(self, e: E) -> Self
349 where
350 E: LowerFilter,
351 {
352 Self::new(self.query.or_filter(e))
353 }
354
355 pub fn order_by<T>(self, by: T) -> Self
356 where
357 T: LowerOrderBy,
358 {
359 Self::new(self.query.order_by(by))
360 }
361
362 pub fn order_by_random(self) -> Self {
363 self.order_by(random())
364 }
365
366 pub fn limit<E>(self, e: E) -> Self
367 where
368 E: LowerCompatible<BigInt>,
369 {
370 Self::new(self.query.limit(e))
371 }
372
373 pub fn offset<E>(self, e: E) -> Self
374 where
375 E: LowerCompatible<BigInt>,
376 {
377 Self::new(self.query.offset(e))
378 }
379
380 pub fn distinct(self) -> Self {
381 Self::new(self.query.distinct())
382 }
383
384 pub fn not_distinct(self) -> Self {
385 Self::new(self.query.not_distinct())
386 }
387
388 pub fn skip_locked(self) -> Self {
389 Self::new(self.query.skip_locked())
390 }
391
392 pub fn nowait(self) -> Self {
393 Self::new(self.query.nowait())
394 }
395
396 pub fn with<C>(self, ctes: C) -> Self
397 where
398 C: IntoCtes,
399 {
400 Self::new(self.query.with(ctes))
401 }
402
403 pub fn with_recursive<C>(self, ctes: C) -> Self
404 where
405 C: IntoCtes,
406 {
407 Self::new(self.query.with_recursive(ctes))
408 }
409
410 pub fn untyped(self) -> Query {
411 self.query
412 }
413
414 pub fn scalar<T: TypeMeta>(self) -> Scalar<T> {
415 self.query.scalar::<T>()
416 }
417
418 #[allow(clippy::wrong_self_convention)]
419 pub fn to_sql<D: HasDialect>(&mut self) -> String {
420 self.query.to_sql::<D>()
421 }
422
423 #[allow(clippy::wrong_self_convention)]
424 pub fn to_debug_sql<D: HasDialect>(&mut self) -> String {
425 self.query.to_debug_sql::<D>()
426 }
427
428 pub fn into_compiled<D: HasDialect>(self) -> TypedCompiled<M> {
429 let c = self.query.into_compiled::<D>();
430 TypedCompiled {
431 sql: c.sql,
432 params: c.params,
433 data: c.data,
434 marker: PhantomData,
435 }
436 }
437}
438
439impl LockedQuery {
440 pub fn new(query: Query) -> Self {
441 Self { query }
442 }
443
444 pub fn select<S>(self, s: S) -> Self
445 where
446 S: LowerProject,
447 {
448 Self::new(self.query.select(s))
449 }
450
451 pub fn left_join<J>(self, join: J) -> Self
452 where
453 J: LowerJoin,
454 {
455 Self::new(self.query.left_join(join))
456 }
457
458 pub fn right_join<J>(self, join: J) -> Self
459 where
460 J: LowerJoin,
461 {
462 Self::new(self.query.right_join(join))
463 }
464
465 pub fn inner_join<J>(self, join: J) -> Self
466 where
467 J: LowerJoin,
468 {
469 Self::new(self.query.inner_join(join))
470 }
471
472 pub fn having<E>(self, e: E) -> Self
473 where
474 E: LowerHaving,
475 {
476 Self::new(self.query.having(e))
477 }
478
479 pub fn or_having<E>(self, e: E) -> Self
480 where
481 E: LowerHaving,
482 {
483 Self::new(self.query.or_having(e))
484 }
485
486 pub fn filter<E>(self, e: E) -> Self
487 where
488 E: LowerFilter,
489 {
490 Self::new(self.query.filter(e))
491 }
492
493 pub fn or_filter<E>(self, e: E) -> Self
494 where
495 E: LowerFilter,
496 {
497 Self::new(self.query.or_filter(e))
498 }
499
500 pub fn group_by<T>(self, by: T) -> Self
501 where
502 T: LowerGroupBy,
503 {
504 Self::new(self.query.group_by(by))
505 }
506
507 pub fn order_by<T>(self, by: T) -> Self
508 where
509 T: LowerOrderBy,
510 {
511 Self::new(self.query.order_by(by))
512 }
513
514 pub fn order_by_random(self) -> Self {
515 self.order_by(random())
516 }
517
518 pub fn limit<E>(self, e: E) -> Self
519 where
520 E: LowerCompatible<BigInt>,
521 {
522 Self::new(self.query.limit(e))
523 }
524
525 pub fn offset<E>(self, e: E) -> Self
526 where
527 E: LowerCompatible<BigInt>,
528 {
529 Self::new(self.query.offset(e))
530 }
531
532 pub fn distinct(self) -> Self {
533 Self::new(self.query.distinct())
534 }
535
536 pub fn not_distinct(self) -> Self {
537 Self::new(self.query.not_distinct())
538 }
539
540 pub fn skip_locked(self) -> Self {
541 Self::new(self.query.skip_locked())
542 }
543
544 pub fn nowait(self) -> Self {
545 Self::new(self.query.nowait())
546 }
547
548 pub fn with<C>(self, ctes: C) -> Self
549 where
550 C: IntoCtes,
551 {
552 Self::new(self.query.with(ctes))
553 }
554
555 pub fn with_recursive<C>(self, ctes: C) -> Self
556 where
557 C: IntoCtes,
558 {
559 Self::new(self.query.with_recursive(ctes))
560 }
561
562 pub fn typed<M>(self) -> LockedQueryOf<M>
563 where
564 M: FromRow,
565 {
566 LockedQueryOf::new(self.query)
567 }
568
569 pub fn scalar<T: TypeMeta>(self) -> Scalar<T> {
570 self.query.scalar::<T>()
571 }
572
573 #[allow(clippy::wrong_self_convention)]
574 pub fn to_sql<D: HasDialect>(&mut self) -> String {
575 self.query.to_sql::<D>()
576 }
577
578 #[allow(clippy::wrong_self_convention)]
579 pub fn to_debug_sql<D: HasDialect>(&mut self) -> String {
580 self.query.to_debug_sql::<D>()
581 }
582
583 pub fn into_compiled<D: HasDialect>(self) -> Compiled {
584 self.query.into_compiled::<D>()
585 }
586}
587
588impl Query {
589 pub(crate) fn default() -> Self {
590 Self {
591 project: Vec::default(),
592 filters: Vec::default(),
593 params: Vec::default(),
594 data: Vec::default(),
595 from: Vec::default(),
596 havings: Vec::default(),
597 group_by: Vec::default(),
598 order_by: Vec::default(),
599 limit: Vec::default(),
600 distinct: false,
601 offset: Vec::default(),
602 lock: None,
603 ctes: Vec::default(),
604 compound: None,
605 }
606 }
607
608 fn merge_query(&mut self, other: &mut Query) {
609 let data_offset = self.data.len() as u32;
610 let param_offset = self.params.len() as u32;
611
612 self.data.extend_from_slice(&other.data);
613 offset_query_data(other, data_offset);
614 shift_query_params(other, param_offset);
615 self.params.extend(other.params.iter().copied());
616 }
617
618 fn where_clause<E>(mut self, e: E, op: Operator) -> Self
619 where
620 E: LowerFilter,
621 {
622 let is_first = self.filters.is_empty();
623 let lhs = self.filters.len();
624
625 let mut ctx = LowerCtx {
626 instrs: &mut self.filters,
627 params: &mut self.params,
628 data: &mut self.data,
629 };
630
631 e.lower_filter(&mut ctx);
632
633 if !is_first {
634 self.filters.push_binary(op, lhs, self.filters.len() - lhs);
635 }
636
637 self
638 }
639
640 fn having_clause<E>(mut self, e: E, op: Operator) -> Self
641 where
642 E: LowerHaving,
643 {
644 let is_first = self.havings.is_empty();
645 let lhs = self.havings.len();
646
647 let mut ctx = LowerCtx {
648 instrs: &mut self.havings,
649 params: &mut self.params,
650 data: &mut self.data,
651 };
652
653 e.lower_having(&mut ctx);
654
655 if !is_first {
656 self.havings.push_binary(op, lhs, self.havings.len() - lhs);
657 }
658
659 self
660 }
661
662 pub fn select<S>(mut self, s: S) -> Self
664 where
665 S: LowerProject,
666 {
667 self.reset_select();
668 let mut ctx = LowerCtx {
669 instrs: &mut self.project,
670 params: &mut self.params,
671 data: &mut self.data,
672 };
673 s.lower_project(&mut ctx);
674 self
675 }
676
677 pub fn reset_select(&mut self) {
679 if !self.project.is_empty() {
680 self.project.clear();
681 }
682 }
683
684 pub fn left_join<J>(mut self, join: J) -> Self
686 where
687 J: LowerJoin,
688 {
689 let mut ctx = LowerCtx {
690 instrs: &mut self.from,
691 params: &mut self.params,
692 data: &mut self.data,
693 };
694 join.lower_join(JoinKind::Left, &mut ctx);
695 self
696 }
697
698 pub fn right_join<J>(mut self, join: J) -> Self
700 where
701 J: LowerJoin,
702 {
703 let mut ctx = LowerCtx {
704 instrs: &mut self.from,
705 params: &mut self.params,
706 data: &mut self.data,
707 };
708 join.lower_join(JoinKind::Right, &mut ctx);
709 self
710 }
711
712 pub fn inner_join<J>(mut self, join: J) -> Self
714 where
715 J: LowerJoin,
716 {
717 let mut ctx = LowerCtx {
718 instrs: &mut self.from,
719 params: &mut self.params,
720 data: &mut self.data,
721 };
722 join.lower_join(JoinKind::Inner, &mut ctx);
723 self
724 }
725
726 pub fn having<E>(self, e: E) -> Self
728 where
729 E: LowerHaving,
730 {
731 self.having_clause(e, Operator::And)
732 }
733
734 pub fn or_having<E>(self, e: E) -> Self
736 where
737 E: LowerHaving,
738 {
739 self.having_clause(e, Operator::Or)
740 }
741
742 pub fn filter<E>(self, e: E) -> Self
744 where
745 E: LowerFilter,
746 {
747 self.where_clause(e, Operator::And)
748 }
749
750 pub fn or_filter<E>(self, e: E) -> Self
752 where
753 E: LowerFilter,
754 {
755 self.where_clause(e, Operator::Or)
756 }
757
758 pub fn from<T>(table: T) -> Self
762 where
763 T: LowerFrom,
764 {
765 let mut me = Self::default();
766 let mut ctx = LowerCtx {
767 instrs: &mut me.from,
768 params: &mut me.params,
769 data: &mut me.data,
770 };
771 table.lower_from(&mut ctx);
772 me
773 }
774
775 pub fn union(self, other: impl Into<Query>) -> Self {
777 self.compound_with(other.into(), SetOperator::Union)
778 }
779
780 pub fn union_all(self, other: impl Into<Query>) -> Self {
782 self.compound_with(other.into(), SetOperator::UnionAll)
783 }
784
785 fn compound_with(mut self, mut other: Query, operator: SetOperator) -> Self {
786 self.merge_query(&mut other);
787 self.compound = Some(CompoundQuery {
788 operator,
789 right: Box::new(other),
790 });
791 self
792 }
793
794 pub(crate) fn base_table_static(&self) -> Option<&'static str> {
795 match self.from.first() {
796 Some(RpnInstr::Table {
797 span: crate::span::TextSpan(TextSource::StaticText(table)),
798 }) => Some(*table),
799 _ => None,
800 }
801 }
802
803 pub fn group_by<T>(mut self, by: T) -> Self
805 where
806 T: LowerGroupBy,
807 {
808 let mut ctx = LowerCtx {
809 instrs: &mut self.group_by,
810 params: &mut self.params,
811 data: &mut self.data,
812 };
813 by.lower_group_by(&mut ctx);
814 self
815 }
816
817 pub fn order_by<T>(mut self, by: T) -> Self
819 where
820 T: LowerOrderBy,
821 {
822 let mut ctx = LowerCtx {
823 instrs: &mut self.order_by,
824 params: &mut self.params,
825 data: &mut self.data,
826 };
827 by.lower_order_by(&mut ctx);
828 self
829 }
830
831 pub fn order_by_random(self) -> Self {
833 self.order_by(random())
834 }
835
836 pub fn limit<E>(mut self, e: E) -> Self
838 where
839 E: LowerCompatible<BigInt>,
840 {
841 self.reset_limit();
842 let mut ctx = LowerCtx {
843 instrs: &mut self.limit,
844 params: &mut self.params,
845 data: &mut self.data,
846 };
847 e.lower_compatible(&mut ctx);
848
849 self
850 }
851
852 pub fn reset_limit(&mut self) {
854 if !self.limit.is_empty() {
855 self.limit.clear();
856 }
857 }
858
859 pub fn offset<E>(mut self, e: E) -> Self
861 where
862 E: LowerCompatible<BigInt>,
863 {
864 self.reset_offset();
865 let mut ctx = LowerCtx {
866 instrs: &mut self.offset,
867 params: &mut self.params,
868 data: &mut self.data,
869 };
870 e.lower_compatible(&mut ctx);
871
872 self
873 }
874
875 pub fn reset_offset(&mut self) {
877 if !self.offset.is_empty() {
878 self.offset.clear();
879 }
880 }
881
882 pub fn lock_for_update(mut self) -> LockedQuery {
884 self.lock = Some(LockClause::ForUpdate {
885 skip_locked: false,
886 nowait: false,
887 });
888 LockedQuery { query: self }
889 }
890
891 pub fn shared_lock(mut self) -> LockedQuery {
893 self.lock = Some(LockClause::Shared {
894 skip_locked: false,
895 nowait: false,
896 });
897 LockedQuery { query: self }
898 }
899
900 fn skip_locked(mut self) -> Self {
901 self.lock = Some(match self.lock.expect("lock clause must be selected") {
902 LockClause::ForUpdate { nowait, .. } => LockClause::ForUpdate {
903 skip_locked: true,
904 nowait,
905 },
906 LockClause::Shared { nowait, .. } => LockClause::Shared {
907 skip_locked: true,
908 nowait,
909 },
910 });
911 self
912 }
913
914 fn nowait(mut self) -> Self {
915 self.lock = Some(match self.lock.expect("lock clause must be selected") {
916 LockClause::ForUpdate { skip_locked, .. } => LockClause::ForUpdate {
917 skip_locked,
918 nowait: true,
919 },
920 LockClause::Shared { skip_locked, .. } => LockClause::Shared {
921 skip_locked,
922 nowait: true,
923 },
924 });
925 self
926 }
927
928 pub fn with<C>(mut self, ctes: C) -> Self
930 where
931 C: IntoCtes,
932 {
933 for cte in ctes.into_ctes(false) {
934 self.push_cte(cte);
935 }
936 self
937 }
938
939 pub(crate) fn with_many(mut self, ctes: Vec<Cte>) -> Self {
940 for cte in ctes {
941 self.push_cte(cte);
942 }
943 self
944 }
945
946 pub fn with_recursive<C>(mut self, ctes: C) -> Self
948 where
949 C: IntoCtes,
950 {
951 for cte in ctes.into_ctes(true) {
952 self.push_cte(cte);
953 }
954 self
955 }
956
957 fn push_cte(&mut self, mut cte: Cte) {
958 let cte_param_offset = self
959 .ctes
960 .iter()
961 .map(|existing| existing.query.params.len())
962 .sum::<usize>();
963 let cte_param_count = cte.query.params.len();
964 let data_offset = self.data.len() as u32;
965
966 self.data.extend_from_slice(&cte.query.data);
967 offset_query_data(&mut cte.query, data_offset);
968 shift_query_params(&mut cte.query, cte_param_offset as u32);
969 shift_main_query_params(self, cte_param_count as u32);
970
971 self.params.splice(
972 cte_param_offset..cte_param_offset,
973 cte.query.params.iter().copied(),
974 );
975 self.ctes.push(cte);
976 }
977
978 pub fn scalar<T: TypeMeta>(self) -> Scalar<T> {
980 Scalar {
981 inner: self,
982 marker: PhantomData,
983 }
984 }
985
986 pub fn distinct(mut self) -> Self {
988 self.distinct = true;
989 self
990 }
991
992 pub fn not_distinct(mut self) -> Self {
994 self.distinct = false;
995 self
996 }
997
998 pub fn typed<M>(self) -> QueryOf<M>
1000 where
1001 M: FromRow,
1002 {
1003 QueryOf::new(self)
1004 }
1005
1006 pub fn typed_locked<M>(self) -> LockedQueryOf<M>
1007 where
1008 M: FromRow,
1009 {
1010 LockedQueryOf::new(self)
1011 }
1012
1013 pub(crate) fn debug_params<W: Write>(&self, writer: &mut W) -> std::fmt::Result {
1014 writer.write_str("; params=[")?;
1015 for (i, param) in self.params.iter().enumerate() {
1016 if i > 0 {
1017 writer.write_str(", ")?;
1018 }
1019 match param {
1020 Param::Null => writer.write_str("null")?,
1021 Param::Bool(value) => match value {
1022 Some(value) => write!(writer, "{}", value)?,
1023 None => writer.write_str("null")?,
1024 },
1025 Param::Float(value) => match value {
1026 Some(value) => write!(writer, "{}", value)?,
1027 None => writer.write_str("null")?,
1028 },
1029 Param::Double(value) => match value {
1030 Some(value) => write!(writer, "{}", value)?,
1031 None => writer.write_str("null")?,
1032 },
1033 Param::Int(value) => match value {
1034 Some(value) => write!(writer, "{}", value)?,
1035 None => writer.write_str("null")?,
1036 },
1037 Param::BigInt(value) => match value {
1038 Some(value) => write!(writer, "{}", value)?,
1039 None => writer.write_str("null")?,
1040 },
1041 Param::Text(span) => match span {
1042 Some(span) => write!(writer, "\"{}\"", self.data.text(*span))?,
1043 None => writer.write_str("null")?,
1044 },
1045 Param::Blob(span) => match span {
1046 Some(span) => write!(writer, "\"{:?}\"", self.data.blob(*span))?,
1047 None => writer.write_str("null")?,
1048 },
1049 Param::UInt(value) => match value {
1050 Some(value) => write!(writer, "{}", value)?,
1051 None => writer.write_str("null")?,
1052 },
1053 Param::UBigInt(value) => match value {
1054 Some(value) => write!(writer, "{}", value)?,
1055 None => writer.write_str("null")?,
1056 },
1057 }
1058 }
1059 writer.write_char(']')?;
1060 Ok(())
1061 }
1062
1063 pub fn to_sql<D: HasDialect>(&mut self) -> String {
1065 let mut buf = String::new();
1066 let mut directives = Vec::new();
1067 let mut params = Vec::new();
1068 let mut emitter = Emitter::new(
1069 &mut buf,
1070 &self.data,
1071 D::DIALECT,
1072 &mut directives,
1073 &mut params,
1074 );
1075 emitter.emit_query(self).unwrap();
1076 for directive in directives {
1077 match directive {
1078 Directive::RewriteGlob { id } => {
1079 let maybe_param = self.params.get_mut(id);
1080 if let Some(Param::Text(Some(text_span))) = maybe_param {
1081 let text = self.data.text(*text_span);
1082 let value = prepare_sqlite_glob(text);
1083 if let Cow::Owned(value) = value {
1084 if let TextSource::Text(span) = text_span.0
1085 && value.len() == text.len()
1086 {
1087 let v = &mut self.data
1088 [span.start as usize..span.start as usize + span.len as usize];
1089 v.copy_from_slice(value.as_bytes());
1090 } else {
1091 let span = self.data.intern_text(&value);
1092 *text_span = span;
1093 }
1094 }
1095 }
1096 }
1097 }
1098 }
1099
1100 rewrite_params(¶ms, &mut self.params);
1101
1102 buf
1103 }
1104
1105 pub fn into_compiled<D: HasDialect>(mut self) -> Compiled {
1107 Compiled {
1108 sql: self.to_sql::<D>(),
1109 params: self.params,
1110 data: self.data,
1111 }
1112 }
1113
1114 pub fn to_debug_sql<D: HasDialect>(&mut self) -> String {
1116 let mut sql = self.to_sql::<D>();
1117 self.debug_params(&mut sql)
1118 .expect("cannot fail with string writer");
1119 sql
1120 }
1121}
1122
1123pub fn rewrite_params(indexes: &[usize], params: &mut [Param]) {
1125 if !indexes.is_empty() {
1126 assert!(indexes.len() == params.len());
1127 let tmp = params.to_vec();
1128 for (i, j) in indexes.iter().enumerate() {
1129 params[i] = tmp[*j];
1130 }
1131 }
1132}
1133
1134fn shift_instr_params(instrs: &mut [RpnInstr], delta: u32) {
1135 for instr in instrs {
1136 if let RpnInstr::Param { id } = instr {
1137 *id += delta;
1138 }
1139 }
1140}
1141
1142fn offset_instr_data(instrs: &mut [RpnInstr], offset: u32) {
1143 for instr in instrs {
1144 match instr {
1145 RpnInstr::Column { span, table } => {
1146 *span = span.offset(offset);
1147 if let Some(table) = table {
1148 *table = table.offset(offset);
1149 }
1150 }
1151 RpnInstr::Table { span }
1152 | RpnInstr::Raw { span, .. }
1153 | RpnInstr::Alias { span, .. } => {
1154 *span = span.offset(offset);
1155 }
1156 _ => {}
1157 }
1158 }
1159}
1160
1161fn shift_main_query_params(query: &mut Query, delta: u32) {
1162 shift_instr_params(&mut query.project, delta);
1163 shift_instr_params(&mut query.from, delta);
1164 shift_instr_params(&mut query.filters, delta);
1165 shift_instr_params(&mut query.havings, delta);
1166 shift_instr_params(&mut query.group_by, delta);
1167 shift_instr_params(&mut query.order_by, delta);
1168 shift_instr_params(&mut query.limit, delta);
1169 shift_instr_params(&mut query.offset, delta);
1170 if let Some(compound) = &mut query.compound {
1171 shift_query_params(&mut compound.right, delta);
1172 }
1173}
1174
1175fn shift_query_params(query: &mut Query, delta: u32) {
1176 shift_main_query_params(query, delta);
1177 for cte in &mut query.ctes {
1178 shift_query_params(&mut cte.query, delta);
1179 }
1180}
1181
1182fn offset_query_data(query: &mut Query, offset: u32) {
1183 offset_instr_data(&mut query.project, offset);
1184 offset_instr_data(&mut query.from, offset);
1185 offset_instr_data(&mut query.filters, offset);
1186 offset_instr_data(&mut query.havings, offset);
1187 offset_instr_data(&mut query.group_by, offset);
1188 offset_instr_data(&mut query.order_by, offset);
1189 offset_instr_data(&mut query.limit, offset);
1190 offset_instr_data(&mut query.offset, offset);
1191 if let Some(compound) = &mut query.compound {
1192 offset_query_data(&mut compound.right, offset);
1193 }
1194 for cte in &mut query.ctes {
1195 offset_query_data(&mut cte.query, offset);
1196 }
1197}
1198
1199#[derive(Debug)]
1201pub struct Compiled {
1202 pub sql: String,
1204 pub params: Vec<Param>,
1206 pub data: Vec<u8>,
1208}
1209
1210#[derive(Debug)]
1212pub struct TypedCompiled<T> {
1213 pub sql: String,
1215 pub params: Vec<Param>,
1217 pub data: Vec<u8>,
1219 pub marker: PhantomData<T>,
1221}
1222
1223#[cfg(test)]
1224mod tests {
1225 use crate::{
1226 BigInt, Bool, Boolean, Float, MySql, Nullable, Numeric, Postgres, Qrafting, Sqlite,
1227 aggregate::count,
1228 alias::Alias,
1229 cte::{CteDefinition, with, with_recursive},
1230 expression::{
1231 Column, EqExt, Expression, In, LikeExt, OrderExt, PredicateExt, TimestampExt,
1232 TimestampRelativeExt, abs, coalesce, current_date, current_time, length, lit, lower,
1233 not, now, null_if, round, upper,
1234 },
1235 query::{Order, Table, select, select_all, star},
1236 tests::{User, id, name, table, username},
1237 };
1238 struct QueuedUser;
1239 impl Qrafting for QueuedUser {
1240 type Schema = ();
1241 type QueryPolicy = crate::DefaultQueryPolicy<Self>;
1242 const FIELD_COUNT: usize = 1;
1243 const TABLE: &'static str = "queued_users";
1244 }
1245
1246 struct NamedUser;
1247 impl Qrafting for NamedUser {
1248 type Schema = ();
1249 type QueryPolicy = crate::DefaultQueryPolicy<Self>;
1250 const FIELD_COUNT: usize = 1;
1251 const TABLE: &'static str = "named_users";
1252 }
1253
1254 struct Chain;
1255 impl Qrafting for Chain {
1256 type Schema = ();
1257 type QueryPolicy = crate::DefaultQueryPolicy<Self>;
1258 const FIELD_COUNT: usize = 1;
1259 const TABLE: &'static str = "chain";
1260 }
1261
1262 fn assert_nullable_bool<E>(_: &E)
1263 where
1264 E: Expression<Type = Nullable<Bool>>,
1265 {
1266 }
1267
1268 fn assert_float<E>(_: &E)
1269 where
1270 E: Expression<Type = Float>,
1271 {
1272 }
1273
1274 fn assert_boolean_expr<E>(_: &E)
1275 where
1276 E: Expression,
1277 E::Type: Boolean,
1278 {
1279 }
1280
1281 fn assert_numeric_expr<E>(_: &E)
1282 where
1283 E: Expression,
1284 E::Type: Numeric,
1285 {
1286 }
1287
1288 fn assert_bigint<E>(_: &E)
1289 where
1290 E: Expression<Type = BigInt>,
1291 {
1292 }
1293
1294 #[test]
1295 fn test_simple_select() {
1296 let stmt = select((id, username))
1297 .from(table)
1298 .filter(id.eq(10))
1299 .order_by_random()
1300 .to_debug_sql::<Sqlite>();
1301
1302 assert_eq!(
1303 stmt,
1304 r#"select "users"."id", "users"."username" from "users" where "users"."id" = ? order by random(); params=[10]"#
1305 );
1306 }
1307
1308 #[test]
1309 fn test_select_like() {
1310 let stmt = select((id, username))
1311 .from(table)
1312 .filter(username.like("hello"))
1313 .to_debug_sql::<Postgres>();
1314
1315 assert_eq!(
1316 stmt,
1317 r#"select "users"."id", "users"."username" from "users" where "users"."username"::text ilike $1; params=["hello"]"#
1318 );
1319 }
1320
1321 #[test]
1322 fn test_select_glob() {
1323 let stmt = select_all()
1324 .from(table)
1325 .filter(username.like("%hel*lo%").case_sensitive())
1326 .to_debug_sql::<Sqlite>();
1327
1328 assert_eq!(
1329 stmt,
1330 r#"select * from "users" where "users"."username" glob ?; params=["*hel[*]lo*"]"#
1331 );
1332 }
1333
1334 #[test]
1335 fn test_select_alias() {
1336 let alias = table.alias("u");
1337 let ia = alias.col(id);
1338 let iu = alias.col(username);
1339 let stmt = select((ia, iu))
1340 .from(alias)
1341 .filter(iu.like("hello").case_sensitive())
1342 .to_debug_sql::<Postgres>();
1343
1344 assert_eq!(
1345 stmt,
1346 r#"select "u"."id", "u"."username" from "users" as "u" where "u"."username"::text like $1; params=["hello"]"#
1347 );
1348 }
1349
1350 #[test]
1351 fn test_select_boolean_precedence() {
1352 let stmt = select_all()
1353 .from(table)
1354 .filter(id.eq(1).or(id.eq(2).and(id.eq(3))))
1355 .to_debug_sql::<Sqlite>();
1356
1357 assert_eq!(
1358 stmt,
1359 r#"select * from "users" where "users"."id" = ? or "users"."id" = ? and "users"."id" = ?; params=[1, 2, 3]"#
1360 );
1361 }
1362
1363 #[test]
1364 fn test_select_between_arithmetic_precedence() {
1365 let stmt = select(lit::<BigInt>(1) + lit::<BigInt>(2) + lit::<BigInt>(3))
1366 .from(table)
1367 .filter(id.gt(0))
1368 .to_debug_sql::<Sqlite>();
1369
1370 assert_eq!(
1371 stmt,
1372 r#"select 1 + 2 + 3 from "users" where "users"."id" > ?; params=[0]"#
1373 );
1374 }
1375
1376 #[test]
1377 fn test_select_join_limit_offset_and_order() {
1378 let other = table.alias("other");
1379 let stmt = select((id, username))
1380 .from(table)
1381 .inner_join(other.on(id.eq(other.col(id))))
1382 .order_by((id.desc(), username.asc()))
1383 .limit(5_i64)
1384 .offset(10_i64)
1385 .to_debug_sql::<Sqlite>();
1386
1387 assert_eq!(
1388 stmt,
1389 r#"select "users"."id", "users"."username" from "users" inner join "users" as "other" on "users"."id" = "other"."id" order by "users"."id" desc, "users"."username" asc limit ? offset ?; params=[5, 10]"#
1390 );
1391 }
1392
1393 #[test]
1394 fn test_select_distinct_group_by_and_having() {
1395 let stmt = select((username, count(id).alias("total")))
1396 .from(table)
1397 .distinct()
1398 .group_by(username)
1399 .having(true)
1400 .to_debug_sql::<Sqlite>();
1401
1402 assert_eq!(
1403 stmt,
1404 r#"select distinct "users"."username", count("users"."id") as "total" from "users" group by "users"."username" having ?; params=[true]"#
1405 );
1406 }
1407
1408 #[test]
1409 fn test_select_limit_and_offset_can_be_reset() {
1410 let mut query = select_all()
1411 .from(table)
1412 .limit(10)
1413 .offset(20)
1414 .typed::<User>();
1415 query.reset_limit();
1416 query.reset_offset();
1417
1418 let stmt = query.to_sql::<Sqlite>();
1419 assert_eq!(stmt, r#"select * from "users""#);
1420 }
1421
1422 #[test]
1423 fn test_nullable_boolean_logic_types_and_sql() {
1424 let admin: Column<User, Nullable<Bool>> = Column::new("admin");
1425 let moderator: Column<User, Nullable<Bool>> = Column::new("moderator");
1426
1427 let expr = admin.or(moderator).and(not(admin));
1428 assert_nullable_bool(&admin.eq(moderator));
1429 assert_nullable_bool(&admin.or(moderator));
1430 assert_boolean_expr(&expr);
1431
1432 let stmt = select_all()
1433 .from(table)
1434 .filter(expr)
1435 .to_debug_sql::<Postgres>();
1436 assert_eq!(
1437 stmt,
1438 r#"select * from "users" where ("users"."admin" or "users"."moderator") and not ("users"."admin"); params=[]"#
1439 );
1440 }
1441
1442 #[test]
1443 fn test_nullable_between_and_in_type_and_sql() {
1444 let score: Column<User, Nullable<BigInt>> = Column::new("score");
1445
1446 let between = score.between(Some(10_i64), Some(20_i64));
1447 let in_list = score.in_([Some(1_i64), Some(2_i64)]);
1448
1449 assert_nullable_bool(&between);
1450 assert_nullable_bool(&in_list);
1451
1452 let stmt = select_all()
1453 .from(table)
1454 .filter(between.and(in_list))
1455 .to_debug_sql::<Postgres>();
1456
1457 assert_eq!(
1458 stmt,
1459 r#"select * from "users" where "users"."score" between $1 and $2 and "users"."score" in ($3, $4); params=[10, 20, 1, 2]"#,
1460 );
1461 }
1462
1463 #[test]
1464 fn test_mixed_numeric_math_types_and_sql() {
1465 let score: Column<User, Float> = Column::new("score");
1466
1467 let expr = id + score;
1468
1469 assert_float(&expr);
1470 assert_numeric_expr(&expr);
1471
1472 let stmt = select_all()
1473 .from(table)
1474 .filter(expr.eq(52.5_f32))
1475 .to_debug_sql::<Postgres>();
1476
1477 assert_eq!(
1478 stmt,
1479 r#"select * from "users" where "users"."id" + "users"."score" = $1; params=[52.5]"#,
1480 );
1481 }
1482
1483 #[test]
1484 fn test_not_in_emits_not_in() {
1485 let stmt = select_all()
1486 .from(table)
1487 .filter(id.not_in([1_i64, 2_i64]))
1488 .to_debug_sql::<Postgres>();
1489
1490 assert_eq!(
1491 stmt,
1492 r#"select * from "users" where "users"."id" not in ($1, $2); params=[1, 2]"#,
1493 );
1494 }
1495
1496 #[test]
1497 fn test_select_lock_for_update_postgres() {
1498 let stmt = select_all()
1499 .from(table)
1500 .lock_for_update()
1501 .to_sql::<Postgres>();
1502
1503 assert_eq!(stmt, r#"select * from "users" for update"#);
1504 }
1505
1506 #[test]
1507 fn test_select_shared_lock_postgres() {
1508 let stmt = select_all().from(table).shared_lock().to_sql::<Postgres>();
1509
1510 assert_eq!(stmt, r#"select * from "users" for share"#);
1511 }
1512
1513 #[test]
1514 fn test_select_shared_lock_mariadb() {
1515 let stmt = select_all().from(table).shared_lock().to_sql::<MySql>();
1516
1517 assert_eq!(stmt, "select * from `users` lock in share mode");
1518 }
1519
1520 #[test]
1521 fn test_select_lock_for_update_skip_locked_postgres() {
1522 let stmt = select_all()
1523 .from(table)
1524 .lock_for_update()
1525 .skip_locked()
1526 .to_sql::<Postgres>();
1527
1528 assert_eq!(stmt, r#"select * from "users" for update skip locked"#);
1529 }
1530
1531 #[test]
1532 fn test_select_lock_for_update_nowait_postgres() {
1533 let stmt = select_all()
1534 .from(table)
1535 .lock_for_update()
1536 .nowait()
1537 .to_sql::<Postgres>();
1538
1539 assert_eq!(stmt, r#"select * from "users" for update nowait"#);
1540 }
1541
1542 #[test]
1543 fn test_select_lock_for_update_skip_locked_nowait_postgres() {
1544 let stmt = select_all()
1545 .from(table)
1546 .lock_for_update()
1547 .skip_locked()
1548 .nowait()
1549 .to_sql::<Postgres>();
1550
1551 assert_eq!(
1552 stmt,
1553 r#"select * from "users" for update skip locked nowait"#
1554 );
1555 }
1556
1557 #[test]
1558 fn test_select_shared_lock_nowait_postgres() {
1559 let stmt = select_all()
1560 .from(table)
1561 .shared_lock()
1562 .nowait()
1563 .to_sql::<Postgres>();
1564
1565 assert_eq!(stmt, r#"select * from "users" for share nowait"#);
1566 }
1567
1568 #[test]
1569 fn test_select_shared_lock_skip_locked_postgres() {
1570 let stmt = select_all()
1571 .from(table)
1572 .shared_lock()
1573 .skip_locked()
1574 .to_sql::<Postgres>();
1575
1576 assert_eq!(stmt, r#"select * from "users" for share skip locked"#);
1577 }
1578
1579 #[test]
1580 fn test_select_shared_lock_skip_locked_nowait_postgres() {
1581 let stmt = select_all()
1582 .from(table)
1583 .shared_lock()
1584 .skip_locked()
1585 .nowait()
1586 .to_sql::<Postgres>();
1587
1588 assert_eq!(
1589 stmt,
1590 r#"select * from "users" for share skip locked nowait"#
1591 );
1592 }
1593
1594 #[test]
1595 fn test_select_lock_for_update_skip_locked_mariadb() {
1596 let stmt = select_all()
1597 .from(table)
1598 .lock_for_update()
1599 .skip_locked()
1600 .to_sql::<MySql>();
1601
1602 assert_eq!(stmt, "select * from `users` for update skip locked");
1603 }
1604
1605 #[test]
1606 fn test_select_lock_for_update_nowait_mariadb() {
1607 let stmt = select_all()
1608 .from(table)
1609 .lock_for_update()
1610 .nowait()
1611 .to_sql::<MySql>();
1612
1613 assert_eq!(stmt, "select * from `users` for update nowait");
1614 }
1615
1616 #[test]
1617 fn test_select_lock_for_update_skip_locked_nowait_mariadb() {
1618 let stmt = select_all()
1619 .from(table)
1620 .lock_for_update()
1621 .skip_locked()
1622 .nowait()
1623 .to_sql::<MySql>();
1624
1625 assert_eq!(stmt, "select * from `users` for update skip locked nowait");
1626 }
1627
1628 #[test]
1629 #[should_panic(expected = "locking clauses are not supported for sqlite")]
1630 fn test_select_lock_for_update_sqlite_panics() {
1631 let _ = select_all()
1632 .from(table)
1633 .lock_for_update()
1634 .to_sql::<Sqlite>();
1635 }
1636
1637 #[test]
1638 #[should_panic(expected = "locking clauses are not supported for sqlite")]
1639 fn test_select_shared_lock_sqlite_panics() {
1640 let _ = select_all().from(table).shared_lock().to_sql::<Sqlite>();
1641 }
1642
1643 #[test]
1644 #[should_panic(expected = "lock modifiers are not supported with shared_lock() for mariadb")]
1645 fn test_select_shared_lock_skip_locked_mariadb_panics() {
1646 let _ = select_all()
1647 .from(table)
1648 .shared_lock()
1649 .skip_locked()
1650 .to_sql::<MySql>();
1651 }
1652
1653 #[test]
1654 #[should_panic(expected = "lock modifiers are not supported with shared_lock() for mariadb")]
1655 fn test_select_shared_lock_nowait_mariadb_panics() {
1656 let _ = select_all()
1657 .from(table)
1658 .shared_lock()
1659 .nowait()
1660 .to_sql::<MySql>();
1661 }
1662
1663 #[test]
1664 fn test_select_with_single_cte() {
1665 let queued = CteDefinition::<QueuedUser>::new(
1666 "queued_users",
1667 &[],
1668 select(id).from(table).filter(id.eq(10)),
1669 );
1670
1671 let stmt = with(queued)
1672 .select(star())
1673 .from(Table::<QueuedUser>::new("queued_users"))
1674 .to_debug_sql::<Postgres>();
1675
1676 assert_eq!(
1677 stmt,
1678 r#"with "queued_users" as (select "users"."id" from "users" where "users"."id" = $1) select * from "queued_users"; params=[10]"#
1679 );
1680 }
1681
1682 #[test]
1683 fn test_select_with_multiple_ctes_and_columns() {
1684 let queued = CteDefinition::<QueuedUser>::new(
1685 "queued_users",
1686 &["id"],
1687 select(id).from(table).filter(id.eq(10)),
1688 );
1689 let named =
1690 CteDefinition::<NamedUser>::new("named_users", &[], select(username).from(table));
1691
1692 let stmt = with((queued, named))
1693 .select(star())
1694 .from((
1695 Table::<QueuedUser>::new("queued_users"),
1696 Table::<NamedUser>::new("named_users"),
1697 ))
1698 .to_debug_sql::<Postgres>();
1699
1700 assert_eq!(
1701 stmt,
1702 r#"with "queued_users"("id") as (select "users"."id" from "users" where "users"."id" = $1), "named_users" as (select "users"."username" from "users") select * from ("queued_users" cross join "named_users"); params=[10]"#
1703 );
1704 }
1705
1706 #[test]
1707 fn test_select_with_recursive_cte() {
1708 let chain = CteDefinition::<Chain>::new("chain", &["id"], select(id).from(table));
1709
1710 let stmt = with_recursive(chain)
1711 .select(star())
1712 .from(Table::<Chain>::new("chain"))
1713 .to_sql::<Postgres>();
1714
1715 assert_eq!(
1716 stmt,
1717 r#"with recursive "chain"("id") as (select "users"."id" from "users") select * from "chain""#
1718 );
1719 }
1720
1721 #[test]
1722 fn test_select_union_all() {
1723 let stmt = select(id)
1724 .from(table)
1725 .filter(id.eq(1))
1726 .union_all(select(id).from(table).filter(id.eq(2)))
1727 .to_debug_sql::<Postgres>();
1728
1729 assert_eq!(
1730 stmt,
1731 r#"(select "users"."id" from "users" where "users"."id" = $1) union all (select "users"."id" from "users" where "users"."id" = $2); params=[1, 2]"#
1732 );
1733 }
1734
1735 #[test]
1736 fn test_cross_dialect_function_helpers_emit_expected_sql() {
1737 assert_bigint(&length(username));
1738 assert_numeric_expr(&abs(id));
1739 assert_numeric_expr(&round(id));
1740
1741 let postgres = select((
1742 lower(username).alias("lower_name"),
1743 upper(username).alias("upper_name"),
1744 length(username).alias("name_len"),
1745 abs(id).alias("abs_id"),
1746 round(id).alias("rounded_id"),
1747 coalesce(name, "fallback").alias("display_name"),
1748 null_if(username, "root").alias("maybe_name"),
1749 ))
1750 .from(table)
1751 .to_debug_sql::<Postgres>();
1752 assert_eq!(
1753 postgres,
1754 r#"select lower("users"."username") as "lower_name", upper("users"."username") as "upper_name", length("users"."username") as "name_len", abs("users"."id") as "abs_id", round("users"."id") as "rounded_id", coalesce("users"."name", $1) as "display_name", nullif("users"."username", $2) as "maybe_name" from "users"; params=["fallback", "root"]"#
1755 );
1756
1757 let postgres_temporal = select((
1758 current_date().alias("today"),
1759 current_time().alias("clock"),
1760 now().alias("current_time"),
1761 ))
1762 .from(table)
1763 .to_debug_sql::<Postgres>();
1764 assert_eq!(
1765 postgres_temporal,
1766 r#"select current_date as "today", current_time as "clock", current_timestamp as "current_time" from "users"; params=[]"#
1767 );
1768
1769 let sqlite = select((
1770 lower(username).alias("lower_name"),
1771 upper(username).alias("upper_name"),
1772 length(username).alias("name_len"),
1773 abs(id).alias("abs_id"),
1774 round(id).alias("rounded_id"),
1775 coalesce(name, "fallback").alias("display_name"),
1776 null_if(username, "root").alias("maybe_name"),
1777 ))
1778 .from(table)
1779 .to_debug_sql::<Sqlite>();
1780 assert_eq!(
1781 sqlite,
1782 r#"select lower("users"."username") as "lower_name", upper("users"."username") as "upper_name", length("users"."username") as "name_len", abs("users"."id") as "abs_id", round("users"."id") as "rounded_id", coalesce("users"."name", ?) as "display_name", nullif("users"."username", ?) as "maybe_name" from "users"; params=["fallback", "root"]"#
1783 );
1784
1785 let sqlite_temporal = select((
1786 current_date().alias("today"),
1787 current_time().alias("clock"),
1788 now().alias("current_time"),
1789 ))
1790 .from(table)
1791 .to_debug_sql::<Sqlite>();
1792 assert_eq!(
1793 sqlite_temporal,
1794 r#"select current_date as "today", current_time as "clock", current_timestamp as "current_time" from "users"; params=[]"#
1795 );
1796
1797 let mariadb = select((
1798 lower(username).alias("lower_name"),
1799 upper(username).alias("upper_name"),
1800 length(username).alias("name_len"),
1801 abs(id).alias("abs_id"),
1802 round(id).alias("rounded_id"),
1803 coalesce(name, "fallback").alias("display_name"),
1804 null_if(username, "root").alias("maybe_name"),
1805 ))
1806 .from(table)
1807 .to_debug_sql::<MySql>();
1808 assert_eq!(
1809 mariadb,
1810 r#"select lower(`users`.`username`) as `lower_name`, upper(`users`.`username`) as `upper_name`, length(`users`.`username`) as `name_len`, abs(`users`.`id`) as `abs_id`, round(`users`.`id`) as `rounded_id`, coalesce(`users`.`name`, ?) as `display_name`, nullif(`users`.`username`, ?) as `maybe_name` from `users`; params=["fallback", "root"]"#
1811 );
1812
1813 let mariadb_temporal = select((
1814 current_date().alias("today"),
1815 current_time().alias("clock"),
1816 now().alias("current_time"),
1817 ))
1818 .from(table)
1819 .to_debug_sql::<MySql>();
1820 assert_eq!(
1821 mariadb_temporal,
1822 r#"select current_date as `today`, current_time as `clock`, current_timestamp as `current_time` from `users`; params=[]"#
1823 );
1824 }
1825
1826 #[test]
1827 fn test_cross_dialect_temporal_extract_helpers_emit_expected_sql() {
1828 let created_at = Column::<User, crate::Timestamp>::new("created_at");
1829 let clock = quex::Time {
1830 hour: 12,
1831 minute: 34,
1832 second: 56,
1833 microsecond: 0,
1834 };
1835
1836 let postgres = select((
1837 created_at.date().alias("date_only"),
1838 created_at.time().alias("time_only"),
1839 created_at.year().alias("year_only"),
1840 created_at.month().alias("month_only"),
1841 created_at.day().alias("day_only"),
1842 ))
1843 .from(table)
1844 .filter(created_at.month().eq(4_i64))
1845 .filter(created_at.time().gt(clock))
1846 .to_debug_sql::<Postgres>();
1847 assert_eq!(
1848 postgres,
1849 r#"select cast("users"."created_at" as date) as "date_only", cast("users"."created_at" as time) as "time_only", cast(extract(year from "users"."created_at") as bigint) as "year_only", cast(extract(month from "users"."created_at") as bigint) as "month_only", cast(extract(day from "users"."created_at") as bigint) as "day_only" from "users" where cast(extract(month from "users"."created_at") as bigint) = $1 and cast("users"."created_at" as time) > $2; params=[4, "12:34:56"]"#
1850 );
1851
1852 let sqlite = select((
1853 created_at.date().alias("date_only"),
1854 created_at.time().alias("time_only"),
1855 created_at.year().alias("year_only"),
1856 created_at.month().alias("month_only"),
1857 created_at.day().alias("day_only"),
1858 ))
1859 .from(table)
1860 .filter(created_at.month().eq(4_i64))
1861 .filter(created_at.time().gt(clock))
1862 .to_debug_sql::<Sqlite>();
1863 assert_eq!(
1864 sqlite,
1865 r#"select date("users"."created_at") as "date_only", time("users"."created_at") as "time_only", cast(strftime('%Y', "users"."created_at") as integer) as "year_only", cast(strftime('%m', "users"."created_at") as integer) as "month_only", cast(strftime('%d', "users"."created_at") as integer) as "day_only" from "users" where cast(strftime('%m', "users"."created_at") as integer) = ? and time("users"."created_at") > ?; params=[4, "12:34:56"]"#
1866 );
1867
1868 let mariadb = select((
1869 created_at.date().alias("date_only"),
1870 created_at.time().alias("time_only"),
1871 created_at.year().alias("year_only"),
1872 created_at.month().alias("month_only"),
1873 created_at.day().alias("day_only"),
1874 ))
1875 .from(table)
1876 .filter(created_at.month().eq(4_i64))
1877 .filter(created_at.time().gt(clock))
1878 .to_debug_sql::<MySql>();
1879 assert_eq!(
1880 mariadb,
1881 r#"select date(`users`.`created_at`) as `date_only`, time(`users`.`created_at`) as `time_only`, year(`users`.`created_at`) as `year_only`, month(`users`.`created_at`) as `month_only`, day(`users`.`created_at`) as `day_only` from `users` where month(`users`.`created_at`) = ? and time(`users`.`created_at`) > ?; params=[4, "12:34:56"]"#
1882 );
1883 }
1884
1885 #[test]
1886 fn test_cross_dialect_temporal_relative_helpers_emit_expected_sql() {
1887 let created_at = Column::<User, crate::Timestamp>::new("created_at");
1888
1889 let postgres = select(id)
1890 .from(table)
1891 .filter(created_at.past())
1892 .filter(created_at.today().or(created_at.after_today()))
1893 .to_debug_sql::<Postgres>();
1894 assert_eq!(
1895 postgres,
1896 r#"select "users"."id" from "users" where "users"."created_at" < current_timestamp and (cast("users"."created_at" as date) = current_date or cast("users"."created_at" as date) > current_date); params=[]"#
1897 );
1898
1899 let sqlite = select(id)
1900 .from(table)
1901 .filter(created_at.past())
1902 .filter(created_at.today().or(created_at.after_today()))
1903 .to_debug_sql::<Sqlite>();
1904 assert_eq!(
1905 sqlite,
1906 r#"select "users"."id" from "users" where "users"."created_at" < current_timestamp and (date("users"."created_at") = current_date or date("users"."created_at") > current_date); params=[]"#
1907 );
1908
1909 let mariadb = select(id)
1910 .from(table)
1911 .filter(created_at.past())
1912 .filter(created_at.today().or(created_at.after_today()))
1913 .to_debug_sql::<MySql>();
1914 assert_eq!(
1915 mariadb,
1916 r#"select `users`.`id` from `users` where `users`.`created_at` < current_timestamp and (date(`users`.`created_at`) = current_date or date(`users`.`created_at`) > current_date); params=[]"#
1917 );
1918 }
1919}