defmodule Plausible.Stats.ParsedQueryParams do @moduledoc false alias Plausible.Stats.Query defstruct input_date_range: nil, # `relative_date` is a convenience currently exclusive to the internal # dashboard API for constructing datetime ranges. It adds the ability # to use `day`, `month` and `year` periods relative to a specific date. # E.g.: `?period=month&date=2021-01-15` will query the entire month of # January 2021. In the public API it is always today in site.timezone. relative_date: nil, metrics: [], filters: [], dimensions: [], order_by: nil, pagination: nil, now: nil, include: %Plausible.Stats.QueryInclude{}, # When true, skips the validation that goal names in `is` filters must be # configured for the site. Missing goals simply match nothing in SQL, matching # the behaviour of legacy endpoints like top_stats. skip_goal_existence_check: false def to_query!(%__MODULE__{} = parsed_query_params) do query_fields = %Query{} |> Map.from_struct() |> Map.keys() struct!(%Query{}, Map.take(parsed_query_params, query_fields)) end def new!(params) when is_map(params) do struct!(__MODULE__, Map.to_list(params)) end def set(params, keywords) do struct!(params, keywords) end def set_include(params, key, value) do struct!(params, include: struct!(params.include, [{key, value}])) end @props_prefix "event:props:" def add_or_replace_filter(%__MODULE__{filters: filters} = parsed_query_params, new_filter) do [_, new_filter_dimension, _] = new_filter prop_filter? = String.starts_with?(new_filter_dimension, @props_prefix) new_filters = filters |> Enum.reject(fn [_, existing_filter_dimension, _] -> existing_filter_dimension == new_filter_dimension or (prop_filter? and String.starts_with?(existing_filter_dimension, @props_prefix)) end) |> Enum.concat([new_filter]) struct!(parsed_query_params, filters: new_filters) end def conversion_goal_filter?(%__MODULE__{filters: filters}) do Plausible.Stats.Filters.filtering_on_dimension?(filters, "event:goal", max_depth: 0, behavioral_filters: :ignore ) end end