From 612e4c533527393490c8e3383d6c65dd076d70cd Mon Sep 17 00:00:00 2001 From: Andrew Wong Date: Wed, 21 Aug 2024 13:07:18 -0700 Subject: [PATCH] C++: accessors for custom attributes Custom attributes are only settable when building a schema. There was previously no way to get the attributes from a parsed schema. This will be useful for reading Iceberg manifests, since we'll want to pull the field ids for each type. --- lang/c++/include/avro/Node.hh | 3 +++ lang/c++/include/avro/NodeImpl.hh | 8 +++++++ lang/c++/test/unittest.cc | 38 +++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/lang/c++/include/avro/Node.hh b/lang/c++/include/avro/Node.hh index d3840e14bd4..4141321ae93 100644 --- a/lang/c++/include/avro/Node.hh +++ b/lang/c++/include/avro/Node.hh @@ -168,6 +168,9 @@ public: doAddCustomAttribute(customAttributes); } + virtual size_t customAttributes() const = 0; + virtual const CustomAttributes& customAttributesAt(size_t index) const = 0; + virtual bool isValid() const = 0; virtual SchemaResolution resolve(const Node &reader) const = 0; diff --git a/lang/c++/include/avro/NodeImpl.hh b/lang/c++/include/avro/NodeImpl.hh index 9bce944636b..faa9b25c8c6 100644 --- a/lang/c++/include/avro/NodeImpl.hh +++ b/lang/c++/include/avro/NodeImpl.hh @@ -147,6 +147,14 @@ protected: return nameIndex_.lookup(name, index); } + size_t customAttributes() const override { + return customAttributes_.size(); + } + + const CustomAttributes& customAttributesAt(size_t index) const override { + return customAttributes_.get(index); + } + void doSetFixedSize(size_t size) override { sizeAttribute_.add(size); } diff --git a/lang/c++/test/unittest.cc b/lang/c++/test/unittest.cc index 2eeaa12da3b..7aed39573f8 100644 --- a/lang/c++/test/unittest.cc +++ b/lang/c++/test/unittest.cc @@ -497,6 +497,42 @@ struct TestSchema { BOOST_CHECK_EQUAL(false, cf.getAttribute("not_existing").is_initialized()); } + void checkCustomAttributesFromNode() + { + std::string jsonWithCustomAttribute = R"( + {"type": "record", "name": "Test","fields": + [{"name": "f1", "type": "long", + "arrayField": [1], + "booleanField": true, + "mapField": {"key1":"value1", "key2":"value2"}, + "nullField": null, + "numberField": 1.23, + "stringField": "field value with \"double quotes\"" + }]} + )"; + auto schema = avro::compileJsonSchemaFromString(jsonWithCustomAttribute); + const auto& nodePtr = schema.root(); + BOOST_CHECK_EQUAL(nodePtr->type(), AVRO_RECORD); + BOOST_CHECK_EQUAL(1, nodePtr->customAttributes()); + const auto& attrs = nodePtr->customAttributesAt(0); + BOOST_CHECK_EQUAL(6, attrs.attributes().size()); + BOOST_CHECK_THROW(nodePtr->customAttributesAt(1), std::out_of_range); + } + + void checkNoCustomAttributesFromNode() + { + std::string jsonNoCustomAttribute = + "{\"type\": \"record\", \"name\": \"Test\",\"fields\": " + "[{\"name\": \"f1\", \"type\": \"long\"}]}"; + auto schema = avro::compileJsonSchemaFromString(jsonNoCustomAttribute); + const auto& nodePtr = schema.root(); + BOOST_CHECK_EQUAL(nodePtr->type(), AVRO_RECORD); + BOOST_CHECK_EQUAL(1, nodePtr->customAttributes()); + const auto& attrs = nodePtr->customAttributesAt(0); + BOOST_CHECK_EQUAL(0, attrs.attributes().size()); + BOOST_CHECK_THROW(nodePtr->customAttributesAt(1), std::out_of_range); + } + void test() { std::cout << "Before\n"; schema_.toJson(std::cout); @@ -522,6 +558,8 @@ struct TestSchema { checkNodeRecordWithoutCustomAttribute(); checkNodeRecordWithCustomAttribute(); checkCustomAttributes_getAttribute(); + checkCustomAttributesFromNode(); + checkNoCustomAttributesFromNode(); } ValidSchema schema_;