Skip to content

Commit 024bbf1

Browse files
authored
feat: add non-validated version of FromJson for SortOrder and PartitionSpec (#518)
1 parent 75204b1 commit 024bbf1

File tree

3 files changed

+101
-7
lines changed

3 files changed

+101
-7
lines changed

src/iceberg/json_internal.cc

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
#include "iceberg/partition_spec.h"
3434
#include "iceberg/result.h"
3535
#include "iceberg/schema.h"
36-
#include "iceberg/schema_internal.h"
3736
#include "iceberg/snapshot.h"
3837
#include "iceberg/sort_order.h"
3938
#include "iceberg/statistics_file.h"
@@ -271,6 +270,18 @@ Result<std::unique_ptr<SortOrder>> SortOrderFromJson(
271270
return SortOrder::Make(*current_schema, order_id, std::move(sort_fields));
272271
}
273272

273+
Result<std::unique_ptr<SortOrder>> SortOrderFromJson(const nlohmann::json& json) {
274+
ICEBERG_ASSIGN_OR_RAISE(auto order_id, GetJsonValue<int32_t>(json, kOrderId));
275+
ICEBERG_ASSIGN_OR_RAISE(auto fields, GetJsonValue<nlohmann::json>(json, kFields));
276+
277+
std::vector<SortField> sort_fields;
278+
for (const auto& field_json : fields) {
279+
ICEBERG_ASSIGN_OR_RAISE(auto sort_field, SortFieldFromJson(field_json));
280+
sort_fields.push_back(std::move(*sort_field));
281+
}
282+
return SortOrder::Make(order_id, std::move(sort_fields));
283+
}
284+
274285
nlohmann::json ToJson(const SchemaField& field) {
275286
nlohmann::json json;
276287
json[kId] = field.field_id();
@@ -615,6 +626,19 @@ Result<std::unique_ptr<PartitionSpec>> PartitionSpecFromJson(
615626
return spec;
616627
}
617628

629+
Result<std::unique_ptr<PartitionSpec>> PartitionSpecFromJson(const nlohmann::json& json) {
630+
ICEBERG_ASSIGN_OR_RAISE(auto spec_id, GetJsonValue<int32_t>(json, kSpecId));
631+
ICEBERG_ASSIGN_OR_RAISE(auto fields, GetJsonValue<nlohmann::json>(json, kFields));
632+
633+
std::vector<PartitionField> partition_fields;
634+
for (const auto& field_json : fields) {
635+
ICEBERG_ASSIGN_OR_RAISE(auto partition_field, PartitionFieldFromJson(field_json));
636+
partition_fields.push_back(std::move(*partition_field));
637+
}
638+
639+
return PartitionSpec::Make(spec_id, std::move(partition_fields));
640+
}
641+
618642
Result<std::unique_ptr<SnapshotRef>> SnapshotRefFromJson(const nlohmann::json& json) {
619643
ICEBERG_ASSIGN_OR_RAISE(auto snapshot_id, GetJsonValue<int64_t>(json, kSnapshotId));
620644
ICEBERG_ASSIGN_OR_RAISE(
@@ -1492,10 +1516,8 @@ Result<std::unique_ptr<TableUpdate>> TableUpdateFromJson(const nlohmann::json& j
14921516
}
14931517
if (action == kActionAddPartitionSpec) {
14941518
ICEBERG_ASSIGN_OR_RAISE(auto spec_json, GetJsonValue<nlohmann::json>(json, kSpec));
1495-
ICEBERG_ASSIGN_OR_RAISE(auto spec_id_opt,
1496-
GetJsonValueOptional<int32_t>(spec_json, kSpecId));
1497-
// TODO(Feiyang Li): add fromJson for UnboundPartitionSpec and then use it here
1498-
return NotImplemented("FromJson of TableUpdate::AddPartitionSpec is not implemented");
1519+
ICEBERG_ASSIGN_OR_RAISE(auto spec, PartitionSpecFromJson(spec_json));
1520+
return std::make_unique<table::AddPartitionSpec>(std::move(spec));
14991521
}
15001522
if (action == kActionSetDefaultPartitionSpec) {
15011523
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
15151537
if (action == kActionAddSortOrder) {
15161538
ICEBERG_ASSIGN_OR_RAISE(auto sort_order_json,
15171539
GetJsonValue<nlohmann::json>(json, kSortOrder));
1518-
// TODO(Feiyang Li): add fromJson for UnboundSortOrder and then use it here
1519-
return NotImplemented("FromJson of TableUpdate::AddSortOrder is not implemented");
1540+
ICEBERG_ASSIGN_OR_RAISE(auto sort_order, SortOrderFromJson(sort_order_json));
1541+
return std::make_unique<table::AddSortOrder>(std::move(sort_order));
15201542
}
15211543
if (action == kActionSetDefaultSortOrder) {
15221544
ICEBERG_ASSIGN_OR_RAISE(auto sort_order_id,

src/iceberg/json_internal.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,14 @@ ICEBERG_EXPORT nlohmann::json ToJson(const SortOrder& sort_order);
7575
ICEBERG_EXPORT Result<std::unique_ptr<SortOrder>> SortOrderFromJson(
7676
const nlohmann::json& json, const std::shared_ptr<Schema>& current_schema);
7777

78+
/// \brief Deserializes a JSON object into a `SortOrder` object.
79+
///
80+
/// \param json The JSON object representing a `SortOrder`.
81+
/// \return An `expected` value containing either a `SortOrder` object or an error. If the
82+
/// JSON is malformed or missing expected fields, an error will be returned.
83+
ICEBERG_EXPORT Result<std::unique_ptr<SortOrder>> SortOrderFromJson(
84+
const nlohmann::json& json);
85+
7886
/// \brief Convert an Iceberg Schema to JSON.
7987
///
8088
/// \param schema The Iceberg schema to convert.
@@ -183,6 +191,14 @@ ICEBERG_EXPORT Result<std::unique_ptr<PartitionSpec>> PartitionSpecFromJson(
183191
const std::shared_ptr<Schema>& schema, const nlohmann::json& json,
184192
int32_t default_spec_id);
185193

194+
/// \brief Deserializes a JSON object into a `PartitionSpec` object.
195+
///
196+
/// \param json The JSON object representing a `PartitionSpec`.
197+
/// \return An `expected` value containing either a `PartitionSpec` object or an error. If
198+
/// the JSON is malformed or missing expected fields, an error will be returned.
199+
ICEBERG_EXPORT Result<std::unique_ptr<PartitionSpec>> PartitionSpecFromJson(
200+
const nlohmann::json& json);
201+
186202
/// \brief Serializes a `SnapshotRef` object to JSON.
187203
///
188204
/// \param snapshot_ref The `SnapshotRef` object to be serialized.

src/iceberg/test/json_internal_test.cc

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,29 @@ TEST(JsonInternalTest, PartitionSpec) {
175175
EXPECT_EQ(*spec, *parsed_spec_result.value());
176176
}
177177

178+
TEST(JsonInternalTest, SortOrderFromJson) {
179+
auto identity_transform = Transform::Identity();
180+
SortField st1(5, identity_transform, SortDirection::kAscending, NullOrder::kFirst);
181+
SortField st2(7, identity_transform, SortDirection::kDescending, NullOrder::kLast);
182+
ICEBERG_UNWRAP_OR_FAIL(auto sort_order, SortOrder::Make(100, {st1, st2}));
183+
184+
auto json = ToJson(*sort_order);
185+
ICEBERG_UNWRAP_OR_FAIL(auto parsed, SortOrderFromJson(json));
186+
EXPECT_EQ(*sort_order, *parsed);
187+
}
188+
189+
TEST(JsonInternalTest, PartitionSpecFromJson) {
190+
auto identity_transform = Transform::Identity();
191+
ICEBERG_UNWRAP_OR_FAIL(
192+
auto spec,
193+
PartitionSpec::Make(1, {PartitionField(3, 101, "region", identity_transform),
194+
PartitionField(5, 102, "ts", identity_transform)}));
195+
196+
auto json = ToJson(*spec);
197+
ICEBERG_UNWRAP_OR_FAIL(auto parsed, PartitionSpecFromJson(json));
198+
EXPECT_EQ(*spec, *parsed);
199+
}
200+
178201
TEST(JsonInternalTest, SnapshotRefBranch) {
179202
SnapshotRef ref(1234567890, SnapshotRef::Branch{.min_snapshots_to_keep = 10,
180203
.max_snapshot_age_ms = 123456789,
@@ -349,6 +372,23 @@ TEST(JsonInternalTest, TableUpdateSetCurrentSchema) {
349372
update);
350373
}
351374

375+
TEST(JsonInternalTest, TableUpdateAddPartitionSpec) {
376+
auto identity_transform = Transform::Identity();
377+
ICEBERG_UNWRAP_OR_FAIL(
378+
auto spec,
379+
PartitionSpec::Make(1, {PartitionField(3, 101, "region", identity_transform)}));
380+
table::AddPartitionSpec update(std::move(spec));
381+
382+
auto json = ToJson(update);
383+
EXPECT_EQ(json["action"], "add-spec");
384+
EXPECT_TRUE(json.contains("spec"));
385+
386+
auto parsed = TableUpdateFromJson(json);
387+
ASSERT_THAT(parsed, IsOk());
388+
auto* actual = internal::checked_cast<table::AddPartitionSpec*>(parsed.value().get());
389+
EXPECT_EQ(*actual->spec(), *update.spec());
390+
}
391+
352392
TEST(JsonInternalTest, TableUpdateSetDefaultPartitionSpec) {
353393
table::SetDefaultPartitionSpec update(2);
354394
nlohmann::json expected = R"({"action":"set-default-spec","spec-id":2})"_json;
@@ -386,6 +426,22 @@ TEST(JsonInternalTest, TableUpdateRemoveSchemas) {
386426
EXPECT_EQ(*internal::checked_cast<table::RemoveSchemas*>(parsed.value().get()), update);
387427
}
388428

429+
TEST(JsonInternalTest, TableUpdateAddSortOrder) {
430+
auto identity_transform = Transform::Identity();
431+
SortField st(5, identity_transform, SortDirection::kAscending, NullOrder::kFirst);
432+
ICEBERG_UNWRAP_OR_FAIL(auto sort_order, SortOrder::Make(1, {st}));
433+
table::AddSortOrder update(std::move(sort_order));
434+
435+
auto json = ToJson(update);
436+
EXPECT_EQ(json["action"], "add-sort-order");
437+
EXPECT_TRUE(json.contains("sort-order"));
438+
439+
auto parsed = TableUpdateFromJson(json);
440+
ASSERT_THAT(parsed, IsOk());
441+
auto* actual = internal::checked_cast<table::AddSortOrder*>(parsed.value().get());
442+
EXPECT_EQ(*actual->sort_order(), *update.sort_order());
443+
}
444+
389445
TEST(JsonInternalTest, TableUpdateSetDefaultSortOrder) {
390446
table::SetDefaultSortOrder update(1);
391447
nlohmann::json expected =

0 commit comments

Comments
 (0)