Skip to content

Commit bfe3152

Browse files
committed
Add partition field/partition spec/transform
1 parent 829dc65 commit bfe3152

14 files changed

+636
-2
lines changed

src/iceberg/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ set(ICEBERG_SOURCES
2222
demo.cc
2323
schema.cc
2424
schema_field.cc
25-
type.cc)
25+
type.cc
26+
transform.cc
27+
partition_field.cc
28+
partition_spec.cc)
2629

2730
set(ICEBERG_STATIC_BUILD_INTERFACE_LIBS)
2831
set(ICEBERG_SHARED_BUILD_INTERFACE_LIBS)

src/iceberg/error.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ enum class ErrorKind {
3232
kAlreadyExists,
3333
kNoSuchTable,
3434
kCommitStateUnknown,
35+
kNotSupported,
3536
};
3637

3738
/// \brief Error with a kind and a message.

src/iceberg/exception.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,11 @@ class ICEBERG_EXPORT IcebergError : public std::runtime_error {
3838
explicit IcebergError(const std::string& what) : std::runtime_error(what) {}
3939
};
4040

41+
#define ICEBERG_CHECK_FMT(condition, ...) \
42+
do { \
43+
if (!(condition)) [[unlikely]] { \
44+
throw iceberg::IcebergError(std::format(__VA_ARGS__)); \
45+
} \
46+
} while (0)
47+
4148
} // namespace iceberg

src/iceberg/partition_field.cc

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include "iceberg/partition_field.h"
21+
22+
#include <format>
23+
24+
#include "iceberg/transform.h"
25+
#include "iceberg/type.h"
26+
#include "iceberg/util/formatter.h"
27+
28+
namespace iceberg {
29+
30+
PartitionField::PartitionField(int32_t source_field_id, int32_t field_id,
31+
std::string name, TransformType transformType)
32+
: source_field_id_(source_field_id),
33+
field_id_(field_id),
34+
name_(std::move(name)),
35+
transform_type_(transformType) {}
36+
37+
int32_t PartitionField::source_field_id() const { return source_field_id_; }
38+
39+
int32_t PartitionField::field_id() const { return field_id_; }
40+
41+
std::string_view PartitionField::name() const { return name_; }
42+
43+
TransformType PartitionField::transform_type() const { return transform_type_; }
44+
45+
std::string PartitionField::ToString() const {
46+
return std::format("{} ({} {}({}))", name_, field_id_,
47+
iceberg::ToString(transform_type_), source_field_id_);
48+
}
49+
50+
bool PartitionField::Equals(const PartitionField& other) const {
51+
return source_field_id_ == other.source_field_id_ && field_id_ == other.field_id_ &&
52+
name_ == other.name_ && transform_type_ == other.transform_type_;
53+
}
54+
55+
} // namespace iceberg

src/iceberg/partition_field.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#pragma once
21+
22+
/// \file iceberg/partition_field.h
23+
/// A partition field in a partition spec
24+
25+
#include <cstdint>
26+
#include <memory>
27+
#include <string>
28+
#include <string_view>
29+
30+
#include "iceberg/iceberg_export.h"
31+
#include "iceberg/type_fwd.h"
32+
#include "iceberg/util/formattable.h"
33+
34+
namespace iceberg {
35+
36+
/// \brief a field with its transform.
37+
class ICEBERG_EXPORT PartitionField : public util::Formattable {
38+
public:
39+
/// \brief Construct a field.
40+
/// \param[in] source_id The source field ID.
41+
/// \param[in] field_id The partition field ID.
42+
/// \param[in] name The partition field name.
43+
/// \param[in] transformType The transform type.
44+
PartitionField(int32_t source_id, int32_t field_id, std::string name, TransformType transformType);
45+
46+
/// \brief Get the source field ID.
47+
[[nodiscard]] int32_t source_field_id() const;
48+
49+
/// \brief Get the partition field ID.
50+
[[nodiscard]] int32_t field_id() const;
51+
52+
/// \brief Get the partition field name.
53+
[[nodiscard]] std::string_view name() const;
54+
55+
/// \brief Get the transform type.
56+
[[nodiscard]] TransformType transform_type() const;
57+
58+
[[nodiscard]] std::string ToString() const override;
59+
60+
friend bool operator==(const PartitionField& lhs, const PartitionField& rhs) {
61+
return lhs.Equals(rhs);
62+
}
63+
64+
friend bool operator!=(const PartitionField& lhs, const PartitionField& rhs) {
65+
return !(lhs == rhs);
66+
}
67+
68+
private:
69+
/// \brief Compare two fields for equality.
70+
[[nodiscard]] bool Equals(const PartitionField& other) const;
71+
72+
int32_t source_field_id_;
73+
int32_t field_id_;
74+
std::string name_;
75+
TransformType transform_type_;
76+
};
77+
78+
} // namespace iceberg

