Path: blob/main/crates/polars-sql/tests/functions_windows.rs
7884 views
use polars_core::prelude::*;1use polars_lazy::prelude::*;2use polars_plan::dsl::Expr;3use polars_sql::*;45fn create_df() -> LazyFrame {6df! {7"a" => [1, 1, 1, 2, 2, 3],8"b" => ["a", "b", "c", "a", "b", "c"]9}10.unwrap()11.lazy()12}1314fn create_expected(exprs: &[Expr], sql: &str) -> (DataFrame, DataFrame) {15let df = create_df();1617let query = format!(18r#"19SELECT20{sql}21FROM22df23"#24);2526let expected = df.clone().select(exprs).collect().unwrap();27let mut ctx = SQLContext::new();28ctx.register("df", df);2930let actual = ctx.execute(&query).unwrap().collect().unwrap();31(expected, actual)32}3334fn ensure_error(sql: &str, expected_error: &str) {35let df = create_df();36let query = format!(37r#"38SELECT39{sql}40FROM41df42"#43);4445let mut ctx = SQLContext::new();46ctx.register("df", df);47match ctx.execute(&query) {48Ok(_) => panic!("expected error: {expected_error}"),49Err(e) => {50assert!(51e.to_string().contains(expected_error),52"expected error: {expected_error}, got: {e}",53)54},55};56}5758#[test]59fn test_lead_lag() {60for shift in [-2, -1, 1, 2] {61let (sql_func, sql_shift) = if shift > 0 {62("LAG", shift)63} else {64("LEAD", -shift)65};66let exprs = [67col("a"),68col("b"),69col("b")70.shift(shift.into())71.over_with_options(72Some([col("a")]),73Some(([col("b")], SortOptions::new().with_order_descending(false))),74Default::default(),75)76.unwrap()77.alias("c"),78];7980let sql_expr =81format!("a, b, {sql_func}(b, {sql_shift}) OVER (PARTITION BY a ORDER BY b) as c");82let (expected, actual) = create_expected(&exprs, &sql_expr);8384assert_eq!(expected, actual, "shift: {shift}");85}86}8788#[test]89fn test_lead_lag_default() {90for shift in [-1, 1] {91let sql_func = if shift > 0 { "LAG" } else { "LEAD" };92let exprs = [93col("a"),94col("b"),95col("b")96.shift(shift.into())97.over_with_options(98Some([col("a")]),99Some(([col("b")], SortOptions::new().with_order_descending(false))),100Default::default(),101)102.unwrap()103.alias("c"),104];105106let sql_expr = format!("a, b, {sql_func}(b) OVER (PARTITION BY a ORDER BY b) as c");107let (expected, actual) = create_expected(&exprs, &sql_expr);108109assert_eq!(expected, actual, "shift: {shift}");110}111}112113#[test]114fn test_incorrect_shift() {115for func in ["LAG", "LEAD"] {116// Type of second argument is not an integer117ensure_error(118&format!("a, b, {func}(b, '1') OVER (PARTITION BY a ORDER BY b) as c"),119"offset must be an integer",120);121ensure_error(122&format!("a, b, {func}(b, 1.0) OVER (PARTITION BY a ORDER BY b) as c"),123"offset must be an integer",124);125ensure_error(126&format!("a, b, {func}(b, 1.0) OVER (PARTITION BY a ORDER BY b) as c"),127"offset must be an integer",128);129130// Number of arguments is incorrect131ensure_error(132&format!("a, b, {func}() OVER (PARTITION BY a ORDER BY b) as c"),133"expects 1 or 2 arguments",134);135ensure_error(136&format!("a, b, {func}(b, 1, 2) OVER (PARTITION BY a ORDER BY b) as c"),137"expects 1 or 2 arguments",138);139140// Second argument is not a constant141ensure_error(142&format!("a, b, {func}(b, a) OVER (PARTITION BY a ORDER BY b) as c"),143"offset must be an integer",144);145ensure_error(146&format!("a, b, {func}(b, a + 1) OVER (PARTITION BY a ORDER BY b) as c"),147"offset must be an integer",148);149150// Second argument is not positive151ensure_error(152&format!("a, b, {func}(b, -1) OVER (PARTITION BY a ORDER BY b) as c"),153"offset must be positive",154);155ensure_error(156&format!("a, b, {func}(b, 0) OVER (PARTITION BY a ORDER BY b) as c"),157"offset must be positive",158);159}160}161162#[test]163fn test_lead_lag_without_partition_by() {164// Test LAG/LEAD with ORDER BY but without PARTITION BY165// This should work correctly over the entire dataset166for shift in [-1, 1] {167let (sql_func, shift_value) = if shift > 0 {168("LAG", shift)169} else {170("LEAD", -shift)171};172173let exprs = [174col("a"),175col("b"),176col("a")177.shift(shift.into())178.over_with_options(179None, // No partition by180Some(([col("a")], SortOptions::new().with_order_descending(false))),181Default::default(),182)183.unwrap()184.alias("a_shifted"),185];186187let sql_expr = format!("a, b, {sql_func}(a, {shift_value}) OVER (ORDER BY a) as a_shifted");188let (expected, actual) = create_expected(&exprs, &sql_expr);189190assert_eq!(expected, actual, "shift: {shift}");191}192}193194#[test]195fn test_lead_lag_without_over_clause() {196// LAG/LEAD without OVER clause should raise an error197for func in ["LAG", "LEAD"] {198ensure_error(&format!("a, b, {func}(b) as c"), "requires an OVER clause");199ensure_error(200&format!("a, b, {func}(b, 1) as c"),201"requires an OVER clause",202);203}204}205206#[test]207fn test_lead_lag_without_order_by() {208// LAG/LEAD with OVER clause but without ORDER BY should raise an error209for func in ["LAG", "LEAD"] {210ensure_error(211&format!("a, b, {func}(b) OVER (PARTITION BY a) as c"),212"requires an ORDER BY",213);214ensure_error(215&format!("a, b, {func}(b, 1) OVER (PARTITION BY a) as c"),216"requires an ORDER BY",217);218// OVER clause with empty parentheses219ensure_error(220&format!("a, b, {func}(b) OVER () as c"),221"requires an ORDER BY",222);223}224}225226227