1use crate::backend::sql_dialect;
2use crate::query_builder::{QueryFragment, QueryId};
3
4use super::aggregate_filter::NoFilter;
5use super::aggregate_order::{NoOrder, Order};
6use super::over_clause::{NoWindow, OverClause, ValidAggregateFilterForWindow};
7use super::partition_by::NoPartition;
8use super::prefix::NoPrefix;
9use super::{AggregateExpression, IsWindowFunction};
10
11empty_clause!(NoFrame);
12
13#[derive(QueryId, Copy, Clone, Debug)]
14pub struct FrameClause<F>(F);
15
16impl<F, DB> QueryFragment<DB> for FrameClause<F>
17where
18 F: QueryFragment<DB>,
19 DB: crate::backend::Backend,
20{
21 fn walk_ast<'b>(
22 &'b self,
23 pass: crate::query_builder::AstPass<'_, 'b, DB>,
24 ) -> crate::QueryResult<()> {
25 self.0.walk_ast(pass)?;
26 Ok(())
27 }
28}
29
30macro_rules! simple_frame_expr {
31 ($(#[doc = $doc: literal])* $name: ident, $kind: expr) => {
32 #[derive(QueryId, Clone, Copy, Debug)]
33 $(#[doc = $doc])*
34 pub struct $name;
35
36 impl<DB> QueryFragment<DB> for $name
37 where
38 DB: crate::backend::Backend,
39 {
40 fn walk_ast<'b>(
41 &'b self,
42 mut pass: crate::query_builder::AstPass<'_, 'b, DB>,
43 ) -> crate::QueryResult<()> {
44 pass.push_sql($kind);
45 Ok(())
46 }
47 }
48 };
49}
50
51macro_rules! simple_frame_expr_with_bound {
52 ($(#[doc = $doc:literal])* $name: ident, $option: ident, $bound: ty, $kind: expr) => {
53 #[derive(QueryId, Clone, Copy, Debug)]
54 $(#[doc = $doc])*
55 pub struct $name;
56
57 impl<DB> QueryFragment<DB> for $name
58 where
59 DB: crate::backend::Backend,
60 Self: QueryFragment<DB, DB::$option>,
61 {
62 fn walk_ast<'b>(
63 &'b self,
64 pass: crate::query_builder::AstPass<'_, 'b, DB>,
65 ) -> crate::QueryResult<()> {
66 <Self as QueryFragment<DB, DB::$option>>::walk_ast(self, pass)
67 }
68 }
69 impl<DB> QueryFragment<DB, $bound> for $name
70 where
71 DB: crate::backend::Backend<$option = $bound>,
72 {
73 fn walk_ast<'b>(
74 &'b self,
75 mut pass: crate::query_builder::AstPass<'_, 'b, DB>,
76 ) -> crate::QueryResult<()> {
77 pass.push_sql($kind);
78 Ok(())
79 }
80 }
81 };
82}
83
84simple_frame_expr!(
86 Range, " RANGE ");
91simple_frame_expr!(
92 Rows, " ROWS ");
97simple_frame_expr_with_bound!(
98 Groups,
108 WindowFrameClauseGroupSupport,
109 sql_dialect::window_frame_clause_group_support::IsoGroupWindowFrameUnit,
110 " GROUPS "
111);
112
113simple_frame_expr!(
115 UnboundedPreceding, "UNBOUNDED PRECEDING ");
122simple_frame_expr!(
123 CurrentRow, "CURRENT ROW ");
135simple_frame_expr!(
136 UnboundedFollowing, "UNBOUNDED FOLLOWING ");
143
144simple_frame_expr_with_bound!(
146 ExcludeCurrentRow,
148 WindowFrameExclusionSupport,
149 sql_dialect::window_frame_exclusion_support::FrameExclusionSupport,
150 "EXCLUDE CURRENT ROW "
151);
152simple_frame_expr_with_bound!(
153 ExcludeGroup,
158 WindowFrameExclusionSupport,
159 sql_dialect::window_frame_exclusion_support::FrameExclusionSupport,
160 "EXCLUDE GROUP "
161);
162simple_frame_expr_with_bound!(
163 ExcludeTies,
168 WindowFrameExclusionSupport,
169 sql_dialect::window_frame_exclusion_support::FrameExclusionSupport,
170 "EXCLUDE TIES "
171);
172simple_frame_expr_with_bound!(
173 ExcludeNoOthers,
177 WindowFrameExclusionSupport,
178 sql_dialect::window_frame_exclusion_support::FrameExclusionSupport,
179 "EXCLUDE NO OTHERS "
180);
181
182#[derive(Clone, Copy, Debug)]
186pub struct OffsetPreceding<T = u64>(T);
187
188impl QueryId for OffsetPreceding {
191 type QueryId = ();
192
193 const HAS_STATIC_QUERY_ID: bool = false;
197}
198
199impl<DB> QueryFragment<DB> for OffsetPreceding
200where
201 DB: crate::backend::Backend,
202{
203 fn walk_ast<'b>(
204 &'b self,
205 mut pass: crate::query_builder::AstPass<'_, 'b, DB>,
206 ) -> crate::QueryResult<()> {
207 pass.push_sql(&self.0.to_string());
210 pass.push_sql(" PRECEDING ");
211 Ok(())
212 }
213}
214
215#[derive(Clone, Copy, Debug)]
219pub struct OffsetFollowing<I = u64>(I);
220
221impl QueryId for OffsetFollowing {
224 type QueryId = ();
225
226 const HAS_STATIC_QUERY_ID: bool = false;
230}
231
232impl<DB> QueryFragment<DB> for OffsetFollowing
233where
234 DB: crate::backend::Backend,
235{
236 fn walk_ast<'b>(
237 &'b self,
238 mut pass: crate::query_builder::AstPass<'_, 'b, DB>,
239 ) -> crate::QueryResult<()> {
240 pass.push_sql(&self.0.to_string());
243 pass.push_sql(" FOLLOWING ");
244 Ok(())
245 }
246}
247
248pub trait FrameDsl<F> {
249 type Output;
250
251 fn frame(self, expr: F) -> Self::Output;
252}
253
254#[diagnostic::on_unimplemented(
255 message = "`Groups` frame clauses require a ordered window function",
256 note = "call `.window_order(some_column)` first"
257)]
258pub trait ValidFrameClause<O> {}
259
260impl<O, Kind, Start, End, Exclusion> ValidFrameClause<O>
261 for BetweenFrame<Kind, Start, End, Exclusion>
262where
263 Kind: ValidFrameClause<O>,
264{
265}
266impl<O, Kind, Start, Exclusion> ValidFrameClause<O> for StartFrame<Kind, Start, Exclusion> where
267 Kind: ValidFrameClause<O>
268{
269}
270impl<O> ValidFrameClause<O> for Rows {}
271impl<O> ValidFrameClause<O> for Range {}
272impl<O> ValidFrameClause<Order<O, true>> for Groups {}
273
274impl<E, Fn, Filter, Frame, Partition, Order> FrameDsl<E>
275 for AggregateExpression<Fn, NoPrefix, NoOrder, Filter, OverClause<Partition, Order, Frame>>
276where
277 E: FrameClauseExpression,
278 E: ValidFrameClause<Order>,
279 Filter: ValidAggregateFilterForWindow<Fn, OverClause<Partition, Order, FrameClause<E>>>,
280{
281 type Output = AggregateExpression<
282 Fn,
283 NoPrefix,
284 NoOrder,
285 Filter,
286 OverClause<Partition, Order, FrameClause<E>>,
287 >;
288
289 fn frame(self, expr: E) -> Self::Output {
290 AggregateExpression {
291 prefix: self.prefix,
292 function: self.function,
293 order: self.order,
294 filter: self.filter,
295 window: OverClause {
296 partition_by: self.window.partition_by,
297 order: self.window.order,
298 frame_clause: FrameClause(expr),
299 },
300 }
301 }
302}
303
304impl<E, Fn, Filter> FrameDsl<E> for AggregateExpression<Fn, NoPrefix, NoOrder, Filter, NoWindow>
305where
306 E: FrameClauseExpression,
307 E: ValidFrameClause<NoOrder>,
308 Filter: ValidAggregateFilterForWindow<Fn, OverClause<NoPartition, NoOrder, FrameClause<E>>>,
309{
310 type Output = AggregateExpression<
311 Fn,
312 NoPrefix,
313 NoOrder,
314 Filter,
315 OverClause<NoPartition, NoOrder, FrameClause<E>>,
316 >;
317
318 fn frame(self, expr: E) -> Self::Output {
319 AggregateExpression {
320 prefix: self.prefix,
321 function: self.function,
322 order: self.order,
323 filter: self.filter,
324 window: OverClause {
325 partition_by: NoPartition,
326 order: NoOrder,
327 frame_clause: FrameClause(expr),
328 },
329 }
330 }
331}
332
333impl<E, Fn> FrameDsl<E> for Fn
334where
335 Fn: IsWindowFunction,
336 E: FrameClauseExpression,
337 E: ValidFrameClause<NoOrder>,
338{
339 type Output = AggregateExpression<
340 Fn,
341 NoPrefix,
342 NoOrder,
343 NoFilter,
344 OverClause<NoPartition, NoOrder, FrameClause<E>>,
345 >;
346
347 fn frame(self, expr: E) -> Self::Output {
348 AggregateExpression {
349 prefix: NoPrefix,
350 function: self,
351 order: NoOrder,
352 filter: NoFilter,
353 window: OverClause {
354 partition_by: NoPartition,
355 order: NoOrder,
356 frame_clause: FrameClause(expr),
357 },
358 }
359 }
360}
361
362pub trait FrameClauseExpression {}
363
364pub trait FrameClauseStartBound: Sealed {}
369
370pub trait FrameClauseEndBound: Sealed {}
375
376impl FrameClauseEndBound for UnboundedFollowing {}
377impl Sealed for UnboundedFollowing {}
378impl FrameClauseStartBound for UnboundedPreceding {}
379impl Sealed for UnboundedPreceding {}
380impl FrameClauseEndBound for CurrentRow {}
381impl FrameClauseStartBound for CurrentRow {}
382impl Sealed for CurrentRow {}
383impl FrameClauseEndBound for OffsetFollowing {}
384impl Sealed for OffsetFollowing {}
385impl FrameClauseStartBound for OffsetPreceding {}
386impl Sealed for OffsetPreceding {}
387
388pub trait FrameClauseExclusion: Sealed {}
393
394impl FrameClauseExclusion for ExcludeGroup {}
395impl Sealed for ExcludeGroup {}
396impl FrameClauseExclusion for ExcludeNoOthers {}
397impl Sealed for ExcludeNoOthers {}
398impl FrameClauseExclusion for ExcludeTies {}
399impl Sealed for ExcludeTies {}
400impl FrameClauseExclusion for ExcludeCurrentRow {}
401impl Sealed for ExcludeCurrentRow {}
402
403pub trait FrameBoundDsl {
405 fn preceding(self) -> OffsetPreceding;
407
408 fn following(self) -> OffsetFollowing;
410}
411
412impl FrameBoundDsl for u64 {
413 fn preceding(self) -> OffsetPreceding {
414 OffsetPreceding(self)
415 }
416
417 fn following(self) -> OffsetFollowing {
418 OffsetFollowing(self)
419 }
420}
421empty_clause!(NoExclusion);
428
429#[derive(QueryId, Copy, Clone, Debug)]
430pub struct StartFrame<Kind, Start, Exclusion = NoExclusion> {
431 kind: Kind,
432 start: Start,
433 exclusion: Exclusion,
434}
435
436impl<Kind, Start, Exclusion, DB> QueryFragment<DB> for StartFrame<Kind, Start, Exclusion>
437where
438 Kind: QueryFragment<DB>,
439 Start: QueryFragment<DB>,
440 Exclusion: QueryFragment<DB>,
441 DB: crate::backend::Backend,
442{
443 fn walk_ast<'b>(
444 &'b self,
445 mut pass: crate::query_builder::AstPass<'_, 'b, DB>,
446 ) -> crate::QueryResult<()> {
447 self.kind.walk_ast(pass.reborrow())?;
448 self.start.walk_ast(pass.reborrow())?;
449 self.exclusion.walk_ast(pass.reborrow())?;
450 Ok(())
451 }
452}
453
454impl<Kind, Start, Exclusion> FrameClauseExpression for StartFrame<Kind, Start, Exclusion> {}
455
456#[derive(QueryId, Copy, Clone, Debug)]
457pub struct BetweenFrame<Kind, Start, End, Exclusion = NoExclusion> {
458 kind: Kind,
459 start: Start,
460 end: End,
461 exclusion: Exclusion,
462}
463
464impl<Kind, Start, End, Exclusion, DB> QueryFragment<DB>
465 for BetweenFrame<Kind, Start, End, Exclusion>
466where
467 Kind: QueryFragment<DB>,
468 Start: QueryFragment<DB>,
469 End: QueryFragment<DB>,
470 Exclusion: QueryFragment<DB>,
471 DB: crate::backend::Backend,
472{
473 fn walk_ast<'b>(
474 &'b self,
475 mut pass: crate::query_builder::AstPass<'_, 'b, DB>,
476 ) -> crate::QueryResult<()> {
477 self.kind.walk_ast(pass.reborrow())?;
478 pass.push_sql(" BETWEEN ");
479 self.start.walk_ast(pass.reborrow())?;
480 pass.push_sql(" AND ");
481 self.end.walk_ast(pass.reborrow())?;
482 self.exclusion.walk_ast(pass.reborrow())?;
483 Ok(())
484 }
485}
486
487impl<Kind, Start, End, Exclusion> FrameClauseExpression
488 for BetweenFrame<Kind, Start, End, Exclusion>
489{
490}
491
492pub trait FrameClauseDslHelper: Sized {}
493
494pub trait FrameClauseDsl: FrameClauseDslHelper {
496 fn frame_start_with<E>(self, start: E) -> super::dsl::FrameStartWith<Self, E>
498 where
499 E: FrameClauseStartBound,
500 {
501 StartFrame {
502 kind: self,
503 start,
504 exclusion: NoExclusion,
505 }
506 }
507
508 fn frame_start_with_exclusion<E1, E2>(
510 self,
511 start: E1,
512 exclusion: E2,
513 ) -> super::dsl::FrameStartWithExclusion<Self, E1, E2>
514 where
515 E1: FrameClauseStartBound,
516 E2: FrameClauseExclusion,
517 {
518 StartFrame {
519 kind: self,
520 start,
521 exclusion,
522 }
523 }
524
525 fn frame_between<E1, E2>(self, start: E1, end: E2) -> super::dsl::FrameBetween<Self, E1, E2>
527 where
528 E1: FrameClauseStartBound,
529 E2: FrameClauseEndBound,
530 {
531 BetweenFrame {
532 kind: self,
533 start,
534 end,
535 exclusion: NoExclusion,
536 }
537 }
538
539 fn frame_between_with_exclusion<E1, E2, E3>(
541 self,
542 start: E1,
543 end: E2,
544 exclusion: E3,
545 ) -> super::dsl::FrameBetweenWithExclusion<Self, E1, E2, E3>
546 where
547 E1: FrameClauseStartBound,
548 E2: FrameClauseEndBound,
549 E3: FrameClauseExclusion,
550 {
551 BetweenFrame {
552 kind: self,
553 start,
554 end,
555 exclusion,
556 }
557 }
558}
559
560impl<T> FrameClauseDsl for T where T: FrameClauseDslHelper {}
561
562impl FrameClauseDslHelper for Range {}
563impl FrameClauseDslHelper for Rows {}
564impl FrameClauseDslHelper for Groups {}
565
566pub trait Sealed {}