Current section

Files

Jump to
launchdarkly_server_sdk src ldclient_rule.erl
Raw

src/ldclient_rule.erl

%%-------------------------------------------------------------------
%% @doc Flag rule data type
%% @private
%% @end
%%-------------------------------------------------------------------
-module(ldclient_rule).
%% API
-export([new/1]).
-export([match_context/4]).
%% Types
-type rule() :: #{
id => binary(),
clauses => [ldclient_clause:clause()],
trackEvents => boolean(),
variationOrRollout => ldclient_flag:variation_or_rollout()
}.
%% Expresses a set of AND-ed matching conditions for a context, along with either
%% a fixed variation or a set of rollout percentages
-export_type([rule/0]).
%%===================================================================
%% API
%%===================================================================
-spec new(map()) -> rule().
new(RawRuleMap) ->
RuleTemplate = #{
<<"id">> => <<>>,
<<"clauses">> => [],
<<"trackEvents">> => false
},
RuleMap = maps:merge(RuleTemplate, RawRuleMap),
new_from_template(RuleMap).
%% @doc Match all clauses to context, includes segmentMatch
%%
%% @end
-spec match_context(rule(), Context :: ldclient_context:context(), FeatureStore :: atom(), Tag :: atom()) -> match | no_match | malformed_flag.
match_context(#{clauses := Clauses}, Context, FeatureStore, Tag) ->
check_clauses(Clauses, Context, FeatureStore, Tag).
%%===================================================================
%% Internal functions
%%===================================================================
-spec new_from_template(map()) -> rule().
new_from_template(#{<<"id">> := Id, <<"clauses">> := Clauses, <<"trackEvents">> := TrackEvents, <<"variation">> := Variation}) ->
#{id => Id, clauses => parse_clauses(Clauses), trackEvents => TrackEvents, variationOrRollout => Variation};
new_from_template(#{<<"id">> := Id, <<"clauses">> := Clauses, <<"trackEvents">> := TrackEvents, <<"rollout">> := #{
<<"variations">> := Variations
} = Rollout}) when is_list(Variations) ->
#{
id => Id,
clauses => parse_clauses(Clauses),
trackEvents => TrackEvents,
variationOrRollout => ldclient_rollout:new(Rollout)
};
new_from_template(#{<<"id">> := Id, <<"clauses">> := Clauses, <<"trackEvents">> := TrackEvents}) ->
#{id => Id, clauses => parse_clauses(Clauses), trackEvents => TrackEvents, variationOrRollout => null}.
-spec parse_clauses([map()]) -> [ldclient_clause:clause()].
parse_clauses(Clauses) ->
F = fun(Clause) -> ldclient_clause:new(Clause) end,
lists:map(F, Clauses).
-spec check_clauses(
Clauses:: [ldclient_clause:clause()],
Context :: ldclient_context:context(),
FeatureStore :: atom(),
Tag :: atom()) -> match | no_match | malformed_flag.
check_clauses([], _Context, _FeatureStore, _Tag) -> match;
check_clauses([Clause|Rest], Context, FeatureStore, Tag) ->
Result = ldclient_clause:match_context(Clause, Context, FeatureStore, Tag),
check_clause_result(Result, Rest, Context, FeatureStore, Tag).
-spec check_clause_result(Result :: match | no_match | malformed_flag,
Clauses :: [ldclient_clause:clause()],
Context :: ldclient_context:context(),
FeatureStore :: atom(),
Tag :: atom()) -> match | no_match | malformed_flag.
check_clause_result(malformed_flag, _Rest, _Context, _FeatureStore, _Tag) -> malformed_flag;
check_clause_result(no_match, _Rest, _Context, _FeatureStore, _Tag) -> no_match;
check_clause_result(match, Rest, Context, FeatureStore, Tag) ->
check_clauses(Rest, Context, FeatureStore, Tag).