| 135 | } |
| 136 | |
| 137 | Result<compute::Expression> FromProto(const substrait::Expression::ReferenceSegment* ref, |
| 138 | const ExtensionSet& ext_set, |
| 139 | const ConversionOptions& conversion_options, |
| 140 | std::optional<compute::Expression> in_expr) { |
| 141 | auto in_ref = ref; |
| 142 | auto& current = in_expr; |
| 143 | while (ref != nullptr) { |
| 144 | switch (ref->reference_type_case()) { |
| 145 | case substrait::Expression::ReferenceSegment::kStructField: { |
| 146 | auto index = ref->struct_field().field(); |
| 147 | if (!current) { |
| 148 | // Root StructField (column selection) |
| 149 | current = compute::field_ref(FieldRef(index)); |
| 150 | } else if (auto current_ref = current->field_ref()) { |
| 151 | // Nested StructFields on the root (selection of struct-typed column |
| 152 | // combined with selecting struct fields) |
| 153 | current = compute::field_ref(FieldRef(*current_ref, index)); |
| 154 | } else if (current->call() && current->call()->function_name == "struct_field") { |
| 155 | // Nested StructFields on top of an arbitrary expression |
| 156 | auto* field_options = |
| 157 | checked_cast<compute::StructFieldOptions*>(current->call()->options.get()); |
| 158 | field_options->field_ref = FieldRef(std::move(field_options->field_ref), index); |
| 159 | } else { |
| 160 | // First StructField on top of an arbitrary expression |
| 161 | current = compute::call("struct_field", {std::move(*current)}, |
| 162 | arrow::compute::StructFieldOptions({index})); |
| 163 | } |
| 164 | |
| 165 | // Segment handled, continue with child segment (if any) |
| 166 | if (ref->struct_field().has_child()) { |
| 167 | ref = &ref->struct_field().child(); |
| 168 | } else { |
| 169 | ref = nullptr; |
| 170 | } |
| 171 | break; |
| 172 | } |
| 173 | case substrait::Expression::ReferenceSegment::kListElement: { |
| 174 | if (!current) { |
| 175 | // Root ListField (illegal) |
| 176 | return Status::Invalid( |
| 177 | "substrait::ListElement cannot take a Relation as an argument"); |
| 178 | } |
| 179 | |
| 180 | // ListField on top of an arbitrary expression |
| 181 | current = compute::call( |
| 182 | "list_element", |
| 183 | {std::move(*current), compute::literal(ref->list_element().offset())}); |
| 184 | |
| 185 | // Segment handled, continue with child segment (if any) |
| 186 | if (ref->list_element().has_child()) { |
| 187 | ref = &ref->list_element().child(); |
| 188 | } else { |
| 189 | ref = nullptr; |
| 190 | } |
| 191 | break; |
| 192 | } |
| 193 | default: |
| 194 | // Unimplemented construct, break current of loop |
no test coverage detected