Skip to content

Commit 5bda712

Browse files
authored
GH-48490: [GLib][Ruby] Add GArrowMakeStructOptions (#48491)
### Rationale for this change The `MakeStructOptions` class is not available in GLib/Ruby, and it is used together with the `make_struct` compute function. ### What changes are included in this PR? This adds the `MakeStructOptions` class to GLib. ### Are these changes tested? Yes, with Ruby unit tests. ### Are there any user-facing changes? Yes, a new class. * GitHub Issue: #48490 Authored-by: Sten Larsson <[email protected]> Signed-off-by: Sutou Kouhei <[email protected]>
1 parent 7ba1a7b commit 5bda712

File tree

8 files changed

+302
-1
lines changed

8 files changed

+302
-1
lines changed

c_glib/arrow-glib/compute.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <arrow-glib/error.hpp>
2929
#include <arrow-glib/executor.hpp>
3030
#include <arrow-glib/expression.hpp>
31+
#include <arrow-glib/internal-hash-table.hpp>
3132
#include <arrow-glib/reader.hpp>
3233
#include <arrow-glib/record-batch.hpp>
3334
#include <arrow-glib/scalar.hpp>
@@ -342,6 +343,9 @@ G_BEGIN_DECLS
342343
* #GArrowSplitOptions is a class to customize the `ascii_split_whitespace` and
343344
* `utf8_split_whitespace` functions.
344345
*
346+
* #GArrowMakeStructOptions is a class to customize the `make_struct`
347+
* function.
348+
*
345349
* There are many functions to compute data on an array.
346350
*/
347351

@@ -10598,6 +10602,67 @@ garrow_split_options_new(void)
1059810602
return GARROW_SPLIT_OPTIONS(g_object_new(GARROW_TYPE_SPLIT_OPTIONS, nullptr));
1059910603
}
1060010604

10605+
G_DEFINE_TYPE(GArrowMakeStructOptions,
10606+
garrow_make_struct_options,
10607+
GARROW_TYPE_FUNCTION_OPTIONS)
10608+
10609+
static void
10610+
garrow_make_struct_options_init(GArrowMakeStructOptions *object)
10611+
{
10612+
auto priv = GARROW_FUNCTION_OPTIONS_GET_PRIVATE(object);
10613+
priv->options = static_cast<arrow::compute::FunctionOptions *>(
10614+
new arrow::compute::MakeStructOptions());
10615+
}
10616+
10617+
static void
10618+
garrow_make_struct_options_class_init(GArrowMakeStructOptionsClass *klass)
10619+
{
10620+
}
10621+
10622+
/**
10623+
* garrow_make_struct_options_new:
10624+
*
10625+
* Returns: A newly created #GArrowMakeStructOptions.
10626+
*
10627+
* Since: 23.0.0
10628+
*/
10629+
GArrowMakeStructOptions *
10630+
garrow_make_struct_options_new(void)
10631+
{
10632+
auto options = g_object_new(GARROW_TYPE_MAKE_STRUCT_OPTIONS, nullptr);
10633+
return GARROW_MAKE_STRUCT_OPTIONS(options);
10634+
}
10635+
10636+
/**
10637+
* garrow_make_struct_options_add_field:
10638+
* @options: A #GArrowMakeStructOptions.
10639+
* @name: The name of the field to add.
10640+
* @nullability: Whether the field is nullable.
10641+
* @metadata: (nullable) (element-type utf8 utf8): A #GHashTable for the field's
10642+
* metadata, or %NULL.
10643+
*
10644+
* Adds a field to the struct options with the specified name, nullability,
10645+
* and optional metadata.
10646+
*
10647+
* Since: 23.0.0
10648+
*/
10649+
void
10650+
garrow_make_struct_options_add_field(GArrowMakeStructOptions *options,
10651+
const char *name,
10652+
gboolean nullability,
10653+
GHashTable *metadata)
10654+
{
10655+
auto arrow_options = garrow_make_struct_options_get_raw(options);
10656+
arrow_options->field_names.emplace_back(name);
10657+
arrow_options->field_nullability.push_back(nullability != FALSE);
10658+
if (metadata) {
10659+
arrow_options->field_metadata.push_back(
10660+
garrow_internal_hash_table_to_metadata(metadata));
10661+
} else {
10662+
arrow_options->field_metadata.push_back(nullptr);
10663+
}
10664+
}
10665+
1060110666
G_END_DECLS
1060210667

