Skip to content

Commit c330bb8

Browse files
authored
feat: make EvaluationReason use enums for Kind and ErrorKind (#40)
* Make enum for EvaluationReason::Kind * Make enum for EvaluationReason::ErrorKind * add JSON deserialization for both types
1 parent c62dcf6 commit c330bb8

File tree

11 files changed

+259
-69
lines changed

11 files changed

+259
-69
lines changed

apps/hello-cpp/main.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ int main() {
6262

6363
auto value = client.BoolVariationDetail("my-bool-flag", false);
6464
LD_LOG(logger, LogLevel::kInfo) << "Value was: " << *value;
65-
LD_LOG(logger, LogLevel::kInfo) << "Reason was: " << value.Reason();
65+
if (auto reason = value.Reason()) {
66+
LD_LOG(logger, LogLevel::kInfo) << "Reason was: " << *reason;
67+
}
6668

6769
// Sit around.
6870
std::cout << "Press enter to exit" << std::endl;

libs/client-sdk/src/api.cpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ EvaluationDetail<T> Client::VariationInternal(FlagKey const& key,
135135
"Returning default value";
136136

137137
// TODO: SC-199918
138-
auto error_reason = EvaluationReason("CLIENT_NOT_READY");
138+
auto error_reason =
139+
EvaluationReason(EvaluationReason::ErrorKind::kClientNotReady);
139140
if (eval_reasons_available_) {
140141
event.reason = error_reason;
141142
}
@@ -147,7 +148,8 @@ EvaluationDetail<T> Client::VariationInternal(FlagKey const& key,
147148
LD_LOG(logger_, LogLevel::kInfo)
148149
<< "Unknown feature flag " << key << "; returning default value";
149150

150-
auto error_reason = EvaluationReason("FLAG_NOT_FOUND");
151+
auto error_reason =
152+
EvaluationReason(EvaluationReason::ErrorKind::kFlagNotFound);
151153
if (eval_reasons_available_) {
152154
event.reason = error_reason;
153155
}
@@ -168,7 +170,8 @@ EvaluationDetail<T> Client::VariationInternal(FlagKey const& key,
168170

169171
if (check_type && default_value.type() != Value::Type::kNull &&
170172
detail.value().type() != default_value.type()) {
171-
auto error_reason = EvaluationReason("WRONG_TYPE");
173+
auto error_reason =
174+
EvaluationReason(EvaluationReason::ErrorKind::kWrongType);
172175
if (eval_reasons_available_) {
173176
event.reason = error_reason;
174177
}
@@ -191,14 +194,8 @@ EvaluationDetail<T> Client::VariationInternal(FlagKey const& key,
191194

192195
event_processor_->AsyncSend(std::move(event));
193196

194-
// TODO: this isn't a valid error, figure out how to handle if reason is
195-
// missing.
196-
EvaluationReason returned_reason("UNKNOWN");
197-
if (detail.reason()) {
198-
returned_reason = detail.reason()->get();
199-
}
200197
return EvaluationDetail<T>(detail.value(), detail.variation_index(),
201-
returned_reason);
198+
detail.reason());
202199
}
203200

204201
EvaluationDetail<bool> Client::BoolVariationDetail(Client::FlagKey const& key,

libs/common/include/data/evaluation_detail.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ class EvaluationDetail {
2525
*/
2626
EvaluationDetail(T value,
2727
std::optional<std::size_t> variation_index,
28-
EvaluationReason reason);
28+
std::optional<EvaluationReason> reason);
2929

3030
/**
3131
* Constructs an EvaluationDetail representing an error and a default
3232
* value.
3333
* @param error_kind Kind of the error.
3434
* @param default_value Default value.
3535
*/
36-
EvaluationDetail(std::string error_kind, T default_value);
36+
EvaluationDetail(EvaluationReason::ErrorKind error_kind, T default_value);
3737

3838
/**
3939
* @return A reference to the variation value. For convenience, the *
@@ -50,7 +50,7 @@ class EvaluationDetail {
5050
/**
5151
* @return A reference to the reason for the results.
5252
*/
53-
[[nodiscard]] EvaluationReason const& Reason() const;
53+
[[nodiscard]] std::optional<EvaluationReason> const& Reason() const;
5454

5555
/**
5656
* @return A reference to the variation value.
@@ -60,6 +60,6 @@ class EvaluationDetail {
6060
private:
6161
T value_;
6262
std::optional<std::size_t> variation_index_;
63-
EvaluationReason reason_;
63+
std::optional<EvaluationReason> reason_;
6464
};
6565
} // namespace launchdarkly

libs/common/include/data/evaluation_reason.hpp

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,53 @@ namespace launchdarkly {
1212
*/
1313
class EvaluationReason {
1414
public:
15+
enum class Kind {
16+
// The flag was off and therefore returned its configured off value.
17+
kOff = 0,
18+
// The flag was on but the context did not match any targets or rules.
19+
kFallthrough = 1,
20+
// The context key was specifically targeted for this flag.
21+
kTargetMatch = 2,
22+
// The context matched one of the flag's rules.
23+
kRuleMatch = 3,
24+
// The flag was considered off because it had at least one prerequisite
25+
// flag that either was off or did not return the desired variation.
26+
kPrerequisiteFailed = 4,
27+
// The flag could not be evaluated, e.g. because it does not exist or
28+
// due to an unexpected error.
29+
kError = 5
30+
};
31+
friend std::ostream& operator<<(std::ostream& out, Kind const& kind);
32+
33+
enum class ErrorKind {
34+
// The SDK was not yet fully initialized and cannot evaluate flags.
35+
kClientNotReady = 0,
36+
// The application did not pass valid context attributes to the SDK
37+
// evaluation method.
38+
kUserNotSpecified = 1,
39+
// No flag existed with the specified flag key.
40+
kFlagNotFound = 2,
41+
// The application requested an evaluation result of one type but the
42+
// resulting flag variation value was of a different type.
43+
kWrongType = 3,
44+
// The flag had invalid properties.
45+
kMalformedFlag = 4,
46+
// An unexpected error happened that stopped evaluation.
47+
kException = 5,
48+
};
49+
50+
friend std::ostream& operator<<(std::ostream& out, ErrorKind const& kind);
51+
1552
/**
16-
* The general category of the reason:
17-
*
18-
* - `"OFF"`: The flag was off and therefore returned its configured off
19-
* value.
20-
* - `"FALLTHROUGH"`: The flag was on but the context did not match any
21-
* targets or rules.
22-
* - `"TARGET_MATCH"`: The context key was specifically targeted for this
23-
* flag.
24-
* - `"RULE_MATCH"`: the context matched one of the flag"s rules.
25-
* - `"PREREQUISITE_FAILED"`: The flag was considered off because it had at
26-
* least one prerequisite flag that either was off or did not return the
27-
* desired variation.
28-
* - `"ERROR"`: The flag could not be evaluated, e.g. because it does not
29-
* exist or due to an unexpected error.
53+
* @return The general category of the reason.
3054
*/
31-
[[nodiscard]] std::string const& kind() const;
55+
[[nodiscard]] Kind const& kind() const;
3256

3357
/**
34-
* A further description of the error condition, if the kind was `"ERROR"`.
58+
* A further description of the error condition, if the Kind was
59+
* Kind::kError.
3560
*/
36-
[[nodiscard]] std::optional<std::string> error_kind() const;
61+
[[nodiscard]] std::optional<ErrorKind> error_kind() const;
3762

3863
/**
3964
* The index of the matched rule (0 for the first), if the kind was
@@ -78,22 +103,22 @@ class EvaluationReason {
78103
*/
79104
[[nodiscard]] std::optional<std::string> big_segment_status() const;
80105

81-
EvaluationReason(std::string kind,
82-
std::optional<std::string> error_kind,
106+
EvaluationReason(Kind kind,
107+
std::optional<ErrorKind> error_kind,
83108
std::optional<std::size_t> rule_index,
84109
std::optional<std::string> rule_id,
85110
std::optional<std::string> prerequisite_key,
86111
bool in_experiment,
87112
std::optional<std::string> big_segment_status);
88113

89-
explicit EvaluationReason(std::string error_kind);
114+
explicit EvaluationReason(ErrorKind error_kind);
90115

91116
friend std::ostream& operator<<(std::ostream& out,
92117
EvaluationReason const& reason);
93118

94119
private:
95-
std::string kind_;
96-
std::optional<std::string> error_kind_;
120+
Kind kind_;
121+
std::optional<ErrorKind> error_kind_;
97122
std::optional<std::size_t> rule_index_;
98123
std::optional<std::string> rule_id_;
99124
std::optional<std::string> prerequisite_key_;

libs/common/include/serialization/json_evaluation_reason.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,24 @@ tl::expected<EvaluationReason, JsonError> tag_invoke(
1818
unused,
1919
boost::json::value const& json_value);
2020

21+
tl::expected<EvaluationReason::Kind, JsonError> tag_invoke(
22+
boost::json::value_to_tag<
23+
tl::expected<EvaluationReason::Kind, JsonError>> const& unused,
24+
boost::json::value const& json_value);
25+
26+
tl::expected<EvaluationReason::ErrorKind, JsonError> tag_invoke(
27+
boost::json::value_to_tag<
28+
tl::expected<EvaluationReason::ErrorKind, JsonError>> const& unused,
29+
boost::json::value const& json_value);
30+
31+
void tag_invoke(boost::json::value_from_tag const& unused,
32+
boost::json::value& json_value,
33+
EvaluationReason::Kind const& kind);
34+
35+
void tag_invoke(boost::json::value_from_tag const& unused,
36+
boost::json::value& json_value,
37+
EvaluationReason::ErrorKind const& kind);
38+
2139
void tag_invoke(boost::json::value_from_tag const& unused,
2240
boost::json::value& json_value,
2341
EvaluationReason const& reason);

libs/common/src/data/evaluation_detail.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ template <typename T>
88
EvaluationDetail<T>::EvaluationDetail(
99
T value,
1010
std::optional<std::size_t> variation_index,
11-
launchdarkly::EvaluationReason reason)
11+
std::optional<launchdarkly::EvaluationReason> reason)
1212
: value_(std::move(value)),
1313
variation_index_(variation_index),
1414
reason_(std::move(reason)) {}
1515

1616
template <typename T>
17-
EvaluationDetail<T>::EvaluationDetail(std::string error_kind, T default_value)
17+
EvaluationDetail<T>::EvaluationDetail(EvaluationReason::ErrorKind error_kind,
18+
T default_value)
1819
: value_(std::move(default_value)),
1920
variation_index_(std::nullopt),
2021
reason_(error_kind) {}
@@ -25,7 +26,7 @@ T const& EvaluationDetail<T>::Value() const {
2526
}
2627

2728
template <typename T>
28-
EvaluationReason const& EvaluationDetail<T>::Reason() const {
29+
std::optional<EvaluationReason> const& EvaluationDetail<T>::Reason() const {
2930
return reason_;
3031
}
3132

libs/common/src/data/evaluation_reason.cpp

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
#include "data/evaluation_reason.hpp"
2-
2+
#include "serialization/json_evaluation_reason.hpp"
33
namespace launchdarkly {
44

5-
std::string const& EvaluationReason::kind() const {
5+
EvaluationReason::Kind const& EvaluationReason::kind() const {
66
return kind_;
77
}
88

9-
std::optional<std::string> EvaluationReason::error_kind() const {
9+
std::optional<EvaluationReason::ErrorKind> EvaluationReason::error_kind()
10+
const {
1011
return error_kind_;
1112
}
1213

@@ -31,23 +32,23 @@ std::optional<std::string> EvaluationReason::big_segment_status() const {
3132
}
3233

3334
EvaluationReason::EvaluationReason(
34-
std::string kind,
35-
std::optional<std::string> error_kind,
35+
Kind kind,
36+
std::optional<ErrorKind> error_kind,
3637
std::optional<std::size_t> rule_index,
3738
std::optional<std::string> rule_id,
3839
std::optional<std::string> prerequisite_key,
3940
bool in_experiment,
4041
std::optional<std::string> big_segment_status)
41-
: kind_(std::move(kind)),
42-
error_kind_(std::move(error_kind)),
42+
: kind_(kind),
43+
error_kind_(error_kind),
4344
rule_index_(rule_index),
4445
rule_id_(std::move(rule_id)),
4546
prerequisite_key_(std::move(prerequisite_key)),
4647
in_experiment_(in_experiment),
4748
big_segment_status_(std::move(big_segment_status)) {}
4849

49-
EvaluationReason::EvaluationReason(std::string error_kind)
50-
: EvaluationReason("ERROR",
50+
EvaluationReason::EvaluationReason(ErrorKind error_kind)
51+
: EvaluationReason(Kind::kError,
5152
error_kind,
5253
std::nullopt,
5354
std::nullopt,
@@ -90,4 +91,17 @@ bool operator==(EvaluationReason const& lhs, EvaluationReason const& rhs) {
9091
bool operator!=(EvaluationReason const& lhs, EvaluationReason const& rhs) {
9192
return !(lhs == rhs);
9293
}
94+
95+
std::ostream& operator<<(std::ostream& out,
96+
EvaluationReason::Kind const& kind) {
97+
out << boost::json::value_from(kind).as_string();
98+
return out;
99+
}
100+
101+
std::ostream& operator<<(std::ostream& out,
102+
EvaluationReason::ErrorKind const& kind) {
103+
out << boost::json::value_from(kind).as_string();
104+
return out;
105+
}
106+
93107
} // namespace launchdarkly

0 commit comments

Comments
 (0)