use crate::input::proto::substrait;
use crate::output::diagnostic;
use crate::output::type_system::data;
use crate::parse::context;
use crate::util;
fn parse_struct_item(
x: &substrait::expression::mask_expression::StructItem,
y: &mut context::Context,
root: &data::Type,
) -> diagnostic::Result<()> {
let data_type = proto_primitive_field!(x, y, field, super::parse_struct_field_index, root)
.1
.unwrap_or_default();
y.set_data_type(data_type.clone());
if x.child.is_some() {
let data_type = proto_required_field!(x, y, child, parse_select, &data_type)
.0
.data_type();
y.set_data_type(data_type);
describe!(y, Expression, "Struct item selection and sub-selection");
} else {
describe!(y, Expression, "Struct item selection");
}
Ok(())
}
fn parse_struct_select(
x: &substrait::expression::mask_expression::StructSelect,
y: &mut context::Context,
root: &data::Type,
) -> diagnostic::Result<()> {
if !root.is_unresolved() && !root.is_struct() {
diagnostic!(
y,
Error,
TypeMismatch,
"struct selection requires a struct type, but got a {}",
root.class()
);
}
let fields = proto_repeated_field!(
x,
y,
struct_items,
parse_struct_item,
|_, _, _, _, _| (),
root
)
.0
.iter()
.map(|x| x.data_type())
.collect::<Vec<_>>();
y.set_data_type(data::new_struct(fields, root.nullable()));
describe!(y, Expression, "Struct selection");
Ok(())
}
fn parse_list_select_item_element(
x: &substrait::expression::mask_expression::list_select::list_select_item::ListElement,
y: &mut context::Context,
) -> diagnostic::Result<()> {
proto_primitive_field!(x, y, field);
describe!(
y,
Expression,
"Select {} element",
util::string::describe_index(x.field)
);
Ok(())
}
fn parse_list_select_item_slice(
x: &substrait::expression::mask_expression::list_select::list_select_item::ListSlice,
y: &mut context::Context,
) -> diagnostic::Result<()> {
proto_primitive_field!(x, y, start);
proto_primitive_field!(x, y, end);
let description = if (x.start >= 0) == (x.end >= 0) && x.start < x.end {
diagnostic!(y, Info, RedundantListSlice, "slice is always null");
String::from("Selects an empty list slice")
} else if x.start == 0 {
match x.end {
i32::MIN..=-3 => format!("Selects all but the last {} elements", -x.end - 1),
-2 => String::from("Selects all but the last element"),
-1 => String::from("Selects the complete list"),
0 => String::from("Selects the first element"),
1..=i32::MAX => format!("Selects the first {} elements", x.end + 1),
}
} else if x.end == -1 {
match x.start {
i32::MIN..=-2 => format!("Selects the last {} elements", -x.start),
-1 => String::from("Selects the last element"),
0 => String::from("Selects the complete list"),
1 => String::from("Selects all but the first element"),
2..=i32::MAX => format!("Selects all but the first {} elements", x.start),
}
} else {
format!(
"Select {} until {} element (inclusive)",
util::string::describe_index(x.start),
util::string::describe_index(x.end)
)
};
describe!(y, Expression, "{}", description);
Ok(())
}
fn parse_list_select_item_type(
x: &substrait::expression::mask_expression::list_select::list_select_item::Type,
y: &mut context::Context,
) -> diagnostic::Result<()> {
match x {
substrait::expression::mask_expression::list_select::list_select_item::Type::Item(x) => {
parse_list_select_item_element(x, y)
}
substrait::expression::mask_expression::list_select::list_select_item::Type::Slice(x) => {
parse_list_select_item_slice(x, y)
}
}
}
fn parse_list_select_item(
x: &substrait::expression::mask_expression::list_select::ListSelectItem,
y: &mut context::Context,
) -> diagnostic::Result<()> {
proto_required_field!(x, y, r#type, parse_list_select_item_type);
Ok(())
}
fn parse_list_select(
x: &substrait::expression::mask_expression::ListSelect,
y: &mut context::Context,
root: &data::Type,
) -> diagnostic::Result<()> {
if !root.is_unresolved() && !root.is_list() {
diagnostic!(
y,
Error,
TypeMismatch,
"list selection requires a list type, but got a {}",
root.class()
);
}
proto_repeated_field!(x, y, selection, parse_list_select_item);
y.set_data_type(root.clone());
if x.child.is_some() {
let data_type = root.unwrap_list().unwrap_or_default();
let data_type = proto_boxed_required_field!(x, y, child, parse_select, &data_type)
.0
.data_type();
y.set_data_type(data::new_list(data_type, root.nullable()));
describe!(y, Expression, "List selection and sub-selection");
} else {
describe!(y, Expression, "List selection");
}
Ok(())
}
fn parse_map_select_key(
_x: &substrait::expression::mask_expression::map_select::MapKey,
y: &mut context::Context,
_key_type: &data::Type,
) -> diagnostic::Result<()> {
diagnostic!(
y,
Error,
NotYetImplemented,
"map key remappings are not yet specified"
);
describe!(y, Expression, "Single-key map selection");
Ok(())
}
fn parse_map_select_expression(
_x: &substrait::expression::mask_expression::map_select::MapKeyExpression,
y: &mut context::Context,
_key_type: &data::Type,
) -> diagnostic::Result<()> {
diagnostic!(
y,
Error,
NotYetImplemented,
"map key remappings are not yet specified"
);
describe!(y, Expression, "Map key remapping");
Ok(())
}
fn parse_map_select_type(
x: &substrait::expression::mask_expression::map_select::Select,
y: &mut context::Context,
root: &data::Type,
) -> diagnostic::Result<()> {
match x {
substrait::expression::mask_expression::map_select::Select::Key(x) => {
parse_map_select_key(x, y, root)
}
substrait::expression::mask_expression::map_select::Select::Expression(x) => {
parse_map_select_expression(x, y, root)
}
}
}
fn parse_map_select(
x: &substrait::expression::mask_expression::MapSelect,
y: &mut context::Context,
root: &data::Type,
) -> diagnostic::Result<()> {
if !root.is_unresolved() && !root.is_map() {
diagnostic!(
y,
Error,
TypeMismatch,
"map selection requires a map type, but got a {}",
root.class()
);
}
if x.select.is_some() {
proto_required_field!(
x,
y,
select,
parse_map_select_type,
&root.unwrap_map_key().unwrap_or_default()
);
} else {
comment!(y, "No select key specified: mapping is left unchanged.");
}
y.set_data_type(root.clone());
if x.child.is_some() {
let value_type = root.unwrap_map().unwrap_or_default();
let key_type = root.unwrap_map_key().unwrap_or_default();
let value_type = proto_boxed_required_field!(x, y, child, parse_select, &value_type)
.0
.data_type();
y.set_data_type(data::new_map(key_type, value_type, root.nullable()));
describe!(y, Expression, "Map selection and sub-selection");
} else {
describe!(y, Expression, "Map selection");
}
Ok(())
}
fn parse_select_type(
x: &substrait::expression::mask_expression::select::Type,
y: &mut context::Context,
root: &data::Type,
) -> diagnostic::Result<()> {
match x {
substrait::expression::mask_expression::select::Type::Struct(x) => {
parse_struct_select(x, y, root)
}
substrait::expression::mask_expression::select::Type::List(x) => {
parse_list_select(x.as_ref(), y, root)
}
substrait::expression::mask_expression::select::Type::Map(x) => {
parse_map_select(x.as_ref(), y, root)
}
}
}
fn parse_select(
x: &substrait::expression::mask_expression::Select,
y: &mut context::Context,
root: &data::Type,
) -> diagnostic::Result<()> {
let data_type = proto_required_field!(x, y, r#type, parse_select_type, root)
.0
.data_type();
y.set_data_type(data_type);
Ok(())
}
fn parse_maintain_singular_struct(
x: &bool,
y: &mut context::Context,
is_singular: bool,
struct_required: bool,
) -> diagnostic::Result<bool> {
let maintain = *x;
match (is_singular, maintain, struct_required) {
(true, true, _) => {
summary!(
y,
"Mask expression yields a singular struct, which is \
maintained as-is."
);
Ok(false)
}
(true, false, true) => {
summary!(
y,
"Mask expression yields a singular struct, which would be \
reduced to its element type, but its context does not allow \
this."
);
diagnostic!(
y,
Error,
TypeStructRequired,
"context requires a struct type and type is a singular \
struct, maintain_singular_struct must be set"
);
Ok(false)
}
(true, false, false) => {
summary!(
y,
"Mask expression yields a singular struct, which is reduced \
to its element type."
);
Ok(true)
}
(false, true, _) => {
summary!(
y,
"Data type of mask expression is not a singular struct, so \
there is nothing to strip or maintain. The explicit true is \
redundant."
);
Ok(false)
}
(false, false, _) => {
summary!(
y,
"Data type of mask expression is not a singular struct, so \
there is nothing to strip or maintain."
);
Ok(false)
}
}
}
pub fn parse_mask_expression(
x: &substrait::expression::MaskExpression,
y: &mut context::Context,
root: &data::Type,
struct_required: bool,
) -> diagnostic::Result<()> {
let data_type = proto_required_field!(x, y, select, parse_struct_select, root)
.0
.data_type();
let singular_type = data_type.unwrap_singular_struct().map(|data_type| {
if root.nullable() {
data_type.make_nullable()
} else {
data_type
}
});
let unwrap = proto_primitive_field!(
x,
y,
maintain_singular_struct,
parse_maintain_singular_struct,
singular_type.is_some(),
struct_required
)
.1
.unwrap_or_default();
y.set_data_type(if unwrap {
singular_type.unwrap()
} else {
data_type
});
describe!(
y,
Expression,
"References fields into a new nested structure"
);
Ok(())
}