MisterRaindrop commented on code in PR #127:
URL: https://github.com/apache/iceberg-cpp/pull/127#discussion_r2218292603


##########
test/avro_schema_test.cc:
##########
@@ -1057,4 +1079,383 @@ TEST(AvroSchemaProjectionTest, 
ProjectDecimalIncompatible) {
   ASSERT_THAT(projection_result, HasErrorMessage("Cannot read"));
 }
 
+// NameMapping tests for Avro schema context
+class NameMappingAvroSchemaTest : public ::testing::Test {
+ protected:
+  // Helper function to create a simple name mapping
+  std::unique_ptr<NameMapping> CreateSimpleNameMapping() {
+    std::vector<MappedField> fields;
+    fields.emplace_back(MappedField{.names = {"id"}, .field_id = 1});
+    fields.emplace_back(MappedField{.names = {"name"}, .field_id = 2});
+    fields.emplace_back(MappedField{.names = {"age"}, .field_id = 3});
+    return NameMapping::Make(std::move(fields));
+  }
+
+  // Helper function to create a nested name mapping
+  std::unique_ptr<NameMapping> CreateNestedNameMapping() {
+    std::vector<MappedField> fields;
+    fields.emplace_back(MappedField{.names = {"id"}, .field_id = 1});
+
+    // Nested mapping for address
+    std::vector<MappedField> address_fields;
+    address_fields.emplace_back(MappedField{.names = {"street"}, .field_id = 
10});
+    address_fields.emplace_back(MappedField{.names = {"city"}, .field_id = 
11});
+    address_fields.emplace_back(MappedField{.names = {"zip"}, .field_id = 12});
+    auto address_mapping = MappedFields::Make(std::move(address_fields));
+
+    fields.emplace_back(MappedField{.names = {"address"},
+                                    .field_id = 2,
+                                    .nested_mapping = 
std::move(address_mapping)});
+
+    return NameMapping::Make(std::move(fields));
+  }
+
+  // Helper function to create a name mapping for array types
+  std::unique_ptr<NameMapping> CreateArrayNameMapping() {
+    std::vector<MappedField> fields;
+    fields.emplace_back(MappedField{.names = {"id"}, .field_id = 1});
+
+    // Nested mapping for array element
+    std::vector<MappedField> element_fields;
+    element_fields.emplace_back(MappedField{.names = {"element"}, .field_id = 
20});
+    auto element_mapping = MappedFields::Make(std::move(element_fields));
+
+    fields.emplace_back(MappedField{
+        .names = {"items"}, .field_id = 2, .nested_mapping = 
std::move(element_mapping)});
+
+    return NameMapping::Make(std::move(fields));
+  }
+
+  // Helper function to create a name mapping for map types
+  std::unique_ptr<NameMapping> CreateMapNameMapping() {
+    std::vector<MappedField> fields;
+    fields.emplace_back(MappedField{.names = {"id"}, .field_id = 1});
+
+    // Nested mapping for map key-value
+    std::vector<MappedField> map_fields;
+    map_fields.emplace_back(MappedField{.names = {"key"}, .field_id = 30});
+    map_fields.emplace_back(MappedField{.names = {"value"}, .field_id = 31});
+    auto map_mapping = MappedFields::Make(std::move(map_fields));
+
+    fields.emplace_back(MappedField{.names = {"properties"},
+                                    .field_id = 2,
+                                    .nested_mapping = std::move(map_mapping)});
+
+    return NameMapping::Make(std::move(fields));
+  }
+
+  // Helper function to create a name mapping for union types
+  std::unique_ptr<NameMapping> CreateUnionNameMapping() {
+    std::vector<MappedField> fields;
+    fields.emplace_back(MappedField{.names = {"id"}, .field_id = 1});
+    fields.emplace_back(MappedField{.names = {"data"}, .field_id = 2});
+    return NameMapping::Make(std::move(fields));
+  }
+};
+
+TEST_F(NameMappingAvroSchemaTest, ApplyNameMappingToRecord) {
+  // Create a simple Avro record schema without field IDs
+  std::string avro_schema_json = R"({
+    "type": "record",
+    "name": "test_record",
+    "fields": [
+      {"name": "id", "type": "int"},
+      {"name": "name", "type": "string"},
+      {"name": "age", "type": "int"}
+    ]
+  })";
+  auto avro_schema = ::avro::compileJsonSchemaFromString(avro_schema_json);
+
+  auto name_mapping = CreateSimpleNameMapping();
+  MappedField mapped_field;
+  mapped_field.nested_mapping =
+      std::make_shared<MappedFields>(name_mapping->AsMappedFields());
+
+  auto result = CreateAvroNodeWithFieldIds(avro_schema.root(), mapped_field);
+  ASSERT_THAT(result, IsOk());
+
+  const auto& new_node = *result;
+  EXPECT_EQ(new_node->type(), ::avro::AVRO_RECORD);
+  EXPECT_EQ(new_node->names(), 3);
+  EXPECT_EQ(new_node->leaves(), 3);
+
+  // Check that field IDs are properly applied
+  ASSERT_EQ(new_node->customAttributes(), 3);
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(new_node, 0, 1));
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(new_node, 1, 2));
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(new_node, 2, 3));
+}
+
+TEST_F(NameMappingAvroSchemaTest, ApplyNameMappingToNestedRecord) {
+  // Create a nested Avro record schema without field IDs
+  std::string avro_schema_json = R"({
+    "type": "record",
+    "name": "test_record",
+    "fields": [
+      {"name": "id", "type": "int"},
+      {"name": "address", "type": {
+        "type": "record",
+        "name": "address",
+        "fields": [
+          {"name": "street", "type": "string"},
+          {"name": "city", "type": "string"},
+          {"name": "zip", "type": "string"}
+        ]
+      }}
+    ]
+  })";
+  auto avro_schema = ::avro::compileJsonSchemaFromString(avro_schema_json);
+
+  auto name_mapping = CreateNestedNameMapping();
+  MappedField mapped_field;
+  mapped_field.nested_mapping =
+      std::make_shared<MappedFields>(name_mapping->AsMappedFields());
+
+  auto result = CreateAvroNodeWithFieldIds(avro_schema.root(), mapped_field);
+  ASSERT_THAT(result, IsOk());
+
+  const auto& new_node = *result;
+  EXPECT_EQ(new_node->type(), ::avro::AVRO_RECORD);
+  EXPECT_EQ(new_node->names(), 2);
+  EXPECT_EQ(new_node->leaves(), 2);
+
+  // Check that field IDs are properly applied to top-level fields
+  ASSERT_EQ(new_node->customAttributes(), 2);
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(new_node, 0, 1));
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(new_node, 1, 2));
+
+  // Check nested record
+  const auto& address_node = new_node->leafAt(1);
+  EXPECT_EQ(address_node->type(), ::avro::AVRO_RECORD);
+  EXPECT_EQ(address_node->names(), 3);
+  EXPECT_EQ(address_node->leaves(), 3);
+
+  // Check that field IDs are properly applied to nested fields
+  ASSERT_EQ(address_node->customAttributes(), 3);
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(address_node, 0, 10));
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(address_node, 1, 11));
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(address_node, 2, 12));
+}
+
+TEST_F(NameMappingAvroSchemaTest, ApplyNameMappingToArray) {
+  // Create an Avro array schema without field IDs
+  std::string avro_schema_json = R"({
+    "type": "record",
+    "name": "test_record",
+    "fields": [
+      {"name": "id", "type": "int"},
+      {"name": "items", "type": {
+        "type": "array",
+        "items": "string"
+      }}
+    ]
+  })";
+  auto avro_schema = ::avro::compileJsonSchemaFromString(avro_schema_json);
+
+  auto name_mapping = CreateArrayNameMapping();
+  MappedField mapped_field;
+  mapped_field.nested_mapping =
+      std::make_shared<MappedFields>(name_mapping->AsMappedFields());
+
+  auto result = CreateAvroNodeWithFieldIds(avro_schema.root(), mapped_field);
+  ASSERT_THAT(result, IsOk());
+
+  const auto& new_node = *result;
+  EXPECT_EQ(new_node->type(), ::avro::AVRO_RECORD);
+  EXPECT_EQ(new_node->names(), 2);
+  EXPECT_EQ(new_node->leaves(), 2);
+
+  // Check array field structure only - don't access any attributes

