Current section

Files

Jump to
launchdarkly_server_sdk src ldclient_rule.erl
Raw

src/ldclient_rule.erl

%%-------------------------------------------------------------------
%% @doc Flag rule data type
%%
%% @end
%%-------------------------------------------------------------------
-module(ldclient_rule).
%% API
-export([new/1]).
-export([match_user/4]).
%% Types
-type rule() :: #{
id => binary(),
clauses => [ldclient_clause:clause()],
track_events => boolean(),
variation_or_rollout => ldclient_flag:variation_or_rollout()
}.
%% Expresses a set of AND-ed matching conditions for a user, 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 user, includes segment_match
%%
%% @end
-spec match_user(rule(), User :: ldclient_user:user(), StorageBackend :: atom(), Tag :: atom()) -> match | no_match.
match_user(#{clauses := Clauses}, User, StorageBackend, Tag) ->
check_clauses(Clauses, User, StorageBackend, 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), track_events => TrackEvents, variation_or_rollout => Variation};
new_from_template(#{<<"id">> := Id, <<"clauses">> := Clauses, <<"trackEvents">> := TrackEvents, <<"rollout">> := #{
<<"variations">> := Variations
} = Rollout}) when is_list(Variations) ->
#{
id => Id,
clauses => parse_clauses(Clauses),
track_events => TrackEvents,
variation_or_rollout => ldclient_rollout:new(Rollout)
};
new_from_template(#{<<"id">> := Id, <<"clauses">> := Clauses, <<"trackEvents">> := TrackEvents}) ->
#{id => Id, clauses => parse_clauses(Clauses), track_events => TrackEvents, variation_or_rollout => 0}.
-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([ldclient_clause:clause()], ldclient_user:user(), atom(), atom()) -> match | no_match.
check_clauses([], _User, _StorageBackend, _Tag) -> match;
check_clauses([Clause|Rest], User, StorageBackend, Tag) ->
Result = ldclient_clause:match_user(Clause, User, StorageBackend, Tag),
check_clause_result(Result, Rest, User, StorageBackend, Tag).
-spec check_clause_result(match | no_match, [ldclient_clause:clause()], ldclient_user:user(), atom(), atom()) -> match | no_match.
check_clause_result(no_match, _Rest, _User, _StorageBackend, _Tag) -> no_match;
check_clause_result(match, Rest, User, StorageBackend, Tag) ->
check_clauses(Rest, User, StorageBackend, Tag).