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 = true;
194}
195
196impl<DB> QueryFragment<DB> for OffsetPreceding
197where
198 DB: crate::backend::Backend,
199{
200 fn walk_ast<'b>(
201 &'b self,
202 mut pass: crate::query_builder::AstPass<'_, 'b, DB>,
203 ) -> crate::QueryResult<()> {
204 pass.push_sql(&self.0.to_string());
207 pass.push_sql(" PRECEDING ");
208 Ok(())
209 }
210}
211
212#[derive(Clone, Copy, Debug)]
216pub struct OffsetFollowing<I = u64>(I);
217
218impl QueryId for OffsetFollowing {
221 type QueryId = ();
222
223 const HAS_STATIC_QUERY_ID: bool = true;
224}
225
226impl<DB> QueryFragment<DB> for OffsetFollowing
227where
228 DB: crate::backend::Backend,
229{
230 fn walk_ast<'b>(
231 &'b self,
232 mut pass: crate::query_builder::AstPass<'_, 'b, DB>,
233 ) -> crate::QueryResult<()> {
234 pass.push_sql(&self.0.to_string());
237 pass.push_sql(" FOLLOWING ");
238 Ok(())
239 }
240}
241
242pub trait FrameDsl<F> {
243 type Output;
244
245 fn frame(self, expr: F) -> Self::Output;
246}
247
248#[diagnostic::on_unimplemented(
249 message = "`Groups` frame clauses require a ordered window function",
250 note = "call `.window_order(some_column)` first"
251)]
252pub trait ValidFrameClause<O> {}
253
254impl<O, Kind, Start, End, Exclusion> ValidFrameClause<O>
255 for BetweenFrame<Kind, Start, End, Exclusion>
256where
257 Kind: ValidFrameClause<O>,
258{
259}
260impl<O, Kind, Start, Exclusion> ValidFrameClause<O> for StartFrame<Kind, Start, Exclusion> where
261 Kind: ValidFrameClause<O>
262{
263}
264impl<O> ValidFrameClause<O> for Rows {}
265impl<O> ValidFrameClause<O> for Range {}
266impl<O> ValidFrameClause<Order<O, true>> for Groups {}
267
268impl<E, Fn, Filter, Frame, Partition, Order> FrameDsl<E>
269 for AggregateExpression<Fn, NoPrefix, NoOrder, Filter, OverClause<Partition, Order, Frame>>
270where
271 E: FrameClauseExpression,
272 E: ValidFrameClause<Order>,
273 Filter: ValidAggregateFilterForWindow<Fn, OverClause<Partition, Order, FrameClause<E>>>,
274{
275 type Output = AggregateExpression<
276 Fn,
277 NoPrefix,
278 NoOrder,
279 Filter,
280 OverClause<Partition, Order, FrameClause<E>>,
281 >;
282
283 fn frame(self, expr: E) -> Self::Output {
284 AggregateExpression {
285 prefix: self.prefix,
286 function: self.function,
287 order: self.order,
288 filter: self.filter,
289 window: OverClause {
290 partition_by: self.window.partition_by,
291 order: self.window.order,
292 frame_clause: FrameClause(expr),
293 },
294 }
295 }
296}
297
298impl<E, Fn, Filter> FrameDsl<E> for AggregateExpression<Fn, NoPrefix, NoOrder, Filter, NoWindow>
299where
300 E: FrameClauseExpression,
301 E: ValidFrameClause<NoOrder>,
302 Filter: ValidAggregateFilterForWindow<Fn, OverClause<NoPartition, NoOrder, FrameClause<E>>>,
303{
304 type Output = AggregateExpression<
305 Fn,
306 NoPrefix,
307 NoOrder,
308 Filter,
309 OverClause<NoPartition, NoOrder, FrameClause<E>>,
310 >;
311
312 fn frame(self, expr: E) -> Self::Output {
313 AggregateExpression {
314 prefix: self.prefix,
315 function: self.function,
316 order: self.order,
317 filter: self.filter,
318 window: OverClause {
319 partition_by: NoPartition,
320 order: NoOrder,
321 frame_clause: FrameClause(expr),
322 },
323 }
324 }
325}
326
327impl<E, Fn> FrameDsl<E> for Fn
328where
329 Fn: IsWindowFunction,
330 E: FrameClauseExpression,
331 E: ValidFrameClause<NoOrder>,
332{
333 type Output = AggregateExpression<
334 Fn,
335 NoPrefix,
336 NoOrder,
337 NoFilter,
338 OverClause<NoPartition, NoOrder, FrameClause<E>>,
339 >;
340
341 fn frame(self, expr: E) -> Self::Output {
342 AggregateExpression {
343 prefix: NoPrefix,
344 function: self,
345 order: NoOrder,
346 filter: NoFilter,
347 window: OverClause {
348 partition_by: NoPartition,
349 order: NoOrder,
350 frame_clause: FrameClause(expr),
351 },
352 }
353 }
354}
355
356pub trait FrameClauseExpression {}
357
358pub trait FrameClauseStartBound: Sealed {}
363
364pub trait FrameClauseEndBound: Sealed {}
369
370impl FrameClauseEndBound for UnboundedFollowing {}
371impl Sealed for UnboundedFollowing {}
372impl FrameClauseStartBound for UnboundedPreceding {}
373impl Sealed for UnboundedPreceding {}
374impl FrameClauseEndBound for CurrentRow {}
375impl FrameClauseStartBound for CurrentRow {}
376impl Sealed for CurrentRow {}
377impl FrameClauseEndBound for OffsetFollowing {}
378impl Sealed for OffsetFollowing {}
379impl FrameClauseStartBound for OffsetPreceding {}
380impl Sealed for OffsetPreceding {}
381
382pub trait FrameClauseExclusion: Sealed {}
387
388impl FrameClauseExclusion for ExcludeGroup {}
389impl Sealed for ExcludeGroup {}
390impl FrameClauseExclusion for ExcludeNoOthers {}
391impl Sealed for ExcludeNoOthers {}
392impl FrameClauseExclusion for ExcludeTies {}
393impl Sealed for ExcludeTies {}
394impl FrameClauseExclusion for ExcludeCurrentRow {}
395impl Sealed for ExcludeCurrentRow {}
396
397pub trait FrameBoundDsl {
399 fn preceding(self) -> OffsetPreceding;
401
402 fn following(self) -> OffsetFollowing;
404}
405
406impl FrameBoundDsl for u64 {
407 fn preceding(self) -> OffsetPreceding {
408 OffsetPreceding(self)
409 }
410
411 fn following(self) -> OffsetFollowing {
412 OffsetFollowing(self)
413 }
414}
415empty_clause!(NoExclusion);
422
423#[derive(QueryId, Copy, Clone, Debug)]
424pub struct StartFrame<Kind, Start, Exclusion = NoExclusion> {
425 kind: Kind,
426 start: Start,
427 exclusion: Exclusion,
428}
429
430impl<Kind, Start, Exclusion, DB> QueryFragment<DB> for StartFrame<Kind, Start, Exclusion>
431where
432 Kind: QueryFragment<DB>,
433 Start: QueryFragment<DB>,
434 Exclusion: QueryFragment<DB>,
435 DB: crate::backend::Backend,
436{
437 fn walk_ast<'b>(
438 &'b self,
439 mut pass: crate::query_builder::AstPass<'_, 'b, DB>,
440 ) -> crate::QueryResult<()> {
441 self.kind.walk_ast(pass.reborrow())?;
442 self.start.walk_ast(pass.reborrow())?;
443 self.exclusion.walk_ast(pass.reborrow())?;
444 Ok(())
445 }
446}
447
448impl<Kind, Start, Exclusion> FrameClauseExpression for StartFrame<Kind, Start, Exclusion> {}
449
450#[derive(QueryId, Copy, Clone, Debug)]
451pub struct BetweenFrame<Kind, Start, End, Exclusion = NoExclusion> {
452 kind: Kind,
453 start: Start,
454 end: End,
455 exclusion: Exclusion,
456}
457
458impl<Kind, Start, End, Exclusion, DB> QueryFragment<DB>
459 for BetweenFrame<Kind, Start, End, Exclusion>
460where
461 Kind: QueryFragment<DB>,
462 Start: QueryFragment<DB>,
463 End: QueryFragment<DB>,
464 Exclusion: QueryFragment<DB>,
465 DB: crate::backend::Backend,
466{
467 fn walk_ast<'b>(
468 &'b self,
469 mut pass: crate::query_builder::AstPass<'_, 'b, DB>,
470 ) -> crate::QueryResult<()> {
471 self.kind.walk_ast(pass.reborrow())?;
472 pass.push_sql(" BETWEEN ");
473 self.start.walk_ast(pass.reborrow())?;
474 pass.push_sql(" AND ");
475 self.end.walk_ast(pass.reborrow())?;
476 self.exclusion.walk_ast(pass.reborrow())?;
477 Ok(())
478 }
479}
480
481impl<Kind, Start, End, Exclusion> FrameClauseExpression
482 for BetweenFrame<Kind, Start, End, Exclusion>
483{
484}
485
486pub trait FrameClauseDslHelper: Sized {}
487
488pub trait FrameClauseDsl: FrameClauseDslHelper {
490 fn frame_start_with<E>(self, start: E) -> super::dsl::FrameStartWith<Self, E>
492 where
493 E: FrameClauseStartBound,
494 {
495 StartFrame {
496 kind: self,
497 start,
498 exclusion: NoExclusion,
499 }
500 }
501
502 fn frame_start_with_exclusion<E1, E2>(
504 self,
505 start: E1,
506 exclusion: E2,
507 ) -> super::dsl::FrameStartWithExclusion<Self, E1, E2>
508 where
509 E1: FrameClauseStartBound,
510 E2: FrameClauseExclusion,
511 {
512 StartFrame {
513 kind: self,
514 start,
515 exclusion,
516 }
517 }
518
519 fn frame_between<E1, E2>(self, start: E1, end: E2) -> super::dsl::FrameBetween<Self, E1, E2>
521 where
522 E1: FrameClauseStartBound,
523 E2: FrameClauseEndBound,
524 {
525 BetweenFrame {
526 kind: self,
527 start,
528 end,
529 exclusion: NoExclusion,
530 }
531 }
532
533 fn frame_between_with_exclusion<E1, E2, E3>(
535 self,
536 start: E1,
537 end: E2,
538 exclusion: E3,
539 ) -> super::dsl::FrameBetweenWithExclusion<Self, E1, E2, E3>
540 where
541 E1: FrameClauseStartBound,
542 E2: FrameClauseEndBound,
543 E3: FrameClauseExclusion,
544 {
545 BetweenFrame {
546 kind: self,
547 start,
548 end,
549 exclusion,
550 }
551 }
552}
553
554impl<T> FrameClauseDsl for T where T: FrameClauseDslHelper {}
555
556impl FrameClauseDslHelper for Range {}
557impl FrameClauseDslHelper for Rows {}
558impl FrameClauseDslHelper for Groups {}
559
560pub trait Sealed {}