Skip to content
4 changes: 2 additions & 2 deletions lib/plausible/stats/api_query_parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -221,14 +221,14 @@ defmodule Plausible.Stats.ApiQueryParser do
end
end

defp parse_dimensions(dimensions) when is_list(dimensions) do
def parse_dimensions(dimensions) when is_list(dimensions) do
parse_list(
dimensions,
&parse_dimension_entry(&1, "Invalid dimensions '#{i(dimensions)}'")
)
end

defp parse_dimensions(nil), do: {:ok, []}
def parse_dimensions(nil), do: {:ok, []}

def parse_order_by(order_by) when is_list(order_by) do
parse_list(order_by, &parse_order_by_entry/1)
Expand Down
15 changes: 8 additions & 7 deletions lib/plausible/stats/dashboard/query_parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,23 @@ defmodule Plausible.Stats.Dashboard.QueryParser do

@valid_comparison_shorthand_keys Map.keys(@valid_comparison_shorthands)

def parse(params) do
def parse(params, opts \\ []) do
with {:ok, input_date_range} <- parse_input_date_range(params),
{:ok, relative_date} <- parse_relative_date(params),
{:ok, filters} <- parse_filters(params),
{:ok, dimensions} <- ApiQueryParser.parse_dimensions(params["dimensions"]),
{:ok, filters} <- ApiQueryParser.parse_filters(params["filters"]),
{:ok, metrics} <- parse_metrics(params),
{:ok, include} <- parse_include(params) do
{:ok,
ParsedQueryParams.new!(%{
input_date_range: input_date_range,
relative_date: relative_date,
dimensions: dimensions,
filters: filters,
metrics: metrics,
include: include,
skip_goal_existence_check: true
skip_goal_existence_check: true,
now: Keyword.get(opts, :now)
})}
end
end
Expand Down Expand Up @@ -79,6 +82,8 @@ defmodule Plausible.Stats.Dashboard.QueryParser do
compare: compare,
compare_match_day_of_week: params["include"]["compare_match_day_of_week"] == true,
time_labels: params["include"]["time_labels"] == true,
partial_time_labels: params["include"]["partial_time_labels"] == true,
present_index: params["include"]["present_index"] == true,
trim_relative_date_range: true,
drop_unavailable_time_on_page: true,
drop_unavailable_revenue_metrics: true
Expand Down Expand Up @@ -114,8 +119,4 @@ defmodule Plausible.Stats.Dashboard.QueryParser do
defp parse_include_compare(_) do
{:ok, nil}
end

defp parse_filters(%{"filters" => filters}) when is_list(filters) do
Plausible.Stats.ApiQueryParser.parse_filters(filters)
end
end
10 changes: 10 additions & 0 deletions lib/plausible/stats/query_include.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ defmodule Plausible.Stats.QueryInclude do
defstruct imports: false,
imports_meta: false,
time_labels: false,
# `time_label_result_indices` is a convenience for our main graph component. It
# is not yet ready for a public API release because it should also account for
# breakdowns by multiple dimensions (time + non-time). Also, at this point it is
# still unclear whether `time_labels` will stay in the public API or not.
time_label_result_indices: false,
present_index: false,
partial_time_labels: false,
total_rows: false,
trim_relative_date_range: false,
compare: nil,
Expand All @@ -19,6 +26,9 @@ defmodule Plausible.Stats.QueryInclude do
imports: boolean(),
imports_meta: boolean(),
time_labels: boolean(),
time_label_result_indices: boolean(),
present_index: boolean(),
partial_time_labels: boolean(),
total_rows: boolean(),
trim_relative_date_range: boolean(),
compare:
Expand Down
110 changes: 105 additions & 5 deletions lib/plausible/stats/query_result.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ defmodule Plausible.Stats.QueryResult do
alias Plausible.Stats.{Query, QueryRunner, Filters}

defstruct results: [],
comparison_results: nil,
meta: %{},
query: nil

Expand Down Expand Up @@ -43,10 +44,11 @@ defmodule Plausible.Stats.QueryResult do

