Path: blob/main/crates/polars-plan/src/plans/aexpr/function_expr/struct_.rs
8391 views
use polars_utils::format_pl_smallstr;12use super::*;34#[derive(Clone, Eq, PartialEq, Hash, Debug)]5#[cfg_attr(feature = "ir_serde", derive(serde::Serialize, serde::Deserialize))]6pub enum IRStructFunction {7FieldByName(PlSmallStr),8RenameFields(Arc<[PlSmallStr]>),9PrefixFields(PlSmallStr),10SuffixFields(PlSmallStr),11#[cfg(feature = "json")]12JsonEncode,13MapFieldNames(PlanCallback<PlSmallStr, PlSmallStr>),14}1516impl IRStructFunction {17pub(super) fn get_field(&self, mapper: FieldsMapper) -> PolarsResult<Field> {18use IRStructFunction::*;1920match self {21FieldByName(name) => mapper.try_map_field(|field| {22if let DataType::Struct(ref fields) = field.dtype {23let fld = fields24.iter()25.find(|fld| fld.name() == name)26.ok_or_else(|| polars_err!(StructFieldNotFound: "{}", name))?;27Ok(fld.clone())28} else {29polars_bail!(StructFieldNotFound: "{}", name);30}31}),32RenameFields(names) => mapper.map_dtype(|dt| match dt {33DataType::Struct(fields) => {34let fields = fields35.iter()36.zip(names.as_ref())37.map(|(fld, name)| Field::new(name.clone(), fld.dtype().clone()))38.collect();39DataType::Struct(fields)40},41// The types will be incorrect, but its better than nothing42// we can get an incorrect type with python lambdas, because we only know return type when running43// the query44dt => DataType::Struct(45names46.iter()47.map(|name| Field::new(name.clone(), dt.clone()))48.collect(),49),50}),51PrefixFields(prefix) => mapper.try_map_dtype(|dt| match dt {52DataType::Struct(fields) => {53let fields = fields54.iter()55.map(|fld| {56let name = fld.name();57Field::new(format_pl_smallstr!("{prefix}{name}"), fld.dtype().clone())58})59.collect();60Ok(DataType::Struct(fields))61},62_ => polars_bail!(op = "prefix_fields", got = dt, expected = "Struct"),63}),64SuffixFields(suffix) => mapper.try_map_dtype(|dt| match dt {65DataType::Struct(fields) => {66let fields = fields67.iter()68.map(|fld| {69let name = fld.name();70Field::new(format_pl_smallstr!("{name}{suffix}"), fld.dtype().clone())71})72.collect();73Ok(DataType::Struct(fields))74},75_ => polars_bail!(op = "suffix_fields", got = dt, expected = "Struct"),76}),77#[cfg(feature = "json")]78JsonEncode => mapper.with_dtype(DataType::String),79MapFieldNames(function) => mapper.try_map_dtype(|dt| match dt {80DataType::Struct(fields) => {81let fields = fields82.iter()83.map(|fld| {84let name = fld.name();85let new_name = function.call(name.clone()).map_err(|e| polars_err!(ComputeError: "'name.map_fields' produced an error: {e}."))?;86Ok(Field::new(new_name, fld.dtype().clone()))87})88.collect::<PolarsResult<_>>()?;89Ok(DataType::Struct(fields))90},91_ => polars_bail!(op = "prefix_fields", got = dt, expected = "Struct"),92}),93}94}9596pub fn function_options(&self) -> FunctionOptions {97use IRStructFunction as S;98match self {99S::FieldByName(_) => {100FunctionOptions::elementwise().with_flags(|f| f | FunctionFlags::ALLOW_RENAME)101},102S::RenameFields(_) | S::PrefixFields(_) | S::SuffixFields(_) => {103FunctionOptions::elementwise()104},105#[cfg(feature = "json")]106S::JsonEncode => FunctionOptions::elementwise(),107S::MapFieldNames(_) => FunctionOptions::elementwise(),108}109}110}111112impl Display for IRStructFunction {113fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {114use IRStructFunction::*;115match self {116FieldByName(name) => write!(f, "struct.field_by_name({name})"),117RenameFields(names) => write!(f, "struct.rename_fields({names:?})"),118PrefixFields(_) => write!(f, "name.prefix_fields"),119SuffixFields(_) => write!(f, "name.suffixFields"),120#[cfg(feature = "json")]121JsonEncode => write!(f, "struct.to_json"),122MapFieldNames(_) => write!(f, "map_field_names"),123}124}125}126127128