Repository: apache/arrow
File: cpp/src/parquet/arrow/schema.cc (C++)

Code before:
          struct_type,
          extension_type->Deserialize(std::move(struct_type), /*serialized_data=*/""));
    }
  }
  out->field = ::arrow::field(node.name(), struct_type, node.is_optional(),
                              FieldIdMetadata(node.field_id()));
  out->level_info = current_levels;
  return Status::OK();
}

Status ListToSchemaField(const GroupNode& group, LevelInfo current_levels,
                         SchemaTreeContext* ctx, const SchemaField* parent,
                         SchemaField* out);

Status MapToSchemaField(const GroupNode& group, LevelInfo current_levels,
                        SchemaTreeContext* ctx, const SchemaField* parent,
                        SchemaField* out) {
  if (group.field_count() != 1) {
    return Status::Invalid("MAP-annotated groups must have a single child.");
  }
  if (group.is_repeated() &&
      (group.parent() == nullptr || !group.parent()->logical_type()->is_list())) {
    return Status::Invalid("MAP-annotated groups must not be repeated.");
  }

  const Node& key_value_node = *group.field(0);

  if (!key_value_node.is_repeated()) {
    return Status::Invalid(
        "Non-repeated key value in a MAP-annotated group are not supported.");
  }

  if (!key_value_node.is_group()) {
    return Status::Invalid("Key-value node must be a group.");
  }

  const GroupNode& key_value = checked_cast<const GroupNode&>(key_value_node);
  if (key_value.field_count() != 1 && key_value.field_count() != 2) {
    return Status::Invalid("Key-value map node must have 1 or 2 child elements. Found: ",
                           key_value.field_count());
  }
  const Node& key_node = *key_value.field(0);
  if (!key_node.is_required()) {
    return Status::Invalid("Map keys must be annotated as required.");
  }
  // Arrow doesn't support 1 column maps (i.e. Sets).  The options are to either
  // make the values column nullable, or process the map as a list.  We choose the
  // latter as it is simpler.
  if (key_value.field_count() == 1) {
    return ListToSchemaField(group, current_levels, ctx, parent, out);
  }

Review comment (suggestion):
Let's add a comment like `MAP-annotated groups cannot be repeated unless in a legacy two-level LIST-annotated group. In this case, the MAP-annotated group is implicitly to be required.`

Code after:
    auto extension_type = ::arrow::GetExtensionType("arrow.parquet.variant");
    if (extension_type) {
      ARROW_ASSIGN_OR_RAISE(
          struct_type,
          extension_type->Deserialize(std::move(struct_type), /*serialized_data=*/""));
    }
  }
  out->field = ::arrow::field(node.name(), struct_type, node.is_optional(),
                              FieldIdMetadata(node.field_id()));
  out->level_info = current_levels;
  return Status::OK();
}

Status ListToSchemaField(const GroupNode& group, LevelInfo current_levels,
                         SchemaTreeContext* ctx, const SchemaField* parent,
                         SchemaField* out);

Status MapToSchemaField(const GroupNode& group, LevelInfo current_levels,
                        SchemaTreeContext* ctx, const SchemaField* parent,
                        SchemaField* out) {
  if (group.field_count() != 1) {
    return Status::Invalid("MAP-annotated groups must have a single child.");
  }
  // MAP-annotated groups cannot be repeated unless served as an element within a
  // LIST-annotated group with 2-level structure.
  if (group.is_repeated() &&
      (group.parent() == nullptr || !group.parent()->logical_type()->is_list())) {
    return Status::Invalid("MAP-annotated groups must not be repeated.");
  }

  const Node& key_value_node = *group.field(0);

  if (!key_value_node.is_repeated()) {
    return Status::Invalid(
        "Non-repeated key value in a MAP-annotated group are not supported.");
  }

  if (!key_value_node.is_group()) {
    return Status::Invalid("Key-value node must be a group.");
  }

  const GroupNode& key_value = checked_cast<const GroupNode&>(key_value_node);
  if (key_value.field_count() != 1 && key_value.field_count() != 2) {
    return Status::Invalid("Key-value map node must have 1 or 2 child elements. Found: ",
                           key_value.field_count());
  }
  const Node& key_node = *key_value.field(0);
  if (!key_node.is_required()) {
    return Status::Invalid("Map keys must be annotated as required.");
  }
  // Arrow doesn't support 1 column maps (i.e. Sets).  The options are to either