Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add getMetricSpikeExplanations API #4431

Merged
merged 3 commits into from
Oct 17, 2024
Merged
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
13 changes: 13 additions & 0 deletions config/runtime.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
import Config

if config_env() == :dev do
IvanIvanoff marked this conversation as resolved.
Show resolved Hide resolved
{ssl, ssl_opts} =
if System.get_env("DATABASE_URL") do
{true, [verify: :verify_none]}
else
{false, []}
end

config :sanbase, Sanbase.Repo,
ssl: ssl,
ssl_opts: ssl_opts
end

if config_env() in [:dev, :test] do
# In order to properly work while developing locally,
# load the .env file before doing the configuration
Expand Down
6 changes: 4 additions & 2 deletions lib/sanbase/metric/sql_query_helper.ex
Original file line number Diff line number Diff line change
Expand Up @@ -214,14 +214,16 @@ defmodule Sanbase.Metric.SqlQuery.Helper do

def metric_id_filter(metric, opts) when is_binary(metric) do
arg_name = Keyword.fetch!(opts, :argument_name)
metric_id_column = Keyword.get(opts, :metric_id_column, "metric_id")

"metric_id = ( SELECT metric_id FROM metric_metadata FINAL PREWHERE name = {{#{arg_name}}} LIMIT 1 )"
"#{metric_id_column} = ( SELECT metric_id FROM metric_metadata FINAL PREWHERE name = {{#{arg_name}}} LIMIT 1 )"
end

def metric_id_filter(metrics, opts) when is_list(metrics) do
arg_name = Keyword.fetch!(opts, :argument_name)
metric_id_column = Keyword.get(opts, :metric_id_column, "metric_id")

"metric_id IN ( SELECT DISTINCT(metric_id) FROM metric_metadata FINAL PREWHERE name IN ({{#{arg_name}}}) )"
"#{metric_id_column} IN ( SELECT DISTINCT(metric_id) FROM metric_metadata FINAL PREWHERE name IN ({{#{arg_name}}}) )"
end

def signal_id_filter(%{signal: signal}, opts) when is_binary(signal) do
Expand Down
44 changes: 44 additions & 0 deletions lib/sanbase/social_data/spikes/spikes.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
defmodule Sanbase.SocialData.Spikes do
import Sanbase.Metric.SqlQuery.Helper,
only: [asset_id_filter: 2, metric_id_filter: 2]

def get_metric_spike_explanations(metric, selector, from, to) do
query =
get_metric_spikes_explanation_query(metric, selector, from, to)

Sanbase.ClickhouseRepo.query_transform(query, fn [from, to, summary] ->
%{
spike_start_datetime: DateTime.from_unix!(from),
spike_end_datetime: DateTime.from_unix!(to),
explanation: summary
}
end)
end

defp get_metric_spikes_explanation_query(metric, %{slug: slug_or_slugs} = selector, from, to) do
sql = """
SELECT
toUnixTimestamp(from_dt),
toUnixTimestamp(to_dt),
summary
FROM spikes
WHERE
#{asset_id_filter(selector, argument_name: "selector")} AND
#{metric_id_filter(metric, metric_id_column: "calculated_on_metric_id", argument_name: "metric")} AND
to_dt >= toDateTime({{from}}) AND
from_dt < toDateTime({{to}})
ORDER BY from_dt ASC
"""

{:ok, metadata} = Sanbase.Metric.metadata(metric)

params = %{
selector: slug_or_slugs,
metric: metadata.internal_metric,
from: DateTime.to_unix(from),
to: DateTime.to_unix(to)
}

Sanbase.Clickhouse.Query.new(sql, params)
end
end
13 changes: 12 additions & 1 deletion lib/sanbase_web/graphql/resolvers/social_data_resolver.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,18 @@ defmodule SanbaseWeb.Graphql.Resolvers.SocialDataResolver do

@context_words_default_size 10

def popular_search_terms(_root, %{from: from, to: to}, _) do
def get_metric_spike_explanations(
_root,
%{metric: metric, slug: slug, from: from, to: to},
_resolution
) do
with false <- Sanbase.Metric.hard_deprecated?(metric),
true <- Sanbase.Metric.has_metric?(metric) do
SocialData.Spikes.get_metric_spike_explanations(metric, %{slug: slug}, from, to)
end
end

