Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libs/common/include/attributes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,5 @@ class Attributes {

// Kinds are contained at the context level, not inside attributes.
};

} // namespace launchdarkly
54 changes: 54 additions & 0 deletions libs/common/include/data/evaluation_detail_internal.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#pragma once

#include <cstddef>
#include <optional>
#include <utility>

#include "data/evaluation_reason.hpp"
#include "value.hpp"

namespace launchdarkly {

/**
* An object that combines the result of a feature flag evaluation with
* information about how it was calculated.
*
* This is the result of calling [TODO: Evaluate detail].
*
* For more information, see the [SDK reference guide]
* (https://docs.launchdarkly.com/sdk/features/evaluation-reasons#TODO).
*/
class EvaluationDetailInternal {
public:
/**
* The result of the flag evaluation. This will be either one of the flag's
* variations or the default value that was passed to [TODO: Evaluate
* detail].
*/
[[nodiscard]] Value const& value() const;

/**
* The index of the returned value within the flag's list of variations,
* e.g. 0 for the first variation-- or `nullopt` if the default value was
* returned.
*/
[[nodiscard]] std::optional<std::size_t> variation_index() const;

/**
* An object describing the main factor that influenced the flag evaluation
* value.
*/
[[nodiscard]] std::optional<std::reference_wrapper<EvaluationReason const>>
reason() const;

EvaluationDetailInternal(Value value,
std::optional<std::size_t> variation_index,
std::optional<EvaluationReason> reason);

private:
Value value_;
std::optional<std::size_t> variation_index_;
std::optional<EvaluationReason> reason_;
};

} // namespace launchdarkly
98 changes: 98 additions & 0 deletions libs/common/include/data/evaluation_reason.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#pragma once

#include <cstddef>
#include <optional>
#include <string>

namespace launchdarkly {

/**
* Describes the reason that a flag evaluation produced a particular value.
*/
class EvaluationReason {
public:
/**
* The general category of the reason:
*
* - `"OFF"`: The flag was off and therefore returned its configured off
* value.
* - `"FALLTHROUGH"`: The flag was on but the context did not match any
* targets or rules.
* - `"TARGET_MATCH"`: The context key was specifically targeted for this
* flag.
* - `"RULE_MATCH"`: the context matched one of the flag"s rules.
* - `"PREREQUISITE_FAILED"`: The flag was considered off because it had at
* least one prerequisite flag that either was off or did not return the
* desired variation.
* - `"ERROR"`: The flag could not be evaluated, e.g. because it does not
* exist or due to an unexpected error.
*/
[[nodiscard]] std::string const& kind() const;

/**
* A further description of the error condition, if the kind was `"ERROR"`.
*/
[[nodiscard]] std::optional<std::string> error_kind() const;

/**
* The index of the matched rule (0 for the first), if the kind was
* `"RULE_MATCH"`.
*/
[[nodiscard]] std::optional<std::size_t> rule_index() const;

/**
* The unique identifier of the matched rule, if the kind was
* `"RULE_MATCH"`.
*/
[[nodiscard]] std::optional<std::string> rule_id() const;

/**
* The key of the failed prerequisite flag, if the kind was
* `"PREREQUISITE_FAILED"`.
*/
[[nodiscard]] std::optional<std::string> prerequisite_key() const;

/**
* Whether the evaluation was part of an experiment.
*
* This is true if the evaluation resulted in an experiment rollout and
* served one of the variations in the experiment. Otherwise it is false or
* undefined.
*/
[[nodiscard]] bool in_experiment() const;

/**
* Describes the validity of Big Segment information, if and only if the
* flag evaluation required querying at least one Big Segment.
*
* - `"HEALTHY"`: The Big Segment query involved in the flag evaluation was
* successful, and the segment state is considered up to date.
* - `"STALE"`: The Big Segment query involved in the flag evaluation was
* successful, but the segment state may not be up to date
* - `"NOT_CONFIGURED"`: Big Segments could not be queried for the flag
* evaluation because the SDK configuration did not include a Big Segment
* store.
* - `"STORE_ERROR"`: The Big Segment query involved in the flag evaluation
* failed, for instance due to a database error.
*/
[[nodiscard]] std::optional<std::string> big_segment_status() const;

EvaluationReason(std::string kind,
std::optional<std::string> error_kind,
std::optional<std::size_t> rule_index,
std::optional<std::string> rule_id,
std::optional<std::string> prerequisite_key,
bool in_experiment,
std::optional<std::string> big_segment_status);

private:
std::string kind_;
std::optional<std::string> error_kind_;
std::optional<std::size_t> rule_index_;
std::optional<std::string> rule_id_;
std::optional<std::string> prerequisite_key_;
bool in_experiment_;
std::optional<std::string> big_segment_status_;
};

} // namespace launchdarkly
69 changes: 69 additions & 0 deletions libs/common/include/data/evaluation_result.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#pragma once

