Skip to main content

nodedb_query/window/
offset.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Offset window functions: lag, lead, nth_value.
4
5use nodedb_types::Value;
6
7use super::arg::{arg_at, const_default_arg, const_usize_arg, eval_arg_values};
8use super::helpers::set_window_col;
9use super::spec::WindowFuncSpec;
10
11pub(super) fn apply_lag(
12    rows: &mut [(String, Value)],
13    indices: &[usize],
14    spec: &WindowFuncSpec,
15) -> Result<(), crate::expr::EvalError> {
16    let arg_values = eval_arg_values(rows, indices, spec, 0)?;
17    let offset = const_usize_arg(spec, 1, 1);
18    let default = const_default_arg(spec, 2);
19
20    for (pos, &i) in indices.iter().enumerate() {
21        let val = if pos >= offset {
22            arg_at(&arg_values, pos - offset)
23        } else {
24            default.clone()
25        };
26        set_window_col(&mut rows[i].1, &spec.alias, val);
27    }
28    Ok(())
29}
30
31pub(super) fn apply_lead(
32    rows: &mut [(String, Value)],
33    indices: &[usize],
34    spec: &WindowFuncSpec,
35) -> Result<(), crate::expr::EvalError> {
36    let arg_values = eval_arg_values(rows, indices, spec, 0)?;
37    let offset = const_usize_arg(spec, 1, 1);
38    let default = const_default_arg(spec, 2);
39
40    for (pos, &i) in indices.iter().enumerate() {
41        let val = if pos + offset < indices.len() {
42            arg_at(&arg_values, pos + offset)
43        } else {
44            default.clone()
45        };
46        set_window_col(&mut rows[i].1, &spec.alias, val);
47    }
48    Ok(())
49}
50
51/// PostgreSQL `nth_value(expr, n)` — value of `expr` at the n'th row of the
52/// window frame, NULL if the frame doesn't yet contain n rows. Default frame
53/// is RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, so the first n-1
54/// rows of each partition return NULL and rows from the n'th onward return
55/// the value of `expr` at the n'th row.
56pub(super) fn apply_nth_value(
57    rows: &mut [(String, Value)],
58    indices: &[usize],
59    spec: &WindowFuncSpec,
60) -> Result<(), crate::expr::EvalError> {
61    let arg_values = eval_arg_values(rows, indices, spec, 0)?;
62    let n = const_usize_arg(spec, 1, 1).max(1);
63
64    for (pos, &i) in indices.iter().enumerate() {
65        let val = if pos + 1 >= n {
66            arg_at(&arg_values, n - 1)
67        } else {
68            Value::Null
69        };
70        set_window_col(&mut rows[i].1, &spec.alias, val);
71    }
72    Ok(())
73}