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: ::std::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> ::std::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> ::std::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> ::std::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> ::std::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()`](super::fn_name)"]
    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    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}