#include <chrono>
#include <optional>

#include "evaluation_detail_internal.hpp"

namespace launchdarkly {

/**
* FlagMeta represents an evaluated flag either from the LaunchDarkly service,
* or in bootstrap data generated by a server SDK.
*/
class EvaluationResult {
public:
/**
* Incremented by LaunchDarkly each time the flag's state changes.
*/
[[nodiscard]] uint64_t version() const;

/**
* Incremented by LaunchDarkly each time the flag's configuration changes.
*/
[[nodiscard]] std::optional<uint64_t> flag_version() const;

/**
* True if a client SDK should track events for this flag.
*/
[[nodiscard]] bool track_events() const;

/**
* True if a client SDK should track reasons for this flag.
*/
[[nodiscard]] bool track_reason() const;

/**
* A timestamp, which if the current time is before, a client SDK
* should send debug events for the flag.
* @return
*/
[[nodiscard]] std::optional<
std::chrono::time_point<std::chrono::system_clock>>
debug_events_until_date() const;

/**
* Details of the flags evaluation.
*/
[[nodiscard]] EvaluationDetailInternal const& detail() const;

EvaluationResult(
uint64_t version,
std::optional<uint64_t> flag_version,
bool track_events,
bool track_reason,
std::optional<std::chrono::time_point<std::chrono::system_clock>>
debug_events_until_date,
EvaluationDetailInternal detail);

private:
uint64_t version_;
std::optional<uint64_t> flag_version_;
bool track_events_;
bool track_reason_;
std::optional<std::chrono::time_point<std::chrono::system_clock>>
debug_events_until_date_;
EvaluationDetailInternal detail_;
};

} // namespace launchdarkly
14 changes: 14 additions & 0 deletions libs/common/include/serialization/json_attributes.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include <boost/json.hpp>
#include "attributes.hpp"

namespace launchdarkly {
/**
* Method used by boost::json for converting launchdarkly::Attributes into a
* boost::json::value.
*/
void tag_invoke(boost::json::value_from_tag const&,
boost::json::value& json_value,
Attributes const& attributes);
} // namespace launchdarkly
15 changes: 15 additions & 0 deletions libs/common/include/serialization/json_context.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include <boost/json.hpp>

#include "context.hpp"

namespace launchdarkly {
/**
* Method used by boost::json for converting a launchdarkly::Context into a
* boost::json::value.
*/
void tag_invoke(boost::json::value_from_tag const&,
boost::json::value& json_value,
Context const& ld_context);
} // namespace launchdarkly
16 changes: 16 additions & 0 deletions libs/common/include/serialization/json_evaluation_reason.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <boost/json.hpp>

#include "data/evaluation_reason.hpp"