1060310668
arrow::Result<arrow::FieldRef>
@@ -10883,6 +10948,11 @@ garrow_function_options_new_raw(const arrow::compute::FunctionOptions *arrow_opt
1088310948
static_cast<const arrow::compute::SplitOptions *>(arrow_options);
1088410949
auto options = garrow_split_options_new_raw(arrow_split_options);
1088510950
return GARROW_FUNCTION_OPTIONS(options);
10951+
} else if (arrow_type_name == "MakeStructOptions") {
10952+
const auto arrow_make_struct_options =
10953+
static_cast<const arrow::compute::MakeStructOptions *>(arrow_options);
10954+
auto options = garrow_make_struct_options_new_raw(arrow_make_struct_options);
10955+
return GARROW_FUNCTION_OPTIONS(options);
1088610956
} else {
1088710957
auto options = g_object_new(GARROW_TYPE_FUNCTION_OPTIONS, NULL);
1088810958
return GARROW_FUNCTION_OPTIONS(options);
@@ -12037,3 +12107,20 @@ garrow_split_options_get_raw(GArrowSplitOptions *options)
1203712107
return static_cast<arrow::compute::SplitOptions *>(
1203812108
garrow_function_options_get_raw(GARROW_FUNCTION_OPTIONS(options)));
1203912109
}
12110+
12111+
GArrowMakeStructOptions *
12112+
garrow_make_struct_options_new_raw(const arrow::compute::MakeStructOptions *arrow_options)
12113+
{
12114+
auto options =
12115+
GARROW_MAKE_STRUCT_OPTIONS(g_object_new(GARROW_TYPE_MAKE_STRUCT_OPTIONS, nullptr));
12116+
auto arrow_new_options = garrow_make_struct_options_get_raw(options);
12117+
*arrow_new_options = *arrow_options;
12118+
return options;
12119+
}
12120+
12121+
arrow::compute::MakeStructOptions *
12122+
garrow_make_struct_options_get_raw(GArrowMakeStructOptions *options)
12123+
{
12124+
return static_cast<arrow::compute::MakeStructOptions *>(
12125+
garrow_function_options_get_raw(GARROW_FUNCTION_OPTIONS(options)));
12126+
}

c_glib/arrow-glib/compute.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,4 +1800,27 @@ GARROW_AVAILABLE_IN_23_0
18001800
GArrowSplitOptions *
18011801
garrow_split_options_new(void);
18021802

1803+
#define GARROW_TYPE_MAKE_STRUCT_OPTIONS (garrow_make_struct_options_get_type())
1804+
GARROW_AVAILABLE_IN_23_0
1805+
G_DECLARE_DERIVABLE_TYPE(GArrowMakeStructOptions,
1806+
garrow_make_struct_options,
1807+
GARROW,
1808+
MAKE_STRUCT_OPTIONS,
1809+
GArrowFunctionOptions)
1810+
struct _GArrowMakeStructOptionsClass
1811+
{
1812+
GArrowFunctionOptionsClass parent_class;
1813+
};
1814+
1815+
GARROW_AVAILABLE_IN_23_0
1816+
GArrowMakeStructOptions *
1817+
garrow_make_struct_options_new(void);
1818+
1819+
GARROW_AVAILABLE_IN_23_0
1820+
void
1821+
garrow_make_struct_options_add_field(GArrowMakeStructOptions *options,
1822+
const char *name,
1823+
gboolean nullability,
1824+
GHashTable *metadata);
1825+
18031826
G_END_DECLS

c_glib/arrow-glib/compute.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,3 +343,9 @@ GArrowSplitOptions *
343343
garrow_split_options_new_raw(const arrow::compute::SplitOptions *arrow_options);
344344
arrow::compute::SplitOptions *
345345
garrow_split_options_get_raw(GArrowSplitOptions *options);
346+
347+
GArrowMakeStructOptions *
348+
garrow_make_struct_options_new_raw(
349+
const arrow::compute::MakeStructOptions *arrow_options);
350+
arrow::compute::MakeStructOptions *
351+
garrow_make_struct_options_get_raw(GArrowMakeStructOptions *options);

c_glib/arrow-glib/internal-hash-table.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ garrow_internal_hash_table_to_metadata(GHashTable *metadata)
4040

