diff --git a/lib/sanbase/clickhouse/founders/founders.ex b/lib/sanbase/clickhouse/founders/founders.ex new file mode 100644 index 000000000..c54bded73 --- /dev/null +++ b/lib/sanbase/clickhouse/founders/founders.ex @@ -0,0 +1,18 @@ +defmodule Sanbase.Clickhouse.Founders do + def get_founders() do + query = get_founders_query() + + Sanbase.ClickhouseRepo.query_transform(query, fn [name, slug] -> + %{name: name, slug: slug} + end) + end + + defp get_founders_query() do + sql = """ + SELECT name, slug + FROM founder_metadata + """ + + Sanbase.Clickhouse.Query.new(sql, %{}) + end +end diff --git a/lib/sanbase_web/graphql/resolvers/metric/metric_resolver.ex b/lib/sanbase_web/graphql/resolvers/metric/metric_resolver.ex index a7bc4af0d..0cfe9c68f 100644 --- a/lib/sanbase_web/graphql/resolvers/metric/metric_resolver.ex +++ b/lib/sanbase_web/graphql/resolvers/metric/metric_resolver.ex @@ -107,6 +107,29 @@ defmodule SanbaseWeb.Graphql.Resolvers.MetricResolver do end end + def get_available_founders(_root, _args, %{source: %{metric: metric}}) do + with {:ok, selectors} <- Metric.available_selectors(metric) do + case :founders in selectors do + true -> + with {:ok, data} <- Sanbase.Clickhouse.Founders.get_founders() do + slugs = Enum.map(data, & &1.slug) + projects = Sanbase.Project.List.by_slugs(slugs) + slug_to_project_map = Map.new(projects, &{&1.slug, &1}) + + result = + Enum.map(data, fn map -> + Map.put(map, :project, slug_to_project_map[map.slug]) + end) + + {:ok, result} + end + + false -> + {:ok, []} + end + end + end + def get_human_readable_name(_root, _args, %{source: %{metric: metric}}), do: Metric.human_readable_name(metric) diff --git a/lib/sanbase_web/graphql/schema/types/metric_types.ex b/lib/sanbase_web/graphql/schema/types/metric_types.ex index a2c870396..13f8650a4 100644 --- a/lib/sanbase_web/graphql/schema/types/metric_types.ex +++ b/lib/sanbase_web/graphql/schema/types/metric_types.ex @@ -117,6 +117,11 @@ defmodule SanbaseWeb.Graphql.MetricTypes do value(:table) end + object :founder do + field(:name, non_null(:string)) + field(:project, :project) + end + object :broken_data do field(:from, non_null(:datetime)) field(:to, non_null(:datetime)) @@ -411,6 +416,10 @@ defmodule SanbaseWeb.Graphql.MetricTypes do resolve(&MetricResolver.get_available_selectors/3) end + field :available_founders, list_of(:founder) do + cache_resolve(&MetricResolver.get_available_founders/3) + end + @desc ~s""" The list of required selectors for the metric. It is used to show the list of selectors that is required in order to fetch the metric. diff --git a/test/sanbase_web/graphql/metric/api_metric_metadata_test.exs b/test/sanbase_web/graphql/metric/api_metric_metadata_test.exs index 111e5ed94..a7c67241c 100644 --- a/test/sanbase_web/graphql/metric/api_metric_metadata_test.exs +++ b/test/sanbase_web/graphql/metric/api_metric_metadata_test.exs @@ -1,11 +1,64 @@ defmodule SanbaseWeb.Graphql.ApiMetricMetadataTest do use SanbaseWeb.ConnCase, async: false - import Sanbase.Factory, only: [rand_str: 0] + import Sanbase.Factory import SanbaseWeb.Graphql.TestHelpers alias Sanbase.Metric + test "returns data for availableFounders", %{conn: conn} do + metrics_with_founders = + Metric.available_metrics() + |> Enum.filter(fn m -> + {:ok, selectors} = Metric.available_selectors(m) + + :founders in selectors + end) + + insert(:project, %{name: "Ethereum", ticker: "ETH", slug: "ethereum"}) + insert(:project, %{name: "Bitcoin", ticker: "BTC", slug: "bitcoin"}) + + rows = [ + ["Vitalik Buterin", "ethereum"], + ["Satoshi Nakamoto", "bitcoin"] + ] + + query = fn metric -> + """ + { + getMetric(metric: "#{metric}"){ + metadata{ + availableFounders{ name project{ name } } + } + } + } + """ + end + + Sanbase.Mock.prepare_mock2(&Sanbase.ClickhouseRepo.query/2, {:ok, %{rows: rows}}) + |> Sanbase.Mock.run_with_mocks(fn -> + for metric <- metrics_with_founders do + result = + conn + |> post("/graphql", query_skeleton(query.(metric))) + |> json_response(200) + |> get_in(["data", "getMetric", "metadata", "availableFounders"]) + + assert %{"name" => "Vitalik Buterin", "project" => %{"name" => "Ethereum"}} in result + assert %{"name" => "Satoshi Nakamoto", "project" => %{"name" => "Bitcoin"}} in result + end + end) + + result = + conn + |> post("/graphql", query_skeleton(query.("price_usd"))) + |> json_response(200) + |> get_in(["data", "getMetric", "metadata", "availableFounders"]) + + # No founders for metrics without founders in their selectors + assert result == [] + end + test "returns data for all available metric", %{conn: conn} do metrics = Metric.available_metrics() |> Enum.shuffle()