diff --git a/extra/lib/plausible/stats/exploration.ex b/extra/lib/plausible/stats/exploration.ex index 1bf0a5437349..42cb19561b35 100644 --- a/extra/lib/plausible/stats/exploration.ex +++ b/extra/lib/plausible/stats/exploration.ex @@ -298,6 +298,7 @@ defmodule Plausible.Stats.Exploration do from(s in q, where: ^step_condition) end) + |> maybe_exclude_step_matches(List.last(steps)) # Fan out each q_combined row into up to two output rows (exact + wildcard) # using ARRAY JOIN over a small boolean array. @@ -399,6 +400,30 @@ defmodule Plausible.Stats.Exploration do ) end + defp maybe_exclude_step_matches(query, %{includes_subpaths: true} = step) do + pattern = wildcard_pattern(step.pathname) + + from m in query, + where: + selected_as(:name) != ^step.name or + not fragment("match(?, ?)", selected_as(:pathname), ^pattern) + end + + defp maybe_exclude_step_matches(query, %{is_goal: true, name: "pageview"} = step) do + if String.contains?(step.pathname, "*") do + pattern = Filters.Utils.page_regex(step.pathname) + + from m in query, + where: + selected_as(:name) != ^step.name or + not fragment("match(?, ?)", selected_as(:pathname), ^pattern) + else + query + end + end + + defp maybe_exclude_step_matches(query, _), do: query + defp exclude_goal_matches(query, goals) do to_exclude = goals @@ -647,9 +672,7 @@ defmodule Plausible.Stats.Exploration do defp step_condition(step, count) when count <= @max_steps do cond do step.includes_subpaths -> - escaped = Regex.escape(step.pathname) - - pattern = "^#{escaped}(/.+)?$" + pattern = wildcard_pattern(step.pathname) dynamic( [s], @@ -675,6 +698,12 @@ defmodule Plausible.Stats.Exploration do end end + defp wildcard_pattern(pathname) when is_binary(pathname) do + escaped = Regex.escape(pathname) + + "^#{escaped}(/.+)?$" + end + defp maybe_search(query, search_term) do case String.trim(search_term) do term when byte_size(term) > 2 ->