Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-plan/src/plans/aexpr/function_expr/struct_.rs
7889 views
1
use polars_utils::format_pl_smallstr;
2
3
use super::*;
4
5
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
6
#[cfg_attr(feature = "ir_serde", derive(serde::Serialize, serde::Deserialize))]
7
pub enum IRStructFunction {
8
FieldByName(PlSmallStr),
9
RenameFields(Arc<[PlSmallStr]>),
10
PrefixFields(PlSmallStr),
11
SuffixFields(PlSmallStr),
12
#[cfg(feature = "json")]
13
JsonEncode,
14
WithFields,
15
MapFieldNames(PlanCallback<PlSmallStr, PlSmallStr>),
16
}
17
18
impl IRStructFunction {
19
pub(super) fn get_field(&self, mapper: FieldsMapper) -> PolarsResult<Field> {
20
use IRStructFunction::*;
21
22
match self {
23
FieldByName(name) => mapper.try_map_field(|field| {
24
if let DataType::Struct(ref fields) = field.dtype {
25
let fld = fields
26
.iter()
27
.find(|fld| fld.name() == name)
28
.ok_or_else(|| polars_err!(StructFieldNotFound: "{}", name))?;
29
Ok(fld.clone())
30
} else {
31
polars_bail!(StructFieldNotFound: "{}", name);
32
}
33
}),
34
RenameFields(names) => mapper.map_dtype(|dt| match dt {
35
DataType::Struct(fields) => {
36
let fields = fields
37
.iter()
38
.zip(names.as_ref())
39
.map(|(fld, name)| Field::new(name.clone(), fld.dtype().clone()))
40
.collect();
41
DataType::Struct(fields)
42
},
43
// The types will be incorrect, but its better than nothing
44
// we can get an incorrect type with python lambdas, because we only know return type when running
45
// the query
46
dt => DataType::Struct(
47
names
48
.iter()
49
.map(|name| Field::new(name.clone(), dt.clone()))
50
.collect(),
51
),
52
}),
53
PrefixFields(prefix) => mapper.try_map_dtype(|dt| match dt {
54
DataType::Struct(fields) => {
55
let fields = fields
56
.iter()
57
.map(|fld| {
58
let name = fld.name();
59
Field::new(format_pl_smallstr!("{prefix}{name}"), fld.dtype().clone())
60
})
61
.collect();
62
Ok(DataType::Struct(fields))
63
},
64
_ => polars_bail!(op = "prefix_fields", got = dt, expected = "Struct"),
65
}),
66
SuffixFields(suffix) => mapper.try_map_dtype(|dt| match dt {
67
DataType::Struct(fields) => {
68
let fields = fields
69
.iter()
70
.map(|fld| {
71
let name = fld.name();
72
Field::new(format_pl_smallstr!("{name}{suffix}"), fld.dtype().clone())
73
})
74
.collect();
75
Ok(DataType::Struct(fields))
76
},
77
_ => polars_bail!(op = "suffix_fields", got = dt, expected = "Struct"),
78
}),
79
#[cfg(feature = "json")]
80
JsonEncode => mapper.with_dtype(DataType::String),
81
WithFields => {
82
let args = mapper.args();
83
let struct_ = &args[0];
84
85
if let DataType::Struct(fields) = struct_.dtype() {
86
let mut name_2_dtype = PlIndexMap::with_capacity(fields.len() * 2);
87
88
for field in fields {
89
name_2_dtype.insert(field.name(), field.dtype());
90
}
91
for arg in &args[1..] {
92
name_2_dtype.insert(arg.name(), arg.dtype());
93
}
94
let dtype = DataType::Struct(
95
name_2_dtype
96
.iter()
97
.map(|(&name, &dtype)| Field::new(name.clone(), dtype.clone()))
98
.collect(),
99
);
100
let mut out = struct_.clone();
101
out.coerce(dtype);
102
Ok(out)
103
} else {
104
let dt = struct_.dtype();
105
polars_bail!(op = "with_fields", got = dt, expected = "Struct")
106
}
107
},
108
MapFieldNames(function) => mapper.try_map_dtype(|dt| match dt {
109
DataType::Struct(fields) => {
110
let fields = fields
111
.iter()
112
.map(|fld| {
113
let name = fld.name();
114
let new_name = function.call(name.clone()).map_err(|e| polars_err!(ComputeError: "'name.map_fields' produced an error: {e}."))?;
115
Ok(Field::new(new_name, fld.dtype().clone()))
116
})
117
.collect::<PolarsResult<_>>()?;
118
Ok(DataType::Struct(fields))
119
},
120
_ => polars_bail!(op = "prefix_fields", got = dt, expected = "Struct"),
121
}),
122
}
123
}
124
125
pub fn function_options(&self) -> FunctionOptions {
126
use IRStructFunction as S;
127
match self {
128
S::FieldByName(_) => {
129
FunctionOptions::elementwise().with_flags(|f| f | FunctionFlags::ALLOW_RENAME)
130
},
131
S::RenameFields(_) | S::PrefixFields(_) | S::SuffixFields(_) => {
132
FunctionOptions::elementwise()
133
},
134
#[cfg(feature = "json")]
135
S::JsonEncode => FunctionOptions::elementwise(),
136
S::WithFields => FunctionOptions::elementwise().with_flags(|f| {
137
f | FunctionFlags::INPUT_WILDCARD_EXPANSION | FunctionFlags::PASS_NAME_TO_APPLY
138
}),
139
S::MapFieldNames(_) => FunctionOptions::elementwise(),
140
}
141
}
142
}
143
144
impl Display for IRStructFunction {
145
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
146
use IRStructFunction::*;
147
match self {
148
FieldByName(name) => write!(f, "struct.field_by_name({name})"),
149
RenameFields(names) => write!(f, "struct.rename_fields({names:?})"),
150
PrefixFields(_) => write!(f, "name.prefix_fields"),
151
SuffixFields(_) => write!(f, "name.suffixFields"),
152
#[cfg(feature = "json")]
153
JsonEncode => write!(f, "struct.to_json"),
154
WithFields => write!(f, "with_fields"),
155
MapFieldNames(_) => write!(f, "map_field_names"),
156
}
157
}
158
}
159
160