polars_plan/dsl/
name.rs

1#[cfg(feature = "dtype-struct")]
2use polars_utils::pl_str::PlSmallStr;
3
4use super::*;
5
6/// Specialized expressions for modifying the name of existing expressions.
7pub struct ExprNameNameSpace(pub(crate) Expr);
8
9impl ExprNameNameSpace {
10    /// Keep the original root name
11    ///
12    /// ```rust,no_run
13    /// # use polars_core::prelude::*;
14    /// # use polars_plan::prelude::*;
15    /// fn example(df: LazyFrame) -> LazyFrame {
16    ///     df.select([
17    /// // even thought the alias yields a different column name,
18    /// // `keep` will make sure that the original column name is used
19    ///         col("*").alias("foo").name().keep()
20    /// ])
21    /// }
22    /// ```
23    pub fn keep(self) -> Expr {
24        Expr::KeepName(Arc::new(self.0))
25    }
26
27    /// Define an alias by mapping a function over the original root column name.
28    pub fn map<F>(self, function: F) -> Expr
29    where
30        F: Fn(&PlSmallStr) -> PolarsResult<PlSmallStr> + 'static + Send + Sync,
31    {
32        let function = SpecialEq::new(Arc::new(function) as Arc<RenameAliasRustFn>);
33        Expr::RenameAlias {
34            expr: Arc::new(self.0),
35            function: RenameAliasFn::Rust(function),
36        }
37    }
38
39    /// Define an alias by mapping a python lambda over the original root column name.
40    #[cfg(feature = "python")]
41    pub fn map_udf(self, function: polars_utils::python_function::PythonObject) -> Expr {
42        Expr::RenameAlias {
43            expr: Arc::new(self.0),
44            function: RenameAliasFn::Python(SpecialEq::new(Arc::new(function))),
45        }
46    }
47
48    /// Add a prefix to the root column name.
49    pub fn prefix(self, prefix: &str) -> Expr {
50        Expr::RenameAlias {
51            expr: Arc::new(self.0),
52            function: RenameAliasFn::Prefix(prefix.into()),
53        }
54    }
55
56    /// Add a suffix to the root column name.
57    pub fn suffix(self, suffix: &str) -> Expr {
58        Expr::RenameAlias {
59            expr: Arc::new(self.0),
60            function: RenameAliasFn::Suffix(suffix.into()),
61        }
62    }
63
64    /// Update the root column name to use lowercase characters.
65    #[allow(clippy::wrong_self_convention)]
66    pub fn to_lowercase(self) -> Expr {
67        Expr::RenameAlias {
68            expr: Arc::new(self.0),
69            function: RenameAliasFn::ToLowercase,
70        }
71    }
72
73    /// Update the root column name to use uppercase characters.
74    #[allow(clippy::wrong_self_convention)]
75    pub fn to_uppercase(self) -> Expr {
76        Expr::RenameAlias {
77            expr: Arc::new(self.0),
78            function: RenameAliasFn::ToUppercase,
79        }
80    }
81
82    #[cfg(feature = "dtype-struct")]
83    pub fn map_fields(self, function: FieldsNameMapper) -> Expr {
84        let f = function.clone();
85        self.0.map(
86            move |s| {
87                let s = s.struct_()?;
88                let fields = s
89                    .fields_as_series()
90                    .iter()
91                    .map(|fd| {
92                        let mut fd = fd.clone();
93                        fd.rename(function(fd.name()));
94                        fd
95                    })
96                    .collect::<Vec<_>>();
97                let mut out = StructChunked::from_series(s.name().clone(), s.len(), fields.iter())?;
98                out.zip_outer_validity(s);
99                Ok(Some(out.into_column()))
100            },
101            GetOutput::map_dtype(move |dt| match dt {
102                DataType::Struct(fds) => {
103                    let fields = fds
104                        .iter()
105                        .map(|fd| Field::new(f(fd.name()), fd.dtype().clone()))
106                        .collect();
107                    Ok(DataType::Struct(fields))
108                },
109                _ => panic!("Only struct dtype is supported for `map_fields`."),
110            }),
111        )
112    }
113
114    #[cfg(all(feature = "dtype-struct", feature = "python"))]
115    pub fn map_fields_udf(self, function: polars_utils::python_function::PythonObject) -> Expr {
116        self.0
117            .map_unary(FunctionExpr::StructExpr(StructFunction::MapFieldNames(
118                SpecialEq::new(Arc::new(function)),
119            )))
120    }
121
122    #[cfg(feature = "dtype-struct")]
123    pub fn prefix_fields(self, prefix: &str) -> Expr {
124        self.0
125            .map_unary(FunctionExpr::StructExpr(StructFunction::PrefixFields(
126                PlSmallStr::from_str(prefix),
127            )))
128    }
129
130    #[cfg(feature = "dtype-struct")]
131    pub fn suffix_fields(self, suffix: &str) -> Expr {
132        self.0
133            .map_unary(FunctionExpr::StructExpr(StructFunction::SuffixFields(
134                PlSmallStr::from_str(suffix),
135            )))
136    }
137}
138
139#[cfg(feature = "dtype-struct")]
140pub type FieldsNameMapper = Arc<dyn Fn(&str) -> PlSmallStr + Send + Sync>;