From 267e69896e84128a17ae493e9b2385cf4e7cb586 Mon Sep 17 00:00:00 2001 From: Sten Larsson Date: Thu, 4 Dec 2025 17:20:17 +0100 Subject: [PATCH] Add GArrowPivotWiderOptions --- c_glib/arrow-glib/compute.cpp | 170 ++++++++++++++++++++++++ c_glib/arrow-glib/compute.h | 33 +++++ c_glib/arrow-glib/compute.hpp | 6 + c_glib/test/test-pivot-wider-options.rb | 60 +++++++++ 4 files changed, 269 insertions(+) create mode 100644 c_glib/test/test-pivot-wider-options.rb diff --git a/c_glib/arrow-glib/compute.cpp b/c_glib/arrow-glib/compute.cpp index 3527724d40a..8a698ab939f 100644 --- a/c_glib/arrow-glib/compute.cpp +++ b/c_glib/arrow-glib/compute.cpp @@ -303,6 +303,9 @@ G_BEGIN_DECLS * #GArrowPartitionNthOptions is a class to customize the * `partition_nth_indices` function. * + * #GArrowPivotWiderOptions is a class to customize the `pivot_wider` and + * `hash_pivot_wider` functions. + * * There are many functions to compute data on an array. */ @@ -8621,6 +8624,144 @@ garrow_partition_nth_options_new(void) g_object_new(GARROW_TYPE_PARTITION_NTH_OPTIONS, nullptr)); } +enum { + PROP_PIVOT_WIDER_OPTIONS_KEY_NAMES = 1, + PROP_PIVOT_WIDER_OPTIONS_UNEXPECTED_KEY_BEHAVIOR, +}; + +G_DEFINE_TYPE(GArrowPivotWiderOptions, + garrow_pivot_wider_options, + GARROW_TYPE_FUNCTION_OPTIONS) + +static void +garrow_pivot_wider_options_set_property(GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + auto options = garrow_pivot_wider_options_get_raw(GARROW_PIVOT_WIDER_OPTIONS(object)); + + switch (prop_id) { + case PROP_PIVOT_WIDER_OPTIONS_KEY_NAMES: + { + auto strv = static_cast(g_value_get_boxed(value)); + options->key_names.clear(); + if (strv) { + for (gchar **p = strv; *p; ++p) { + options->key_names.emplace_back(*p); + } + } + } + break; + case PROP_PIVOT_WIDER_OPTIONS_UNEXPECTED_KEY_BEHAVIOR: + options->unexpected_key_behavior = + static_cast( + g_value_get_enum(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +garrow_pivot_wider_options_get_property(GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + auto options = garrow_pivot_wider_options_get_raw(GARROW_PIVOT_WIDER_OPTIONS(object)); + + switch (prop_id) { + case PROP_PIVOT_WIDER_OPTIONS_KEY_NAMES: + { + const auto &names = options->key_names; + auto strv = static_cast(g_new0(gchar *, names.size() + 1)); + for (gsize i = 0; i < names.size(); ++i) { + strv[i] = g_strdup(names[i].c_str()); + } + g_value_take_boxed(value, strv); + } + break; + case PROP_PIVOT_WIDER_OPTIONS_UNEXPECTED_KEY_BEHAVIOR: + g_value_set_enum(value, + static_cast( + options->unexpected_key_behavior)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +garrow_pivot_wider_options_init(GArrowPivotWiderOptions *object) +{ + auto priv = GARROW_FUNCTION_OPTIONS_GET_PRIVATE(object); + priv->options = static_cast( + new arrow::compute::PivotWiderOptions()); +} + +static void +garrow_pivot_wider_options_class_init(GArrowPivotWiderOptionsClass *klass) +{ + auto gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->set_property = garrow_pivot_wider_options_set_property; + gobject_class->get_property = garrow_pivot_wider_options_get_property; + + arrow::compute::PivotWiderOptions options; + + GParamSpec *spec; + /** + * GArrowPivotWiderOptions:key-names: + * + * The values expected in the pivot key column. + * + * Since: 23.0.0 + */ + spec = g_param_spec_boxed("key-names", + "Key names", + "The values expected in the pivot key column", + G_TYPE_STRV, + static_cast(G_PARAM_READWRITE)); + g_object_class_install_property(gobject_class, + PROP_PIVOT_WIDER_OPTIONS_KEY_NAMES, + spec); + + /** + * GArrowPivotWiderOptions:unexpected-key-behavior: + * + * The behavior when pivot keys not in key_names are encountered. + * + * Since: 23.0.0 + */ + spec = g_param_spec_enum( + "unexpected-key-behavior", + "Unexpected key behavior", + "The behavior when pivot keys not in key_names are encountered", + GARROW_TYPE_PIVOT_WIDER_UNEXPECTED_KEY_BEHAVIOR, + static_cast(options.unexpected_key_behavior), + static_cast(G_PARAM_READWRITE)); + g_object_class_install_property(gobject_class, + PROP_PIVOT_WIDER_OPTIONS_UNEXPECTED_KEY_BEHAVIOR, + spec); +} + +/** + * garrow_pivot_wider_options_new: + * + * Returns: A newly created #GArrowPivotWiderOptions. + * + * Since: 23.0.0 + */ +GArrowPivotWiderOptions * +garrow_pivot_wider_options_new(void) +{ + return GARROW_PIVOT_WIDER_OPTIONS( + g_object_new(GARROW_TYPE_PIVOT_WIDER_OPTIONS, nullptr)); +} + G_END_DECLS arrow::Result @@ -8835,6 +8976,11 @@ garrow_function_options_new_raw(const arrow::compute::FunctionOptions *arrow_opt static_cast(arrow_options); auto options = garrow_partition_nth_options_new_raw(arrow_partition_nth_options); return GARROW_FUNCTION_OPTIONS(options); + } else if (arrow_type_name == "PivotWiderOptions") { + const auto arrow_pivot_wider_options = + static_cast(arrow_options); + auto options = garrow_pivot_wider_options_new_raw(arrow_pivot_wider_options); + return GARROW_FUNCTION_OPTIONS(options); } else { auto options = g_object_new(GARROW_TYPE_FUNCTION_OPTIONS, NULL); return GARROW_FUNCTION_OPTIONS(options); @@ -9700,3 +9846,27 @@ garrow_partition_nth_options_get_raw(GArrowPartitionNthOptions *options) return static_cast( garrow_function_options_get_raw(GARROW_FUNCTION_OPTIONS(options))); } + +GArrowPivotWiderOptions * +garrow_pivot_wider_options_new_raw(const arrow::compute::PivotWiderOptions *arrow_options) +{ + auto strv = static_cast(g_new0(gchar *, arrow_options->key_names.size() + 1)); + for (gsize i = 0; i < arrow_options->key_names.size(); ++i) { + strv[i] = g_strdup(arrow_options->key_names[i].c_str()); + } + return GARROW_PIVOT_WIDER_OPTIONS( + g_object_new(GARROW_TYPE_PIVOT_WIDER_OPTIONS, + "key-names", + strv, + "unexpected-key-behavior", + static_cast( + arrow_options->unexpected_key_behavior), + nullptr)); +} + +arrow::compute::PivotWiderOptions * +garrow_pivot_wider_options_get_raw(GArrowPivotWiderOptions *options) +{ + return static_cast( + garrow_function_options_get_raw(GARROW_FUNCTION_OPTIONS(options))); +} diff --git a/c_glib/arrow-glib/compute.h b/c_glib/arrow-glib/compute.h index c79c704b40b..53fb5ae7fc8 100644 --- a/c_glib/arrow-glib/compute.h +++ b/c_glib/arrow-glib/compute.h @@ -1507,4 +1507,37 @@ GARROW_AVAILABLE_IN_23_0 GArrowPartitionNthOptions * garrow_partition_nth_options_new(void); +/** + * GArrowPivotWiderUnexpectedKeyBehavior: + * @GARROW_PIVOT_WIDER_UNEXPECTED_KEY_BEHAVIOR_IGNORE: Unexpected pivot keys are ignored + * silently. + * @GARROW_PIVOT_WIDER_UNEXPECTED_KEY_BEHAVIOR_RAISE: Unexpected pivot keys return a + * KeyError. + * + * They correspond to the values of + * `arrow::compute::PivotWiderOptions::UnexpectedKeyBehavior`. + * + * Since: 23.0.0 + */ +typedef enum { + GARROW_PIVOT_WIDER_UNEXPECTED_KEY_BEHAVIOR_IGNORE, + GARROW_PIVOT_WIDER_UNEXPECTED_KEY_BEHAVIOR_RAISE, +} GArrowPivotWiderUnexpectedKeyBehavior; + +#define GARROW_TYPE_PIVOT_WIDER_OPTIONS (garrow_pivot_wider_options_get_type()) +GARROW_AVAILABLE_IN_23_0 +G_DECLARE_DERIVABLE_TYPE(GArrowPivotWiderOptions, + garrow_pivot_wider_options, + GARROW, + PIVOT_WIDER_OPTIONS, + GArrowFunctionOptions) +struct _GArrowPivotWiderOptionsClass +{ + GArrowFunctionOptionsClass parent_class; +}; + +GARROW_AVAILABLE_IN_23_0 +GArrowPivotWiderOptions * +garrow_pivot_wider_options_new(void); + G_END_DECLS diff --git a/c_glib/arrow-glib/compute.hpp b/c_glib/arrow-glib/compute.hpp index 692ec45b4e8..7b7a11df1bc 100644 --- a/c_glib/arrow-glib/compute.hpp +++ b/c_glib/arrow-glib/compute.hpp @@ -268,3 +268,9 @@ garrow_partition_nth_options_new_raw( const arrow::compute::PartitionNthOptions *arrow_options); arrow::compute::PartitionNthOptions * garrow_partition_nth_options_get_raw(GArrowPartitionNthOptions *options); + +GArrowPivotWiderOptions * +garrow_pivot_wider_options_new_raw( + const arrow::compute::PivotWiderOptions *arrow_options); +arrow::compute::PivotWiderOptions * +garrow_pivot_wider_options_get_raw(GArrowPivotWiderOptions *options); diff --git a/c_glib/test/test-pivot-wider-options.rb b/c_glib/test/test-pivot-wider-options.rb new file mode 100644 index 00000000000..71483e4c6a7 --- /dev/null +++ b/c_glib/test/test-pivot-wider-options.rb @@ -0,0 +1,60 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +class TestPivotWiderOptions < Test::Unit::TestCase + include Helper::Buildable + + def setup + @options = Arrow::PivotWiderOptions.new + end + + def test_key_names_property + assert_equal([], @options.key_names) + @options.key_names = ["height", "width"] + assert_equal(["height", "width"], @options.key_names) + end + + def test_unexpected_key_behavior_property + assert_equal(Arrow::PivotWiderUnexpectedKeyBehavior::IGNORE, @options.unexpected_key_behavior) + @options.unexpected_key_behavior = :raise + assert_equal(Arrow::PivotWiderUnexpectedKeyBehavior::RAISE, @options.unexpected_key_behavior) + @options.unexpected_key_behavior = :ignore + assert_equal(Arrow::PivotWiderUnexpectedKeyBehavior::IGNORE, @options.unexpected_key_behavior) + end + + def test_pivot_wider_function + keys = build_string_array(["height", "width", "depth"]) + values = build_int32_array([10, 20, 30]) + args = [ + Arrow::ArrayDatum.new(keys), + Arrow::ArrayDatum.new(values), + ] + @options.key_names = ["height", "width"] + pivot_wider_function = Arrow::Function.find("pivot_wider") + result = pivot_wider_function.execute(args, @options).value + fields = [ + Arrow::Field.new("height", Arrow::Int32DataType.new), + Arrow::Field.new("width", Arrow::Int32DataType.new), + ] + data_type = Arrow::StructDataType.new(fields) + expected = Arrow::StructScalar.new(data_type, [ + Arrow::Int32Scalar.new(10), + Arrow::Int32Scalar.new(20), + ]) + assert_equal(expected, result) + end +end