Skip to main content

qraft_core/select/
query.rs

1//! Query state for full select statements and typed row projections.
2
3use 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/// Untyped query state used while shaping SQL structure.
43///
44/// This is the flexible form you use while adding joins, changing projections,
45/// or otherwise building a statement whose final row shape is not settled yet.
46#[derive(Debug, Clone)]
47pub struct Query {
48    pub(crate) project: Vec<RpnInstr>,
49    pub(crate) distinct: bool,
50
51    // from with joins / needs join offset after from to mutate joins here
52    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    // limit with offset and such
61    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/// Query state with an attached row type.
72///
73/// This is the typed form used once the statement's result shape is known and
74/// can be decoded into `M`.
75#[derive(Debug)]
76pub struct QueryOf<M> {
77    pub(crate) query: Query,
78    pub(crate) marker: PhantomData<M>,
79}
80
81/// Query state that already selected a lock clause.
82#[derive(Debug, Clone)]
83pub struct LockedQuery {
84    pub(crate) query: Query,
85}
86
87/// Typed query state that already selected a lock clause.
88#[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    /// Attaches a row type to an existing untyped query.
129    pub fn new(query: Query) -> Self {
130        Self {
131            query,
132            marker: PhantomData,
133        }
134    }
135
136    /// Replaces the current projection list.
137    ///
138    /// Use [`QueryOf::untyped`] first when the new projection no longer matches
139    /// `M` and you want to attach a different row type with `typed()`.
140    pub fn select<S>(self, s: S) -> Self
141    where
142        S: LowerProject,
143    {
144        self.query.select(s).typed()
145    }
146
147    /// Adds a `left join` to the current `from` clause.
148    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    /// Adds a `right join` to the current `from` clause.
156    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    /// Adds an `inner join` to the current `from` clause.
164    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    /// Adds a `where` predicate combined with `and`.
172    pub fn filter<E>(self, e: E) -> Self
173    where
174        E: LowerFilter,
175    {
176        self.query.filter(e).typed()
177    }
178
179    /// Adds a `where` predicate combined with `or`.
180    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    /// Adds an `order by` clause.
188    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    /// Orders by a dialect-specific random function.
196    pub fn order_by_random(self) -> Self {
197        self.order_by(random())
198    }
199
200    /// Replaces any existing `limit` clause.
201    pub fn limit<E>(self, e: E) -> Self
202    where
203        E: LowerCompatible<BigInt>,
204    {
205        self.query.limit(e).typed()
206    }
207
208    /// Clears the current `limit` clause.
209    pub fn reset_limit(&mut self) {
210        self.query.reset_limit();
211    }
212
213    /// Replaces any existing `offset` clause.
214    pub fn offset<E>(self, e: E) -> Self
215    where
216        E: LowerCompatible<BigInt>,
217    {
218        self.query.offset(e).typed()
219    }
220
221    /// Clears the current `offset` clause.
222    pub fn reset_offset(&mut self) {
223        self.query.reset_offset();
224    }
225
226    /// Emits `select distinct`.
227    pub fn distinct(self) -> Self {
228        self.query.distinct().typed()
229    }
230
231    /// Clears the distinct flag.
232    pub fn not_distinct(self) -> Self {
233        self.query.not_distinct().typed()
234    }
235
236    /// Adds `for update`.
237    pub fn lock_for_update(self) -> LockedQueryOf<M> {
238        self.query.lock_for_update().typed()
239    }
240
241    /// Adds the dialect's shared-row lock clause.
242    pub fn shared_lock(self) -> LockedQueryOf<M> {
243        self.query.shared_lock().typed()
244    }
245
246    /// Attaches a common table expression.
247    pub fn with<C>(self, ctes: C) -> Self
248    where
249        C: IntoCtes,
250    {
251        self.query.with(ctes).typed()
252    }
253
254    /// Attaches a recursive common table expression.
255    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    /// Drops the attached row type.
263    pub fn untyped(self) -> Query {
264        self.query
265    }
266
267    /// Re-attaches a different row type to the current query.
268    pub fn typed<N>(self) -> QueryOf<N>
269    where
270        N: FromRow,
271    {
272        self.query.typed()
273    }
274
275    /// Treats the query as a scalar subquery of the requested type.
276    pub fn scalar<T: TypeMeta>(self) -> Scalar<T> {
277        self.query.scalar::<T>()
278    }
279
280    /// Combines this query with another one using `union`.
281    pub fn union(self, other: impl Into<Query>) -> Self {
282        self.query.union(other).typed()
283    }
284
285    /// Combines this query with another one using `union all`.
286    pub fn union_all(self, other: impl Into<Query>) -> Self {
287        self.query.union_all(other).typed()
288    }
289
290    /// Emits SQL for the requested dialect.
291    #[allow(clippy::wrong_self_convention)]
292    pub fn to_sql<D: HasDialect>(&mut self) -> String {
293        self.query.to_sql::<D>()
294    }
295
296    /// Emits SQL followed by a debug view of the current parameters.
297    #[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    /// Compiles the query into the typed representation used by executors.
303    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    /// Starts an insert into the query model's table.
319    ///
320    /// This is a convenience helper that targets `M::TABLE`; it does not reuse
321    /// the current query's filter scope as insert assignments.
322    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    /// Replaces the current projection list.
663    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    /// Clears the current projection list.
678    pub fn reset_select(&mut self) {
679        if !self.project.is_empty() {
680            self.project.clear();
681        }
682    }
683
684    /// Adds a `left join` to the current `from` clause.
685    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    /// Adds a `right join` to the current `from` clause.
699    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    /// Adds an `inner join` to the current `from` clause.
713    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    /// Adds a `having` predicate combined with `and`.
727    pub fn having<E>(self, e: E) -> Self
728    where
729        E: LowerHaving,
730    {
731        self.having_clause(e, Operator::And)
732    }
733
734    /// Adds a `having` predicate combined with `or`.
735    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    /// Adds a `where` predicate combined with `and`.
743    pub fn filter<E>(self, e: E) -> Self
744    where
745        E: LowerFilter,
746    {
747        self.where_clause(e, Operator::And)
748    }
749
750    /// Adds a `where` predicate combined with `or`.
751    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    // joins here
759
760    /// Starts a query from the given source.
761    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    /// Combines this query with another one using `union`.
776    pub fn union(self, other: impl Into<Query>) -> Self {
777        self.compound_with(other.into(), SetOperator::Union)
778    }
779
780    /// Combines this query with another one using `union all`.
781    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    /// Appends grouping expressions to `group by`.
804    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    /// Appends ordering expressions to `order by`.
818    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    /// Appends a random ordering expression.
832    pub fn order_by_random(self) -> Self {
833        self.order_by(random())
834    }
835
836    /// Replaces any existing `limit` clause.
837    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    /// Clears the current `limit` clause.
853    pub fn reset_limit(&mut self) {
854        if !self.limit.is_empty() {
855            self.limit.clear();
856        }
857    }
858
859    /// Replaces any existing `offset` clause.
860    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    /// Clears the current `offset` clause.
876    pub fn reset_offset(&mut self) {
877        if !self.offset.is_empty() {
878            self.offset.clear();
879        }
880    }
881
882    /// Adds `for update`.
883    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    /// Adds the dialect's shared-row lock clause.
892    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    /// Attaches a common table expression.
929    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    /// Attaches a recursive common table expression.
947    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    /// Treats the query as a scalar subquery of the requested type.
979    pub fn scalar<T: TypeMeta>(self) -> Scalar<T> {
980        Scalar {
981            inner: self,
982            marker: PhantomData,
983        }
984    }
985
986    /// Emits `select distinct`.
987    pub fn distinct(mut self) -> Self {
988        self.distinct = true;
989        self
990    }
991
992    /// Clears the distinct flag.
993    pub fn not_distinct(mut self) -> Self {
994        self.distinct = false;
995        self
996    }
997
998    /// Attaches a row type once the result shape is known.
999    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    /// Emits SQL for the requested dialect.
1064    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(&params, &mut self.params);
1101
1102        buf
1103    }
1104
1105    /// Compiles the query into an untyped executable payload.
1106    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    /// Emits SQL followed by a debug view of the current parameters.
1115    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
1123/// Reorders parameters after SQL emission when the dialect required rewrites.
1124pub 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/// Fully compiled query payload without a row type.
1200#[derive(Debug)]
1201pub struct Compiled {
1202    /// Final SQL string ready to hand to a driver.
1203    pub sql: String,
1204    /// Compact parameter values referenced by the SQL string.
1205    pub params: Vec<Param>,
1206    /// Interned text and blob storage referenced by `params`.
1207    pub data: Vec<u8>,
1208}
1209
1210/// Fully compiled query payload with an attached row type.
1211#[derive(Debug)]
1212pub struct TypedCompiled<T> {
1213    /// Final SQL string ready to hand to a driver.
1214    pub sql: String,
1215    /// Compact parameter values referenced by the SQL string.
1216    pub params: Vec<Param>,
1217    /// Interned text and blob storage referenced by `params`.
1218    pub data: Vec<u8>,
1219    /// Row type marker.
1220    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}