diesel/expression/functions/window_functions.rs
1#[cfg(doc)]
2use super::aggregate_expressions::WindowExpressionMethods;
3use crate::sql_types::helper::CombinedNullableValue;
4use crate::sql_types::{Integer, IntoNotNullable, IntoNullable, SingleValue, SqlType};
5use diesel_derives::declare_sql_function;
6
7#[declare_sql_function]
8extern "SQL" {
9
10 /// Number of th current row within its partition
11 ///
12 /// Returns the number of the current row within its partition, counting from 1.
13 ///
14 /// This function must be used as window function. You need to call at least one
15 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
16 /// clause. It cannot be used outside of `SELECT` clauses.
17 ///
18 /// ```
19 /// # include!("../../doctest_setup.rs");
20 /// # use diesel::dsl::*;
21 /// #
22 /// # fn main() -> QueryResult<()> {
23 /// # use schema::posts::dsl::*;
24 /// # let connection = &mut establish_connection();
25 /// let res = posts
26 /// .select((title, user_id, row_number().partition_by(user_id)))
27 /// .load::<(String, i32, i64)>(connection)?;
28 /// let expected = vec![
29 /// ("My first post".to_owned(), 1, 1),
30 /// ("About Rust".into(), 1, 2),
31 /// ("My first post too".into(), 2, 1),
32 /// ];
33 /// assert_eq!(expected, res);
34 /// # Ok(())
35 /// # }
36 /// ```
37 #[window]
38 fn row_number() -> BigInt;
39
40 /// Rank of current row within its partition, with gaps
41 ///
42 /// Returns the rank of the current row, with gaps;
43 /// that is, the row_number of the first row in its peer group.
44 ///
45 /// This function must be used as window function. You need to call at least one
46 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
47 /// clause. It cannot be used outside of `SELECT` clauses.
48 ///
49 /// For MySQL this function requires you to call [`.window_order()`](WindowExpressionMethods::window_order())
50 ///
51 /// ```
52 /// # include!("../../doctest_setup.rs");
53 /// # use diesel::dsl::*;
54 /// #
55 /// # fn main() -> QueryResult<()> {
56 /// # use schema::posts::dsl::*;
57 /// # let connection = &mut establish_connection();
58 /// let res = posts
59 /// .select((
60 /// title,
61 /// user_id,
62 /// rank().partition_by(user_id).window_order(user_id),
63 /// ))
64 /// .load::<(String, i32, i64)>(connection)?;
65 /// let expected = vec![
66 /// ("My first post".to_owned(), 1, 1),
67 /// ("About Rust".into(), 1, 1),
68 /// ("My first post too".into(), 2, 1),
69 /// ];
70 /// assert_eq!(expected, res);
71 /// # Ok(())
72 /// # }
73 /// ```
74 #[window(dialect(
75 BuiltInWindowFunctionRequireOrder,
76 crate::backend::sql_dialect::built_in_window_function_require_order::NoOrderRequired
77 ))]
78 #[cfg_attr(
79 feature = "mysql_backend",
80 window(backends(diesel::mysql::Mysql), require_order = true)
81 )]
82 fn rank() -> BigInt;
83
84 /// Rank of current row within its partition, without gaps
85 ///
86 /// Returns the rank of the current row, without gaps;
87 /// this function effectively counts peer groups.
88 ///
89 /// This function must be used as window function. You need to call at least one
90 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
91 /// clause. It cannot be used outside of `SELECT` clauses.
92 ///
93 /// For MySQL this function requires you to call [`.window_order()`](WindowExpressionMethods::window_order())
94 ///
95 /// ```
96 /// # include!("../../doctest_setup.rs");
97 /// # use diesel::dsl::*;
98 /// #
99 /// # fn main() -> QueryResult<()> {
100 /// # use schema::posts::dsl::*;
101 /// # let connection = &mut establish_connection();
102 /// let res = posts
103 /// .select((
104 /// title,
105 /// user_id,
106 /// dense_rank().partition_by(user_id).window_order(user_id),
107 /// ))
108 /// .load::<(String, i32, i64)>(connection)?;
109 /// let expected = vec![
110 /// ("My first post".to_owned(), 1, 1),
111 /// ("About Rust".into(), 1, 1),
112 /// ("My first post too".into(), 2, 1),
113 /// ];
114 /// assert_eq!(expected, res);
115 /// # Ok(())
116 /// # }
117 /// ```
118 #[window(dialect(
119 BuiltInWindowFunctionRequireOrder,
120 crate::backend::sql_dialect::built_in_window_function_require_order::NoOrderRequired
121 ))]
122 #[cfg_attr(
123 feature = "mysql_backend",
124 window(backends(diesel::mysql::Mysql), require_order = true)
125 )]
126 fn dense_rank() -> BigInt;
127
128 /// Percentage rank value
129 ///
130 /// Returns the relative rank of the current row,
131 /// that is (rank - 1) / (total partition rows - 1).
132 /// The value thus ranges from 0 to 1 inclusive.
133 ///
134 /// This function must be used as window function. You need to call at least one
135 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
136 /// clause. It cannot be used outside of `SELECT` clauses.
137 ///
138 /// For MySQL this function requires you to call [`.window_order()`](WindowExpressionMethods::window_order())
139 ///
140 /// ```
141 /// # include!("../../doctest_setup.rs");
142 /// # use diesel::dsl::*;
143 /// #
144 /// # fn main() -> QueryResult<()> {
145 /// # use schema::posts::dsl::*;
146 /// # let connection = &mut establish_connection();
147 /// let res = posts
148 /// .select((
149 /// title,
150 /// user_id,
151 /// percent_rank().partition_by(user_id).window_order(user_id),
152 /// ))
153 /// .load::<(String, i32, f64)>(connection)?;
154 /// let expected = vec![
155 /// ("My first post".to_owned(), 1, 0.0),
156 /// ("About Rust".into(), 1, 0.0),
157 /// ("My first post too".into(), 2, 0.0),
158 /// ];
159 /// assert_eq!(expected, res);
160 /// # Ok(())
161 /// # }
162 /// ```
163 #[window(dialect(
164 BuiltInWindowFunctionRequireOrder,
165 crate::backend::sql_dialect::built_in_window_function_require_order::NoOrderRequired
166 ))]
167 #[cfg_attr(
168 feature = "mysql_backend",
169 window(backends(diesel::mysql::Mysql), require_order = true)
170 )]
171 fn percent_rank() -> Double;
172
173 /// Cumulative distribution value
174 ///
175 /// Returns the cumulative distribution,
176 /// that is (number of partition rows preceding or peers with current row) / (total partition rows).
177 /// The value thus ranges from 1/N to 1.
178 ///
179 /// This function must be used as window function. You need to call at least one
180 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
181 /// clause. It cannot be used outside of `SELECT` clauses.
182 ///
183 /// For MySQL this function requires you to call [`.window_order()`](WindowExpressionMethods::window_order())
184 ///
185 /// ```
186 /// # include!("../../doctest_setup.rs");
187 /// # use diesel::dsl::*;
188 /// #
189 /// # fn main() -> QueryResult<()> {
190 /// # use schema::posts::dsl::*;
191 /// # let connection = &mut establish_connection();
192 /// let res = posts
193 /// .select((
194 /// title,
195 /// user_id,
196 /// cume_dist().partition_by(user_id).window_order(user_id),
197 /// ))
198 /// .load::<(String, i32, f64)>(connection)?;
199 /// let expected = vec![
200 /// ("My first post".to_owned(), 1, 1.0),
201 /// ("About Rust".into(), 1, 1.0),
202 /// ("My first post too".into(), 2, 1.0),
203 /// ];
204 /// assert_eq!(expected, res);
205 /// # Ok(())
206 /// # }
207 /// ```
208 #[window(dialect(
209 BuiltInWindowFunctionRequireOrder,
210 crate::backend::sql_dialect::built_in_window_function_require_order::NoOrderRequired
211 ))]
212 #[cfg_attr(
213 feature = "mysql_backend",
214 window(backends(diesel::mysql::Mysql), require_order = true)
215 )]
216 fn cume_dist() -> Double;
217
218 /// Bucket number of current row within its partition
219 ///
220 /// Returns an integer ranging from 1 to the argument value,
221 /// dividing the partition as equally as possible.
222 ///
223 ///
224 /// This function must be used as window function. You need to call at least one
225 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
226 /// clause. It cannot be used outside of `SELECT` clauses.
227 ///
228 /// ```
229 /// # include!("../../doctest_setup.rs");
230 /// # use diesel::dsl::*;
231 /// #
232 /// # fn main() -> QueryResult<()> {
233 /// # use schema::posts::dsl::*;
234 /// # let connection = &mut establish_connection();
235 /// let res = posts
236 /// .select((title, user_id, ntile(2).partition_by(user_id)))
237 /// .load::<(String, i32, i32)>(connection)?;
238 /// let expected = vec![
239 /// ("My first post".to_owned(), 1, 1),
240 /// ("About Rust".into(), 1, 2),
241 /// ("My first post too".into(), 2, 1),
242 /// ];
243 /// assert_eq!(expected, res);
244 /// # Ok(())
245 /// # }
246 /// ```
247 #[window]
248 fn ntile(num_buckets: Integer) -> Integer;
249
250 /// Value of argument from row lagging current row within partition
251 ///
252 /// Returns value evaluated at the row that is one row before the current
253 /// row within the partition. If there is no such row, NULL is returned instead.
254 ///
255 /// See [`lag_with_offset`] and [`lag_with_offset_and_default`] for variants with configurable offset
256 /// and default values.
257 ///
258 /// This function must be used as window function. You need to call at least one
259 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
260 /// clause. It cannot be used outside of `SELECT` clauses.
261 ///
262 /// For MySQL this function requires you to call [`.window_order()`](WindowExpressionMethods::window_order())
263 ///
264 /// ```
265 /// # include!("../../doctest_setup.rs");
266 /// # use diesel::dsl::*;
267 /// #
268 /// # fn main() -> QueryResult<()> {
269 /// # use schema::posts::dsl::*;
270 /// # let connection = &mut establish_connection();
271 /// let res = posts
272 /// .select((
273 /// title,
274 /// user_id,
275 /// lag(id).partition_by(user_id).window_order(user_id),
276 /// ))
277 /// .load::<(String, i32, Option<i32>)>(connection)?;
278 /// let expected = vec![
279 /// ("My first post".to_owned(), 1, None),
280 /// ("About Rust".into(), 1, Some(1)),
281 /// ("My first post too".into(), 2, None),
282 /// ];
283 /// assert_eq!(expected, res);
284 /// # Ok(())
285 /// # }
286 /// ```
287 #[window(dialect(
288 BuiltInWindowFunctionRequireOrder,
289 crate::backend::sql_dialect::built_in_window_function_require_order::NoOrderRequired
290 ))]
291 #[cfg_attr(
292 feature = "mysql_backend",
293 window(backends(diesel::mysql::Mysql), require_order = true)
294 )]
295 fn lag<T: SqlType + SingleValue + IntoNullable<Nullable: SingleValue>>(value: T)
296 -> T::Nullable;
297
298 /// Value of argument from row lagging current row within partition
299 ///
300 /// Returns value evaluated at the row that is offset rows before the current
301 /// row within the partition; If there is no such row, NULL is returned instead.
302 ///
303 /// This function must be used as window function. You need to call at least one
304 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
305 /// clause. It cannot be used outside of `SELECT` clauses.
306 ///
307 /// For MySQL this function requires you to call [`.window_order()`](WindowExpressionMethods::window_order())
308 ///
309 /// ```
310 /// # include!("../../doctest_setup.rs");
311 /// # use diesel::dsl::*;
312 /// #
313 /// # fn main() -> QueryResult<()> {
314 /// # use schema::posts::dsl::*;
315 /// # let connection = &mut establish_connection();
316 /// let res = posts
317 /// .select((
318 /// title,
319 /// user_id,
320 /// lag_with_offset(id, 1)
321 /// .partition_by(user_id)
322 /// .window_order(user_id),
323 /// ))
324 /// .load::<(String, i32, Option<i32>)>(connection)?;
325 /// let expected = vec![
326 /// ("My first post".to_owned(), 1, None),
327 /// ("About Rust".into(), 1, Some(1)),
328 /// ("My first post too".into(), 2, None),
329 /// ];
330 /// assert_eq!(expected, res);
331 /// # Ok(())
332 /// # }
333 /// ```
334 #[doc(alias = "lag")]
335 #[sql_name = "lag"]
336 #[window(dialect(
337 BuiltInWindowFunctionRequireOrder,
338 crate::backend::sql_dialect::built_in_window_function_require_order::NoOrderRequired
339 ))]
340 #[cfg_attr(
341 feature = "mysql_backend",
342 window(backends(diesel::mysql::Mysql), require_order = true)
343 )]
344 fn lag_with_offset<T: SqlType + SingleValue + IntoNullable<Nullable: SingleValue>>(
345 value: T,
346 offset: Integer,
347 ) -> T::Nullable;
348
349 /// Value of argument from row lagging current row within partition
350 ///
351 /// Returns value evaluated at the row that is offset rows before the current
352 /// row within the partition; if there is no such row, instead returns default
353 /// (which must be of a type compatible with value).
354 /// Both offset and default are evaluated with respect to the current row.
355 /// If omitted, offset defaults to 1 and default to NULL.
356 ///
357 /// This function returns a nullable value if either the value or the default expression are
358 /// nullable.
359 ///
360 /// This function must be used as window function. You need to call at least one
361 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
362 /// clause. It cannot be used outside of `SELECT` clauses.
363 ///
364 /// For MySQL this function requires you to call [`.window_order()`](WindowExpressionMethods::window_order())
365 ///
366 /// ```
367 /// # include!("../../doctest_setup.rs");
368 /// # use diesel::dsl::*;
369 /// #
370 /// # #[cfg(not(feature = "mysql"))] // mariadb doesn't support this variant
371 /// # fn main() -> QueryResult<()> {
372 /// # use schema::posts::dsl::*;
373 /// # use diesel::sql_types::{Integer, Nullable};
374 /// # let connection = &mut establish_connection();
375 /// let res = posts
376 /// .select((
377 /// title,
378 /// user_id,
379 /// lag_with_offset_and_default(id, 1, user_id)
380 /// .partition_by(user_id)
381 /// .window_order(user_id),
382 /// ))
383 /// .load::<(String, i32, i32)>(connection)?;
384 /// let expected = vec![
385 /// ("My first post".to_owned(), 1, 1),
386 /// ("About Rust".into(), 1, 1),
387 /// ("My first post too".into(), 2, 2),
388 /// ];
389 /// assert_eq!(expected, res);
390 ///
391 /// let res = posts
392 /// .select((
393 /// title,
394 /// user_id,
395 /// lag_with_offset_and_default(None::<i32>.into_sql::<Nullable<Integer>>(), 1, user_id)
396 /// .partition_by(user_id)
397 /// .window_order(user_id),
398 /// ))
399 /// .load::<(String, i32, Option<i32>)>(connection)?;
400 /// let expected = vec![
401 /// ("My first post".to_owned(), 1, Some(1)),
402 /// ("About Rust".into(), 1, None),
403 /// ("My first post too".into(), 2, Some(2)),
404 /// ];
405 /// assert_eq!(expected, res);
406 ///
407 /// let res = posts
408 /// .select((
409 /// title,
410 /// user_id,
411 /// lag_with_offset_and_default(id, 1, None::<i32>.into_sql::<Nullable<Integer>>())
412 /// .partition_by(user_id)
413 /// .window_order(user_id),
414 /// ))
415 /// .load::<(String, i32, Option<i32>)>(connection)?;
416 /// let expected = vec![
417 /// ("My first post".to_owned(), 1, None),
418 /// ("About Rust".into(), 1, Some(1)),
419 /// ("My first post too".into(), 2, None),
420 /// ];
421 /// assert_eq!(expected, res);
422 /// # Ok(())
423 /// # }
424 /// # #[cfg(feature = "mysql")]
425 /// # fn main() {}
426 /// ```
427 #[doc(alias = "lag")]
428 #[sql_name = "lag"]
429 #[window(dialect(
430 BuiltInWindowFunctionRequireOrder,
431 crate::backend::sql_dialect::built_in_window_function_require_order::NoOrderRequired
432 ))]
433 #[cfg_attr(
434 feature = "mysql_backend",
435 window(backends(diesel::mysql::Mysql), require_order = true)
436 )]
437 fn lag_with_offset_and_default<
438 T: SqlType
439 + SingleValue
440 + IntoNotNullable<NotNullable: self::private::SameType<T2::NotNullable>>
441 + CombinedNullableValue<T2, T::NotNullable>,
442 T2: SqlType + SingleValue + IntoNotNullable,
443 >(
444 value: T,
445 offset: Integer,
446 default: T2,
447 ) -> T::Out;
448
449 /// Value of argument from row leading current row within partition
450 ///
451 /// Returns value evaluated at the row that is offset rows after the current
452 /// row within the partition; if there is no such row,
453 /// `NULL` will be returned instead.
454 ///
455 /// See [`lead_with_offset`] and [`lead_with_offset_and_default`] for variants with configurable offset
456 /// and default values.
457 ///
458 /// This function must be used as window function. You need to call at least one
459 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
460 /// clause. It cannot be used outside of `SELECT` clauses.
461 ///
462 /// For MySQL this function requires you to call [`.window_order()`](WindowExpressionMethods::window_order())
463 ///
464 /// ```
465 /// # include!("../../doctest_setup.rs");
466 /// # use diesel::dsl::*;
467 /// #
468 /// # fn main() -> QueryResult<()> {
469 /// # use schema::posts::dsl::*;
470 /// # let connection = &mut establish_connection();
471 /// let res = posts
472 /// .select((
473 /// title,
474 /// user_id,
475 /// lead(id).partition_by(user_id).window_order(user_id),
476 /// ))
477 /// .load::<(String, i32, Option<i32>)>(connection)?;
478 /// let expected = vec![
479 /// ("My first post".to_owned(), 1, Some(2)),
480 /// ("About Rust".into(), 1, None),
481 /// ("My first post too".into(), 2, None),
482 /// ];
483 /// assert_eq!(expected, res);
484 /// # Ok(())
485 /// # }
486 /// ```
487 #[window(dialect(
488 BuiltInWindowFunctionRequireOrder,
489 crate::backend::sql_dialect::built_in_window_function_require_order::NoOrderRequired
490 ))]
491 #[cfg_attr(
492 feature = "mysql_backend",
493 window(backends(diesel::mysql::Mysql), require_order = true)
494 )]
495 fn lead<T: SqlType + SingleValue + IntoNullable<Nullable: SingleValue>>(
496 value: T,
497 ) -> T::Nullable;
498
499 /// Value of argument from row leading current row within partition
500 ///
501 /// Returns value evaluated at the row that is offset rows after the current
502 /// row within the partition; if there is no such row,
503 /// `NULL` is returned instead
504 ///
505 ///
506 /// This function must be used as window function. You need to call at least one
507 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
508 /// clause. It cannot be used outside of `SELECT` clauses.
509 ///
510 /// For MySQL this function requires you to call [`.window_order()`](WindowExpressionMethods::window_order())
511 ///
512 /// ```
513 /// # include!("../../doctest_setup.rs");
514 /// # use diesel::dsl::*;
515 /// #
516 /// # fn main() -> QueryResult<()> {
517 /// # use schema::posts::dsl::*;
518 /// # let connection = &mut establish_connection();
519 /// let res = posts
520 /// .select((
521 /// title,
522 /// user_id,
523 /// lead_with_offset(id, 1)
524 /// .partition_by(user_id)
525 /// .window_order(user_id),
526 /// ))
527 /// .load::<(String, i32, Option<i32>)>(connection)?;
528 /// let expected = vec![
529 /// ("My first post".to_owned(), 1, Some(2)),
530 /// ("About Rust".into(), 1, None),
531 /// ("My first post too".into(), 2, None),
532 /// ];
533 /// assert_eq!(expected, res);
534 /// # Ok(())
535 /// # }
536 /// ```
537 #[doc(alias = "lead")]
538 #[sql_name = "lead"]
539 #[window(dialect(
540 BuiltInWindowFunctionRequireOrder,
541 crate::backend::sql_dialect::built_in_window_function_require_order::NoOrderRequired
542 ))]
543 #[cfg_attr(
544 feature = "mysql_backend",
545 window(backends(diesel::mysql::Mysql), require_order = true)
546 )]
547 fn lead_with_offset<T: SqlType + SingleValue + IntoNullable<Nullable: SingleValue>>(
548 value: T,
549 offset: Integer,
550 ) -> T::Nullable;
551
552 /// Value of argument from row leading current row within partition
553 ///
554 /// Returns value evaluated at the row that is offset rows after the current
555 /// row within the partition; if there is no such row,
556 /// instead returns default (which must be of a type compatible with value).
557 /// Both offset and default are evaluated with respect to the current row.
558 /// If omitted, offset defaults to 1 and default to NULL.
559 ///
560 /// This function returns a nullable value if either the value or the default expression are
561 /// nullable.
562 ///
563 /// This function must be used as window function. You need to call at least one
564 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
565 /// clause. It cannot be used outside of `SELECT` clauses.
566 ///
567 /// For MySQL this function requires you to call [`.window_order()`](WindowExpressionMethods::window_order())
568 ///
569 /// ```
570 /// # include!("../../doctest_setup.rs");
571 /// # use diesel::dsl::*;
572 /// #
573 /// # #[cfg(not(feature = "mysql"))] // mariadb doesn't support this variant
574 /// # fn main() -> QueryResult<()> {
575 /// # use schema::posts::dsl::*;
576 /// # use diesel::sql_types::{Integer, Nullable};
577 /// # let connection = &mut establish_connection();
578 /// let res = posts
579 /// .select((
580 /// title,
581 /// user_id,
582 /// lead_with_offset_and_default(id, 1, user_id)
583 /// .partition_by(user_id)
584 /// .window_order(user_id),
585 /// ))
586 /// .load::<(String, i32, i32)>(connection)?;
587 /// let expected = vec![
588 /// ("My first post".to_owned(), 1, 2),
589 /// ("About Rust".into(), 1, 1),
590 /// ("My first post too".into(), 2, 2),
591 /// ];
592 /// assert_eq!(expected, res);
593 ///
594 /// let res = posts
595 /// .select((
596 /// title,
597 /// user_id,
598 /// lead_with_offset_and_default(None::<i32>.into_sql::<Nullable<Integer>>(), 1, user_id)
599 /// .partition_by(user_id)
600 /// .window_order(user_id),
601 /// ))
602 /// .load::<(String, i32, Option<i32>)>(connection)?;
603 /// let expected = vec![
604 /// ("My first post".to_owned(), 1, None),
605 /// ("About Rust".into(), 1, Some(1)),
606 /// ("My first post too".into(), 2, Some(2)),
607 /// ];
608 /// assert_eq!(expected, res);
609 ///
610 /// let res = posts
611 /// .select((
612 /// title,
613 /// user_id,
614 /// lead_with_offset_and_default(id, 1, None::<i32>.into_sql::<Nullable<Integer>>())
615 /// .partition_by(user_id)
616 /// .window_order(user_id),
617 /// ))
618 /// .load::<(String, i32, Option<i32>)>(connection)?;
619 /// let expected = vec![
620 /// ("My first post".to_owned(), 1, Some(2)),
621 /// ("About Rust".into(), 1, None),
622 /// ("My first post too".into(), 2, None),
623 /// ];
624 /// assert_eq!(expected, res);
625 /// # Ok(())
626 /// # }
627 /// # #[cfg(feature = "mysql")]
628 /// fn main() {}
629 /// ```
630 #[doc(alias = "lead")]
631 #[sql_name = "lead"]
632 #[window(dialect(
633 BuiltInWindowFunctionRequireOrder,
634 crate::backend::sql_dialect::built_in_window_function_require_order::NoOrderRequired
635 ))]
636 #[cfg_attr(
637 feature = "mysql_backend",
638 window(backends(diesel::mysql::Mysql), require_order = true)
639 )]
640 fn lead_with_offset_and_default<
641 T: SqlType
642 + SingleValue
643 + IntoNotNullable<NotNullable: self::private::SameType<T2::NotNullable>>
644 + CombinedNullableValue<T2, T::NotNullable>,
645 T2: SqlType + SingleValue + IntoNotNullable,
646 >(
647 value: T,
648 offset: Integer,
649 default: T2,
650 ) -> T::Out;
651
652 /// Value of argument from first row of window frame
653 ///
654 /// Returns value evaluated at the row that is the first row of the window frame.
655 ///
656 ///
657 /// This function must be used as window function. You need to call at least one
658 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
659 /// clause. It cannot be used outside of `SELECT` clauses.
660 ///
661 /// ```
662 /// # include!("../../doctest_setup.rs");
663 /// # use diesel::dsl::*;
664 /// #
665 /// # fn main() -> QueryResult<()> {
666 /// # use schema::posts::dsl::*;
667 /// # let connection = &mut establish_connection();
668 /// let res = posts
669 /// .select((title, user_id, first_value(id).partition_by(user_id)))
670 /// .load::<(String, i32, i32)>(connection)?;
671 /// let expected = vec![
672 /// ("My first post".to_owned(), 1, 1),
673 /// ("About Rust".into(), 1, 1),
674 /// ("My first post too".into(), 2, 3),
675 /// ];
676 /// assert_eq!(expected, res);
677 /// # Ok(())
678 /// # }
679 /// ```
680 #[window]
681 fn first_value<T: SqlType + SingleValue>(value: T) -> T;
682
683 /// Value of argument from last row of window frame
684 ///
685 /// Returns value evaluated at the row that is the last row of the window frame.
686 ///
687 ///
688 /// This function must be used as window function. You need to call at least one
689 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
690 /// clause. It cannot be used outside of `SELECT` clauses.
691 ///
692 /// ```
693 /// # include!("../../doctest_setup.rs");
694 /// # use diesel::dsl::*;
695 /// #
696 /// # fn main() -> QueryResult<()> {
697 /// # use schema::posts::dsl::*;
698 /// # let connection = &mut establish_connection();
699 /// let res = posts
700 /// .select((title, user_id, last_value(id).partition_by(user_id)))
701 /// .load::<(String, i32, i32)>(connection)?;
702 /// let expected = vec![
703 /// ("My first post".to_owned(), 1, 2),
704 /// ("About Rust".into(), 1, 2),
705 /// ("My first post too".into(), 2, 3),
706 /// ];
707 /// assert_eq!(expected, res);
708 /// # Ok(())
709 /// # }
710 /// ```
711 #[window]
712 fn last_value<T: SqlType + SingleValue>(value: T) -> T;
713
714 /// Value of argument from N-th row of window frame
715 ///
716 /// Returns value evaluated at the row that is the n'th row of the window frame (counting from 1);
717 /// returns NULL if there is no such row.
718 ///
719 ///
720 /// This function must be used as window function. You need to call at least one
721 /// of the methods [`WindowExpressionMethods`] from to use this function in your `SELECT`
722 /// clause. It cannot be used outside of `SELECT` clauses.
723 ///
724 /// ```
725 /// # include!("../../doctest_setup.rs");
726 /// # use diesel::dsl::*;
727 /// #
728 /// # fn main() -> QueryResult<()> {
729 /// # use schema::posts::dsl::*;
730 /// # let connection = &mut establish_connection();
731 /// let res = posts
732 /// .select((title, user_id, nth_value(id, 2).partition_by(user_id)))
733 /// .load::<(String, i32, Option<i32>)>(connection)?;
734 /// let expected = vec![
735 /// ("My first post".to_owned(), 1, Some(2)),
736 /// ("About Rust".into(), 1, Some(2)),
737 /// ("My first post too".into(), 2, None),
738 /// ];
739 /// assert_eq!(expected, res);
740 /// # Ok(())
741 /// # }
742 /// ```
743 #[window]
744 fn nth_value<T: SqlType + SingleValue + IntoNullable<Nullable: SingleValue>>(
745 value: T,
746 n: Integer,
747 ) -> T::Nullable;
748}
749
750mod private {
751 pub trait SameType<T> {}
752
753 impl<T> SameType<T> for T {}
754}