Path: blob/main/crates/polars-plan/src/plans/aexpr/function_expr/struct_.rs
7889 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,13WithFields,14MapFieldNames(PlanCallback<PlSmallStr, PlSmallStr>),15}1617impl IRStructFunction {18pub(super) fn get_field(&self, mapper: FieldsMapper) -> PolarsResult<Field> {19use IRStructFunction::*;2021match self {22FieldByName(name) => mapper.try_map_field(|field| {23if let DataType::Struct(ref fields) = field.dtype {24let fld = fields25.iter()26.find(|fld| fld.name() == name)27.ok_or_else(|| polars_err!(StructFieldNotFound: "{}", name))?;28Ok(fld.clone())29} else {30polars_bail!(StructFieldNotFound: "{}", name);31}32}),33RenameFields(names) => mapper.map_dtype(|dt| match dt {34DataType::Struct(fields) => {35let fields = fields36.iter()37.zip(names.as_ref())38.map(|(fld, name)| Field::new(name.clone(), fld.dtype().clone()))39.collect();40DataType::Struct(fields)41},42// The types will be incorrect, but its better than nothing43// we can get an incorrect type with python lambdas, because we only know return type when running44// the query45dt => DataType::Struct(46names47.iter()48.map(|name| Field::new(name.clone(), dt.clone()))49.collect(),50),51}),52PrefixFields(prefix) => mapper.try_map_dtype(|dt| match dt {53DataType::Struct(fields) => {54let fields = fields55.iter()56.map(|fld| {57let name = fld.name();58Field::new(format_pl_smallstr!("{prefix}{name}"), fld.dtype().clone())59})60.collect();61Ok(DataType::Struct(fields))62},63_ => polars_bail!(op = "prefix_fields", got = dt, expected = "Struct"),64}),65SuffixFields(suffix) => mapper.try_map_dtype(|dt| match dt {66DataType::Struct(fields) => {67let fields = fields68.iter()69.map(|fld| {70let name = fld.name();71Field::new(format_pl_smallstr!("{name}{suffix}"), fld.dtype().clone())72})73.collect();74Ok(DataType::Struct(fields))75},76_ => polars_bail!(op = "suffix_fields", got = dt, expected = "Struct"),77}),78#[cfg(feature = "json")]79JsonEncode => mapper.with_dtype(DataType::String),80WithFields => {81let args = mapper.args();82let struct_ = &args[0];8384if let DataType::Struct(fields) = struct_.dtype() {85let mut name_2_dtype = PlIndexMap::with_capacity(fields.len() * 2);8687for field in fields {88name_2_dtype.insert(field.name(), field.dtype());89}90for arg in &args[1..] {91name_2_dtype.insert(arg.name(), arg.dtype());92}93let dtype = DataType::Struct(94name_2_dtype95.iter()96.map(|(&name, &dtype)| Field::new(name.clone(), dtype.clone()))97.collect(),98);99let mut out = struct_.clone();100out.coerce(dtype);101Ok(out)102} else {103let dt = struct_.dtype();104polars_bail!(op = "with_fields", got = dt, expected = "Struct")105}106},107MapFieldNames(function) => mapper.try_map_dtype(|dt| match dt {108DataType::Struct(fields) => {109let fields = fields110.iter()111.map(|fld| {112let name = fld.name();113let new_name = function.call(name.clone()).map_err(|e| polars_err!(ComputeError: "'name.map_fields' produced an error: {e}."))?;114Ok(Field::new(new_name, fld.dtype().clone()))115})116.collect::<PolarsResult<_>>()?;117Ok(DataType::Struct(fields))118},119_ => polars_bail!(op = "prefix_fields", got = dt, expected = "Struct"),120}),121}122}123124pub fn function_options(&self) -> FunctionOptions {125use IRStructFunction as S;126match self {127S::FieldByName(_) => {128FunctionOptions::elementwise().with_flags(|f| f | FunctionFlags::ALLOW_RENAME)129},130S::RenameFields(_) | S::PrefixFields(_) | S::SuffixFields(_) => {131FunctionOptions::elementwise()132},133#[cfg(feature = "json")]134S::JsonEncode => FunctionOptions::elementwise(),135S::WithFields => FunctionOptions::elementwise().with_flags(|f| {136f | FunctionFlags::INPUT_WILDCARD_EXPANSION | FunctionFlags::PASS_NAME_TO_APPLY137}),138S::MapFieldNames(_) => FunctionOptions::elementwise(),139}140}141}142143impl Display for IRStructFunction {144fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {145use IRStructFunction::*;146match self {147FieldByName(name) => write!(f, "struct.field_by_name({name})"),148RenameFields(names) => write!(f, "struct.rename_fields({names:?})"),149PrefixFields(_) => write!(f, "name.prefix_fields"),150SuffixFields(_) => write!(f, "name.suffixFields"),151#[cfg(feature = "json")]152JsonEncode => write!(f, "struct.to_json"),153WithFields => write!(f, "with_fields"),154MapFieldNames(_) => write!(f, "map_field_names"),155}156}157}158159160