fgerlits commented on code in PR #1926:
URL: https://github.com/apache/nifi-minifi-cpp/pull/1926#discussion_r1977778331


##########
extension-utils/src/core/ProcessContext.cpp:
##########
@@ -16,21 +16,7 @@
  */
 
 #include "minifi-cpp/core/ProcessContext.h"
-#include "core/TypedValues.h"
 
 namespace org::apache::nifi::minifi::core {
 
-bool ProcessContext::getProperty(std::string_view name, detail::NotAFlowFile 
auto &value) const {

Review Comment:
   `NotAFlowFile` is not used anywhere now, so it can be removed from the 
header file.



##########
extension-utils/src/utils/ListingStateManager.cpp:
##########
@@ -51,10 +51,11 @@ uint64_t 
ListingStateManager::getLatestListedKeyTimestampInMilliseconds(const st
     stored_listed_key_timestamp_str = it->second;
   }
 
-  int64_t stored_listed_key_timestamp = 0;
-  core::Property::StringToInt(stored_listed_key_timestamp_str, 
stored_listed_key_timestamp);
+  if (auto stored_listed_key_timestamp = 
parsing::parseIntegral<int64_t>(stored_listed_key_timestamp_str)) {
+    return *stored_listed_key_timestamp;
+  }
 
-  return stored_listed_key_timestamp;
+  throw std::runtime_error("Invalid listed key timestamp");

Review Comment:
   Until now, we simply ignored the error (which is very unlikely).  I would 
prefer to log an error and continue to ignore it as before.  We could also put 
in an assertion.  Throwing and rolling back the flow file (which most likely 
did not cause the error) doesn't seem like the correct way to handle this.



##########
extension-utils/src/utils/ProcessorConfigUtils.cpp:
##########
@@ -16,37 +16,93 @@
  */
 #include "utils/ProcessorConfigUtils.h"
 
-#include <vector>
 #include <string>
-#include <string_view>
 
-#include "range/v3/algorithm/contains.hpp"
-#include "utils/StringUtils.h"
+#include "utils/expected.h"
 
 namespace org::apache::nifi::minifi::utils {
 
-std::vector<std::string> listFromCommaSeparatedProperty(const 
core::ProcessContext& context, std::string_view property_name) {
-  std::string property_string;
-  context.getProperty(property_name, property_string);
-  return utils::string::splitAndTrim(property_string, ",");
+std::string parseProperty(const core::ProcessContext& ctx, const 
core::PropertyReference& property, const core::FlowFile* flow_file) {
+  return ctx.getProperty(property, flow_file) | 
utils::expect(fmt::format("Expected valid value from {}::{}", 
ctx.getProcessor().getName(), property.name));
 }
 
-std::vector<std::string> listFromRequiredCommaSeparatedProperty(const 
core::ProcessContext& context, std::string_view property_name) {
-  return utils::string::splitAndTrim(getRequiredPropertyOrThrow(context, 
property_name), ",");
+std::optional<std::string> parseOptionalProperty(const core::ProcessContext& 
ctx, const core::PropertyReference& property, const core::FlowFile* flow_file) {
+  if (const auto property_str = ctx.getProperty(property, flow_file)) {
+    return *property_str;
+  }
+  return std::nullopt;
+}
+
+std::optional<bool> parseOptionalBoolProperty(const core::ProcessContext& ctx, 
const core::PropertyReference& property, const core::FlowFile* flow_file) {
+  if (const auto property_str = ctx.getProperty(property, flow_file)) {
+    return parsing::parseBool(*property_str) | 
utils::expect(fmt::format("Expected parsable bool from {}::{}", 
ctx.getProcessor().getName(), property.name));
+  }
+  return std::nullopt;
+}
+
+bool parseBoolProperty(const core::ProcessContext& ctx, const 
core::PropertyReference& property, const core::FlowFile* flow_file) {
+  return ctx.getProperty(property, flow_file) | 
utils::andThen(parsing::parseBool) | utils::expect(fmt::format("Expected 
parsable bool from {}::{}", ctx.getProcessor().getName(), property.name));
+}
+
+std::optional<uint64_t> parseOptionalU64Property(const core::ProcessContext& 
ctx, const core::PropertyReference& property, const core::FlowFile* flow_file) {
+  if (const auto property_str = ctx.getProperty(property, flow_file)) {
+    if (property_str->empty()) {
+        return std::nullopt;
+    }
+    return parsing::parseIntegral<uint64_t>(*property_str) | 
utils::expect(fmt::format("Expected parsable uint64_t from {}::{}", 
ctx.getProcessor().getName(), property.name));
+  }
+
+  return std::nullopt;
+}
+
+uint64_t parseU64Property(const core::ProcessContext& ctx, const 
core::PropertyReference& property, const core::FlowFile* flow_file) {
+  return ctx.getProperty(property, flow_file) | 
utils::andThen(parsing::parseIntegral<uint64_t>) | 
utils::expect(fmt::format("Expected parsable uint64_t from {}::{}", 
ctx.getProcessor().getName(), property.name));
+}
+
+std::optional<int64_t> parseOptionalI64Property(const core::ProcessContext& 
ctx, const core::PropertyReference& property, const core::FlowFile* flow_file) {
+  if (const auto property_str = ctx.getProperty(property, flow_file)) {
+    if (property_str->empty()) {
+      return std::nullopt;
+    }
+    return parsing::parseIntegral<int64_t>(*property_str) | 
utils::expect(fmt::format("Expected parsable int64_t from {}::{}", 
ctx.getProcessor().getName(), property.name));
+  }
+
+  return std::nullopt;
 }
 
-bool parseBooleanPropertyOrThrow(const core::ProcessContext& context, 
std::string_view property_name) {
-  const std::string value_str = getRequiredPropertyOrThrow(context, 
property_name);
-  const auto maybe_value = utils::string::toBool(value_str);
-  if (!maybe_value) {
-    throw std::runtime_error(std::string(property_name) + " property is 
invalid: value is " + value_str);
+int64_t parseI64Property(const core::ProcessContext& ctx, const 
core::PropertyReference& property, const core::FlowFile* flow_file) {
+  return ctx.getProperty(property, flow_file) | 
utils::andThen(parsing::parseIntegral<int64_t>) | 
utils::expect(fmt::format("Expected parsable int64_t from {}::{}", 
ctx.getProcessor().getName(), property.name));
+}
+
+std::optional<std::chrono::milliseconds> parseOptionalMsProperty(const 
core::ProcessContext& ctx, const core::PropertyReference& property, const 
core::FlowFile* flow_file) {
+  if (const auto property_str = ctx.getProperty(property, flow_file)) {
+    if (property_str->empty()) {
+      return std::nullopt;
+    }
+    return parsing::parseDuration(*property_str) | 
utils::expect(fmt::format("Expected parsable duration from {}::{}", 
ctx.getProcessor().getName(), property.name));
   }
-  return maybe_value.value();
+
+  return std::nullopt;
 }
 
-std::chrono::milliseconds parseTimePropertyMSOrThrow(const 
core::ProcessContext& context, std::string_view property_name) {
-  const auto time_property = 
getRequiredPropertyOrThrow<core::TimePeriodValue>(context, property_name);
-  return time_property.getMilliseconds();
+std::chrono::milliseconds parseMsProperty(const core::ProcessContext& ctx, 
const core::PropertyReference& property, const core::FlowFile* flow_file) {

Review Comment:
   I would prefer `parse[Optional]DurationProperty`, since the property value 
is a duration which can use many other units, not just milliseconds. The return 
type already shows that it gets converted to milliseconds.



##########
extensions/couchbase/controllerservices/CouchbaseClusterService.cpp:
##########
@@ -216,12 +216,10 @@ void CouchbaseClusterService::initialize() {
 }
 
 void CouchbaseClusterService::onEnable() {
-  std::string connection_string;
-  getProperty(ConnectionString, connection_string);
-  std::string username;
-  getProperty(UserName, username);
-  std::string password;
-  getProperty(UserPassword, password);
+  std::string connection_string = getProperty(ConnectionString.name) | 
utils::expect("required property");

Review Comment:
   This message is misleading, as this will only throw if `ConnectionString` is 
not a supported property (ie., never).
   
   Maybe we could have two types of `utils::expect` (with two different names, 
of course), one that throws and one that terminates (for situations which 
should be impossible)?



##########
extension-utils/src/utils/ProcessorConfigUtils.cpp:
##########
@@ -16,37 +16,93 @@
  */
 #include "utils/ProcessorConfigUtils.h"
 
-#include <vector>
 #include <string>
-#include <string_view>
 
-#include "range/v3/algorithm/contains.hpp"
-#include "utils/StringUtils.h"
+#include "utils/expected.h"
 
 namespace org::apache::nifi::minifi::utils {
 
-std::vector<std::string> listFromCommaSeparatedProperty(const 
core::ProcessContext& context, std::string_view property_name) {
-  std::string property_string;
-  context.getProperty(property_name, property_string);
-  return utils::string::splitAndTrim(property_string, ",");
+std::string parseProperty(const core::ProcessContext& ctx, const 
core::PropertyReference& property, const core::FlowFile* flow_file) {
+  return ctx.getProperty(property, flow_file) | 
utils::expect(fmt::format("Expected valid value from {}::{}", 
ctx.getProcessor().getName(), property.name));
 }
 
-std::vector<std::string> listFromRequiredCommaSeparatedProperty(const 
core::ProcessContext& context, std::string_view property_name) {
-  return utils::string::splitAndTrim(getRequiredPropertyOrThrow(context, 
property_name), ",");
+std::optional<std::string> parseOptionalProperty(const core::ProcessContext& 
ctx, const core::PropertyReference& property, const core::FlowFile* flow_file) {
+  if (const auto property_str = ctx.getProperty(property, flow_file)) {
+    return *property_str;
+  }
+  return std::nullopt;

Review Comment:
   this could be
   ```suggestion
     return ctx.getProperty(property, flow_file)) | utils::toOptional();
   ```



##########
extension-utils/src/utils/ProcessorConfigUtils.cpp:
##########


Review Comment:
   We could help the compiler eliminate a `PropertyDefinition` -> 
`PropertyReference` conversion if we moved these functions to the header and 
used the `string_view` version of `getProperty()` in their bodies, i.e., 
`ctx.getProperty(property.name, flow_file)`.
   
   This may be premature optimization, but we use these functions in so many 
places, it may be worth it.



##########
extensions/aws/s3/MultipartUploadStateStorage.cpp:
##########
@@ -57,11 +57,11 @@ std::optional<MultipartUploadState> 
MultipartUploadStateStorage::getState(const
   MultipartUploadState state;
   state.upload_id = state_map[state_key + ".upload_id"];
 
-  core::Property::StringToInt(state_map[state_key + ".upload_time"], 
state.upload_time_ms_since_epoch);
-  core::Property::StringToInt(state_map[state_key + ".uploaded_parts"], 
state.uploaded_parts);
-  core::Property::StringToInt(state_map[state_key + ".uploaded_size"], 
state.uploaded_size);
-  core::Property::StringToInt(state_map[state_key + ".part_size"], 
state.part_size);
-  core::Property::StringToInt(state_map[state_key + ".full_size"], 
state.full_size);
+  state.upload_time_ms_since_epoch = 
parsing::parseIntegral<int64_t>(state_map[state_key + ".upload_time"]) | 
utils::expect("Expected parsable upload_time_ms_since_epoch");
+  state.uploaded_parts = parsing::parseIntegral<size_t>(state_map[state_key + 
".uploaded_parts"]) | utils::expect("Expected parsable state.uploaded_parts");
+  state.uploaded_size = parsing::parseIntegral<uint64_t>(state_map[state_key + 
".uploaded_size"]) | utils::expect("Expected parsable state.uploaded_size");
+  state.part_size = parsing::parseIntegral<uint64_t>(state_map[state_key + 
".part_size"]) | utils::expect("Expected parsable state.part_size");
+  state.full_size = parsing::parseIntegral<uint64_t>(state_map[state_key + 
".full_size"]) | utils::expect("Expected parsable state.full_size");

Review Comment:
   not sure how useful it would be, but we could add the value of `state_key` 
to the text of the exception



##########
extensions/aws/processors/S3Processor.cpp:
##########
@@ -155,8 +139,9 @@ std::optional<CommonProperties> 
S3Processor::getCommonELSupportedProperties(
   }
   properties.proxy = proxy.value();
 
-  context.getProperty(EndpointOverrideURL, properties.endpoint_override_url, 
flow_file);
-  if (!properties.endpoint_override_url.empty()) {
+  const auto endpoint_override_url = context.getProperty(EndpointOverrideURL, 
flow_file);
+  if (endpoint_override_url) {
+    properties.endpoint_override_url = *endpoint_override_url;

Review Comment:
   `EndpointOverrideURL` should have a `NON_BLANK_VALIDATOR`



-- 
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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to