Review Comment:
   because array and map types do not have attributes, this comment was added. 
I will remove this comment to avoid misunderstanding.



##########
test/avro_schema_test.cc:
##########
@@ -1057,4 +1079,383 @@ TEST(AvroSchemaProjectionTest, 
ProjectDecimalIncompatible) {
   ASSERT_THAT(projection_result, HasErrorMessage("Cannot read"));
 }
 
+// NameMapping tests for Avro schema context
+class NameMappingAvroSchemaTest : public ::testing::Test {
+ protected:
+  // Helper function to create a simple name mapping
+  std::unique_ptr<NameMapping> CreateSimpleNameMapping() {
+    std::vector<MappedField> fields;
+    fields.emplace_back(MappedField{.names = {"id"}, .field_id = 1});
+    fields.emplace_back(MappedField{.names = {"name"}, .field_id = 2});
+    fields.emplace_back(MappedField{.names = {"age"}, .field_id = 3});
+    return NameMapping::Make(std::move(fields));
+  }
+
+  // Helper function to create a nested name mapping
+  std::unique_ptr<NameMapping> CreateNestedNameMapping() {
+    std::vector<MappedField> fields;
+    fields.emplace_back(MappedField{.names = {"id"}, .field_id = 1});
+
+    // Nested mapping for address
+    std::vector<MappedField> address_fields;
+    address_fields.emplace_back(MappedField{.names = {"street"}, .field_id = 
10});
+    address_fields.emplace_back(MappedField{.names = {"city"}, .field_id = 
11});
+    address_fields.emplace_back(MappedField{.names = {"zip"}, .field_id = 12});
+    auto address_mapping = MappedFields::Make(std::move(address_fields));
+
+    fields.emplace_back(MappedField{.names = {"address"},
+                                    .field_id = 2,
+                                    .nested_mapping = 
std::move(address_mapping)});
+
+    return NameMapping::Make(std::move(fields));
+  }
+
+  // Helper function to create a name mapping for array types
+  std::unique_ptr<NameMapping> CreateArrayNameMapping() {
+    std::vector<MappedField> fields;
+    fields.emplace_back(MappedField{.names = {"id"}, .field_id = 1});
+
+    // Nested mapping for array element
+    std::vector<MappedField> element_fields;
+    element_fields.emplace_back(MappedField{.names = {"element"}, .field_id = 
20});
+    auto element_mapping = MappedFields::Make(std::move(element_fields));
+
+    fields.emplace_back(MappedField{
+        .names = {"items"}, .field_id = 2, .nested_mapping = 
std::move(element_mapping)});
+
+    return NameMapping::Make(std::move(fields));
+  }
+
+  // Helper function to create a name mapping for map types
+  std::unique_ptr<NameMapping> CreateMapNameMapping() {
+    std::vector<MappedField> fields;
+    fields.emplace_back(MappedField{.names = {"id"}, .field_id = 1});
+
+    // Nested mapping for map key-value
+    std::vector<MappedField> map_fields;
+    map_fields.emplace_back(MappedField{.names = {"key"}, .field_id = 30});
+    map_fields.emplace_back(MappedField{.names = {"value"}, .field_id = 31});
+    auto map_mapping = MappedFields::Make(std::move(map_fields));
+
+    fields.emplace_back(MappedField{.names = {"properties"},
+                                    .field_id = 2,
+                                    .nested_mapping = std::move(map_mapping)});
+
+    return NameMapping::Make(std::move(fields));
+  }
+
+  // Helper function to create a name mapping for union types
+  std::unique_ptr<NameMapping> CreateUnionNameMapping() {
+    std::vector<MappedField> fields;
+    fields.emplace_back(MappedField{.names = {"id"}, .field_id = 1});
+    fields.emplace_back(MappedField{.names = {"data"}, .field_id = 2});
+    return NameMapping::Make(std::move(fields));
+  }
+};
+
+TEST_F(NameMappingAvroSchemaTest, ApplyNameMappingToRecord) {
+  // Create a simple Avro record schema without field IDs
+  std::string avro_schema_json = R"({
+    "type": "record",
+    "name": "test_record",
+    "fields": [
+      {"name": "id", "type": "int"},
+      {"name": "name", "type": "string"},
+      {"name": "age", "type": "int"}
+    ]
+  })";
+  auto avro_schema = ::avro::compileJsonSchemaFromString(avro_schema_json);
+
+  auto name_mapping = CreateSimpleNameMapping();
+  MappedField mapped_field;
+  mapped_field.nested_mapping =
+      std::make_shared<MappedFields>(name_mapping->AsMappedFields());
+
+  auto result = CreateAvroNodeWithFieldIds(avro_schema.root(), mapped_field);
+  ASSERT_THAT(result, IsOk());
+
+  const auto& new_node = *result;
+  EXPECT_EQ(new_node->type(), ::avro::AVRO_RECORD);
+  EXPECT_EQ(new_node->names(), 3);
+  EXPECT_EQ(new_node->leaves(), 3);
+
+  // Check that field IDs are properly applied
+  ASSERT_EQ(new_node->customAttributes(), 3);
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(new_node, 0, 1));
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(new_node, 1, 2));
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(new_node, 2, 3));
+}
+
+TEST_F(NameMappingAvroSchemaTest, ApplyNameMappingToNestedRecord) {
+  // Create a nested Avro record schema without field IDs
+  std::string avro_schema_json = R"({
+    "type": "record",
+    "name": "test_record",
+    "fields": [
+      {"name": "id", "type": "int"},
+      {"name": "address", "type": {
+        "type": "record",
+        "name": "address",
+        "fields": [
+          {"name": "street", "type": "string"},
+          {"name": "city", "type": "string"},
+          {"name": "zip", "type": "string"}
+        ]
+      }}
+    ]
+  })";
+  auto avro_schema = ::avro::compileJsonSchemaFromString(avro_schema_json);
+
+  auto name_mapping = CreateNestedNameMapping();
+  MappedField mapped_field;
+  mapped_field.nested_mapping =
+      std::make_shared<MappedFields>(name_mapping->AsMappedFields());
+
+  auto result = CreateAvroNodeWithFieldIds(avro_schema.root(), mapped_field);
+  ASSERT_THAT(result, IsOk());
+
+  const auto& new_node = *result;
+  EXPECT_EQ(new_node->type(), ::avro::AVRO_RECORD);
+  EXPECT_EQ(new_node->names(), 2);
+  EXPECT_EQ(new_node->leaves(), 2);
+
+  // Check that field IDs are properly applied to top-level fields
+  ASSERT_EQ(new_node->customAttributes(), 2);
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(new_node, 0, 1));
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(new_node, 1, 2));
+
+  // Check nested record
+  const auto& address_node = new_node->leafAt(1);
+  EXPECT_EQ(address_node->type(), ::avro::AVRO_RECORD);
+  EXPECT_EQ(address_node->names(), 3);
+  EXPECT_EQ(address_node->leaves(), 3);
+
+  // Check that field IDs are properly applied to nested fields
+  ASSERT_EQ(address_node->customAttributes(), 3);
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(address_node, 0, 10));
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(address_node, 1, 11));
+  ASSERT_NO_FATAL_FAILURE(CheckFieldIdAt(address_node, 2, 12));
+}
+
+TEST_F(NameMappingAvroSchemaTest, ApplyNameMappingToArray) {
+  // Create an Avro array schema without field IDs
+  std::string avro_schema_json = R"({
+    "type": "record",
+    "name": "test_record",
+    "fields": [
+      {"name": "id", "type": "int"},
+      {"name": "items", "type": {
+        "type": "array",
+        "items": "string"
+      }}
+    ]
+  })";
+  auto avro_schema = ::avro::compileJsonSchemaFromString(avro_schema_json);
+
+  auto name_mapping = CreateArrayNameMapping();
+  MappedField mapped_field;
+  mapped_field.nested_mapping =
+      std::make_shared<MappedFields>(name_mapping->AsMappedFields());
+
+  auto result = CreateAvroNodeWithFieldIds(avro_schema.root(), mapped_field);
+  ASSERT_THAT(result, IsOk());
+
+  const auto& new_node = *result;
+  EXPECT_EQ(new_node->type(), ::avro::AVRO_RECORD);
+  EXPECT_EQ(new_node->names(), 2);
+  EXPECT_EQ(new_node->leaves(), 2);
+
+  // Check array field structure only - don't access any attributes
+  const auto& array_node = new_node->leafAt(1);
+  EXPECT_EQ(array_node->type(), ::avro::AVRO_ARRAY);
+  EXPECT_EQ(array_node->leaves(), 1);
+}
+
+TEST_F(NameMappingAvroSchemaTest, ApplyNameMappingToMap) {
+  // Create an Avro map schema without field IDs
+  std::string avro_schema_json = R"({
+    "type": "record",
+    "name": "test_record",
+    "fields": [
+      {"name": "id", "type": "int"},
+      {"name": "properties", "type": {
+        "type": "map",
+        "values": "string"
+      }}
+    ]
+  })";
+  auto avro_schema = ::avro::compileJsonSchemaFromString(avro_schema_json);
+
+  auto name_mapping = CreateMapNameMapping();
+  MappedField mapped_field;
+  mapped_field.nested_mapping =
+      std::make_shared<MappedFields>(name_mapping->AsMappedFields());
+
+  auto result = CreateAvroNodeWithFieldIds(avro_schema.root(), mapped_field);
+  ASSERT_THAT(result, IsOk());
+
+  const auto& new_node = *result;
+  EXPECT_EQ(new_node->type(), ::avro::AVRO_RECORD);
+  EXPECT_EQ(new_node->names(), 2);
+  EXPECT_EQ(new_node->leaves(), 2);
+
+  // Check map field structure only - don't access any attributes

Review Comment:
   the same



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscr...@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscr...@iceberg.apache.org
For additional commands, e-mail: issues-h...@iceberg.apache.org

Reply via email to