defmodule ConfigCat.Config do
@moduledoc """
Defines configuration-related types used in the rest of the library.
"""
alias ConfigCat.Config.Preferences
alias ConfigCat.Config.Segment
alias ConfigCat.Config.Setting
@typedoc false
@type comparator :: non_neg_integer()
@typedoc "The name of a configuration setting."
@type key :: String.t()
@typedoc false
@type opt :: {:preferences, Preferences.t()} | {:settings, settings()}
@typedoc false
@type salt :: String.t()
@typedoc false
@type settings :: %{String.t() => Setting.t()}
@typedoc "A collection of configuration settings and preferences."
@type t :: %{String.t() => map()}
@typedoc false
@type url :: String.t()
@typedoc "The actual value of a configuration setting."
@type value :: String.t() | boolean() | number()
@typedoc "The name of a variation being tested."
@type variation_id :: String.t()
@settings "f"
@preferences "p"
@segments "s"
@doc false
@spec new([opt]) :: t()
def new(opts \\ []) do
settings = Keyword.get(opts, :settings, %{})
preferences = Keyword.get_lazy(opts, :preferences, &Preferences.new/0)
%{@settings => settings, @preferences => preferences}
end
@doc false
@spec preferences(t()) :: Preferences.t()
def preferences(config) do
Map.get_lazy(config, @preferences, &Preferences.new/0)
end
@doc false
@spec segments(t()) :: [Segment.t()]
def segments(config) do
Map.get(config, @segments, [])
end
@doc false
@spec settings(t()) :: settings()
def settings(config) do
Map.get(config, @settings, %{})
end
@doc false
@spec fetch_settings(t()) :: {:ok, settings()} | {:error, :not_found}
def fetch_settings(config) do
case Map.fetch(config, @settings) do
{:ok, settings} -> {:ok, settings}
:error -> {:error, :not_found}
end
end
@doc false
@spec merge(left :: t(), right :: t()) :: t()
def merge(left, right) do
left_flags = settings(left)
right_flags = settings(right)
Map.put(left, @settings, Map.merge(left_flags, right_flags))
end
@doc false
@spec inline_salt_and_segments(t()) :: t()
def inline_salt_and_segments(config) do
salt = config |> preferences() |> Preferences.salt()
segments = segments(config)
Map.update(
config,
@settings,
%{},
&Map.new(&1, fn {key, setting} -> {key, Setting.inline_salt_and_segments(setting, salt, segments)} end)
)
end
end