Path: blob/main/crates/polars-plan/src/plans/aexpr/builder.rs
8422 views
use polars_core::chunked_array::cast::CastOptions;1use polars_core::prelude::{DataType, ExplodeOptions, SortMultipleOptions, SortOptions};2use polars_core::scalar::Scalar;3use polars_utils::IdxSize;4use polars_utils::arena::{Arena, Node};5use polars_utils::pl_str::PlSmallStr;67use super::{AExpr, IRAggExpr, IRBooleanFunction, IRFunctionExpr, RowEncodingVariant};8use crate::dsl::Operator;9use crate::plans::{ExprIR, LiteralValue, OutputName};1011#[derive(Clone, Copy)]12pub struct AExprBuilder {13node: Node,14}1516impl AExprBuilder {17pub fn new_from_node(node: Node) -> Self {18Self { node }19}2021pub fn new_from_aexpr(expr: AExpr, arena: &mut Arena<AExpr>) -> Self {22Self::new_from_node(arena.add(expr))23}2425pub fn lit(lit: LiteralValue, arena: &mut Arena<AExpr>) -> Self {26Self::new_from_aexpr(AExpr::Literal(lit), arena)27}2829pub fn lit_scalar(scalar: Scalar, arena: &mut Arena<AExpr>) -> Self {30Self::lit(LiteralValue::Scalar(scalar), arena)31}3233pub fn col(name: impl Into<PlSmallStr>, arena: &mut Arena<AExpr>) -> Self {34Self::new_from_aexpr(AExpr::Column(name.into()), arena)35}3637pub fn dataframe_length(arena: &mut Arena<AExpr>) -> Self {38Self::new_from_aexpr(AExpr::Len, arena)39}4041pub fn function(42input: Vec<ExprIR>,43function: IRFunctionExpr,44arena: &mut Arena<AExpr>,45) -> Self {46let options = function.function_options();47Self::new_from_aexpr(48AExpr::Function {49input,50function,51options,52},53arena,54)55}5657pub fn map_as_expr_ir<F: Fn(ExprIR, &mut Arena<AExpr>) -> AExpr>(58self,59mapper: F,60arena: &mut Arena<AExpr>,61) -> Self {62let eir = ExprIR::from_node(self.node, arena);6364let ae = mapper(eir, arena);65let node = arena.add(ae);66Self { node }67}6869pub fn row_encode(70exprs: Vec<ExprIR>,71dtypes: Vec<DataType>,72variant: RowEncodingVariant,73arena: &mut Arena<AExpr>,74) -> Self {75Self::function(exprs, IRFunctionExpr::RowEncode(dtypes, variant), arena)76}7778pub fn cast(self, dtype: DataType, arena: &mut Arena<AExpr>) -> Self {79Self {80node: arena.add(AExpr::Cast {81expr: self.node,82dtype,83options: CastOptions::Strict,84}),85}86}8788pub fn binary_op(89self,90other: impl IntoAExprBuilder,91op: Operator,92arena: &mut Arena<AExpr>,93) -> Self {94Self {95node: arena.add(AExpr::BinaryExpr {96left: self.node,97op,98right: other.into_aexpr_builder().node,99}),100}101}102103pub fn agg(agg: IRAggExpr, arena: &mut Arena<AExpr>) -> Self {104Self::new_from_aexpr(AExpr::Agg(agg), arena)105}106107pub fn first(self, arena: &mut Arena<AExpr>) -> Self {108Self::agg(IRAggExpr::First(self.node()), arena)109}110111pub fn first_non_null(self, arena: &mut Arena<AExpr>) -> Self {112Self::agg(IRAggExpr::FirstNonNull(self.node()), arena)113}114115pub fn last(self, arena: &mut Arena<AExpr>) -> Self {116Self::agg(IRAggExpr::Last(self.node()), arena)117}118119pub fn last_non_null(self, arena: &mut Arena<AExpr>) -> Self {120Self::agg(IRAggExpr::LastNonNull(self.node()), arena)121}122123pub fn min(self, arena: &mut Arena<AExpr>) -> Self {124Self::agg(125IRAggExpr::Min {126input: self.node(),127propagate_nans: false,128},129arena,130)131}132133pub fn max(self, arena: &mut Arena<AExpr>) -> Self {134Self::agg(135IRAggExpr::Max {136input: self.node(),137propagate_nans: false,138},139arena,140)141}142143pub fn nan_min(self, arena: &mut Arena<AExpr>) -> Self {144Self::agg(145IRAggExpr::Min {146input: self.node(),147propagate_nans: true,148},149arena,150)151}152153pub fn nan_max(self, arena: &mut Arena<AExpr>) -> Self {154Self::agg(155IRAggExpr::Max {156input: self.node(),157propagate_nans: true,158},159arena,160)161}162163pub fn min_by(self, by: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {164let by = by.into_aexpr_builder().expr_ir_retain_name(arena);165Self::function(166vec![self.expr_ir_retain_name(arena), by],167IRFunctionExpr::MinBy,168arena,169)170}171172pub fn max_by(self, by: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {173let by = by.into_aexpr_builder().expr_ir_retain_name(arena);174Self::function(175vec![self.expr_ir_retain_name(arena), by],176IRFunctionExpr::MaxBy,177arena,178)179}180181pub fn sum(self, arena: &mut Arena<AExpr>) -> Self {182Self::agg(IRAggExpr::Sum(self.node()), arena)183}184185pub fn len(self, arena: &mut Arena<AExpr>) -> Self {186Self::agg(187IRAggExpr::Count {188input: self.node(),189include_nulls: true,190},191arena,192)193}194195pub fn any_horizontal(exprs: Vec<ExprIR>, arena: &mut Arena<AExpr>) -> Self {196Self::function(197exprs,198IRFunctionExpr::Boolean(IRBooleanFunction::AnyHorizontal),199arena,200)201}202203pub fn all_horizontal(exprs: Vec<ExprIR>, arena: &mut Arena<AExpr>) -> Self {204Self::function(205exprs,206IRFunctionExpr::Boolean(IRBooleanFunction::AllHorizontal),207arena,208)209}210211pub fn count(self, arena: &mut Arena<AExpr>) -> Self {212Self::agg(213IRAggExpr::Count {214input: self.node(),215include_nulls: false,216},217arena,218)219}220221pub fn count_opt_nulls(self, include_nulls: bool, arena: &mut Arena<AExpr>) -> Self {222Self::agg(223IRAggExpr::Count {224input: self.node(),225include_nulls,226},227arena,228)229}230231pub fn explode(self, arena: &mut Arena<AExpr>, options: ExplodeOptions) -> Self {232Self::new_from_aexpr(233AExpr::Explode {234expr: self.node(),235options,236},237arena,238)239}240241pub fn sort(self, options: SortOptions, arena: &mut Arena<AExpr>) -> Self {242Self::new_from_aexpr(243AExpr::Sort {244expr: self.node(),245options,246},247arena,248)249}250251pub fn sort_by(252self,253by: Vec<Node>,254options: SortMultipleOptions,255arena: &mut Arena<AExpr>,256) -> Self {257Self::new_from_aexpr(258AExpr::SortBy {259expr: self.node(),260by,261sort_options: options,262},263arena,264)265}266267pub fn filter(self, by: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {268Self::new_from_aexpr(269AExpr::Filter {270input: self.node(),271by: by.into_aexpr_builder().node(),272},273arena,274)275}276277pub fn when_then_otherwise(278when: impl IntoAExprBuilder,279then: impl IntoAExprBuilder,280otherwise: impl IntoAExprBuilder,281arena: &mut Arena<AExpr>,282) -> Self {283when.into_aexpr_builder().ternary(then, otherwise, arena)284}285286pub fn ternary(287self,288truthy: impl IntoAExprBuilder,289falsy: impl IntoAExprBuilder,290arena: &mut Arena<AExpr>,291) -> Self {292Self::new_from_aexpr(293AExpr::Ternary {294predicate: self.into_aexpr_builder().node(),295truthy: truthy.into_aexpr_builder().node(),296falsy: falsy.into_aexpr_builder().node(),297},298arena,299)300}301302pub fn shift(self, periods: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {303Self::function(304vec![305self.expr_ir_unnamed(),306periods.into_aexpr_builder().expr_ir_unnamed(),307],308IRFunctionExpr::Shift,309arena,310)311}312313pub fn slice(314self,315offset: impl IntoAExprBuilder,316length: impl IntoAExprBuilder,317arena: &mut Arena<AExpr>,318) -> Self {319Self::new_from_aexpr(320AExpr::Slice {321input: self.into_aexpr_builder().node(),322offset: offset.into_aexpr_builder().node(),323length: length.into_aexpr_builder().node(),324},325arena,326)327}328329#[cfg(feature = "is_in")]330pub fn is_in(331self,332other: impl IntoAExprBuilder,333nulls_equal: bool,334arena: &mut Arena<AExpr>,335) -> Self {336Self::function(337vec![338self.expr_ir_unnamed(),339other.into_aexpr_builder().expr_ir_unnamed(),340],341IRFunctionExpr::Boolean(IRBooleanFunction::IsIn { nulls_equal }),342arena,343)344}345346pub fn to_physical(self, arena: &mut Arena<AExpr>) -> Self {347Self::function(348vec![self.expr_ir_unnamed()],349IRFunctionExpr::ToPhysical,350arena,351)352}353354#[cfg(feature = "abs")]355pub fn abs(self, arena: &mut Arena<AExpr>) -> Self {356Self::function(vec![self.expr_ir_unnamed()], IRFunctionExpr::Abs, arena)357}358359pub fn negate(self, arena: &mut Arena<AExpr>) -> Self {360Self::function(vec![self.expr_ir_unnamed()], IRFunctionExpr::Negate, arena)361}362363pub fn not(self, arena: &mut Arena<AExpr>) -> Self {364Self::function(365vec![self.expr_ir_unnamed()],366IRFunctionExpr::Boolean(IRBooleanFunction::Not),367arena,368)369}370371pub fn null_count(self, arena: &mut Arena<AExpr>) -> Self {372Self::function(373vec![self.expr_ir_unnamed()],374IRFunctionExpr::NullCount,375arena,376)377}378379pub fn is_null(self, arena: &mut Arena<AExpr>) -> Self {380Self::function(381vec![self.expr_ir_unnamed()],382IRFunctionExpr::Boolean(IRBooleanFunction::IsNull),383arena,384)385}386387pub fn is_not_null(self, arena: &mut Arena<AExpr>) -> Self {388Self::function(389vec![self.expr_ir_unnamed()],390IRFunctionExpr::Boolean(IRBooleanFunction::IsNotNull),391arena,392)393}394395pub fn is_nan(self, arena: &mut Arena<AExpr>) -> Self {396Self::function(397vec![self.expr_ir_unnamed()],398IRFunctionExpr::Boolean(IRBooleanFunction::IsNan),399arena,400)401}402403pub fn is_not_nan(self, arena: &mut Arena<AExpr>) -> Self {404Self::function(405vec![self.expr_ir_unnamed()],406IRFunctionExpr::Boolean(IRBooleanFunction::IsNotNan),407arena,408)409}410411pub fn has_no_nulls(self, arena: &mut Arena<AExpr>) -> Self {412let nc = self.null_count(arena);413let idx_zero = Self::lit_scalar(Scalar::from(0 as IdxSize), arena);414nc.eq(idx_zero, arena)415}416417pub fn has_nulls(self, arena: &mut Arena<AExpr>) -> Self {418let nc = self.null_count(arena);419let idx_zero = Self::lit_scalar(Scalar::from(0 as IdxSize), arena);420nc.gt(idx_zero, arena)421}422423pub fn drop_nulls(self, arena: &mut Arena<AExpr>) -> Self {424Self::function(425vec![self.expr_ir_retain_name(arena)],426IRFunctionExpr::DropNulls,427arena,428)429}430431pub fn drop_nans(self, arena: &mut Arena<AExpr>) -> Self {432Self::function(433vec![self.expr_ir_retain_name(arena)],434IRFunctionExpr::DropNans,435arena,436)437}438439pub fn eq(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {440self.binary_op(other, Operator::Eq, arena)441}442443pub fn eq_validity(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {444self.binary_op(other, Operator::EqValidity, arena)445}446447pub fn not_eq(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {448self.binary_op(other, Operator::NotEq, arena)449}450451pub fn not_eq_validity(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {452self.binary_op(other, Operator::NotEqValidity, arena)453}454455pub fn lt(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {456self.binary_op(other, Operator::Lt, arena)457}458459pub fn lt_eq(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {460self.binary_op(other, Operator::LtEq, arena)461}462463pub fn gt(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {464self.binary_op(other, Operator::Gt, arena)465}466467pub fn gt_eq(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {468self.binary_op(other, Operator::GtEq, arena)469}470471pub fn plus(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {472self.binary_op(other, Operator::Plus, arena)473}474475pub fn minus(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {476self.binary_op(other, Operator::Minus, arena)477}478479pub fn multiply(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {480self.binary_op(other, Operator::Multiply, arena)481}482483pub fn divide(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {484self.binary_op(other, Operator::RustDivide, arena)485}486487pub fn true_divide(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {488self.binary_op(other, Operator::TrueDivide, arena)489}490491pub fn floor_divide(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {492self.binary_op(other, Operator::FloorDivide, arena)493}494495pub fn modulus(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {496self.binary_op(other, Operator::Modulus, arena)497}498499pub fn and(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {500self.binary_op(other, Operator::And, arena)501}502503pub fn or(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {504self.binary_op(other, Operator::Or, arena)505}506507pub fn xor(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {508self.binary_op(other, Operator::Xor, arena)509}510511pub fn logical_and(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {512self.binary_op(other, Operator::LogicalAnd, arena)513}514515pub fn logical_or(self, other: impl IntoAExprBuilder, arena: &mut Arena<AExpr>) -> Self {516self.binary_op(other, Operator::LogicalOr, arena)517}518519pub fn expr_ir(self, name: impl Into<PlSmallStr>) -> ExprIR {520ExprIR::new(self.node(), OutputName::Alias(name.into()))521}522523pub fn expr_ir_retain_name(self, arena: &Arena<AExpr>) -> ExprIR {524ExprIR::from_node(self.node(), arena)525}526527pub fn expr_ir_unnamed(self) -> ExprIR {528self.expr_ir(PlSmallStr::EMPTY)529}530531pub fn node(self) -> Node {532self.node533}534}535536pub trait IntoAExprBuilder {537fn into_aexpr_builder(self) -> AExprBuilder;538}539540impl IntoAExprBuilder for Node {541fn into_aexpr_builder(self) -> AExprBuilder {542AExprBuilder { node: self }543}544}545546impl IntoAExprBuilder for AExprBuilder {547fn into_aexpr_builder(self) -> AExprBuilder {548self549}550}551552553