namespace launchdarkly {
/**
* Method used by boost::json for converting a boost::json::value into a
* launchdarkly::EvaluationReason.
* @return A EvaluationReason representation of the boost::json::value.
*/
EvaluationReason tag_invoke(
boost::json::value_to_tag<EvaluationReason> const& unused,
boost::json::value const& json_value);
} // namespace launchdarkly
16 changes: 16 additions & 0 deletions libs/common/include/serialization/json_evaluation_result.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <boost/json.hpp>

#include "data/evaluation_result.hpp"

namespace launchdarkly {
/**
* Method used by boost::json for converting a boost::json::value into a
* launchdarkly::EvaluationResult.
* @return A EvaluationResult representation of the boost::json::value.
*/
EvaluationResult tag_invoke(
boost::json::value_to_tag<EvaluationResult> const& unused,
boost::json::value const& json_value);
} // namespace launchdarkly
23 changes: 23 additions & 0 deletions libs/common/include/serialization/json_value.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include <boost/json.hpp>

#include "value.hpp"

namespace launchdarkly {
/**
* Method used by boost::json for converting a boost::json::value into a
* launchdarkly::Value.
* @return A Value representation of the boost::json::value.
*/
Value tag_invoke(boost::json::value_to_tag<Value> const&,
boost::json::value const&);

/**
* Method used by boost::json for converting a launchdarkly::Value into a
* boost::json::value.
*/
void tag_invoke(boost::json::value_from_tag const&,
boost::json::value& json_value,
Value const& ld_value);
} // namespace launchdarkly
59 changes: 59 additions & 0 deletions libs/common/include/serialization/value_mapping.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#pragma once

#include <boost/json.hpp>

namespace launchdarkly {

template <typename Type>
std::optional<Type> ValueAsOpt(boost::json::object::iterator iterator,
boost::json::object::iterator end) {
boost::ignore_unused(iterator);
boost::ignore_unused(end);

static_assert(sizeof(Type) == -1, "Must be specialized to use ValueAsOpt");
}

template <typename Type>
Type ValueOrDefault(boost::json::object::iterator iterator,
boost::json::object::iterator end,
Type default_value) {
boost::ignore_unused(iterator);
boost::ignore_unused(end);
boost::ignore_unused(default_value);

static_assert(sizeof(Type) == -1,
"Must be specialized to use ValueOrDefault");
}

template <typename OutType, typename InType>
std::optional<OutType> MapOpt(std::optional<InType> opt,
std::function<OutType(InType&)> const& mapper) {
if (opt.has_value()) {
return std::make_optional(mapper(opt.value()));
}
return std::nullopt;
}

template <>
std::optional<uint64_t> ValueAsOpt(boost::json::object::iterator iterator,
boost::json::object::iterator end);

template <>
std::optional<std::string> ValueAsOpt(boost::json::object::iterator iterator,
boost::json::object::iterator end);

template <>
bool ValueOrDefault(boost::json::object::iterator iterator,
boost::json::object::iterator end,
bool default_value);

template <>
uint64_t ValueOrDefault(boost::json::object::iterator iterator,
boost::json::object::iterator end,
uint64_t default_value);

template <>
std::string ValueOrDefault(boost::json::object::iterator iterator,
boost::json::object::iterator end,
std::string default_value);
} // namespace launchdarkly
13 changes: 11 additions & 2 deletions libs/common/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,18 @@ add_library(${LIBNAME}
config/endpoints_builder.cpp
config/config_builder.cpp
config/config.cpp
context_filter.cpp lib.cpp
data/evaluation_reason.cpp
data/evaluation_detail_internal.cpp
data/evaluation_result.cpp
context_filter.cpp
config/application_info.cpp
)
lib.cpp
value_mapping.cpp
serialization/json_attributes.cpp
serialization/json_context.cpp
serialization/json_evaluation_reason.cpp
serialization/json_evaluation_result.cpp
serialization/json_value.cpp)


add_library(launchdarkly::common ALIAS ${LIBNAME})
Expand Down
Loading