Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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