diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 815d5d02a5c..53280443d29 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -21,6 +21,9 @@ on: pull_request_target jobs: triage: + permissions: + contents: read + pull-requests: write runs-on: ubuntu-latest steps: - uses: actions/labeler@v5 diff --git a/lang/c++/impl/Compiler.cc b/lang/c++/impl/Compiler.cc index 2599f7cc664..f3c2397da24 100644 --- a/lang/c++/impl/Compiler.cc +++ b/lang/c++/impl/Compiler.cc @@ -369,10 +369,14 @@ static LogicalType makeLogicalType(const Entity &e, const Object &m) { t = LogicalType::TIMESTAMP_MILLIS; else if (typeField == "timestamp-micros") t = LogicalType::TIMESTAMP_MICROS; + else if (typeField == "timestamp-nanos") + t = LogicalType::TIMESTAMP_NANOS; else if (typeField == "local-timestamp-millis") t = LogicalType::LOCAL_TIMESTAMP_MILLIS; else if (typeField == "local-timestamp-micros") t = LogicalType::LOCAL_TIMESTAMP_MICROS; + else if (typeField == "local-timestamp-nanos") + t = LogicalType::LOCAL_TIMESTAMP_NANOS; else if (typeField == "duration") t = LogicalType::DURATION; else if (typeField == "uuid") diff --git a/lang/c++/impl/LogicalType.cc b/lang/c++/impl/LogicalType.cc index a7260accd16..ed6a12f0892 100644 --- a/lang/c++/impl/LogicalType.cc +++ b/lang/c++/impl/LogicalType.cc @@ -71,12 +71,18 @@ void LogicalType::printJson(std::ostream &os) const { case TIMESTAMP_MICROS: os << R"("logicalType": "timestamp-micros")"; break; + case TIMESTAMP_NANOS: + os << R"("logicalType": "timestamp-nanos")"; + break; case LOCAL_TIMESTAMP_MILLIS: os << R"("logicalType": "local-timestamp-millis")"; break; case LOCAL_TIMESTAMP_MICROS: os << R"("logicalType": "local-timestamp-micros")"; break; + case LOCAL_TIMESTAMP_NANOS: + os << R"("logicalType": "local-timestamp-nanos")"; + break; case DURATION: os << R"("logicalType": "duration")"; break; diff --git a/lang/c++/impl/Node.cc b/lang/c++/impl/Node.cc index 9f641e2956a..bde556bf314 100644 --- a/lang/c++/impl/Node.cc +++ b/lang/c++/impl/Node.cc @@ -189,6 +189,12 @@ void Node::setLogicalType(LogicalType logicalType) { "LONG type"); } break; + case LogicalType::TIMESTAMP_NANOS: + if (type_ != AVRO_LONG) { + throw Exception("TIMESTAMP-NANOS logical type can only annotate " + "LONG type"); + } + break; case LogicalType::LOCAL_TIMESTAMP_MILLIS: if (type_ != AVRO_LONG) { throw Exception("LOCAL-TIMESTAMP-MILLIS logical type can only annotate " @@ -201,6 +207,12 @@ void Node::setLogicalType(LogicalType logicalType) { "LONG type"); } break; + case LogicalType::LOCAL_TIMESTAMP_NANOS: + if (type_ != AVRO_LONG) { + throw Exception("LOCAL-TIMESTAMP-NANOS logical type can only annotate " + "LONG type"); + } + break; case LogicalType::DURATION: if (type_ != AVRO_FIXED || fixedSize() != 12) { throw Exception("DURATION logical type can only annotate " diff --git a/lang/c++/include/avro/LogicalType.hh b/lang/c++/include/avro/LogicalType.hh index 3156f164e1f..b2a7d0294ff 100644 --- a/lang/c++/include/avro/LogicalType.hh +++ b/lang/c++/include/avro/LogicalType.hh @@ -35,8 +35,10 @@ public: TIME_MICROS, TIMESTAMP_MILLIS, TIMESTAMP_MICROS, + TIMESTAMP_NANOS, LOCAL_TIMESTAMP_MILLIS, LOCAL_TIMESTAMP_MICROS, + LOCAL_TIMESTAMP_NANOS, DURATION, UUID }; diff --git a/lang/c++/test/SchemaTests.cc b/lang/c++/test/SchemaTests.cc index f57cfd1352b..029be79d57e 100644 --- a/lang/c++/test/SchemaTests.cc +++ b/lang/c++/test/SchemaTests.cc @@ -217,8 +217,10 @@ const char *roundTripSchemas[] = { R"({"type":"long","logicalType":"time-micros"})", R"({"type":"long","logicalType":"timestamp-millis"})", R"({"type":"long","logicalType":"timestamp-micros"})", + R"({"type":"long","logicalType":"timestamp-nanos"})", R"({"type":"long","logicalType":"local-timestamp-millis"})", R"({"type":"long","logicalType":"local-timestamp-micros"})", + R"({"type":"long","logicalType":"local-timestamp-nanos"})", R"({"type":"fixed","name":"test","size":12,"logicalType":"duration"})", R"({"type":"string","logicalType":"uuid"})", @@ -244,8 +246,10 @@ const char *malformedLogicalTypes[] = { R"({"type":"string","logicalType":"time-micros"})", R"({"type":"string","logicalType":"timestamp-millis"})", R"({"type":"string","logicalType":"timestamp-micros"})", + R"({"type":"string","logicalType":"timestamp-nanos"})", R"({"type":"string","logicalType":"local-timestamp-millis"})", R"({"type":"string","logicalType":"local-timestamp-micros"})", + R"({"type":"string","logicalType":"local-timestamp-nanos"})", R"({"type":"string","logicalType":"duration"})", R"({"type":"long","logicalType":"uuid"})", // Missing the required field 'precision'. @@ -360,12 +364,18 @@ static void testLogicalTypes() { const char *timestampMicrosType = "{\n\ \"type\": \"long\", \"logicalType\": \"timestamp-micros\"\n\ }"; + const char *timestampNanosType = "{\n\ + \"type\": \"long\", \"logicalType\": \"timestamp-nanos\"\n\ + }"; const char *localTimestampMillisType = "{\n\ \"type\": \"long\", \"logicalType\": \"local-timestamp-millis\"\n\ }"; const char *localTimestampMicrosType = "{\n\ \"type\": \"long\", \"logicalType\": \"local-timestamp-micros\"\n\ }"; + const char *localTimestampNanosType = "{\n\ + \"type\": \"long\", \"logicalType\": \"local-timestamp-nanos\"\n\ + }"; const char *durationType = "{\n\ \"type\": \"fixed\",\n\ \"size\": 12,\n\ @@ -446,6 +456,15 @@ static void testLogicalTypes() { GenericDatum datum(schema); BOOST_CHECK(datum.logicalType().type() == LogicalType::TIMESTAMP_MICROS); } + { + BOOST_TEST_CHECKPOINT(timestampNanosType); + ValidSchema schema = compileJsonSchemaFromString(timestampNanosType); + BOOST_CHECK(schema.root()->type() == AVRO_LONG); + LogicalType logicalType = schema.root()->logicalType(); + BOOST_CHECK(logicalType.type() == LogicalType::TIMESTAMP_NANOS); + GenericDatum datum(schema); + BOOST_CHECK(datum.logicalType().type() == LogicalType::TIMESTAMP_NANOS); + } { BOOST_TEST_CHECKPOINT(localTimestampMillisType); ValidSchema schema = compileJsonSchemaFromString(localTimestampMillisType); @@ -464,6 +483,15 @@ static void testLogicalTypes() { GenericDatum datum(schema); BOOST_CHECK(datum.logicalType().type() == LogicalType::LOCAL_TIMESTAMP_MICROS); } + { + BOOST_TEST_CHECKPOINT(localTimestampNanosType); + ValidSchema schema = compileJsonSchemaFromString(localTimestampNanosType); + BOOST_CHECK(schema.root()->type() == AVRO_LONG); + LogicalType logicalType = schema.root()->logicalType(); + BOOST_CHECK(logicalType.type() == LogicalType::LOCAL_TIMESTAMP_NANOS); + GenericDatum datum(schema); + BOOST_CHECK(datum.logicalType().type() == LogicalType::LOCAL_TIMESTAMP_NANOS); + } { BOOST_TEST_CHECKPOINT(durationType); ValidSchema schema = compileJsonSchemaFromString(durationType);