Skip to main content

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