From 3fc7b8734111101962fd7ea31989e99f0a57a2d7 Mon Sep 17 00:00:00 2001 From: Casey Waldren Date: Wed, 7 Feb 2024 14:12:33 -0800 Subject: [PATCH 1/2] fix(client-sdk): handle omitted evaluation result value when deserializing --- .../serialization/json_evaluation_result.cpp | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/libs/internal/src/serialization/json_evaluation_result.cpp b/libs/internal/src/serialization/json_evaluation_result.cpp index 7b7b8a335..51937d991 100644 --- a/libs/internal/src/serialization/json_evaluation_result.cpp +++ b/libs/internal/src/serialization/json_evaluation_result.cpp @@ -56,15 +56,21 @@ tl::expected, JsonError> tag_invoke( // when deserializing FlagMeta. Primarily `variation` not // `variationIndex`. - auto* value_iter = json_obj.find("value"); - if (value_iter == json_obj.end()) { - return tl::unexpected(JsonError::kSchemaFailure); - } - - auto maybe_value = boost::json::value_to>( - value_iter->value()); - if (!maybe_value) { - return tl::unexpected(maybe_value.error()); + // We're looking for the evaluated value. If it's not there, we should treat + // it as null and *not* a schema error. This is because the server-side SDK + // that produced the EvaluationResult may have omitted the 'null' value. + // Otherwise, if it is there, it must deserialize to a valid Value (which + // might itself be null.) + Value value = Value::Null(); + if (auto* value_iter = json_obj.find("value"); + value_iter != json_obj.end()) { + auto maybe_value = + boost::json::value_to>( + value_iter->value()); + if (!maybe_value) { + return tl::unexpected(maybe_value.error()); + } + value = *maybe_value; } auto* variation_iter = json_obj.find("variation"); @@ -85,7 +91,7 @@ tl::expected, JsonError> tag_invoke( track_events, track_reason, debug_events_until_date, - EvaluationDetailInternal(*maybe_value, variation, + EvaluationDetailInternal(std::move(value), variation, std::make_optional(reason.value()))}; } // We could not parse the reason. @@ -99,7 +105,7 @@ tl::expected, JsonError> tag_invoke( track_events, track_reason, debug_events_until_date, - EvaluationDetailInternal(*maybe_value, variation, std::nullopt)}; + EvaluationDetailInternal(std::move(value), variation, std::nullopt)}; } void tag_invoke(boost::json::value_from_tag const& unused, From bb2b99f69ec1c96bc39fcce2f960058e0938612c Mon Sep 17 00:00:00 2001 From: Casey Waldren Date: Tue, 12 Mar 2024 12:53:57 -0700 Subject: [PATCH 2/2] add a story ID --- libs/internal/src/serialization/json_evaluation_result.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libs/internal/src/serialization/json_evaluation_result.cpp b/libs/internal/src/serialization/json_evaluation_result.cpp index 51937d991..6583cc70f 100644 --- a/libs/internal/src/serialization/json_evaluation_result.cpp +++ b/libs/internal/src/serialization/json_evaluation_result.cpp @@ -8,7 +8,6 @@ #include namespace launchdarkly { - tl::expected, JsonError> tag_invoke( boost::json::value_to_tag< tl::expected, JsonError>> const& unused, @@ -56,6 +55,7 @@ tl::expected, JsonError> tag_invoke( // when deserializing FlagMeta. Primarily `variation` not // `variationIndex`. + // todo(cwaldren): SC-203949 + SC-236165 // We're looking for the evaluated value. If it's not there, we should treat // it as null and *not* a schema error. This is because the server-side SDK // that produced the EvaluationResult may have omitted the 'null' value. @@ -133,7 +133,7 @@ void tag_invoke(boost::json::value_from_tag const& unused, "debugEventsUntilDate", std::chrono::duration_cast( evaluation_result.DebugEventsUntilDate()->time_since_epoch()) - .count()); + .count()); } auto& detail = evaluation_result.Detail(); @@ -149,5 +149,4 @@ void tag_invoke(boost::json::value_from_tag const& unused, obj.emplace("reason", reason_json); } } - -} // namespace launchdarkly +} // namespace launchdarkly