4141
static inline GHashTable *
4242
garrow_internal_hash_table_from_metadata(
43-
const std::shared_ptr<arrow::KeyValueMetadata> &arrow_metadata)
43+
const std::shared_ptr<const arrow::KeyValueMetadata> &arrow_metadata)
4444
{
4545
auto metadata = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
4646
const auto &keys = arrow_metadata->keys();
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
class TestMakeStructOptions < Test::Unit::TestCase
19+
include Helper::Buildable
20+
21+
def setup
22+
@options = Arrow::MakeStructOptions.new
23+
end
24+
25+
def test_make_struct_function
26+
a = build_int8_array([1, 2, 3])
27+
b = build_boolean_array([true, false, nil])
28+
args = [
29+
Arrow::ArrayDatum.new(a),
30+
Arrow::ArrayDatum.new(b),
31+
]
32+
@options.add_field("a", true, nil)
33+
@options.add_field("b", true, nil)
34+
make_struct_function = Arrow::Function.find("make_struct")
35+
result = make_struct_function.execute(args, @options).value
36+
37+
expected = build_struct_array(
38+
[
39+
Arrow::Field.new("a", Arrow::Int8DataType.new),
40+
Arrow::Field.new("b", Arrow::BooleanDataType.new),
41+
],
42+
[
43+
{"a" => 1, "b" => true},
44+
{"a" => 2, "b" => false},
45+
{"a" => 3, "b" => nil},
46+
]
47+
)
48+
assert_equal(expected, result)
49+
end
50+
51+
def test_make_struct_function_with_nullability
52+
a = build_int8_array([1, 2, 3])
53+
b = build_boolean_array([true, false, nil])
54+
args = [
55+
Arrow::ArrayDatum.new(a),
56+
Arrow::ArrayDatum.new(b),
57+
]
58+
@options.add_field("a", false, nil)
59+
@options.add_field("b", true, nil)
60+
make_struct_function = Arrow::Function.find("make_struct")
61+
result = make_struct_function.execute(args, @options).value
62+
63+
expected = build_struct_array(
64+
[
65+
Arrow::Field.new("a", Arrow::Int8DataType.new, false),
66+
Arrow::Field.new("b", Arrow::BooleanDataType.new, true),
67+
],
68+
[
69+
{"a" => 1, "b" => true},
70+
{"a" => 2, "b" => false},
71+
{"a" => 3, "b" => nil},
72+
]
73+
)
74+
assert_equal(expected, result)
75+
end
76+
77+
def test_make_struct_function_with_metadata
78+
a = build_int8_array([1, 2, 3])
79+
b = build_boolean_array([true, false, nil])
80+
args = [
81+
Arrow::ArrayDatum.new(a),
82+
Arrow::ArrayDatum.new(b),
83+
]
84+
metadata1 = {"key1" => "value1"}
85+
metadata2 = {"key2" => "value2"}
86+
@options.add_field("a", true, metadata1)
87+
@options.add_field("b", true, metadata2)
88+
make_struct_function = Arrow::Function.find("make_struct")
89+
result = make_struct_function.execute(args, @options).value
90+
91+
fields = result.value_data_type.fields
92+
assert_equal(metadata1, fields[0].metadata)
93+
assert_equal(metadata2, fields[1].metadata)
94+
end
95+
end

ruby/red-arrow/lib/arrow/libraries.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
require_relative "list-array-builder"
8282
require_relative "list-data-type"
8383
require_relative "list-slice-options"
84+
require_relative "make-struct-options"
8485
require_relative "map-array"
8586
require_relative "map-array-builder"
8687
require_relative "map-data-type"
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
module Arrow
19+
class MakeStructOptions
20+
class << self
21+
def try_convert(value)
22+
case value
23+
when Hash
24+
options = new
25+
field_names = value[:field_names] || []
26+
field_nullability = value[:field_nullability] || []
27+
field_metadata = value[:field_metadata] || []
28+
field_names.zip(field_nullability, field_metadata) do |name, nullability, metadata|
29+
options.add_field(name, nullability, metadata)
30+
end
31+
options
32+
else
33+
nil
34+
end
35+
end
36+
end
37+
end
38+
end
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
class TestMakeStructOptions < Test::Unit::TestCase
19+
def test_make_struct_function
20+
a = Arrow::Int8Array.new([1, 2, 3])
21+
b = Arrow::BooleanArray.new([true, false, nil])
22+
metadata1 = {"a" => "b"}
23+
metadata2 = {"c" => "d"}
24+
options = {
25+
field_names: ["a", "b"],
26+
field_nullability: [false, true],
27+
field_metadata: [metadata1, metadata2]
28+
}
29+
args = [a, b]
30+
make_struct_function = Arrow::Function.find("make_struct")
31+
result = make_struct_function.execute(args, options).value
32+
33+
expected = Arrow::StructArray.new(
34+
Arrow::StructDataType.new(
35+
[
36+
Arrow::Field.new("a", Arrow::Int8DataType.new, false),
37+
Arrow::Field.new("b", Arrow::BooleanDataType.new, true),
38+
]
39+
),
40+
[
41+
{"a" => 1, "b" => true},
42+
{"a" => 2, "b" => false},
43+
{"a" => 3, "b" => nil},
44+
]
45+
)
46+
assert_equal(expected, result)
47+
fields = result.value_data_type.fields
48+
assert_equal(metadata1, fields[0].metadata)
49+
assert_equal(metadata2, fields[1].metadata)
50+
end
51+
end

0 commit comments

Comments
 (0)