From a6c3f17d7b6939cea0b8c1070827aa9449d3f56a Mon Sep 17 00:00:00 2001 From: Guotao Yu Date: Sun, 30 Mar 2025 23:10:40 +0800 Subject: [PATCH] Add partition field/partition spec/transform --- src/iceberg/CMakeLists.txt | 3 ++ src/iceberg/error.h | 1 + src/iceberg/exception.h | 7 +++ src/iceberg/partition_field.cc | 56 +++++++++++++++++++++ src/iceberg/partition_field.h | 80 +++++++++++++++++++++++++++++ src/iceberg/partition_spec.cc | 54 ++++++++++++++++++++ src/iceberg/partition_spec.h | 71 ++++++++++++++++++++++++++ src/iceberg/transform.cc | 75 +++++++++++++++++++++++++++ src/iceberg/transform.h | 92 ++++++++++++++++++++++++++++++++++ src/iceberg/type_fwd.h | 2 + test/CMakeLists.txt | 8 ++- test/partition_field_test.cc | 76 ++++++++++++++++++++++++++++ test/partition_spec_test.cc | 87 ++++++++++++++++++++++++++++++++ test/transform_test.cc | 54 ++++++++++++++++++++ 14 files changed, 665 insertions(+), 1 deletion(-) create mode 100644 src/iceberg/partition_field.cc create mode 100644 src/iceberg/partition_field.h create mode 100644 src/iceberg/partition_spec.cc create mode 100644 src/iceberg/partition_spec.h create mode 100644 src/iceberg/transform.cc create mode 100644 src/iceberg/transform.h create mode 100644 test/partition_field_test.cc create mode 100644 test/partition_spec_test.cc create mode 100644 test/transform_test.cc diff --git a/src/iceberg/CMakeLists.txt b/src/iceberg/CMakeLists.txt index 817652246..ac33be2c1 100644 --- a/src/iceberg/CMakeLists.txt +++ b/src/iceberg/CMakeLists.txt @@ -23,6 +23,9 @@ set(ICEBERG_SOURCES schema.cc schema_field.cc schema_internal.cc + partition_field.cc + partition_spec.cc + transform.cc type.cc) set(ICEBERG_STATIC_BUILD_INTERFACE_LIBS) diff --git a/src/iceberg/error.h b/src/iceberg/error.h index 066ef87f0..60f07f331 100644 --- a/src/iceberg/error.h +++ b/src/iceberg/error.h @@ -34,6 +34,7 @@ enum class ErrorKind { kCommitStateUnknown, kInvalidSchema, kInvalidArgument, + kNotSupported, }; /// \brief Error with a kind and a message. diff --git a/src/iceberg/exception.h b/src/iceberg/exception.h index 67c8f6ce9..c5160bc43 100644 --- a/src/iceberg/exception.h +++ b/src/iceberg/exception.h @@ -38,4 +38,11 @@ class ICEBERG_EXPORT IcebergError : public std::runtime_error { explicit IcebergError(const std::string& what) : std::runtime_error(what) {} }; +#define ICEBERG_CHECK(condition, ...) \ + do { \ + if (!(condition)) [[unlikely]] { \ + throw iceberg::IcebergError(std::format(__VA_ARGS__)); \ + } \ + } while (0) + } // namespace iceberg diff --git a/src/iceberg/partition_field.cc b/src/iceberg/partition_field.cc new file mode 100644 index 000000000..ddfe8bada --- /dev/null +++ b/src/iceberg/partition_field.cc @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#include "iceberg/partition_field.h" + +#include + +#include "iceberg/transform.h" +#include "iceberg/type.h" +#include "iceberg/util/formatter.h" + +namespace iceberg { + +PartitionField::PartitionField(int32_t source_id, int32_t field_id, std::string name, + std::shared_ptr transform) + : source_id_(source_id), + field_id_(field_id), + name_(std::move(name)), + transform_(std::move(transform)) {} + +int32_t PartitionField::source_id() const { return source_id_; } + +int32_t PartitionField::field_id() const { return field_id_; } + +std::string_view PartitionField::name() const { return name_; } + +std::shared_ptr const& PartitionField::transform() const { + return transform_; +} + +std::string PartitionField::ToString() const { + return std::format("{} ({} {}({}))", name_, field_id_, *transform_, source_id_); +} + +bool PartitionField::Equals(const PartitionField& other) const { + return source_id_ == other.source_id_ && field_id_ == other.field_id_ && + name_ == other.name_ && *transform_ == *other.transform_; +} + +} // namespace iceberg diff --git a/src/iceberg/partition_field.h b/src/iceberg/partition_field.h new file mode 100644 index 000000000..3b75f21ce --- /dev/null +++ b/src/iceberg/partition_field.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#pragma once + +/// \file iceberg/partition_field.h +/// A partition field in a partition spec + +#include +#include +#include +#include +#include + +#include "iceberg/iceberg_export.h" +#include "iceberg/type_fwd.h" +#include "iceberg/util/formattable.h" + +namespace iceberg { + +/// \brief a field with its transform. +class ICEBERG_EXPORT PartitionField : public util::Formattable { + public: + /// \brief Construct a field. + /// \param[in] source_id The source field ID. + /// \param[in] field_id The partition field ID. + /// \param[in] name The partition field name. + /// \param[in] transform The transform function. + PartitionField(int32_t source_id, int32_t field_id, std::string name, + std::shared_ptr transform); + + /// \brief Get the source field ID. + int32_t source_id() const; + + /// \brief Get the partition field ID. + int32_t field_id() const; + + /// \brief Get the partition field name. + std::string_view name() const; + + /// \brief Get the transform type. + std::shared_ptr const& transform() const; + + std::string ToString() const override; + + friend bool operator==(const PartitionField& lhs, const PartitionField& rhs) { + return lhs.Equals(rhs); + } + + friend bool operator!=(const PartitionField& lhs, const PartitionField& rhs) { + return !(lhs == rhs); + } + + private: + /// \brief Compare two fields for equality. + [[nodiscard]] bool Equals(const PartitionField& other) const; + + int32_t source_id_; + int32_t field_id_; + std::string name_; + std::shared_ptr transform_; +}; + +} // namespace iceberg diff --git a/src/iceberg/partition_spec.cc b/src/iceberg/partition_spec.cc new file mode 100644 index 000000000..6b86750dc --- /dev/null +++ b/src/iceberg/partition_spec.cc @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#include "iceberg/partition_spec.h" + +#include + +#include "iceberg/schema.h" +#include "iceberg/type.h" +#include "iceberg/util/formatter.h" + +namespace iceberg { + +PartitionSpec::PartitionSpec(std::shared_ptr schema, int32_t spec_id, + std::vector fields) + : schema_(std::move(schema)), spec_id_(spec_id), fields_(std::move(fields)) {} + +const std::shared_ptr& PartitionSpec::schema() const { return schema_; } + +int32_t PartitionSpec::spec_id() const { return spec_id_; } + +std::span PartitionSpec::fields() const { return fields_; } + +std::string PartitionSpec::ToString() const { + std::string repr = std::format("partition_spec[spec_id<{}>,\n", spec_id_); + for (const auto& field : fields_) { + std::format_to(std::back_inserter(repr), " {}\n", field); + } + repr += "]"; + return repr; +} + +bool PartitionSpec::Equals(const PartitionSpec& other) const { + return *schema_ == *other.schema_ && spec_id_ == other.spec_id_ && + fields_ == other.fields_; +} + +} // namespace iceberg diff --git a/src/iceberg/partition_spec.h b/src/iceberg/partition_spec.h new file mode 100644 index 000000000..9bd36968b --- /dev/null +++ b/src/iceberg/partition_spec.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#pragma once + +/// \file iceberg/partition_spec.h +/// Partition specs for Iceberg tables. + +#include +#include +#include +#include + +#include "iceberg/iceberg_export.h" +#include "iceberg/partition_field.h" +#include "iceberg/util/formattable.h" + +namespace iceberg { + +/// \brief A partition spec for a Table. +/// +/// A partition spec is a list of partition fields, along with a unique integer ID. A +/// Table may have different partition specs over its lifetime due to partition spec +/// evolution. +class ICEBERG_EXPORT PartitionSpec : public util::Formattable { + public: + PartitionSpec(std::shared_ptr schema, int32_t spec_id, + std::vector fields); + /// \brief Get the table schema + const std::shared_ptr& schema() const; + /// \brief Get the spec ID. + int32_t spec_id() const; + /// \brief Get a view of the partition fields. + std::span fields() const; + + std::string ToString() const override; + + friend bool operator==(const PartitionSpec& lhs, const PartitionSpec& rhs) { + return lhs.Equals(rhs); + } + + friend bool operator!=(const PartitionSpec& lhs, const PartitionSpec& rhs) { + return !(lhs == rhs); + } + + private: + /// \brief Compare two partition specs for equality. + [[nodiscard]] bool Equals(const PartitionSpec& other) const; + + std::shared_ptr schema_; + const int32_t spec_id_; + std::vector fields_; +}; + +} // namespace iceberg diff --git a/src/iceberg/transform.cc b/src/iceberg/transform.cc new file mode 100644 index 000000000..6511ba92d --- /dev/null +++ b/src/iceberg/transform.cc @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#include "iceberg/transform.h" + +#include + +namespace iceberg { + +namespace { +/// \brief Get the relative transform name +constexpr std::string_view ToString(TransformType type) { + switch (type) { + case TransformType::kUnknown: + return "unknown"; + case TransformType::kIdentity: + return "identity"; + case TransformType::kBucket: + return "bucket"; + case TransformType::kTruncate: + return "truncate"; + case TransformType::kYear: + return "year"; + case TransformType::kMonth: + return "month"; + case TransformType::kDay: + return "day"; + case TransformType::kHour: + return "hour"; + case TransformType::kVoid: + return "void"; + default: + return "invalid"; + } +} +} // namespace + +TransformFunction::TransformFunction(TransformType type) : transform_type_(type) {} + +TransformType TransformFunction::transform_type() const { return transform_type_; } + +std::string TransformFunction::ToString() const { + return std::format("{}", iceberg::ToString(transform_type_)); +} + +bool TransformFunction::Equals(const TransformFunction& other) const { + return transform_type_ == other.transform_type_; +} + +IdentityTransformFunction::IdentityTransformFunction() + : TransformFunction(TransformType::kIdentity) {} + +expected IdentityTransformFunction::Transform( + const ArrowArray& input) { + return unexpected({.kind = ErrorKind::kNotSupported, + .message = "IdentityTransformFunction::Transform"}); +} + +} // namespace iceberg diff --git a/src/iceberg/transform.h b/src/iceberg/transform.h new file mode 100644 index 000000000..1d12a7702 --- /dev/null +++ b/src/iceberg/transform.h @@ -0,0 +1,92 @@ +/* + * 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. + */ + +#pragma once + +/// \file iceberg/transform.h + +#include +#include + +#include "iceberg/arrow_c_data.h" +#include "iceberg/error.h" +#include "iceberg/expected.h" +#include "iceberg/iceberg_export.h" +#include "iceberg/type_fwd.h" +#include "iceberg/util/formattable.h" + +namespace iceberg { + +/// \brief Transform types used for partitioning +enum class TransformType { + /// Used to represent some customized transform that can't be recognized or supported + /// now. + kUnknown, + /// Equal to source value, unmodified + kIdentity, + /// Hash of value, mod `N` + kBucket, + /// Value truncated to width `W` + kTruncate, + /// Extract a date or timestamp year, as years from 1970 + kYear, + /// Extract a date or timestamp month, as months from 1970-01 + kMonth, + /// Extract a date or timestamp day, as days from 1970-01-01 + kDay, + /// Extract a timestamp hour, as hours from 1970-01-01 00:00:00 + kHour, + /// Always produces `null` + kVoid, +}; + +/// \brief A transform function used for partitioning. +class ICEBERG_EXPORT TransformFunction : public util::Formattable { + public: + explicit TransformFunction(TransformType type); + /// \brief Transform an input array to a new array + virtual expected Transform(const ArrowArray& data) = 0; + /// \brief Get the transform type + virtual TransformType transform_type() const; + + std::string ToString() const override; + + friend bool operator==(const TransformFunction& lhs, const TransformFunction& rhs) { + return lhs.Equals(rhs); + } + + friend bool operator!=(const TransformFunction& lhs, const TransformFunction& rhs) { + return !(lhs == rhs); + } + + private: + /// \brief Compare two partition specs for equality. + [[nodiscard]] virtual bool Equals(const TransformFunction& other) const; + + TransformType transform_type_; +}; + +class IdentityTransformFunction : public TransformFunction { + public: + IdentityTransformFunction(); + /// \brief Transform will take an input array and transform it into a new array. + expected Transform(const ArrowArray& input) override; +}; + +} // namespace iceberg diff --git a/src/iceberg/type_fwd.h b/src/iceberg/type_fwd.h index bcbf84b72..f16b646e1 100644 --- a/src/iceberg/type_fwd.h +++ b/src/iceberg/type_fwd.h @@ -99,6 +99,8 @@ class Snapshot; class SortOrder; class StructLike; class TableMetadata; +enum class TransformType; +class TransformFunction; class MetadataUpdate; class UpdateRequirement; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 76006e0f9..9849d4378 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -24,7 +24,13 @@ fetchcontent_declare(googletest fetchcontent_makeavailable(googletest) add_executable(schema_test) -target_sources(schema_test PRIVATE schema_test.cc schema_field_test.cc type_test.cc) +target_sources(schema_test + PRIVATE schema_test.cc + schema_field_test.cc + type_test.cc + transform_test.cc + partition_field_test.cc + partition_spec_test.cc) target_link_libraries(schema_test PRIVATE iceberg_static GTest::gtest_main GTest::gmock) add_test(NAME schema_test COMMAND schema_test) diff --git a/test/partition_field_test.cc b/test/partition_field_test.cc new file mode 100644 index 000000000..6c21c1fa3 --- /dev/null +++ b/test/partition_field_test.cc @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#include "iceberg/partition_field.h" + +#include + +#include + +#include "iceberg/transform.h" +#include "iceberg/util/formatter.h" + +namespace iceberg { + +namespace { +class TestTransformFunction : public TransformFunction { + public: + TestTransformFunction() : TransformFunction(TransformType::kUnknown) {} + expected Transform(const ArrowArray& input) override { + return unexpected( + Error{.kind = ErrorKind::kNotSupported, .message = "test transform function"}); + } +}; + +} // namespace + +TEST(PartitionFieldTest, Basics) { + { + const auto transform = std::make_shared(); + PartitionField field(1, 1000, "pt", transform); + EXPECT_EQ(1, field.source_id()); + EXPECT_EQ(1000, field.field_id()); + EXPECT_EQ("pt", field.name()); + EXPECT_EQ(*transform, *field.transform()); + EXPECT_EQ("pt (1000 identity(1))", field.ToString()); + EXPECT_EQ("pt (1000 identity(1))", std::format("{}", field)); + } +} + +TEST(PartitionFieldTest, Equality) { + auto test_transform = std::make_shared(); + auto identity_transform = std::make_shared(); + + PartitionField field1(1, 10000, "pt", test_transform); + PartitionField field2(2, 10000, "pt", test_transform); + PartitionField field3(1, 10001, "pt", test_transform); + PartitionField field4(1, 10000, "pt2", test_transform); + PartitionField field5(1, 10000, "pt", identity_transform); + + ASSERT_EQ(field1, field1); + ASSERT_NE(field1, field2); + ASSERT_NE(field2, field1); + ASSERT_NE(field1, field3); + ASSERT_NE(field3, field1); + ASSERT_NE(field1, field4); + ASSERT_NE(field4, field1); + ASSERT_NE(field1, field5); + ASSERT_NE(field5, field1); +} +} // namespace iceberg diff --git a/test/partition_spec_test.cc b/test/partition_spec_test.cc new file mode 100644 index 000000000..9e486557a --- /dev/null +++ b/test/partition_spec_test.cc @@ -0,0 +1,87 @@ +/* + * 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. + */ + +#include "iceberg/partition_spec.h" + +#include +#include + +#include +#include + +#include "iceberg/partition_field.h" +#include "iceberg/schema.h" +#include "iceberg/transform.h" +#include "iceberg/util/formatter.h" + +namespace iceberg { + +TEST(PartitionSpecTest, Basics) { + { + SchemaField field1(5, "ts", std::make_shared(), true); + SchemaField field2(7, "bar", std::make_shared(), true); + auto const schema = std::make_shared(100, std::vector{field1, field2}); + + auto identity_transform = std::make_shared(); + PartitionField pt_field1(5, 1000, "day", identity_transform); + PartitionField pt_field2(5, 1001, "hour", identity_transform); + PartitionSpec spec(schema, 100, {pt_field1, pt_field2}); + ASSERT_EQ(spec, spec); + ASSERT_EQ(100, spec.spec_id()); + std::span fields = spec.fields(); + ASSERT_EQ(2, fields.size()); + ASSERT_EQ(pt_field1, fields[0]); + ASSERT_EQ(pt_field2, fields[1]); + ASSERT_EQ(*schema, *spec.schema()); + auto spec_str = + "partition_spec[spec_id<100>,\n day (1000 identity(5))\n hour (1001 " + "identity(5))\n]"; + EXPECT_EQ(spec_str, spec.ToString()); + EXPECT_EQ(spec_str, std::format("{}", spec)); + } +} + +TEST(PartitionSpecTest, Equality) { + SchemaField field1(5, "ts", std::make_shared(), true); + SchemaField field2(7, "bar", std::make_shared(), true); + auto const schema = std::make_shared(100, std::vector{field1, field2}); + auto identity_transform = std::make_shared(); + PartitionField pt_field1(5, 1000, "day", identity_transform); + PartitionField pt_field2(7, 1001, "hour", identity_transform); + PartitionField pt_field3(7, 1001, "hour", identity_transform); + PartitionSpec schema1(schema, 100, {pt_field1, pt_field2}); + PartitionSpec schema2(schema, 101, {pt_field1, pt_field2}); + PartitionSpec schema3(schema, 101, {pt_field1}); + PartitionSpec schema4(schema, 101, {pt_field3, pt_field1}); + PartitionSpec schema5(schema, 100, {pt_field1, pt_field2}); + PartitionSpec schema6(schema, 100, {pt_field2, pt_field1}); + + ASSERT_EQ(schema1, schema1); + ASSERT_NE(schema1, schema2); + ASSERT_NE(schema2, schema1); + ASSERT_NE(schema1, schema3); + ASSERT_NE(schema3, schema1); + ASSERT_NE(schema1, schema4); + ASSERT_NE(schema4, schema1); + ASSERT_EQ(schema1, schema5); + ASSERT_EQ(schema5, schema1); + ASSERT_NE(schema1, schema6); + ASSERT_NE(schema6, schema1); +} +} // namespace iceberg diff --git a/test/transform_test.cc b/test/transform_test.cc new file mode 100644 index 000000000..fc0086b7d --- /dev/null +++ b/test/transform_test.cc @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#include "iceberg/transform.h" + +#include +#include + +#include +#include + +#include "iceberg/util/formatter.h" + +namespace iceberg { + +TEST(TransformTest, TransformFunction) { + class TestTransformFunction : public TransformFunction { + public: + TestTransformFunction() : TransformFunction(TransformType::kUnknown) {} + expected Transform(const ArrowArray& input) override { + return unexpected( + Error{.kind = ErrorKind::kNotSupported, .message = "test transform function"}); + } + }; + + TestTransformFunction transform; + EXPECT_EQ(TransformType::kUnknown, transform.transform_type()); + EXPECT_EQ("unknown", transform.ToString()); + EXPECT_EQ("unknown", std::format("{}", transform)); + + ArrowArray arrow_array; + auto result = transform.Transform(arrow_array); + ASSERT_FALSE(result); + EXPECT_EQ(ErrorKind::kNotSupported, result.error().kind); + EXPECT_EQ("test transform function", result.error().message); +} + +} // namespace iceberg