def popular_search_terms(_root, %{from: from, to: to}, _resolution) do
Sanbase.SocialData.PopularSearchTerm.get(from, to)
end

Expand Down
11 changes: 11 additions & 0 deletions lib/sanbase_web/graphql/schema/queries/social_data_queries.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ defmodule SanbaseWeb.Graphql.Schema.SocialDataQueries do
alias SanbaseWeb.Graphql.Resolvers.SocialDataResolver

object :social_data_queries do
field :get_metric_spike_explanations, list_of(:metric_spike_explanation) do
meta(access: :free)

arg(:metric, non_null(:string))
arg(:slug, non_null(:string))
arg(:from, non_null(:datetime))
arg(:to, non_null(:datetime))

cache_resolve(&SocialDataResolver.get_metric_spike_explanations/3)
end

field :popular_search_terms, list_of(:popular_search_term) do
meta(access: :free)

Expand Down
6 changes: 6 additions & 0 deletions lib/sanbase_web/graphql/schema/types/social_data_types.ex
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ defmodule SanbaseWeb.Graphql.SocialDataTypes do
value(:telegram_discussion_overview)
end

object :metric_spike_explanation do
field(:spike_start_datetime, non_null(:datetime))
field(:spike_end_datetime, non_null(:datetime))
field(:explanation, non_null(:string))
end

object :popular_search_term do
field(:title, non_null(:string))
field(:options, :json)
Expand Down
1 change: 1 addition & 0 deletions test/sanbase/billing/query_access_level_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ defmodule Sanbase.Billing.QueryAccessLevelTest do
:get_market_exchanges,
:get_menu,
:get_metric,
:get_metric_spike_explanations,
:get_most_recent,
:get_most_used,
:get_most_voted,
Expand Down
70 changes: 70 additions & 0 deletions test/sanbase_web/graphql/social_data/spikes_api_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
defmodule SanbaseWeb.Graphql.SocialDataSpikesApiTest do
use SanbaseWeb.ConnCase, async: false

import Sanbase.Factory
import SanbaseWeb.Graphql.TestHelpers

setup do
%{user: user} = insert(:subscription_pro_sanbase, user: insert(:user))
conn = setup_jwt_auth(build_conn(), user)

%{conn: conn}
end

test "get metric spike explanations", context do
rows = [
[
DateTime.to_unix(~U[2024-01-01 01:00:00Z]),
DateTime.to_unix(~U[2024-01-01 02:00:00Z]),
"Reason 1"
],
[
DateTime.to_unix(~U[2024-01-02 10:00:00Z]),
DateTime.to_unix(~U[2024-01-01 12:30:00Z]),
"Reason 2"
]
]

Sanbase.Mock.prepare_mock2(&Sanbase.ClickhouseRepo.query/2, {:ok, %{rows: rows}})
|> Sanbase.Mock.run_with_mocks(fn ->
query =
get_metric_spike_explanations_query(%{
metric: "social_dominance_total",
slug: "ethereum",
from: ~U[2024-01-01 00:00:00Z],
to: ~U[2024-01-10 00:00:00Z]
})

result =
context.conn
|> post("/graphql", query_skeleton(query))
|> json_response(200)
|> get_in(["data", "getMetricSpikeExplanations"])

assert result == [
%{
"explanation" => "Reason 1",
"spikeEndDatetime" => "2024-01-01T02:00:00Z",
"spikeStartDatetime" => "2024-01-01T01:00:00Z"
},
%{
"explanation" => "Reason 2",
"spikeEndDatetime" => "2024-01-01T12:30:00Z",
"spikeStartDatetime" => "2024-01-02T10:00:00Z"
}
]
end)
end

defp get_metric_spike_explanations_query(args) do
"""
{
getMetricSpikeExplanations(#{map_to_args(args)}) {
spikeStartDatetime
spikeEndDatetime
explanation
}
}
"""
end
end