generator/explores/glean_ping_explore.py (81 lines of code) (raw):
"""Glean Ping explore type."""
from __future__ import annotations
from pathlib import Path
from typing import Any, Dict, Iterator, List, Optional
from mozilla_schema_generator.glean_ping import GleanPing
from ..views import GleanPingView, View
from .ping_explore import PingExplore
class GleanPingExplore(PingExplore):
"""A Glean Ping Table explore."""
type: str = "glean_ping_explore"
def _to_lookml(self, v1_name: Optional[str]) -> List[Dict[str, Any]]:
"""Generate LookML to represent this explore."""
repo = next((r for r in GleanPing.get_repos() if r["name"] == v1_name))
glean_app = GleanPing(repo)
# convert ping description indexes to snake case, as we already have
# for the explore name
ping_descriptions = {
k.replace("-", "_"): v for k, v in glean_app.get_ping_descriptions().items()
}
# collapse whitespace in the description so the lookml looks a little better
ping_description = " ".join(ping_descriptions.get(self.name, "").split())
views_lookml = self.get_view_lookml(self.views["base_view"])
# The first view, by convention, is always the base view with the
# majority of the dimensions from the top level.
base = views_lookml["views"][0]
base_name = base["name"]
joins = []
for view in views_lookml["views"][1:]:
if view["name"].startswith("suggest__"):
continue
view_name = view["name"]
metric = "__".join(view["name"].split("__")[1:])
if "labeled_counter" in metric:
joins.append(
{
"name": view_name,
"relationship": "one_to_many",
"sql": (
f"LEFT JOIN UNNEST(${{{base_name}.{metric}}}) AS {view_name} "
f"ON ${{{base_name}.document_id}} = ${{{view_name}.document_id}}"
),
}
)
else:
if metric.startswith("metrics__"):
continue
try:
# get repeated, nested fields that exist as separate views in lookml
base_name, metric = self._get_base_name_and_metric(
view_name=view_name,
views=[v["name"] for v in views_lookml["views"]],
)
metric_name = view_name
joins.append(
{
"name": view_name,
"relationship": "one_to_many",
"sql": (
f"LEFT JOIN UNNEST(${{{base_name}.{metric}}}) AS {metric_name} "
),
}
)
except Exception:
# ignore nested views that cannot be joined on to the base view
continue
base_explore: Dict[str, Any] = {
"name": self.name,
# list the base explore first by prefixing with a space
"view_label": f" {self.name.title()}",
"description": f"Explore for the {self.name} ping. {ping_description}",
"view_name": self.views["base_view"],
"joins": joins,
}
if datagroup := self.get_datagroup():
base_explore["persist_with"] = datagroup
required_filters = self.get_required_filters("base_view")
if len(required_filters) > 0:
base_explore["always_filter"] = {"filters": required_filters}
suggests = []
for view in views_lookml["views"][1:]:
if not view["name"].startswith("suggest__"):
continue
suggests.append({"name": view["name"], "hidden": "yes"})
return [base_explore] + suggests
@staticmethod
def from_views(views: List[View]) -> Iterator[PingExplore]:
"""Generate all possible GleanPingExplores from the views."""
for view in views:
if view.view_type == GleanPingView.type:
yield GleanPingExplore(view.name, {"base_view": view.name})
@staticmethod
def from_dict(name: str, defn: dict, views_path: Path) -> GleanPingExplore:
"""Get an instance of this explore from a name and dictionary definition."""
return GleanPingExplore(name, defn["views"], views_path)