Path: blob/main/crates/polars-plan/src/plans/aexpr/traverse.rs
8427 views
use super::*;12impl AExpr {3/// Push the inputs of this node to the given container, in reverse order.4/// This ensures the primary node responsible for the name is pushed last.5///6/// This is subtly different from `children_rev` as this only includes the input expressions,7/// not expressions used during evaluation.8pub fn inputs_rev<E>(&self, container: &mut E)9where10E: Extend<Node>,11{12use AExpr::*;1314match self {15Element | Column(_) | Literal(_) | Len => {},16#[cfg(feature = "dtype-struct")]17StructField(_) => {},18BinaryExpr { left, op: _, right } => {19container.extend([*right, *left]);20},21Cast { expr, .. } => container.extend([*expr]),22Sort { expr, .. } => container.extend([*expr]),23Gather { expr, idx, .. } => {24container.extend([*idx, *expr]);25},26SortBy { expr, by, .. } => {27container.extend(by.iter().cloned().rev());28container.extend([*expr]);29},30Filter { input, by } => {31container.extend([*by, *input]);32},33Agg(agg_e) => match agg_e.get_input() {34NodeInputs::Single(node) => container.extend([node]),35NodeInputs::Many(nodes) => container.extend(nodes.into_iter().rev()),36NodeInputs::Leaf => {},37},38Ternary {39truthy,40falsy,41predicate,42} => {43container.extend([*predicate, *falsy, *truthy]);44},45AnonymousFunction { input, .. }46| Function { input, .. }47| AnonymousAgg { input, .. } => container.extend(input.iter().rev().map(|e| e.node())),48Explode { expr: e, .. } => container.extend([*e]),49#[cfg(feature = "dynamic_group_by")]50Rolling {51function,52index_column,53period: _,54offset: _,55closed_window: _,56} => {57container.extend([*index_column, *function]);58},59Over {60function,61partition_by,62order_by,63mapping: _,64} => {65if let Some((n, _)) = order_by {66container.extend([*n]);67}68container.extend(partition_by.iter().rev().cloned());69container.extend([*function]);70},71Eval {72expr,73evaluation,74variant: _,75} => {76// We don't use the evaluation here because it does not contain inputs.77_ = evaluation;78container.extend([*expr]);79},80#[cfg(feature = "dtype-struct")]81StructEval { expr, evaluation } => {82// Evaluation is included. In case this is not allowed, use `inputs_rev_strict()`.83container.extend(evaluation.iter().rev().map(ExprIR::node));84container.extend([*expr]);85},86Slice {87input,88offset,89length,90} => {91container.extend([*length, *offset, *input]);92},93}94}9596/// Push the inputs of this node to the given container, in reverse order.97/// This ensures the primary node responsible for the name is pushed last.98///99/// Unlike `inputs_rev`, this excludes Eval expressions. These use an extended schema,100/// determined by their input, which implies a different traversal order.101///102/// This is subtly different from `children_rev` as this only includes the input expressions,103/// not expressions used during evaluation.104pub fn inputs_rev_strict<E>(&self, container: &mut E)105where106E: Extend<Node>,107{108use AExpr::*;109110match self {111#[cfg(feature = "dtype-struct")]112StructEval { expr, evaluation } => {113// Evaluation is explicitly excluded. It is up to the caller to handle114// any tree traversal if required.115_ = evaluation;116container.extend([*expr]);117},118expr => expr.inputs_rev(container),119}120}121122/// Push the children of this node to the given container, in reverse order.123/// This ensures the primary node responsible for the name is pushed last.124///125/// This is subtly different from `input_rev` as this only all expressions included in the126/// expression not only the input expressions,127pub fn children_rev<E: Extend<Node>>(&self, container: &mut E) {128use AExpr::*;129130match self {131Element | Column(_) | Literal(_) | Len => {},132#[cfg(feature = "dtype-struct")]133StructField(_) => {},134BinaryExpr { left, op: _, right } => {135container.extend([*right, *left]);136},137Cast { expr, .. } => container.extend([*expr]),138Sort { expr, .. } => container.extend([*expr]),139Gather { expr, idx, .. } => {140container.extend([*idx, *expr]);141},142SortBy { expr, by, .. } => {143container.extend(by.iter().cloned().rev());144container.extend([*expr]);145},146Filter { input, by } => {147container.extend([*by, *input]);148},149Agg(agg_e) => match agg_e.get_input() {150NodeInputs::Single(node) => container.extend([node]),151NodeInputs::Many(nodes) => container.extend(nodes.into_iter().rev()),152NodeInputs::Leaf => {},153},154Ternary {155truthy,156falsy,157predicate,158} => {159container.extend([*predicate, *falsy, *truthy]);160},161AnonymousFunction { input, .. }162| Function { input, .. }163| AnonymousAgg { input, .. } => container.extend(input.iter().rev().map(|e| e.node())),164Explode { expr: e, .. } => container.extend([*e]),165#[cfg(feature = "dynamic_group_by")]166Rolling {167function,168index_column,169period: _,170offset: _,171closed_window: _,172} => {173container.extend([*index_column, *function]);174},175Over {176function,177partition_by,178order_by,179mapping: _,180} => {181if let Some((n, _)) = order_by {182container.extend([*n]);183}184container.extend(partition_by.iter().rev().cloned());185container.extend([*function]);186},187Eval {188expr,189evaluation,190variant: _,191} => container.extend([*evaluation, *expr]),192#[cfg(feature = "dtype-struct")]193StructEval { expr, evaluation } => {194container.extend(evaluation.iter().rev().map(ExprIR::node));195container.extend([*expr]);196},197Slice {198input,199offset,200length,201} => {202container.extend([*length, *offset, *input]);203},204}205}206207pub fn replace_inputs(mut self, inputs: &[Node]) -> Self {208use AExpr::*;209let input = match &mut self {210Element | Column(_) | Literal(_) | Len => return self,211#[cfg(feature = "dtype-struct")]212StructField(_) => return self,213Cast { expr, .. } => expr,214Explode { expr, .. } => expr,215BinaryExpr { left, right, .. } => {216*left = inputs[0];217*right = inputs[1];218return self;219},220Gather { expr, idx, .. } => {221*expr = inputs[0];222*idx = inputs[1];223return self;224},225Sort { expr, .. } => expr,226SortBy { expr, by, .. } => {227*expr = inputs[0];228by.clear();229by.extend_from_slice(&inputs[1..]);230return self;231},232Filter { input, by, .. } => {233*input = inputs[0];234*by = inputs[1];235return self;236},237Agg(a) => {238match a {239IRAggExpr::Quantile {240expr,241quantile,242method: _,243} => {244*expr = inputs[0];245*quantile = inputs[1];246},247_ => {248a.set_input(inputs[0]);249},250}251return self;252},253Ternary {254truthy,255falsy,256predicate,257} => {258*truthy = inputs[0];259*falsy = inputs[1];260*predicate = inputs[2];261return self;262},263AnonymousFunction { input, .. }264| Function { input, .. }265| AnonymousAgg { input, .. } => {266assert_eq!(input.len(), inputs.len());267for (e, node) in input.iter_mut().zip(inputs.iter()) {268e.set_node(*node);269}270return self;271},272Eval {273expr,274evaluation,275variant: _,276} => {277*expr = inputs[0];278_ = evaluation; // Intentional.279return self;280},281#[cfg(feature = "dtype-struct")]282StructEval { expr, evaluation } => {283*expr = inputs[0];284_ = evaluation; // Intentional.285return self;286},287Slice {288input,289offset,290length,291} => {292*input = inputs[0];293*offset = inputs[1];294*length = inputs[2];295return self;296},297#[cfg(feature = "dynamic_group_by")]298Rolling {299function,300index_column,301period: _,302offset: _,303closed_window: _,304} => {305*function = inputs[0];306*index_column = inputs[1];307return self;308},309Over {310function,311partition_by,312order_by,313..314} => {315let offset = order_by.is_some() as usize;316*function = inputs[0];317partition_by.clear();318partition_by.extend_from_slice(&inputs[1..inputs.len() - offset]);319if let Some((_, options)) = order_by {320*order_by = Some((*inputs.last().unwrap(), *options));321}322return self;323},324};325*input = inputs[0];326self327}328329pub fn replace_children(mut self, inputs: &[Node]) -> Self {330use AExpr::*;331let input = match &mut self {332Element | Column(_) | Literal(_) | Len => return self,333#[cfg(feature = "dtype-struct")]334StructField(_) => return self,335Cast { expr, .. } => expr,336Explode { expr, .. } => expr,337BinaryExpr { left, right, .. } => {338*left = inputs[0];339*right = inputs[1];340return self;341},342Gather { expr, idx, .. } => {343*expr = inputs[0];344*idx = inputs[1];345return self;346},347Sort { expr, .. } => expr,348SortBy { expr, by, .. } => {349*expr = inputs[0];350by.clear();351by.extend_from_slice(&inputs[1..]);352return self;353},354Filter { input, by, .. } => {355*input = inputs[0];356*by = inputs[1];357return self;358},359Agg(a) => {360if let IRAggExpr::Quantile {361expr,362quantile,363method: _,364} = a365{366*expr = inputs[0];367*quantile = inputs[1];368} else {369a.set_input(inputs[0]);370}371return self;372},373Ternary {374truthy,375falsy,376predicate,377} => {378*truthy = inputs[0];379*falsy = inputs[1];380*predicate = inputs[2];381return self;382},383AnonymousAgg { input, .. }384| AnonymousFunction { input, .. }385| Function { input, .. } => {386assert_eq!(input.len(), inputs.len());387for (e, node) in input.iter_mut().zip(inputs.iter()) {388e.set_node(*node);389}390return self;391},392Eval {393expr,394evaluation,395variant: _,396} => {397*expr = inputs[0];398*evaluation = inputs[1];399return self;400},401#[cfg(feature = "dtype-struct")]402StructEval { expr, evaluation } => {403assert_eq!(inputs.len(), evaluation.len() + 1);404*expr = inputs[0];405for (e, node) in evaluation.iter_mut().zip(inputs[1..].iter()) {406e.set_node(*node);407}408return self;409},410Slice {411input,412offset,413length,414} => {415*input = inputs[0];416*offset = inputs[1];417*length = inputs[2];418return self;419},420#[cfg(feature = "dynamic_group_by")]421Rolling {422function,423index_column,424period: _,425offset: _,426closed_window: _,427} => {428*function = inputs[0];429*index_column = inputs[1];430return self;431},432Over {433function,434partition_by,435order_by,436..437} => {438let offset = order_by.is_some() as usize;439*function = inputs[0];440partition_by.clear();441partition_by.extend_from_slice(&inputs[1..inputs.len() - offset]);442if let Some((_, options)) = order_by {443*order_by = Some((*inputs.last().unwrap(), *options));444}445return self;446},447};448*input = inputs[0];449self450}451}452453impl IRAggExpr {454pub fn get_input(&self) -> NodeInputs {455use IRAggExpr::*;456use NodeInputs::*;457458match self {459Min { input, .. } => Single(*input),460Max { input, .. } => Single(*input),461Median(input) => Single(*input),462NUnique(input) => Single(*input),463First(input) => Single(*input),464FirstNonNull(input) => Single(*input),465Last(input) => Single(*input),466LastNonNull(input) => Single(*input),467Item { input, .. } => Single(*input),468Mean(input) => Single(*input),469Implode(input) => Single(*input),470Quantile { expr, quantile, .. } => Many(vec![*expr, *quantile]),471Sum(input) => Single(*input),472Count { input, .. } => Single(*input),473Std(input, _) => Single(*input),474Var(input, _) => Single(*input),475AggGroups(input) => Single(*input),476}477}478pub fn set_input(&mut self, input: Node) {479use IRAggExpr::*;480let node = match self {481Min { input, .. } => input,482Max { input, .. } => input,483Median(input) => input,484NUnique(input) => input,485First(input) => input,486FirstNonNull(input) => input,487Last(input) => input,488LastNonNull(input) => input,489Item { input, .. } => input,490Mean(input) => input,491Implode(input) => input,492Quantile { expr, .. } => expr,493Sum(input) => input,494Count { input, .. } => input,495Std(input, _) => input,496Var(input, _) => input,497AggGroups(input) => input,498};499*node = input;500}501}502503pub enum NodeInputs {504Leaf,505Single(Node),506Many(Vec<Node>),507}508509impl NodeInputs {510pub fn first(&self) -> Node {511match self {512NodeInputs::Single(node) => *node,513NodeInputs::Many(nodes) => nodes[0],514NodeInputs::Leaf => panic!(),515}516}517}518519520