This is an automated email from the ASF dual-hosted git repository.
gangwu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-cpp.git
The following commit(s) were added to refs/heads/main by this push:
new 024bbf11 feat: add non-validated version of FromJson for SortOrder and
PartitionSpec (#518)
024bbf11 is described below
commit 024bbf11504eb3526b115204e41f989280c4942e
Author: Feiyang Li <[email protected]>
AuthorDate: Wed Jan 21 17:55:27 2026 +0800
feat: add non-validated version of FromJson for SortOrder and PartitionSpec
(#518)
---
src/iceberg/json_internal.cc | 36 +++++++++++++++++-----
src/iceberg/json_internal.h | 16 ++++++++++
src/iceberg/test/json_internal_test.cc | 56 ++++++++++++++++++++++++++++++++++
3 files changed, 101 insertions(+), 7 deletions(-)
diff --git a/src/iceberg/json_internal.cc b/src/iceberg/json_internal.cc
index 7e2652d6..e92d3dd5 100644
--- a/src/iceberg/json_internal.cc
+++ b/src/iceberg/json_internal.cc
@@ -33,7 +33,6 @@
#include "iceberg/partition_spec.h"
#include "iceberg/result.h"
#include "iceberg/schema.h"
-#include "iceberg/schema_internal.h"
#include "iceberg/snapshot.h"
#include "iceberg/sort_order.h"
#include "iceberg/statistics_file.h"
@@ -271,6 +270,18 @@ Result<std::unique_ptr<SortOrder>> SortOrderFromJson(
return SortOrder::Make(*current_schema, order_id, std::move(sort_fields));
}
+Result<std::unique_ptr<SortOrder>> SortOrderFromJson(const nlohmann::json&
json) {
+ ICEBERG_ASSIGN_OR_RAISE(auto order_id, GetJsonValue<int32_t>(json,
kOrderId));
+ ICEBERG_ASSIGN_OR_RAISE(auto fields, GetJsonValue<nlohmann::json>(json,
kFields));
+
+ std::vector<SortField> sort_fields;
+ for (const auto& field_json : fields) {
+ ICEBERG_ASSIGN_OR_RAISE(auto sort_field, SortFieldFromJson(field_json));
+ sort_fields.push_back(std::move(*sort_field));
+ }
+ return SortOrder::Make(order_id, std::move(sort_fields));
+}
+
nlohmann::json ToJson(const SchemaField& field) {
nlohmann::json json;
json[kId] = field.field_id();
@@ -615,6 +626,19 @@ Result<std::unique_ptr<PartitionSpec>>
PartitionSpecFromJson(
return spec;
}
+Result<std::unique_ptr<PartitionSpec>> PartitionSpecFromJson(const
nlohmann::json& json) {
+ ICEBERG_ASSIGN_OR_RAISE(auto spec_id, GetJsonValue<int32_t>(json, kSpecId));
+ ICEBERG_ASSIGN_OR_RAISE(auto fields, GetJsonValue<nlohmann::json>(json,
kFields));
+
+ std::vector<PartitionField> partition_fields;
+ for (const auto& field_json : fields) {
+ ICEBERG_ASSIGN_OR_RAISE(auto partition_field,
PartitionFieldFromJson(field_json));
+ partition_fields.push_back(std::move(*partition_field));
+ }
+
+ return PartitionSpec::Make(spec_id, std::move(partition_fields));
+}
+
Result<std::unique_ptr<SnapshotRef>> SnapshotRefFromJson(const nlohmann::json&
json) {
ICEBERG_ASSIGN_OR_RAISE(auto snapshot_id, GetJsonValue<int64_t>(json,
kSnapshotId));
ICEBERG_ASSIGN_OR_RAISE(
@@ -1492,10 +1516,8 @@ Result<std::unique_ptr<TableUpdate>>
TableUpdateFromJson(const nlohmann::json& j
}
if (action == kActionAddPartitionSpec) {
ICEBERG_ASSIGN_OR_RAISE(auto spec_json, GetJsonValue<nlohmann::json>(json,
kSpec));
- ICEBERG_ASSIGN_OR_RAISE(auto spec_id_opt,
- GetJsonValueOptional<int32_t>(spec_json, kSpecId));
- // TODO(Feiyang Li): add fromJson for UnboundPartitionSpec and then use it
here
- return NotImplemented("FromJson of TableUpdate::AddPartitionSpec is not
implemented");
+ ICEBERG_ASSIGN_OR_RAISE(auto spec, PartitionSpecFromJson(spec_json));
+ return std::make_unique<table::AddPartitionSpec>(std::move(spec));
}
if (action == kActionSetDefaultPartitionSpec) {
ICEBERG_ASSIGN_OR_RAISE(auto spec_id, GetJsonValue<int32_t>(json,
kSpecId));
@@ -1515,8 +1537,8 @@ Result<std::unique_ptr<TableUpdate>>
TableUpdateFromJson(const nlohmann::json& j
if (action == kActionAddSortOrder) {
ICEBERG_ASSIGN_OR_RAISE(auto sort_order_json,
GetJsonValue<nlohmann::json>(json, kSortOrder));
- // TODO(Feiyang Li): add fromJson for UnboundSortOrder and then use it here
- return NotImplemented("FromJson of TableUpdate::AddSortOrder is not
implemented");
+ ICEBERG_ASSIGN_OR_RAISE(auto sort_order,
SortOrderFromJson(sort_order_json));
+ return std::make_unique<table::AddSortOrder>(std::move(sort_order));
}
if (action == kActionSetDefaultSortOrder) {
ICEBERG_ASSIGN_OR_RAISE(auto sort_order_id,
diff --git a/src/iceberg/json_internal.h b/src/iceberg/json_internal.h
index d55252ca..7b09acdb 100644
--- a/src/iceberg/json_internal.h
+++ b/src/iceberg/json_internal.h
@@ -75,6 +75,14 @@ ICEBERG_EXPORT nlohmann::json ToJson(const SortOrder&
sort_order);
ICEBERG_EXPORT Result<std::unique_ptr<SortOrder>> SortOrderFromJson(
const nlohmann::json& json, const std::shared_ptr<Schema>& current_schema);
+/// \brief Deserializes a JSON object into a `SortOrder` object.
+///
+/// \param json The JSON object representing a `SortOrder`.
+/// \return An `expected` value containing either a `SortOrder` object or an
error. If the
+/// JSON is malformed or missing expected fields, an error will be returned.
+ICEBERG_EXPORT Result<std::unique_ptr<SortOrder>> SortOrderFromJson(
+ const nlohmann::json& json);
+
/// \brief Convert an Iceberg Schema to JSON.
///
/// \param schema The Iceberg schema to convert.
@@ -183,6 +191,14 @@ ICEBERG_EXPORT Result<std::unique_ptr<PartitionSpec>>
PartitionSpecFromJson(
const std::shared_ptr<Schema>& schema, const nlohmann::json& json,
int32_t default_spec_id);
+/// \brief Deserializes a JSON object into a `PartitionSpec` object.
+///
+/// \param json The JSON object representing a `PartitionSpec`.
+/// \return An `expected` value containing either a `PartitionSpec` object or
an error. If
+/// the JSON is malformed or missing expected fields, an error will be
returned.
+ICEBERG_EXPORT Result<std::unique_ptr<PartitionSpec>> PartitionSpecFromJson(
+ const nlohmann::json& json);
+
/// \brief Serializes a `SnapshotRef` object to JSON.
///
/// \param snapshot_ref The `SnapshotRef` object to be serialized.
diff --git a/src/iceberg/test/json_internal_test.cc
b/src/iceberg/test/json_internal_test.cc
index 0b5f4f59..d6a171e0 100644
--- a/src/iceberg/test/json_internal_test.cc
+++ b/src/iceberg/test/json_internal_test.cc
@@ -175,6 +175,29 @@ TEST(JsonInternalTest, PartitionSpec) {
EXPECT_EQ(*spec, *parsed_spec_result.value());
}
+TEST(JsonInternalTest, SortOrderFromJson) {
+ auto identity_transform = Transform::Identity();
+ SortField st1(5, identity_transform, SortDirection::kAscending,
NullOrder::kFirst);
+ SortField st2(7, identity_transform, SortDirection::kDescending,
NullOrder::kLast);
+ ICEBERG_UNWRAP_OR_FAIL(auto sort_order, SortOrder::Make(100, {st1, st2}));
+
+ auto json = ToJson(*sort_order);
+ ICEBERG_UNWRAP_OR_FAIL(auto parsed, SortOrderFromJson(json));
+ EXPECT_EQ(*sort_order, *parsed);
+}
+
+TEST(JsonInternalTest, PartitionSpecFromJson) {
+ auto identity_transform = Transform::Identity();
+ ICEBERG_UNWRAP_OR_FAIL(
+ auto spec,
+ PartitionSpec::Make(1, {PartitionField(3, 101, "region",
identity_transform),
+ PartitionField(5, 102, "ts",
identity_transform)}));
+
+ auto json = ToJson(*spec);
+ ICEBERG_UNWRAP_OR_FAIL(auto parsed, PartitionSpecFromJson(json));
+ EXPECT_EQ(*spec, *parsed);
+}
+
TEST(JsonInternalTest, SnapshotRefBranch) {
SnapshotRef ref(1234567890, SnapshotRef::Branch{.min_snapshots_to_keep = 10,
.max_snapshot_age_ms =
123456789,
@@ -349,6 +372,23 @@ TEST(JsonInternalTest, TableUpdateSetCurrentSchema) {
update);
}
+TEST(JsonInternalTest, TableUpdateAddPartitionSpec) {
+ auto identity_transform = Transform::Identity();
+ ICEBERG_UNWRAP_OR_FAIL(
+ auto spec,
+ PartitionSpec::Make(1, {PartitionField(3, 101, "region",
identity_transform)}));
+ table::AddPartitionSpec update(std::move(spec));
+
+ auto json = ToJson(update);
+ EXPECT_EQ(json["action"], "add-spec");
+ EXPECT_TRUE(json.contains("spec"));
+
+ auto parsed = TableUpdateFromJson(json);
+ ASSERT_THAT(parsed, IsOk());
+ auto* actual =
internal::checked_cast<table::AddPartitionSpec*>(parsed.value().get());
+ EXPECT_EQ(*actual->spec(), *update.spec());
+}
+
TEST(JsonInternalTest, TableUpdateSetDefaultPartitionSpec) {
table::SetDefaultPartitionSpec update(2);
nlohmann::json expected =
R"({"action":"set-default-spec","spec-id":2})"_json;
@@ -386,6 +426,22 @@ TEST(JsonInternalTest, TableUpdateRemoveSchemas) {
EXPECT_EQ(*internal::checked_cast<table::RemoveSchemas*>(parsed.value().get()),
update);
}
+TEST(JsonInternalTest, TableUpdateAddSortOrder) {
+ auto identity_transform = Transform::Identity();
+ SortField st(5, identity_transform, SortDirection::kAscending,
NullOrder::kFirst);
+ ICEBERG_UNWRAP_OR_FAIL(auto sort_order, SortOrder::Make(1, {st}));
+ table::AddSortOrder update(std::move(sort_order));
+
+ auto json = ToJson(update);
+ EXPECT_EQ(json["action"], "add-sort-order");
+ EXPECT_TRUE(json.contains("sort-order"));
+
+ auto parsed = TableUpdateFromJson(json);
+ ASSERT_THAT(parsed, IsOk());
+ auto* actual =
internal::checked_cast<table::AddSortOrder*>(parsed.value().get());
+ EXPECT_EQ(*actual->sort_order(), *update.sort_order());
+}
+
TEST(JsonInternalTest, TableUpdateSetDefaultSortOrder) {
table::SetDefaultSortOrder update(1);
nlohmann::json expected =