-
Notifications
You must be signed in to change notification settings - Fork 3
feat: Serialize flags and segments. #194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ebbc06c
3c67018
43533c9
7e6210e
4e18a58
726e0e6
4bf1340
2ba923c
e1ad89a
c236d77
934e611
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,7 +31,8 @@ struct Flag { | |
| Weight weight; | ||
| bool untracked; | ||
|
|
||
| WeightedVariation() = default; | ||
| WeightedVariation(); | ||
|
|
||
| WeightedVariation(Variation index, Weight weight); | ||
| static WeightedVariation Untracked(Variation index, Weight weight); | ||
|
|
||
|
|
@@ -48,7 +49,7 @@ struct Flag { | |
| DEFINE_CONTEXT_KIND_FIELD(contextKind) | ||
|
|
||
| Rollout() = default; | ||
| Rollout(std::vector<WeightedVariation>); | ||
| explicit Rollout(std::vector<WeightedVariation>); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To prevent infinite template recursion. |
||
| }; | ||
|
|
||
| using VariationOrRollout = std::variant<Variation, Rollout>; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -208,4 +208,158 @@ tag_invoke(boost::json::value_to_tag< | |
| return std::make_optional(variation); | ||
| } | ||
|
|
||
| namespace data_model { | ||
| void tag_invoke( | ||
| boost::json::value_from_tag const& unused, | ||
| boost::json::value& json_value, | ||
| data_model::Flag::Rollout::WeightedVariation const& weighted_variation) { | ||
| auto& obj = json_value.emplace_object(); | ||
| obj.emplace("variation", weighted_variation.variation); | ||
| obj.emplace("weight", weighted_variation.weight); | ||
|
|
||
| WriteMinimal(obj, "untracked", weighted_variation.untracked); | ||
| } | ||
|
|
||
| void tag_invoke(boost::json::value_from_tag const& unused, | ||
| boost::json::value& json_value, | ||
| data_model::Flag::Rollout::Kind const& kind) { | ||
| switch (kind) { | ||
| case Flag::Rollout::Kind::kUnrecognized: | ||
| // TODO: Should we be preserving the original string. | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I imagine all strongly typed SDKs have this problem. So I will check some others. I am not super happy with it. (Though generally I don't like having to serialize, but it doesn't seem like there is any real alternative.) |
||
| break; | ||
| case Flag::Rollout::Kind::kExperiment: | ||
| json_value.emplace_string() = "experiment"; | ||
| break; | ||
| case Flag::Rollout::Kind::kRollout: | ||
| json_value.emplace_string() = "rollout"; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| void tag_invoke(boost::json::value_from_tag const& unused, | ||
| boost::json::value& json_value, | ||
| data_model::Flag::Rollout const& rollout) { | ||
| auto& obj = json_value.emplace_object(); | ||
|
|
||
| obj.emplace("variations", boost::json::value_from(rollout.variations)); | ||
| if (rollout.kind != Flag::Rollout::Kind::kUnrecognized) { | ||
| // TODO: Should we be preserving the original string and putting it in. | ||
| obj.emplace("kind", boost::json::value_from(rollout.kind)); | ||
| } | ||
| WriteMinimal(obj, "seed", rollout.seed); | ||
| obj.emplace("bucketBy", rollout.bucketBy.RedactionName()); | ||
| obj.emplace("contextKind", rollout.contextKind.t); | ||
| } | ||
|
|
||
| void tag_invoke( | ||
| boost::json::value_from_tag const& unused, | ||
| boost::json::value& json_value, | ||
| data_model::Flag::VariationOrRollout const& variation_or_rollout) { | ||
| auto& obj = json_value.emplace_object(); | ||
| std::visit( | ||
| [&obj](auto&& arg) { | ||
| using T = std::decay_t<decltype(arg)>; | ||
| if constexpr (std::is_same_v<T, data_model::Flag::Rollout>) { | ||
| obj.emplace("rollout", boost::json::value_from(arg)); | ||
| } else if constexpr (std::is_same_v<T, | ||
| data_model::Flag::Variation>) { | ||
| obj.emplace("variation", arg); | ||
| } | ||
| }, | ||
| variation_or_rollout); | ||
| } | ||
|
|
||
| void tag_invoke(boost::json::value_from_tag const& unused, | ||
| boost::json::value& json_value, | ||
| data_model::Flag::Prerequisite const& prerequisite) { | ||
| auto& obj = json_value.emplace_object(); | ||
| obj.emplace("key", prerequisite.key); | ||
| obj.emplace("variation", prerequisite.variation); | ||
| } | ||
|
|
||
| void tag_invoke(boost::json::value_from_tag const& unused, | ||
| boost::json::value& json_value, | ||
| data_model::Flag::Target const& target) { | ||
| auto& obj = json_value.emplace_object(); | ||
| obj.emplace("values", boost::json::value_from(target.values)); | ||
| obj.emplace("variation", target.variation); | ||
| obj.emplace("contextKind", target.contextKind.t); | ||
| } | ||
|
|
||
| void tag_invoke(boost::json::value_from_tag const& unused, | ||
| boost::json::value& json_value, | ||
| data_model::Flag::ClientSideAvailability const& availability) { | ||
| auto& obj = json_value.emplace_object(); | ||
| WriteMinimal(obj, "usingEnvironmentId", availability.usingEnvironmentId); | ||
| WriteMinimal(obj, "usingMobileKey", availability.usingMobileKey); | ||
| } | ||
|
|
||
| void tag_invoke(boost::json::value_from_tag const& unused, | ||
| boost::json::value& json_value, | ||
| data_model::Flag::Rule const& rule) { | ||
| auto& obj = json_value.emplace_object(); | ||
| WriteMinimal(obj, "trackEvents", rule.trackEvents); | ||
| WriteMinimal(obj, "id", rule.id); | ||
| std::visit( | ||
| [&obj](auto&& arg) { | ||
| using T = std::decay_t<decltype(arg)>; | ||
| if constexpr (std::is_same_v<T, data_model::Flag::Rollout>) { | ||
| obj.emplace("rollout", boost::json::value_from(arg)); | ||
| } else if constexpr (std::is_same_v<T, | ||
| data_model::Flag::Variation>) { | ||
| obj.emplace("variation", arg); | ||
| } | ||
| }, | ||
| rule.variationOrRollout); | ||
| obj.emplace("clauses", boost::json::value_from(rule.clauses)); | ||
| } | ||
|
|
||
| // The "targets" array in a flag cannot have a contextKind, so this intermediate | ||
| // representation allows the flag data model to use Flag::Target, but still | ||
| // serialize a user target correctly. | ||
| struct UserTarget { | ||
| std::vector<std::string> values; | ||
| std::uint64_t variation; | ||
| UserTarget(data_model::Flag::Target const& target) | ||
| : values(target.values), variation(target.variation) {} | ||
| }; | ||
|
|
||
| void tag_invoke(boost::json::value_from_tag const& unused, | ||
| boost::json::value& json_value, | ||
| UserTarget const& target) { | ||
| auto& obj = json_value.emplace_object(); | ||
| obj.emplace("values", boost::json::value_from(target.values)); | ||
| obj.emplace("variation", target.variation); | ||
| } | ||
|
|
||
| void tag_invoke(boost::json::value_from_tag const& unused, | ||
| boost::json::value& json_value, | ||
| data_model::Flag const& flag) { | ||
| auto& obj = json_value.emplace_object(); | ||
| WriteMinimal(obj, "trackEvents", flag.trackEvents); | ||
| WriteMinimal(obj, "clientSide", flag.clientSide); | ||
| WriteMinimal(obj, "on", flag.on); | ||
| WriteMinimal(obj, "trackEventsFallthrough", flag.trackEventsFallthrough); | ||
| WriteMinimal(obj, "debugEventsUntilDate", flag.debugEventsUntilDate); | ||
| WriteMinimal(obj, "salt", flag.salt); | ||
| WriteMinimal(obj, "offVariation", flag.offVariation); | ||
| obj.emplace("key", flag.key); | ||
| obj.emplace("version", flag.version); | ||
| obj.emplace("variations", boost::json::value_from(flag.variations)); | ||
| obj.emplace("rules", boost::json::value_from(flag.rules)); | ||
| obj.emplace("prerequisites", boost::json::value_from(flag.prerequisites)); | ||
| obj.emplace("fallthrough", boost::json::value_from(flag.fallthrough)); | ||
| obj.emplace("clientSideAvailability", | ||
| boost::json::value_from(flag.clientSideAvailability)); | ||
| obj.emplace("contextTargets", boost::json::value_from(flag.contextTargets)); | ||
|
|
||
| std::vector<UserTarget> user_targets; | ||
| for (auto const& target : flag.targets) { | ||
| user_targets.emplace_back(target); | ||
| } | ||
| obj.emplace("targets", boost::json::value_from(user_targets)); | ||
| } | ||
|
|
||
| } // namespace data_model | ||
|
|
||
| } // namespace launchdarkly | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed the build names to it is easier to scan them in the PR checks.