Skip to main content

drizzle_core/expr/
window.rs

1//! Window functions and the `OVER (...)` clause.
2//!
3//! - [`window`] starts a window specification ([`WindowSpec`]) with
4//!   `PARTITION BY`, `ORDER BY` and a frame.
5//! - `.over(spec)` on an aggregate (such as [`sum`](super::sum) or
6//!   [`count`](super::count)) makes it a window function. The result is
7//!   scalar, so it can sit next to plain columns without `GROUP BY`.
8//! - Pure window functions ([`row_number`], [`rank`], [`lag`], ...) return a
9//!   [`WindowFnExpr`], which cannot be used until `.over(...)` is called.
10//!
11//! # Examples
12//!
13//! ```rust
14//! # use drizzle_core::asc;
15//! # use drizzle_core::desc;
16//! # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
17//! # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
18//! # #[derive(Clone, Debug)] struct Value(String);
19//! # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
20//! # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
21//! # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
22//! # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
23//! # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
24//! # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
25//! # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
26//! # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
27//! let running_total = sum(users.score).over(window().order_by(asc(users.id)));
28//! assert_eq!(
29//!     running_total.sql(),
30//!     r#"SUM ("users"."score") OVER (ORDER BY "users"."id" ASC)"#
31//! );
32//!
33//! let position = row_number().over(window().partition_by([users.name]).order_by(desc(users.age)));
34//! assert_eq!(
35//!     position.sql(),
36//!     r#"ROW_NUMBER() OVER (PARTITION BY "users"."name" ORDER BY "users"."age" DESC)"#
37//! );
38//! ```
39
40use crate::dialect::{DialectSupports, feature};
41use core::marker::PhantomData;
42
43use crate::sql::{SQL, Token};
44use crate::traits::{SQLParam, ToSQL};
45use crate::types::{BooleanLike, Compatible, DataType};
46
47use super::{Agg, Expr, ExprSources, NonNull, Null, Nullability, SQLExpr, Scalar};
48use crate::dialect::DialectTypes;
49use crate::scope::ScopeOnly;
50
51impl DialectSupports<feature::AggregateFilter> for crate::SQLiteDialect {}
52impl DialectSupports<feature::AggregateFilter> for crate::PostgresDialect {}
53
54// =============================================================================
55// Frame Bounds
56// =============================================================================
57
58/// One end of a window frame, for [`WindowSpec::rows_between`] and
59/// [`WindowSpec::range_between`].
60#[derive(Debug, Clone, Copy)]
61pub enum FrameBound {
62    /// `UNBOUNDED PRECEDING`: the first row of the partition.
63    UnboundedPreceding,
64    /// `n PRECEDING`: `n` rows (or, for `RANGE`, values) before the current row.
65    Preceding(u64),
66    /// `CURRENT ROW`.
67    CurrentRow,
68    /// `n FOLLOWING`: `n` rows (or, for `RANGE`, values) after the current row.
69    Following(u64),
70    /// `UNBOUNDED FOLLOWING`: the last row of the partition.
71    UnboundedFollowing,
72}
73
74impl FrameBound {
75    fn write_sql<'a, V: SQLParam>(&self) -> SQL<'a, V> {
76        match self {
77            Self::UnboundedPreceding => SQL::from(Token::UNBOUNDED).push(Token::PRECEDING),
78            Self::Preceding(n) => {
79                SQL::number(usize::try_from(*n).unwrap_or(usize::MAX)).push(Token::PRECEDING)
80            }
81            Self::CurrentRow => SQL::from(Token::CURRENT).push(Token::ROW),
82            Self::Following(n) => {
83                SQL::number(usize::try_from(*n).unwrap_or(usize::MAX)).push(Token::FOLLOWING)
84            }
85            Self::UnboundedFollowing => SQL::from(Token::UNBOUNDED).push(Token::FOLLOWING),
86        }
87    }
88}
89
90// =============================================================================
91// WindowSpec
92// =============================================================================
93
94/// The contents of an `OVER (...)` clause; start one with [`window`].
95///
96/// `S` records the tables that `PARTITION BY` and `ORDER BY` read, for the
97/// query's scope check.
98///
99/// # Examples
100///
101/// ```rust
102/// # use drizzle_core::asc;
103/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
104/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
105/// # #[derive(Clone, Debug)] struct Value(String);
106/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
107/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
108/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
109/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
110/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
111/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
112/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
113/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
114/// let spec = window()
115///     .partition_by([users.name])
116///     .order_by(asc(users.created_at))
117///     .rows_between(FrameBound::UnboundedPreceding, FrameBound::CurrentRow);
118/// let total = sum(users.score).over(spec);
119/// assert_eq!(
120///     total.sql(),
121///     r#"SUM ("users"."score") OVER (PARTITION BY "users"."name" ORDER BY "users"."created_at" ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)"#
122/// );
123/// ```
124#[derive(Debug, Clone)]
125pub struct WindowSpec<'a, V: SQLParam, S = ()> {
126    partition: Option<SQL<'a, V>>,
127    order: Option<SQL<'a, V>>,
128    frame: Option<SQL<'a, V>>,
129    /// Sources read by `PARTITION BY` / `ORDER BY` (never NULL-making).
130    sources: PhantomData<fn() -> S>,
131}
132
133/// Starts an empty window specification (`OVER ()`).
134///
135/// An empty window covers the whole result set.
136///
137/// # Examples
138///
139/// ```rust
140/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
141/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
142/// # #[derive(Clone, Debug)] struct Value(String);
143/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
144/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
145/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
146/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
147/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
148/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
149/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
150/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
151/// let share = count::<Value, _>(()).over(window());
152/// assert_eq!(share.sql(), "COUNT(*) OVER ()");
153/// ```
154#[must_use]
155pub const fn window<'a, V: SQLParam>() -> WindowSpec<'a, V> {
156    WindowSpec {
157        partition: None,
158        order: None,
159        frame: None,
160        sources: PhantomData,
161    }
162}
163
164impl<'a, V: SQLParam + 'a, S> WindowSpec<'a, V, S> {
165    fn with_sources<S2>(self) -> WindowSpec<'a, V, S2> {
166        WindowSpec {
167            partition: self.partition,
168            order: self.order,
169            frame: self.frame,
170            sources: PhantomData,
171        }
172    }
173
174    /// Sets `PARTITION BY`; the window restarts for each distinct value.
175    ///
176    /// Takes an array or other iterator of expressions of one Rust type.
177    #[must_use]
178    #[allow(clippy::type_complexity)]
179    pub fn partition_by<I>(
180        mut self,
181        exprs: I,
182    ) -> WindowSpec<'a, V, (S, ScopeOnly<<I::Item as ExprSources>::Sources>)>
183    where
184        I: IntoIterator,
185        I::Item: ToSQL<'a, V> + ExprSources,
186    {
187        self.partition = Some(
188            SQL::from(Token::PARTITION)
189                .push(Token::BY)
190                .append(SQL::join(exprs, Token::COMMA)),
191        );
192        self.with_sources()
193    }
194
195    /// Sets `ORDER BY` inside the window.
196    ///
197    /// Takes one ordering term such as [`asc`](crate::asc)`(col)`, or a tuple or
198    /// array of terms.
199    #[must_use]
200    pub fn order_by<T: ToSQL<'a, V> + ExprSources>(
201        mut self,
202        exprs: T,
203    ) -> WindowSpec<'a, V, (S, ScopeOnly<T::Sources>)> {
204        self.order = Some(
205            SQL::from(Token::ORDER)
206                .push(Token::BY)
207                .append(exprs.into_sql()),
208        );
209        self.with_sources()
210    }
211
212    /// Sets a `ROWS BETWEEN start AND end` frame, counted in rows.
213    #[must_use]
214    pub fn rows_between(mut self, start: FrameBound, end: FrameBound) -> Self {
215        self.frame = Some(
216            SQL::from(Token::ROWS)
217                .push(Token::BETWEEN)
218                .append(start.write_sql())
219                .push(Token::AND)
220                .append(end.write_sql()),
221        );
222        self
223    }
224
225    /// Sets a `RANGE BETWEEN start AND end` frame, measured in `ORDER BY` values.
226    #[must_use]
227    pub fn range_between(mut self, start: FrameBound, end: FrameBound) -> Self {
228        self.frame = Some(
229            SQL::from(Token::RANGE)
230                .push(Token::BETWEEN)
231                .append(start.write_sql())
232                .push(Token::AND)
233                .append(end.write_sql()),
234        );
235        self
236    }
237
238    /// Renders the clause contents, without the surrounding `OVER (...)`.
239    fn into_sql(self) -> SQL<'a, V> {
240        let mut sql = SQL::empty();
241        if let Some(p) = self.partition {
242            sql.append_mut(p);
243        }
244        if let Some(o) = self.order {
245            sql.append_mut(o);
246        }
247        if let Some(f) = self.frame {
248            sql.append_mut(f);
249        }
250        sql
251    }
252}
253
254// =============================================================================
255// .over() on aggregate expressions — Agg → Scalar
256// =============================================================================
257
258impl<'a, V, T, N, S> SQLExpr<'a, V, T, N, Agg, S>
259where
260    V: SQLParam + 'a,
261    T: DataType,
262    N: Nullability,
263{
264    /// Turns this aggregate into a window function (`agg OVER (...)`).
265    ///
266    /// The result keeps the SQL type and nullability but is scalar, so it can
267    /// be selected next to plain columns.
268    ///
269    /// # Examples
270    ///
271    /// ```rust
272    /// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
273    /// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
274    /// # #[derive(Clone, Debug)] struct Value(String);
275    /// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
276    /// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
277    /// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
278    /// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
279    /// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
280    /// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
281    /// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
282    /// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
283    /// let per_name = sum(users.score).over(window().partition_by([users.name]));
284    /// assert_eq!(
285    ///     per_name.sql(),
286    ///     r#"SUM ("users"."score") OVER (PARTITION BY "users"."name")"#
287    /// );
288    /// ```
289    pub fn over<W>(self, spec: WindowSpec<'a, V, W>) -> SQLExpr<'a, V, T, N, Scalar, (S, W)> {
290        let sql = self
291            .into_sql()
292            .push(Token::OVER)
293            .push(Token::LPAREN)
294            .append(spec.into_sql())
295            .push(Token::RPAREN);
296        SQLExpr::new(sql)
297    }
298
299    /// Limits the rows an aggregate sees (`agg FILTER (WHERE condition)`), on
300    /// SQLite and PostgreSQL.
301    ///
302    /// The condition must be boolean. The result is still an aggregate.
303    ///
304    /// # Examples
305    ///
306    /// ```rust
307    /// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
308    /// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
309    /// # #[derive(Clone, Debug)] struct Value(String);
310    /// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
311    /// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
312    /// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
313    /// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
314    /// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
315    /// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
316    /// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
317    /// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
318    /// let adults = count(users.id).filter(gt(users.age, 18));
319    /// assert_eq!(
320    ///     adults.sql(),
321    ///     r#"COUNT ("users"."id") FILTER (WHERE "users"."age" > ?)"#
322    /// );
323    /// ```
324    #[allow(clippy::type_complexity)]
325    pub fn filter<C>(self, condition: C) -> SQLExpr<'a, V, T, N, Agg, (S, ScopeOnly<C::Sources>)>
326    where
327        C: Expr<'a, V>,
328        C::SQLType: BooleanLike,
329        V::DialectMarker: DialectSupports<feature::AggregateFilter>,
330    {
331        let sql = self
332            .into_sql()
333            .push(Token::FILTER)
334            .push(Token::LPAREN)
335            .push(Token::WHERE)
336            .append(condition.into_expr_sql())
337            .push(Token::RPAREN);
338        SQLExpr::new(sql)
339    }
340}
341
342// =============================================================================
343// WindowFnExpr — pure window functions that require .over()
344// =============================================================================
345
346/// A window function that still needs its `OVER (...)` clause.
347///
348/// [`row_number`], [`rank`], [`lag`] and the other pure window functions
349/// return this type. It implements neither [`Expr`] nor [`ToSQL`], so it
350/// cannot be used in a query until [`over`](Self::over) is called.
351///
352/// ```rust,compile_fail
353/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
354/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
355/// # #[derive(Clone, Debug)] struct Value(String);
356/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
357/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
358/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
359/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
360/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
361/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
362/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
363/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
364/// // ROW_NUMBER() without OVER is not an expression.
365/// let wrong = gt(row_number::<Value>(), 1);
366/// ```
367#[derive(Debug, Clone)]
368pub struct WindowFnExpr<'a, V: SQLParam, T: DataType, N: Nullability, S = ()> {
369    sql: SQL<'a, V>,
370    _marker: super::TypeMarker<(T, N, S)>,
371}
372
373impl<'a, V, T, N, S> WindowFnExpr<'a, V, T, N, S>
374where
375    V: SQLParam + 'a,
376    T: DataType,
377    N: Nullability,
378{
379    const fn new(sql: SQL<'a, V>) -> Self {
380        Self {
381            sql,
382            _marker: PhantomData,
383        }
384    }
385
386    /// Adds the window clause, producing a scalar expression (`fn OVER (...)`).
387    pub fn over<W>(self, spec: WindowSpec<'a, V, W>) -> SQLExpr<'a, V, T, N, Scalar, (S, W)> {
388        let sql = self
389            .sql
390            .push(Token::OVER)
391            .push(Token::LPAREN)
392            .append(spec.into_sql())
393            .push(Token::RPAREN);
394        SQLExpr::new(sql)
395    }
396}
397
398// =============================================================================
399// Pure Window Functions
400// =============================================================================
401
402/// Number of the row within its partition, from 1 (`ROW_NUMBER()`).
403///
404/// The result is the dialect's big-integer type and never NULL.
405///
406/// # Examples
407///
408/// ```rust
409/// # use drizzle_core::asc;
410/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
411/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
412/// # #[derive(Clone, Debug)] struct Value(String);
413/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
414/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
415/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
416/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
417/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
418/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
419/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
420/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
421/// let n = row_number().over(window().order_by(asc(users.age)));
422/// assert_eq!(n.sql(), r#"ROW_NUMBER() OVER (ORDER BY "users"."age" ASC)"#);
423/// ```
424#[must_use]
425pub fn row_number<'a, V>()
426-> WindowFnExpr<'a, V, <V::DialectMarker as DialectTypes>::BigInt, NonNull>
427where
428    V: SQLParam + 'a,
429{
430    WindowFnExpr::new(SQL::raw("ROW_NUMBER()"))
431}
432
433/// Rank of the row, with gaps after ties (`RANK()`).
434///
435/// Tied rows share a rank and the next rank skips ahead (1, 1, 3). The result
436/// is the dialect's big-integer type and never NULL.
437///
438/// # Examples
439///
440/// ```rust
441/// # use drizzle_core::asc;
442/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
443/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
444/// # #[derive(Clone, Debug)] struct Value(String);
445/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
446/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
447/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
448/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
449/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
450/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
451/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
452/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
453/// let n = rank().over(window().order_by(asc(users.age)));
454/// assert_eq!(n.sql(), r#"RANK() OVER (ORDER BY "users"."age" ASC)"#);
455/// ```
456#[must_use]
457pub fn rank<'a, V>() -> WindowFnExpr<'a, V, <V::DialectMarker as DialectTypes>::BigInt, NonNull>
458where
459    V: SQLParam + 'a,
460{
461    WindowFnExpr::new(SQL::raw("RANK()"))
462}
463
464/// Rank of the row, without gaps after ties (`DENSE_RANK()`).
465///
466/// Tied rows share a rank and the next rank follows on (1, 1, 2). The result
467/// is the dialect's big-integer type and never NULL.
468///
469/// # Examples
470///
471/// ```rust
472/// # use drizzle_core::asc;
473/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
474/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
475/// # #[derive(Clone, Debug)] struct Value(String);
476/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
477/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
478/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
479/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
480/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
481/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
482/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
483/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
484/// let n = dense_rank().over(window().order_by(asc(users.age)));
485/// assert_eq!(n.sql(), r#"DENSE_RANK() OVER (ORDER BY "users"."age" ASC)"#);
486/// ```
487#[must_use]
488pub fn dense_rank<'a, V>()
489-> WindowFnExpr<'a, V, <V::DialectMarker as DialectTypes>::BigInt, NonNull>
490where
491    V: SQLParam + 'a,
492{
493    WindowFnExpr::new(SQL::raw("DENSE_RANK()"))
494}
495
496/// Splits the partition into `n` groups of nearly equal size (`NTILE(n)`).
497///
498/// Returns the group number, from 1. The result is the dialect's integer type
499/// and never NULL.
500///
501/// # Examples
502///
503/// ```rust
504/// # use drizzle_core::asc;
505/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
506/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
507/// # #[derive(Clone, Debug)] struct Value(String);
508/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
509/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
510/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
511/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
512/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
513/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
514/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
515/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
516/// let n = ntile(4).over(window().order_by(asc(users.age)));
517/// assert_eq!(n.sql(), r#"NTILE (4) OVER (ORDER BY "users"."age" ASC)"#);
518/// ```
519#[must_use]
520pub fn ntile<'a, V>(
521    n: usize,
522) -> WindowFnExpr<'a, V, <V::DialectMarker as DialectTypes>::Int, NonNull>
523where
524    V: SQLParam + 'a,
525{
526    WindowFnExpr::new(SQL::func("NTILE", SQL::number(n)))
527}
528
529/// Relative rank: `(rank - 1) / (rows - 1)` (`PERCENT_RANK()`).
530///
531/// The result is the dialect's double type, between 0 and 1, and never NULL.
532///
533/// # Examples
534///
535/// ```rust
536/// # use drizzle_core::asc;
537/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
538/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
539/// # #[derive(Clone, Debug)] struct Value(String);
540/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
541/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
542/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
543/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
544/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
545/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
546/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
547/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
548/// let n = percent_rank().over(window().order_by(asc(users.age)));
549/// assert_eq!(n.sql(), r#"PERCENT_RANK() OVER (ORDER BY "users"."age" ASC)"#);
550/// ```
551#[must_use]
552pub fn percent_rank<'a, V>()
553-> WindowFnExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, NonNull>
554where
555    V: SQLParam + 'a,
556{
557    WindowFnExpr::new(SQL::raw("PERCENT_RANK()"))
558}
559
560/// Fraction of rows ordered at or before this row (`CUME_DIST()`).
561///
562/// The result is the dialect's double type, greater than 0 and at most 1, and
563/// never NULL.
564///
565/// # Examples
566///
567/// ```rust
568/// # use drizzle_core::asc;
569/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
570/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
571/// # #[derive(Clone, Debug)] struct Value(String);
572/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
573/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
574/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
575/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
576/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
577/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
578/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
579/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
580/// let n = cume_dist().over(window().order_by(asc(users.age)));
581/// assert_eq!(n.sql(), r#"CUME_DIST() OVER (ORDER BY "users"."age" ASC)"#);
582/// ```
583#[must_use]
584pub fn cume_dist<'a, V>() -> WindowFnExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, NonNull>
585where
586    V: SQLParam + 'a,
587{
588    WindowFnExpr::new(SQL::raw("CUME_DIST()"))
589}
590
591/// The value of `expr` in the previous row (`LAG(expr)`).
592///
593/// The result has `expr`'s SQL type and is always nullable: the first row has
594/// no previous row.
595///
596/// # Examples
597///
598/// ```rust
599/// # use drizzle_core::asc;
600/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
601/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
602/// # #[derive(Clone, Debug)] struct Value(String);
603/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
604/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
605/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
606/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
607/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
608/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
609/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
610/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
611/// let n = lag(users.name).over(window().order_by(asc(users.age)));
612/// assert_eq!(n.sql(), r#"LAG ("users"."name") OVER (ORDER BY "users"."age" ASC)"#);
613/// ```
614pub fn lag<'a, V, E>(expr: E) -> WindowFnExpr<'a, V, E::SQLType, Null, E::Sources>
615where
616    V: SQLParam + 'a,
617    E: Expr<'a, V>,
618{
619    WindowFnExpr::new(SQL::func("LAG", expr.into_sql()))
620}
621
622/// The value of `expr` `offset` rows back, or `default` (`LAG(expr, offset, default)`).
623///
624/// `default` must have a type compatible with `expr`. The result has `expr`'s
625/// SQL type and is nullable if `expr` or `default` is.
626///
627/// # Examples
628///
629/// ```rust
630/// # use drizzle_core::asc;
631/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
632/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
633/// # #[derive(Clone, Debug)] struct Value(String);
634/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
635/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
636/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
637/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
638/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
639/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
640/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
641/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
642/// let n = lag_with_default(users.name, 2, "none").over(window().order_by(asc(users.age)));
643/// assert_eq!(n.sql(), r#"LAG ("users"."name", 2, ?) OVER (ORDER BY "users"."age" ASC)"#);
644/// ```
645#[allow(clippy::type_complexity)]
646pub fn lag_with_default<'a, V, E, D>(
647    expr: E,
648    offset: usize,
649    default: D,
650) -> WindowFnExpr<
651    'a,
652    V,
653    E::SQLType,
654    <E::Nullable as Nullability>::Or<D::Nullable>,
655    (E::Sources, D::Sources),
656>
657where
658    V: SQLParam + 'a,
659    E: Expr<'a, V>,
660    D: Expr<'a, V>,
661    E::SQLType: Compatible<D::SQLType>,
662    D::Nullable: Nullability,
663{
664    let args = expr
665        .into_sql()
666        .push(Token::COMMA)
667        .append(SQL::number(offset))
668        .push(Token::COMMA)
669        .append(default.into_sql());
670    WindowFnExpr::new(SQL::func("LAG", args))
671}
672
673/// The value of `expr` in the next row (`LEAD(expr)`).
674///
675/// The result has `expr`'s SQL type and is always nullable: the last row has
676/// no next row.
677///
678/// # Examples
679///
680/// ```rust
681/// # use drizzle_core::asc;
682/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
683/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
684/// # #[derive(Clone, Debug)] struct Value(String);
685/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
686/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
687/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
688/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
689/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
690/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
691/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
692/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
693/// let n = lead(users.name).over(window().order_by(asc(users.age)));
694/// assert_eq!(n.sql(), r#"LEAD ("users"."name") OVER (ORDER BY "users"."age" ASC)"#);
695/// ```
696pub fn lead<'a, V, E>(expr: E) -> WindowFnExpr<'a, V, E::SQLType, Null, E::Sources>
697where
698    V: SQLParam + 'a,
699    E: Expr<'a, V>,
700{
701    WindowFnExpr::new(SQL::func("LEAD", expr.into_sql()))
702}
703
704/// The value of `expr` `offset` rows ahead, or `default` (`LEAD(expr, offset, default)`).
705///
706/// `default` must have a type compatible with `expr`. The result has `expr`'s
707/// SQL type and is nullable if `expr` or `default` is.
708///
709/// # Examples
710///
711/// ```rust
712/// # use drizzle_core::asc;
713/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
714/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
715/// # #[derive(Clone, Debug)] struct Value(String);
716/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
717/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
718/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
719/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
720/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
721/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
722/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
723/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
724/// let n = lead_with_default(users.name, 1, "none").over(window().order_by(asc(users.age)));
725/// assert_eq!(n.sql(), r#"LEAD ("users"."name", 1, ?) OVER (ORDER BY "users"."age" ASC)"#);
726/// ```
727#[allow(clippy::type_complexity)]
728pub fn lead_with_default<'a, V, E, D>(
729    expr: E,
730    offset: usize,
731    default: D,
732) -> WindowFnExpr<
733    'a,
734    V,
735    E::SQLType,
736    <E::Nullable as Nullability>::Or<D::Nullable>,
737    (E::Sources, D::Sources),
738>
739where
740    V: SQLParam + 'a,
741    E: Expr<'a, V>,
742    D: Expr<'a, V>,
743    E::SQLType: Compatible<D::SQLType>,
744    D::Nullable: Nullability,
745{
746    let args = expr
747        .into_sql()
748        .push(Token::COMMA)
749        .append(SQL::number(offset))
750        .push(Token::COMMA)
751        .append(default.into_sql());
752    WindowFnExpr::new(SQL::func("LEAD", args))
753}
754
755/// The value of `expr` in the first row of the frame (`FIRST_VALUE(expr)`).
756///
757/// The result has `expr`'s SQL type and is typed as nullable.
758///
759/// # Examples
760///
761/// ```rust
762/// # use drizzle_core::asc;
763/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
764/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
765/// # #[derive(Clone, Debug)] struct Value(String);
766/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
767/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
768/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
769/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
770/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
771/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
772/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
773/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
774/// let n = first_value(users.name).over(window().order_by(asc(users.age)));
775/// assert_eq!(n.sql(), r#"FIRST_VALUE ("users"."name") OVER (ORDER BY "users"."age" ASC)"#);
776/// ```
777pub fn first_value<'a, V, E>(expr: E) -> WindowFnExpr<'a, V, E::SQLType, Null, E::Sources>
778where
779    V: SQLParam + 'a,
780    E: Expr<'a, V>,
781{
782    WindowFnExpr::new(SQL::func("FIRST_VALUE", expr.into_sql()))
783}
784
785/// The value of `expr` in the last row of the frame (`LAST_VALUE(expr)`).
786///
787/// With an `ORDER BY` and the default frame, the frame ends at the current
788/// row (and its ties); use [`WindowSpec::rows_between`] to look further.
789/// The result has `expr`'s SQL type and is typed as nullable.
790///
791/// # Examples
792///
793/// ```rust
794/// # use drizzle_core::asc;
795/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
796/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
797/// # #[derive(Clone, Debug)] struct Value(String);
798/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
799/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
800/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
801/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
802/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
803/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
804/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
805/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
806/// let n = last_value(users.name).over(window().order_by(asc(users.age)));
807/// assert_eq!(n.sql(), r#"LAST_VALUE ("users"."name") OVER (ORDER BY "users"."age" ASC)"#);
808/// ```
809pub fn last_value<'a, V, E>(expr: E) -> WindowFnExpr<'a, V, E::SQLType, Null, E::Sources>
810where
811    V: SQLParam + 'a,
812    E: Expr<'a, V>,
813{
814    WindowFnExpr::new(SQL::func("LAST_VALUE", expr.into_sql()))
815}
816
817/// The value of `expr` in the `n`-th row of the frame, from 1 (`NTH_VALUE(expr, n)`).
818///
819/// The result has `expr`'s SQL type and is always nullable: the frame may
820/// have fewer than `n` rows.
821///
822/// # Examples
823///
824/// ```rust
825/// # use drizzle_core::asc;
826/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
827/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
828/// # #[derive(Clone, Debug)] struct Value(String);
829/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
830/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
831/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
832/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
833/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
834/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
835/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
836/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
837/// let n = nth_value(users.name, 2).over(window().order_by(asc(users.age)));
838/// assert_eq!(n.sql(), r#"NTH_VALUE ("users"."name", 2) OVER (ORDER BY "users"."age" ASC)"#);
839/// ```
840pub fn nth_value<'a, V, E>(expr: E, n: usize) -> WindowFnExpr<'a, V, E::SQLType, Null, E::Sources>
841where
842    V: SQLParam + 'a,
843    E: Expr<'a, V>,
844{
845    let args = expr.into_sql().push(Token::COMMA).append(SQL::number(n));
846    WindowFnExpr::new(SQL::func("NTH_VALUE", args))
847}