| 263 | } |
| 264 | |
| 265 | Result<PartitionPathFormat> KeyValuePartitioning::Format( |
| 266 | const compute::Expression& expr) const { |
| 267 | ScalarVector values{static_cast<size_t>(schema_->num_fields()), nullptr}; |
| 268 | |
| 269 | ARROW_ASSIGN_OR_RAISE(auto known_values, ExtractKnownFieldValues(expr)); |
| 270 | for (const auto& ref_value : known_values.map) { |
| 271 | if (!ref_value.second.is_scalar()) { |
| 272 | return Status::Invalid("non-scalar partition key ", ref_value.second.ToString()); |
| 273 | } |
| 274 | |
| 275 | ARROW_ASSIGN_OR_RAISE(auto match, ref_value.first.FindOneOrNone(*schema_)); |
| 276 | if (match.empty()) continue; |
| 277 | |
| 278 | auto value = ref_value.second.scalar(); |
| 279 | |
| 280 | const auto& field = schema_->field(match[0]); |
| 281 | if (!value->type->Equals(field->type())) { |
| 282 | if (value->is_valid) { |
| 283 | auto maybe_converted = compute::Cast(value, field->type()); |
| 284 | if (!maybe_converted.ok()) { |
| 285 | return Status::TypeError("Error converting scalar ", value->ToString(), |
| 286 | " (of type ", *value->type, |
| 287 | ") to a partition key for ", field->ToString(), ": ", |
| 288 | maybe_converted.status().message()); |
| 289 | } |
| 290 | value = maybe_converted->scalar(); |
| 291 | } else { |
| 292 | value = MakeNullScalar(field->type()); |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | if (value->type->id() == Type::DICTIONARY) { |
| 297 | ARROW_ASSIGN_OR_RAISE( |
| 298 | value, checked_cast<const DictionaryScalar&>(*value).GetEncodedValue()); |
| 299 | } |
| 300 | |
| 301 | values[match[0]] = std::move(value); |
| 302 | } |
| 303 | |
| 304 | return FormatValues(values); |
| 305 | } |
| 306 | |
| 307 | inline std::optional<int> NextValid(const ScalarVector& values, int first_null) { |
| 308 | auto it = std::find_if(values.begin() + first_null + 1, values.end(), |