`results` should already-built by Plausible.Stats.QueryRunner
"""
def from(%QueryRunner{results: results} = runner) do
def from(%QueryRunner{results: results, comparison_results: comparison_results} = runner) do
struct!(
__MODULE__,
results: results,
comparison_results: comparison_results,
meta: meta(runner) |> Jason.OrderedObject.new(),
query: query(runner) |> Jason.OrderedObject.new()
)
Expand All @@ -56,7 +58,12 @@ defmodule Plausible.Stats.QueryResult do
%{}
|> add_imports_meta(runner.main_query)
|> add_metric_warnings_meta(runner.main_query)
|> add_time_labels_meta(runner.main_query)
|> add_time_labels_meta(runner)
|> add_time_labels_result_indices_meta(runner)
|> add_comparison_time_labels_meta(runner)
|> add_comparison_time_label_result_indices_meta(runner)
|> add_present_index_meta(runner.main_query)
|> add_partial_time_labels_meta(runner.main_query)
|> add_total_rows_meta(runner.main_query, runner.total_rows)
|> Enum.sort_by(&elem(&1, 0))
end
Expand Down Expand Up @@ -85,14 +92,81 @@ defmodule Plausible.Stats.QueryResult do
end
end

defp add_time_labels_meta(meta, query) do
defp add_time_labels_meta(meta, %QueryRunner{main_query: query}) do
if query.include.time_labels do
Map.put(meta, :time_labels, Plausible.Stats.Time.time_labels(query))
else
meta
end
end

defp add_comparison_time_labels_meta(meta, %QueryRunner{main_query: query} = runner) do
if query.include.time_labels && query.include.compare do
Map.put(
meta,
:comparison_time_labels,
Plausible.Stats.Time.time_labels(runner.comparison_query)
)
else
meta
end
end

defp add_time_labels_result_indices_meta(meta, %QueryRunner{main_query: query} = runner) do
time_labels = meta[:time_labels]

if query.include.time_label_result_indices and is_list(time_labels) do
Map.put(
meta,
:time_label_result_indices,
result_indices_for_time_labels(time_labels, runner.main_results)
)
else
meta
end
end

defp add_comparison_time_label_result_indices_meta(
meta,
%QueryRunner{main_query: query} = runner
) do
comp_time_labels = meta[:comparison_time_labels]

if query.include.time_label_result_indices and is_list(comp_time_labels) do
Map.put(
meta,
:comparison_time_label_result_indices,
result_indices_for_time_labels(comp_time_labels, runner.comparison_results)
)
else
meta
end
end

defp add_present_index_meta(meta, query) do
time_labels = meta[:time_labels]

if query.include.present_index and is_list(time_labels) do
Map.put(meta, :present_index, Plausible.Stats.Time.present_index(time_labels, query))
else
meta
end
end

defp add_partial_time_labels_meta(meta, query) do
time_labels = meta[:time_labels]

if query.include.partial_time_labels and is_list(time_labels) do
Map.put(
meta,
:partial_time_labels,
Plausible.Stats.Time.partial_time_labels(time_labels, query)
)
else
meta
end
end

defp add_total_rows_meta(meta, query, total_rows) do
if query.include.total_rows do
Map.put(meta, :total_rows, total_rows)
Expand Down Expand Up @@ -209,6 +283,15 @@ defmodule Plausible.Stats.QueryResult do

defp metric_warning(_metric, _query), do: nil

defp result_indices_for_time_labels(time_labels, results_list) do
index_lookup_map =
results_list
|> Enum.with_index()
|> Map.new(fn {%{dimensions: [dim]}, idx} -> {dim, idx} end)

Enum.map(time_labels, &Map.get(index_lookup_map, &1))
end

defp to_iso8601(datetime, timezone) do
datetime
|> DateTime.shift_zone!(timezone)
Expand All @@ -217,8 +300,25 @@ defmodule Plausible.Stats.QueryResult do
end

defimpl Jason.Encoder, for: Plausible.Stats.QueryResult do
def encode(%Plausible.Stats.QueryResult{results: results, meta: meta, query: query}, opts) do
Jason.OrderedObject.new(results: results, meta: meta, query: query)
def encode(
%Plausible.Stats.QueryResult{
results: results,
comparison_results: comparison_results,
meta: meta,
query: query
},
opts
) do
if comparison_results do
Jason.OrderedObject.new(
results: results,
comparison_results: comparison_results,
meta: meta,
query: query
)
else
Jason.OrderedObject.new(results: results, meta: meta, query: query)
end
|> Jason.Encoder.encode(opts)
end
end
Loading
Loading