1use std::marker::PhantomData;
6
7use crate::cte::Cte;
8use crate::dialect::{Dialect, SupportsFullOuterJoin, SupportsRightJoin};
9use crate::expr::{BoolLike, Expr, ExprKind, IntoExpr, Value};
10use crate::render::{
11 Fragment, FragmentSink, QuerySink, SelectItem, Sink, render_and_list, render_expr,
12 render_expr_list, render_order_by, render_select_list,
13};
14use crate::scope::{
15 BaseTable, Cons, MapNullable, MaybeNull, Nil, NotNull, ScopeTables, Superset, Table, TableSlot,
16};
17
18mod dyn_select;
19mod prepared;
20mod selection;
21mod set_op;
22
23pub use crate::expr::SortDir;
24pub use dyn_select::{CannotFilterAfterErase, DynSelect};
25pub use prepared::{Prepared, PreparedParams, Total, UnresolvedPlaceholder};
26pub use selection::{
27 All, AllColumns, ColumnList, RowField, SelectableSealed, Selection, SelectionPart, SingleColumn,
28};
29pub use set_op::SetOp;
30
31#[doc(hidden)]
36#[derive(Debug, Clone)]
37pub struct CteDef {
38 name: &'static str,
39 column_names: Vec<&'static str>,
40 body: Fragment,
41}
42
43impl CteDef {
44 pub(crate) fn new(name: &'static str, column_names: Vec<&'static str>, body: Fragment) -> Self {
45 CteDef {
46 name,
47 column_names,
48 body,
49 }
50 }
51}
52
53#[derive(Debug, Clone)]
54enum JoinKind {
55 Inner,
56 Left,
57 Right,
58 Full,
59}
60
61#[derive(Debug, Clone)]
62struct JoinClause {
63 kind: JoinKind,
64 table: &'static str,
65 on: ExprKind,
66}
67
68pub struct OrderKey<Req> {
72 kind: ExprKind,
73 dir: SortDir,
74 _marker: PhantomData<fn() -> Req>,
75}
76
77impl<Req> Clone for OrderKey<Req> {
80 fn clone(&self) -> Self {
81 OrderKey {
82 kind: self.kind.clone(),
83 dir: self.dir,
84 _marker: PhantomData,
85 }
86 }
87}
88
89impl<Req> OrderKey<Req> {
90 pub(crate) fn into_parts(self) -> (ExprKind, SortDir) {
91 (self.kind, self.dir)
92 }
93}
94
95pub trait OrderExt: IntoExpr + Sized {
96 fn asc(self) -> OrderKey<Self::Req> {
97 OrderKey {
98 kind: self.into_expr().kind,
99 dir: SortDir::Asc,
100 _marker: PhantomData,
101 }
102 }
103 fn sort(self, dir: SortDir) -> OrderKey<Self::Req> {
106 OrderKey {
107 kind: self.into_expr().kind,
108 dir,
109 _marker: PhantomData,
110 }
111 }
112 fn desc(self) -> OrderKey<Self::Req> {
113 OrderKey {
114 kind: self.into_expr().kind,
115 dir: SortDir::Desc,
116 _marker: PhantomData,
117 }
118 }
119}
120impl<T: IntoExpr> OrderExt for T {}
121
122pub trait JoinSource<D>: join_source::Sealed {
127 type Table: Table;
129 #[doc(hidden)]
132 fn binding(self) -> Option<CteDef>;
133}
134
135mod join_source {
136 pub trait Sealed {}
139 impl<T: super::BaseTable> Sealed for T {}
140 impl<D, Marker> Sealed for crate::cte::Cte<D, Marker> {}
141}
142
143impl<D, T: BaseTable> JoinSource<D> for T {
144 type Table = T;
145 fn binding(self) -> Option<CteDef> {
146 None
147 }
148}
149
150impl<D, Marker: crate::cte::CteShape> JoinSource<D> for Cte<D, Marker> {
151 type Table = Marker;
152 fn binding(self) -> Option<CteDef> {
153 Some(CteDef::new(
154 <Marker as Table>::NAME,
155 <Marker::Row as crate::row::ColumnNames>::names(),
156 self.into_body(),
157 ))
158 }
159}
160
161#[diagnostic::on_unimplemented(
165 message = "`{Self}` isn't a sort key",
166 label = "a column or expression with `.asc()`/`.desc()`/`.sort(dir)` on it, or a `sort_key(..)`",
167 note = "a `SortKey` also has to have been discharged against *this* scope — a scope lists its tables most-recently-joined first, so two that look alike can still differ in order"
168)]
169pub trait SortBy<Scope, Idxs> {
170 #[doc(hidden)]
171 fn into_sort_key(self) -> SortKey<Scope>;
172}
173
174impl<Scope: Superset<Req, Idxs>, Req, Idxs> SortBy<Scope, Idxs> for OrderKey<Req> {
175 fn into_sort_key(self) -> SortKey<Scope> {
176 SortKey {
177 kind: self.kind,
178 dir: self.dir,
179 _marker: PhantomData,
180 }
181 }
182}
183
184impl<Scope> SortBy<Scope, ()> for SortKey<Scope> {
185 fn into_sort_key(self) -> SortKey<Scope> {
186 self
187 }
188}
189
190#[diagnostic::on_unimplemented(
193 message = "`{Self}` isn't a grouping key",
194 label = "a column or expression, or a `grouping(..)`",
195 note = "a `Grouping` also has to have been discharged against *this* scope — a scope lists its tables most-recently-joined first, so two that look alike can still differ in order"
196)]
197pub trait GroupBy<Scope, Idxs> {
198 #[doc(hidden)]
199 fn into_grouping(self) -> Grouping<Scope>;
200}
201
202impl<Scope: Superset<Req, Idxs>, Req, Idxs, T: IntoExpr<Req = Req>> GroupBy<Scope, Idxs> for T {
203 fn into_grouping(self) -> Grouping<Scope> {
204 Grouping {
205 kind: self.into_expr().kind,
206 _marker: PhantomData,
207 }
208 }
209}
210
211impl<Scope> GroupBy<Scope, ()> for Grouping<Scope> {
212 fn into_grouping(self) -> Grouping<Scope> {
213 self
214 }
215}
216
217pub struct SortKey<Scope> {
222 kind: ExprKind,
223 dir: SortDir,
224 _marker: PhantomData<fn() -> Scope>,
225}
226
227impl<Scope> Clone for SortKey<Scope> {
228 fn clone(&self) -> Self {
229 SortKey {
230 kind: self.kind.clone(),
231 dir: self.dir,
232 _marker: PhantomData,
233 }
234 }
235}
236
237pub fn sort_key<Scope, Idxs, K: SortBy<Scope, Idxs>>(key: K) -> SortKey<Scope> {
242 key.into_sort_key()
243}
244
245pub struct Grouping<Scope> {
248 kind: ExprKind,
249 _marker: PhantomData<fn() -> Scope>,
250}
251
252impl<Scope> Clone for Grouping<Scope> {
253 fn clone(&self) -> Self {
254 Grouping {
255 kind: self.kind.clone(),
256 _marker: PhantomData,
257 }
258 }
259}
260
261pub fn grouping<Scope, Idxs, K: GroupBy<Scope, Idxs>>(key: K) -> Grouping<Scope> {
264 key.into_grouping()
265}
266
267#[diagnostic::on_unimplemented(
272 message = "`{Self}` isn't a condition",
273 label = "a comparison (`.eq(..)`, `.gt(..)`, `.is_null()`), an `any_of`/`all_of` of them, a `sql!` fragment of type `Bool`, a `predicate(..)`, or an `EXISTS` of a subquery in *this* dialect",
274 note = "a `Predicate` also has to have been discharged against *this* scope — a scope lists its tables most-recently-joined first, so two that look alike can still differ in order"
275)]
276pub trait Condition<D, Scope, Idxs> {
277 #[doc(hidden)]
280 fn into_predicate(self) -> Predicate<D, Scope>;
281}
282
283impl<D, Scope: Superset<Req, Idxs>, Req, Idxs, T: IntoExpr<Req = Req>> Condition<D, Scope, Idxs>
284 for T
285where
286 T::Sql: BoolLike,
287{
288 fn into_predicate(self) -> Predicate<D, Scope> {
289 Predicate {
290 kind: self.into_expr().kind,
291 _marker: PhantomData,
292 }
293 }
294}
295
296impl<D, Scope> Condition<D, Scope, ()> for Predicate<D, Scope> {
297 fn into_predicate(self) -> Predicate<D, Scope> {
298 self
299 }
300}
301
302pub struct Exists<D, Req> {
311 kind: ExprKind,
312 _marker: PhantomData<fn() -> (D, Req)>,
313}
314
315impl<D, Req> Clone for Exists<D, Req> {
318 fn clone(&self) -> Self {
319 Exists {
320 kind: self.kind.clone(),
321 _marker: PhantomData,
322 }
323 }
324}
325
326impl<D, Scope: Superset<Req, Idxs>, Req, Idxs> Condition<D, Scope, Idxs> for Exists<D, Req> {
327 fn into_predicate(self) -> Predicate<D, Scope> {
328 Predicate {
329 kind: self.kind,
330 _marker: PhantomData,
331 }
332 }
333}
334
335pub struct Predicate<D, Scope> {
341 kind: ExprKind,
342 _marker: PhantomData<fn() -> (D, Scope)>,
343}
344
345impl<D, Scope> Clone for Predicate<D, Scope> {
348 fn clone(&self) -> Self {
349 Predicate {
350 kind: self.kind.clone(),
351 _marker: PhantomData,
352 }
353 }
354}
355
356impl<D, Scope> Predicate<D, Scope> {
357 pub fn any_of(preds: impl IntoIterator<Item = Predicate<D, Scope>>) -> Self {
362 Predicate::combine(preds, false)
363 }
364
365 pub fn all_of(preds: impl IntoIterator<Item = Predicate<D, Scope>>) -> Self {
368 Predicate::combine(preds, true)
369 }
370
371 fn combine(preds: impl IntoIterator<Item = Predicate<D, Scope>>, all: bool) -> Self {
372 Predicate {
373 kind: crate::expr::fold_conditions(preds.into_iter().map(Predicate::into_kind), all),
374 _marker: PhantomData,
375 }
376 }
377
378 pub(crate) fn into_kind(self) -> ExprKind {
379 self.kind
380 }
381}
382
383pub fn predicate<D, Scope, Idxs, C: Condition<D, Scope, Idxs>>(cond: C) -> Predicate<D, Scope> {
387 cond.into_predicate()
388}
389
390pub struct SelectSeed<Sel> {
397 selection: Sel,
398}
399
400pub fn select<Sel>(selection: Sel) -> SelectSeed<Sel> {
401 SelectSeed { selection }
402}
403
404impl<Sel> SelectSeed<Sel> {
405 pub fn from<D, S: JoinSource<D>>(
409 self,
410 source: S,
411 ) -> Select<D, Cons<TableSlot<S::Table, NotNull>, Nil>, Sel> {
412 let mut body = SelectBody::new(<S::Table as Table>::NAME);
413 body.bind(source);
414 Select {
415 body,
416 selection: self.selection,
417 _marker: PhantomData,
418 }
419 }
420}
421
422#[derive(Debug, Clone)]
427pub(crate) struct SelectBody {
428 ctes: Vec<CteDef>,
429 distinct: bool,
430 from_table: &'static str,
431 joins: Vec<JoinClause>,
432 wheres: Vec<ExprKind>,
433 order_by: Vec<(ExprKind, SortDir)>,
434 group_by: Vec<ExprKind>,
435 having: Vec<ExprKind>,
436 limit: Option<RowCount>,
437 offset: Option<RowCount>,
438}
439
440impl SelectBody {
441 fn new(from_table: &'static str) -> Self {
442 SelectBody {
443 ctes: Vec::new(),
444 distinct: false,
445 from_table,
446 joins: Vec::new(),
447 wheres: Vec::new(),
448 order_by: Vec::new(),
449 group_by: Vec::new(),
450 having: Vec::new(),
451 limit: None,
452 offset: None,
453 }
454 }
455
456 fn count_sql<D: Dialect>(&self, selection: &[SelectItem]) -> (String, Vec<Value>) {
466 let mut body = self.clone();
467 body.order_by.clear();
468 body.limit = None;
469 body.offset = None;
470 let one_row_each = body.group_by.is_empty()
471 && body.having.is_empty()
472 && !body.distinct
473 && selection
474 .iter()
475 .all(|item| matches!(item.kind, ExprKind::Column { .. }));
476
477 let mut sink = QuerySink::<D>::new();
478 if one_row_each {
479 body.render_into::<D>(&[crate::expr::count_item()], &mut sink);
480 return sink.finish();
481 }
482 crate::render::render_count_wrapped::<D>(&mut sink, |sink| {
483 body.render_into::<D>(selection, sink)
484 });
485 sink.finish()
486 }
487
488 fn bind<D, S: JoinSource<D>>(&mut self, source: S) {
491 self.ctes.extend(source.binding());
492 }
493}
494
495pub struct Select<D, Scope, Sel, Outer = Nil> {
500 body: SelectBody,
501 selection: Sel,
502 _marker: PhantomData<fn() -> (D, Scope, Outer)>,
503}
504
505impl<D, Scope, Sel: Clone, Outer> Clone for Select<D, Scope, Sel, Outer> {
507 fn clone(&self) -> Self {
508 Select {
509 body: self.body.clone(),
510 selection: self.selection.clone(),
511 _marker: PhantomData,
512 }
513 }
514}
515
516impl<D, Scope, Sel, Outer> Select<D, Scope, Sel, Outer> {
517 fn retype<NewScope>(self) -> Select<D, NewScope, Sel, Outer> {
518 Select {
519 body: self.body,
520 selection: self.selection,
521 _marker: PhantomData,
522 }
523 }
524
525 pub fn reselect<NewSel>(self, selection: NewSel) -> Select<D, Scope, NewSel, Outer> {
528 Select {
529 body: self.body,
530 selection,
531 _marker: PhantomData,
532 }
533 }
534
535 pub fn filter<C: Condition<D, Scope, Idxs>, Idxs>(mut self, cond: C) -> Self {
539 self.body.wheres.push(cond.into_predicate().into_kind());
540 self
541 }
542
543 pub fn filter_all(mut self, conds: impl IntoIterator<Item = Predicate<D, Scope>>) -> Self {
547 self.body
548 .wheres
549 .extend(conds.into_iter().map(Predicate::into_kind));
550 self
551 }
552
553 pub fn order_by<K: SortBy<Scope, Idxs>, Idxs>(mut self, key: K) -> Self {
554 let key = key.into_sort_key();
555 self.body.order_by.push((key.kind, key.dir));
556 self
557 }
558
559 pub fn order_by_all(mut self, keys: impl IntoIterator<Item = SortKey<Scope>>) -> Self {
563 self.body
564 .order_by
565 .extend(keys.into_iter().map(|k| (k.kind, k.dir)));
566 self
567 }
568
569 pub fn distinct(mut self) -> Self {
583 self.body.distinct = true;
584 self
585 }
586
587 pub fn group_by<K: GroupBy<Scope, Idxs>, Idxs>(mut self, key: K) -> Self {
591 self.body.group_by.push(key.into_grouping().kind);
592 self
593 }
594
595 pub fn group_by_all(mut self, keys: impl IntoIterator<Item = Grouping<Scope>>) -> Self {
598 self.body.group_by.extend(keys.into_iter().map(|g| g.kind));
599 self
600 }
601
602 pub fn having<C: Condition<D, Scope, Idxs>, Idxs>(mut self, cond: C) -> Self {
605 self.body.having.push(cond.into_predicate().into_kind());
606 self
607 }
608
609 pub fn having_all(mut self, conds: impl IntoIterator<Item = Predicate<D, Scope>>) -> Self {
612 self.body
613 .having
614 .extend(conds.into_iter().map(Predicate::into_kind));
615 self
616 }
617
618 pub fn limit(mut self, n: impl IntoRowCount) -> Self {
619 self.body.limit = Some(n.into_row_count());
620 self
621 }
622
623 pub fn offset(mut self, n: impl IntoRowCount) -> Self {
624 self.body.offset = Some(n.into_row_count());
625 self
626 }
627
628 pub fn inner_join<S: JoinSource<D>, C, Idxs>(
632 mut self,
633 source: S,
634 on: C,
635 ) -> Select<D, Cons<TableSlot<S::Table, NotNull>, Scope>, Sel, Outer>
636 where
637 C: Condition<D, Cons<TableSlot<S::Table, NotNull>, Scope>, Idxs>,
638 {
639 self.body.bind(source);
640 self.body.joins.push(JoinClause {
641 kind: JoinKind::Inner,
642 table: <S::Table as Table>::NAME,
643 on: on.into_predicate().into_kind(),
644 });
645 self.retype()
646 }
647
648 pub fn left_join<S: JoinSource<D>, C, Idxs>(
649 mut self,
650 source: S,
651 on: C,
652 ) -> Select<D, Cons<TableSlot<S::Table, MaybeNull>, Scope>, Sel, Outer>
653 where
654 C: Condition<D, Cons<TableSlot<S::Table, MaybeNull>, Scope>, Idxs>,
655 {
656 self.body.bind(source);
657 self.body.joins.push(JoinClause {
658 kind: JoinKind::Left,
659 table: <S::Table as Table>::NAME,
660 on: on.into_predicate().into_kind(),
661 });
662 self.retype()
663 }
664
665 pub fn right_join<S: JoinSource<D>, C, Idxs>(
669 mut self,
670 source: S,
671 on: C,
672 ) -> Select<D, Cons<TableSlot<S::Table, NotNull>, Scope::Output>, Sel, Outer>
673 where
674 D: SupportsRightJoin,
675 Scope: MapNullable,
676 C: Condition<D, Cons<TableSlot<S::Table, NotNull>, Scope::Output>, Idxs>,
677 {
678 self.body.bind(source);
679 self.body.joins.push(JoinClause {
680 kind: JoinKind::Right,
681 table: <S::Table as Table>::NAME,
682 on: on.into_predicate().into_kind(),
683 });
684 self.retype()
685 }
686
687 pub fn full_join<S: JoinSource<D>, C, Idxs>(
688 mut self,
689 source: S,
690 on: C,
691 ) -> Select<D, Cons<TableSlot<S::Table, MaybeNull>, Scope::Output>, Sel, Outer>
692 where
693 D: SupportsFullOuterJoin,
694 Scope: MapNullable,
695 C: Condition<D, Cons<TableSlot<S::Table, MaybeNull>, Scope::Output>, Idxs>,
696 {
697 self.body.bind(source);
698 self.body.joins.push(JoinClause {
699 kind: JoinKind::Full,
700 table: <S::Table as Table>::NAME,
701 on: on.into_predicate().into_kind(),
702 });
703 self.retype()
704 }
705}
706
707impl<D: Dialect, Scope, Sel> Select<D, Scope, Sel> {
712 pub fn to_sql<Idx>(&self, _dialect: D) -> (String, Vec<Value>)
721 where
722 Sel: Selection<Scope, Idx>,
723 {
724 self.render_as::<Idx>()
725 }
726
727 pub fn count_sql<Idx>(&self, _dialect: D) -> (String, Vec<Value>)
736 where
737 Sel: Selection<Scope, Idx>,
738 {
739 self.body.count_sql::<D>(&self.selection.items())
740 }
741}
742
743impl<D: Dialect, Scope, Sel> Select<D, Scope, Sel> {
744 pub(crate) fn fragment<Idx>(&self) -> Fragment
751 where
752 Sel: Selection<Scope, Idx>,
753 {
754 let mut sink = FragmentSink::new();
755 self.body
756 .render_into::<D>(&self.selection.items(), &mut sink);
757 sink.finish()
758 }
759
760 fn render_as<Idx>(&self) -> (String, Vec<Value>)
761 where
762 Sel: Selection<Scope, Idx>,
763 {
764 let mut sink = QuerySink::<D>::new();
765 self.body
766 .render_into::<D>(&self.selection.items(), &mut sink);
767 sink.finish()
768 }
769}
770
771impl SelectBody {
772 pub(crate) fn render_into<D: Dialect>(&self, selection: &[SelectItem], sink: &mut dyn Sink) {
773 let SelectBody {
774 ctes,
775 distinct,
776 from_table,
777 joins,
778 wheres,
779 order_by,
780 group_by,
781 having,
782 limit,
783 offset,
784 } = self;
785
786 if !ctes.is_empty() {
787 sink.text("WITH ");
788 for (i, cte) in ctes.iter().enumerate() {
789 if i > 0 {
790 sink.text(", ");
791 }
792 crate::render::render_ident::<D>(sink, cte.name);
793 sink.text(" (");
794 for (i, col) in cte.column_names.iter().enumerate() {
795 if i > 0 {
796 sink.text(", ");
797 }
798 crate::render::render_ident::<D>(sink, col);
799 }
800 sink.text(") AS (");
801 cte.body.splice_into(sink);
802 sink.ch(')');
803 }
804 sink.ch(' ');
805 }
806 sink.text("SELECT ");
807 if *distinct {
808 sink.text("DISTINCT ");
809 }
810
811 render_select_list::<D>(selection, sink);
812
813 sink.text(" FROM ");
814 crate::render::render_ident::<D>(sink, from_table);
815
816 for j in joins {
817 sink.ch(' ');
818 sink.text(match j.kind {
819 JoinKind::Inner => "INNER JOIN",
820 JoinKind::Left => "LEFT JOIN",
821 JoinKind::Right => "RIGHT JOIN",
822 JoinKind::Full => "FULL JOIN",
823 });
824 sink.ch(' ');
825 crate::render::render_ident::<D>(sink, j.table);
826 sink.text(" ON ");
827 render_expr::<D>(&j.on, sink);
828 }
829
830 render_and_list::<D>(sink, " WHERE ", wheres);
831
832 render_expr_list::<D>(sink, " GROUP BY ", group_by);
833 render_and_list::<D>(sink, " HAVING ", having);
834 render_order_by::<D>(sink, " ORDER BY ", order_by);
835 render_limit_offset::<D>(sink, limit.as_ref(), offset.as_ref());
836 }
837}
838
839pub(crate) fn correlated_with<D, Scope, S: JoinSource<D>, InnerSel>(
844 source: S,
845 selection: InnerSel,
846) -> Select<D, Cons<TableSlot<S::Table, NotNull>, Scope>, InnerSel, Scope> {
847 let mut body = SelectBody::new(<S::Table as Table>::NAME);
848 body.bind(source);
849 Select {
850 body,
851 selection,
852 _marker: PhantomData,
853 }
854}
855
856impl<D, Scope, Sel, Outer> Select<D, Scope, Sel, Outer> {
857 pub fn correlated<S: JoinSource<D>, InnerSel>(
870 &self,
871 source: S,
872 selection: InnerSel,
873 ) -> Select<D, Cons<TableSlot<S::Table, NotNull>, Scope>, InnerSel, Scope> {
874 correlated_with(source, selection)
875 }
876}
877
878impl<D: Dialect, Scope, Sel, Outer: ScopeTables> Select<D, Scope, Sel, Outer> {
879 pub fn exists<Idx>(&self) -> Exists<D, Outer::Tables>
885 where
886 Sel: Selection<Scope, Idx>,
887 {
888 self.exists_kind::<Idx>(false)
889 }
890
891 pub fn not_exists<Idx>(&self) -> Exists<D, Outer::Tables>
892 where
893 Sel: Selection<Scope, Idx>,
894 {
895 self.exists_kind::<Idx>(true)
896 }
897
898 fn exists_kind<Idx>(&self, negated: bool) -> Exists<D, Outer::Tables>
899 where
900 Sel: Selection<Scope, Idx>,
901 {
902 Exists {
903 kind: ExprKind::Exists {
904 body: Box::new(self.body.clone()),
905 selection: self.selection.items(),
906 negated,
907 },
908 _marker: PhantomData,
909 }
910 }
911}
912
913#[diagnostic::on_unimplemented(
921 message = "`{Self}` isn't a number of rows",
922 label = "an integer, or a `prepare!{{}}` placeholder of type `Integer`/`BigInt`"
923)]
924pub trait IntoRowCount {
925 fn into_row_count(self) -> RowCount;
926}
927
928#[derive(Debug, Clone)]
931pub struct RowCount(RowCountKind);
932
933#[derive(Debug, Clone)]
934enum RowCountKind {
935 Literal(i64),
938 Bound(ExprKind),
940}
941
942macro_rules! into_row_count {
943 ($($signed:ty),+ ; $($unsigned:ty),+) => {
944 $(impl IntoRowCount for $signed {
945 fn into_row_count(self) -> RowCount {
946 RowCount(RowCountKind::Literal((self as i64).max(0)))
947 }
948 })+
949 $(impl IntoRowCount for $unsigned {
950 fn into_row_count(self) -> RowCount {
951 RowCount(RowCountKind::Literal(i64::try_from(self).unwrap_or(i64::MAX)))
952 }
953 })+
954 };
955}
956into_row_count!(i8, i16, i32, i64, isize ; u8, u16, u32, u64, usize);
957
958impl IntoRowCount for Expr<Nil, crate::expr::Integer> {
962 fn into_row_count(self) -> RowCount {
963 RowCount(RowCountKind::Bound(self.kind))
964 }
965}
966
967impl IntoRowCount for Expr<Nil, crate::expr::BigInt> {
968 fn into_row_count(self) -> RowCount {
969 RowCount(RowCountKind::Bound(self.kind))
970 }
971}
972
973pub(crate) fn render_limit_offset<D: Dialect>(
976 sink: &mut dyn Sink,
977 limit: Option<&RowCount>,
978 offset: Option<&RowCount>,
979) {
980 match (limit, offset, D::OFFSET_WITHOUT_LIMIT) {
981 (Some(l), _, _) => {
982 sink.text(" LIMIT ");
983 render_row_count::<D>(sink, l);
984 }
985 (None, Some(_), Some(filler)) => {
986 sink.text(" LIMIT ");
987 sink.text(filler);
988 }
989 _ => {}
990 }
991 if let Some(o) = offset {
992 sink.text(" OFFSET ");
993 render_row_count::<D>(sink, o);
994 }
995}
996
997fn render_row_count<D: Dialect>(sink: &mut dyn Sink, count: &RowCount) {
998 match &count.0 {
999 RowCountKind::Literal(n) => sink.text(&n.to_string()),
1000 RowCountKind::Bound(kind) => render_expr::<D>(kind, sink),
1001 }
1002}