src/iceberg/partition_spec.cc

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include "iceberg/partition_spec.h"
21+
22+
#include <format>
23+
24+
#include "iceberg/exception.h"
25+
#include "iceberg/type.h"
26+
#include "iceberg/util/formatter.h"
27+
28+
namespace iceberg {
29+
30+
PartitionSpec::PartitionSpec(int32_t spec_id, std::vector<PartitionField> fields)
31+
: spec_id_(spec_id), fields_(std::move(fields)) {
32+
size_t index = 0;
33+
for (const auto& field : fields_) {
34+
auto [it, inserted] = field_id_to_index_.try_emplace(field.field_id(), index);
35+
ICEBERG_CHECK_FMT(inserted,
36+
"PartitionSpec: duplicate field ID {} (field indices {} and {})",
37+
field.field_id(), it->second, index);
38+
++index;
39+
}
40+
}
41+
42+
int32_t PartitionSpec::spec_id() const { return spec_id_; }
43+
44+
std::span<const PartitionField> PartitionSpec::fields() const { return fields_; }
45+
46+
std::optional<std::reference_wrapper<const PartitionField>> PartitionSpec::GetFieldById(
47+
int32_t field_id) const {
48+
if (auto it = field_id_to_index_.find(field_id); it != field_id_to_index_.end()) {
49+
return fields_[it->second];
50+
}
51+
return std::nullopt;
52+
}
53+
54+
std::optional<std::reference_wrapper<const PartitionField>>
55+
PartitionSpec::GetFieldByIndex(int32_t index) const {
56+
if (index >= 0 && index < static_cast<int>(fields_.size())) {
57+
return fields_[index];
58+
}
59+
return std::nullopt;
60+
}
61+
62+
std::optional<std::reference_wrapper<const PartitionField>> PartitionSpec::GetFieldByName(
63+
std::string_view name) const {
64+
auto findField = [&name](auto& field) { return field.name() == name; };
65+
if (auto it = std::ranges::find_if(fields_, findField); it != fields_.end()) {
66+
return *it;
67+
}
68+
return std::nullopt;
69+
}
70+
71+
std::string PartitionSpec::ToString() const {
72+
std::string repr = "partition_spec(<";
73+
for (const auto& field : fields_) {
74+
std::format_to(std::back_inserter(repr), " {}\n", field);
75+
}
76+
repr += ">";
77+
return repr;
78+
}
79+
80+
bool PartitionSpec::Equals(const PartitionSpec& other) const {
81+
return spec_id_ == other.spec_id_ && fields_ == other.fields_;
82+
}
83+
84+
} // namespace iceberg

src/iceberg/partition_spec.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#pragma once
21+
22+
/// \file iceberg/partition_spec.h
23+
/// Partition specs for Iceberg tables.
24+
25+
#include <cstdint>
26+
#include <string>
27+
#include <vector>
28+
#include <span>
29+
30+
#include "iceberg/iceberg_export.h"
31+
#include "iceberg/partition_field.h"
32+
33+
namespace iceberg {
34+
35+
/// \brief A partition spec for a Table.
36+
///
37+
/// A partition spec is a list of partition fields, along with a unique integer ID. A
38+
/// Table may have different partition specs over its lifetime due to partition spec
39+
/// evolution.
40+
class ICEBERG_EXPORT PartitionSpec {
41+
public:
42+
virtual ~PartitionSpec() = default;
43+
PartitionSpec(int32_t spec_id, std::vector<PartitionField> fields);
44+
/// \brief Get the spec ID.
45+
[[nodiscard]] int32_t spec_id() const;
46+
/// \brief Get a view of the partition fields.
47+
[[nodiscard]] virtual std::span<const PartitionField> fields() const;
48+
/// \brief Get a field by field ID.
49+
[[nodiscard]] virtual std::optional<std::reference_wrapper<const PartitionField>>
50+
GetFieldById(int32_t field_id) const;
51+
/// \brief Get a field by index.
52+
[[nodiscard]] virtual std::optional<std::reference_wrapper<const PartitionField>>
53+
GetFieldByIndex(int32_t index) const;
54+
/// \brief Get a field by name (case-sensitive).
55+
[[nodiscard]] virtual std::optional<std::reference_wrapper<const PartitionField>>
56+
GetFieldByName(std::string_view name) const;
57+
58+
[[nodiscard]] std::string ToString() const;
59+
60+
friend bool operator==(const PartitionSpec& lhs, const PartitionSpec& rhs) { return lhs.Equals(rhs); }
61+
62+
friend bool operator!=(const PartitionSpec& lhs, const PartitionSpec& rhs) { return !(lhs == rhs); }
63+
64+
private:
65+
/// \brief Compare two partition specs for equality.
66+
[[nodiscard]] bool Equals(const PartitionSpec& other) const;
67+
68+
const int32_t spec_id_;
69+
std::vector<PartitionField> fields_;
70+
std::unordered_map<int32_t, size_t> field_id_to_index_;
71+
};
72+
73+
} // namespace iceberg

src/iceberg/transform.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include "iceberg/transform.h"
21+
22+
#include <format>
23+
24+
namespace iceberg {
25+
26+
TransformFunction::TransformFunction(TransformType type) : transform_type_(type) {}
27+
28+
TransformType TransformFunction::transform_type() const { return transform_type_; }
29+
30+
std::string TransformFunction::ToString() const {
31+
return std::format("{}", iceberg::ToString(transform_type_));
32+
}
33+
34+
} // namespace iceberg

0 commit comments

Comments
 (0)