Skip to content

Commit d76992d

Browse files
committed
refactor: BigSegmentsStatus uses kNone sentinel; restore deprecated string-typed APIs
1 parent 9cd44ee commit d76992d

4 files changed

Lines changed: 105 additions & 36 deletions

File tree

libs/common/include/launchdarkly/data/evaluation_reason.hpp

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,18 @@ class EvaluationReason {
5959
* Do not change these values. They must remain stable for the C API.
6060
*/
6161
enum class BigSegmentsStatus {
62+
// The evaluation did not query any Big Segments.
63+
kNone = 0,
6264
// The query was successful and the segment state is up to date.
63-
kHealthy = 0,
65+
kHealthy = 1,
6466
// The query was successful, but the segment state may not be up to
6567
// date.
66-
kStale = 1,
68+
kStale = 2,
6769
// Big Segments could not be queried because the SDK configuration did
6870
// not include a Big Segment store.
69-
kNotConfigured = 2,
71+
kNotConfigured = 3,
7072
// The query failed, for instance due to a database error.
71-
kStoreError = 3,
73+
kStoreError = 4,
7274
};
7375

7476
friend std::ostream& operator<<(std::ostream& out,
@@ -87,12 +89,14 @@ class EvaluationReason {
8789

8890
/**
8991
* The validity of the Big Segment information used in this evaluation, or
90-
* std::nullopt if the evaluation did not query any Big Segments.
92+
* BigSegmentsStatus::kNone if the evaluation did not query any Big
93+
* Segments.
9194
*/
92-
[[nodiscard]] std::optional<BigSegmentsStatus> BigSegmentsStatus() const;
95+
[[nodiscard]] enum BigSegmentsStatus BigSegmentsStatus() const;
9396

9497
/**
95-
* Deprecated; use BigSegmentsStatus() instead. Always returns std::nullopt.
98+
* Deprecated; use BigSegmentsStatus() instead. Returns the string passed
99+
* to the deprecated string-typed constructor, or std::nullopt otherwise.
96100
*/
97101
[[deprecated("use BigSegmentsStatus()")]] [[nodiscard]] std::optional<
98102
std::string>
@@ -131,7 +135,19 @@ class EvaluationReason {
131135
std::optional<std::string> rule_id,
132136
std::optional<std::string> prerequisite_key,
133137
bool in_experiment,
134-
std::optional<enum BigSegmentsStatus> big_segments_status);
138+
enum BigSegmentsStatus big_segments_status);
139+
140+
/**
141+
* Deprecated; use the overload taking @ref BigSegmentsStatus instead.
142+
*/
143+
[[deprecated("use the BigSegmentsStatus overload")]] EvaluationReason(
144+
enum Kind kind,
145+
std::optional<enum ErrorKind> error_kind,
146+
std::optional<std::size_t> rule_index,
147+
std::optional<std::string> rule_id,
148+
std::optional<std::string> prerequisite_key,
149+
bool in_experiment,
150+
std::optional<std::string> big_segment_status);
135151

136152
explicit EvaluationReason(enum ErrorKind error_kind);
137153

@@ -181,7 +197,8 @@ class EvaluationReason {
181197
std::optional<std::string> rule_id_;
182198
std::optional<std::string> prerequisite_key_;
183199
bool in_experiment_;
184-
std::optional<enum BigSegmentsStatus> big_segments_status_;
200+
enum BigSegmentsStatus big_segments_status_;
201+
std::optional<std::string> big_segment_status_;
185202
};
186203

187204
bool operator==(EvaluationReason const& lhs, EvaluationReason const& rhs);

libs/common/src/data/evaluation_reason.cpp

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ bool EvaluationReason::InExperiment() const {
2727
return in_experiment_;
2828
}
2929

30-
std::optional<enum EvaluationReason::BigSegmentsStatus>
30+
enum EvaluationReason::BigSegmentsStatus
3131
EvaluationReason::BigSegmentsStatus() const {
3232
return big_segments_status_;
3333
}
3434

3535
std::optional<std::string> EvaluationReason::BigSegmentStatus() const {
36-
return std::nullopt;
36+
return big_segment_status_;
3737
}
3838

3939
EvaluationReason::EvaluationReason(
@@ -43,51 +43,93 @@ EvaluationReason::EvaluationReason(
4343
std::optional<std::string> rule_id,
4444
std::optional<std::string> prerequisite_key,
4545
bool in_experiment,
46-
std::optional<enum BigSegmentsStatus> big_segments_status)
46+
enum BigSegmentsStatus big_segments_status)
4747
: kind_(kind),
4848
error_kind_(error_kind),
4949
rule_index_(rule_index),
5050
rule_id_(std::move(rule_id)),
5151
prerequisite_key_(std::move(prerequisite_key)),
5252
in_experiment_(in_experiment),
53-
big_segments_status_(std::move(big_segments_status)) {}
53+
big_segments_status_(big_segments_status),
54+
big_segment_status_(std::nullopt) {}
55+
56+
EvaluationReason::EvaluationReason(
57+
enum Kind kind,
58+
std::optional<enum ErrorKind> error_kind,
59+
std::optional<std::size_t> rule_index,
60+
std::optional<std::string> rule_id,
61+
std::optional<std::string> prerequisite_key,
62+
bool in_experiment,
63+
std::optional<std::string> big_segment_status)
64+
: kind_(kind),
65+
error_kind_(error_kind),
66+
rule_index_(rule_index),
67+
rule_id_(std::move(rule_id)),
68+
prerequisite_key_(std::move(prerequisite_key)),
69+
in_experiment_(in_experiment),
70+
big_segments_status_(BigSegmentsStatus::kNone),
71+
big_segment_status_(std::move(big_segment_status)) {}
5472

5573
EvaluationReason::EvaluationReason(enum ErrorKind error_kind)
5674
: EvaluationReason(Kind::kError,
5775
error_kind,
58-
std::nullopt,
59-
std::nullopt,
60-
std::nullopt,
61-
false,
62-
std::nullopt) {}
76+
/* rule_index= */ std::nullopt,
77+
/* rule_id= */ std::nullopt,
78+
/* prerequisite_key= */ std::nullopt,
79+
/* in_experiment= */ false,
80+
BigSegmentsStatus::kNone) {}
6381

6482
EvaluationReason EvaluationReason::Off() {
65-
return {Kind::kOff, std::nullopt, std::nullopt, std::nullopt,
66-
std::nullopt, false, std::nullopt};
83+
return {Kind::kOff,
84+
/* error_kind= */ std::nullopt,
85+
/* rule_index= */ std::nullopt,
86+
/* rule_id= */ std::nullopt,
87+
/* prerequisite_key= */ std::nullopt,
88+
/* in_experiment= */ false,
89+
BigSegmentsStatus::kNone};
6790
}
6891

6992
EvaluationReason EvaluationReason::PrerequisiteFailed(
7093
std::string prerequisite_key) {
71-
return {
72-
Kind::kPrerequisiteFailed, std::nullopt, std::nullopt, std::nullopt,
73-
std::move(prerequisite_key), false, std::nullopt};
94+
return {Kind::kPrerequisiteFailed,
95+
/* error_kind= */ std::nullopt,
96+
/* rule_index= */ std::nullopt,
97+
/* rule_id= */ std::nullopt,
98+
std::move(prerequisite_key),
99+
/* in_experiment= */ false,
100+
BigSegmentsStatus::kNone};
74101
}
75102

76103
EvaluationReason EvaluationReason::TargetMatch() {
77-
return {Kind::kTargetMatch, std::nullopt, std::nullopt, std::nullopt,
78-
std::nullopt, false, std::nullopt};
104+
return {Kind::kTargetMatch,
105+
/* error_kind= */ std::nullopt,
106+
/* rule_index= */ std::nullopt,
107+
/* rule_id= */ std::nullopt,
108+
/* prerequisite_key= */ std::nullopt,
109+
/* in_experiment= */ false,
110+
BigSegmentsStatus::kNone};
79111
}
80112

81113
EvaluationReason EvaluationReason::Fallthrough(bool in_experiment) {
82-
return {Kind::kFallthrough, std::nullopt, std::nullopt, std::nullopt,
83-
std::nullopt, in_experiment, std::nullopt};
114+
return {Kind::kFallthrough,
115+
/* error_kind= */ std::nullopt,
116+
/* rule_index= */ std::nullopt,
117+
/* rule_id= */ std::nullopt,
118+
/* prerequisite_key= */ std::nullopt,
119+
in_experiment,
120+
BigSegmentsStatus::kNone};
84121
}
85122

86123
EvaluationReason EvaluationReason::RuleMatch(std::size_t rule_index,
87124
std::optional<std::string> rule_id,
88125
bool in_experiment) {
89-
return {Kind::kRuleMatch, std::nullopt, rule_index, std::move(rule_id),
90-
std::nullopt, in_experiment, std::nullopt};
126+
return {Kind::kRuleMatch,
127+
/* error_kind= */ std::nullopt,
128+
rule_index,
129+
std::move(rule_id),
130+
/* prerequisite_key= */ std::nullopt,
131+
in_experiment,
132+
BigSegmentsStatus::kNone};
91133
}
92134

93135
EvaluationReason EvaluationReason::MalformedFlag() {
@@ -110,8 +152,9 @@ std::ostream& operator<<(std::ostream& out, EvaluationReason const& reason) {
110152
out << " prerequisiteKey: " << reason.prerequisite_key_.value();
111153
}
112154
out << " inExperiment: " << reason.in_experiment_;
113-
if (reason.big_segments_status_.has_value()) {
114-
out << " bigSegmentsStatus: " << reason.big_segments_status_.value();
155+
if (reason.big_segments_status_ !=
156+
EvaluationReason::BigSegmentsStatus::kNone) {
157+
out << " bigSegmentsStatus: " << reason.big_segments_status_;
115158
}
116159
out << "}";
117160
return out;
@@ -121,6 +164,7 @@ bool operator==(EvaluationReason const& lhs, EvaluationReason const& rhs) {
121164
return lhs.Kind() == rhs.Kind() && lhs.ErrorKind() == rhs.ErrorKind() &&
122165
lhs.InExperiment() == rhs.InExperiment() &&
123166
lhs.BigSegmentsStatus() == rhs.BigSegmentsStatus() &&
167+
lhs.BigSegmentStatus() == rhs.BigSegmentStatus() &&
124168
lhs.PrerequisiteKey() == rhs.PrerequisiteKey() &&
125169
lhs.RuleId() == rhs.RuleId() && lhs.RuleIndex() == rhs.RuleIndex();
126170
}
@@ -158,6 +202,9 @@ std::ostream& operator<<(
158202
std::ostream& out,
159203
enum EvaluationReason::BigSegmentsStatus const& status) {
160204
switch (status) {
205+
case EvaluationReason::BigSegmentsStatus::kNone:
206+
out << "NONE";
207+
break;
161208
case EvaluationReason::BigSegmentsStatus::kHealthy:
162209
out << "HEALTHY";
163210
break;

libs/internal/src/serialization/json_evaluation_reason.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ void tag_invoke(boost::json::value_from_tag const& unused,
158158

159159
auto& str = json_value.emplace_string();
160160
switch (status) {
161+
case EvaluationReason::BigSegmentsStatus::kNone:
162+
// kNone is the "no status" sentinel and shouldn't reach the wire;
163+
// callers guard. If it ever does, emit an empty string.
164+
break;
161165
case EvaluationReason::BigSegmentsStatus::kHealthy:
162166
str = "HEALTHY";
163167
break;
@@ -221,8 +225,7 @@ tl::expected<EvaluationReason, JsonError> tag_invoke(
221225
ValueOrDefault(in_experiment_iter, json_obj.end(), false);
222226

223227
auto* big_segments_status_iter = json_obj.find("bigSegmentsStatus");
224-
std::optional<enum EvaluationReason::BigSegmentsStatus>
225-
big_segments_status;
228+
auto big_segments_status = EvaluationReason::BigSegmentsStatus::kNone;
226229
if (big_segments_status_iter != json_obj.end()) {
227230
auto parsed = boost::json::value_to<tl::expected<
228231
enum EvaluationReason::BigSegmentsStatus, JsonError>>(
@@ -254,9 +257,10 @@ void tag_invoke(boost::json::value_from_tag const& unused,
254257
if (auto error_kind = reason.ErrorKind()) {
255258
obj.emplace("errorKind", boost::json::value_from(*error_kind));
256259
}
257-
if (auto big_segments_status = reason.BigSegmentsStatus()) {
260+
auto big_segments_status = reason.BigSegmentsStatus();
261+
if (big_segments_status != EvaluationReason::BigSegmentsStatus::kNone) {
258262
obj.emplace("bigSegmentsStatus",
259-
boost::json::value_from(*big_segments_status));
263+
boost::json::value_from(big_segments_status));
260264
}
261265
if (auto rule_id = reason.RuleId()) {
262266
obj.emplace("ruleId", *rule_id);

libs/internal/tests/evaluation_reason_test.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ TEST(EvaluationReasonsTests, FromMinimalJson) {
4444
EXPECT_EQ(std::nullopt, reason.value().RuleIndex());
4545
EXPECT_EQ(std::nullopt, reason.value().RuleId());
4646
EXPECT_EQ(std::nullopt, reason.value().PrerequisiteKey());
47-
EXPECT_EQ(std::nullopt, reason.value().BigSegmentsStatus());
47+
EXPECT_EQ(EvaluationReason::BigSegmentsStatus::kNone,
48+
reason.value().BigSegmentsStatus());
4849
EXPECT_FALSE(reason.value().InExperiment());
4950
}
5051

0 commit comments

Comments
 (0)