generator.views.events_view

Class to describe an Events view.

  1"""Class to describe an Events view."""
  2
  3from __future__ import annotations
  4
  5from copy import deepcopy
  6from typing import Any, Dict, Iterator, List, Optional
  7
  8from . import lookml_utils
  9from .view import View, ViewDict
 10
 11
 12class EventsView(View):
 13    """A view for querying events data, with one row per-event."""
 14
 15    type: str = "events_view"
 16
 17    default_measures: List[Dict[str, str]] = [
 18        {
 19            "name": "event_count",
 20            "type": "count",
 21            "description": ("The number of times the event(s) occurred."),
 22        },
 23    ]
 24
 25    def __init__(self, namespace: str, name: str, tables: List[Dict[str, str]]):
 26        """Get an instance of an EventsView."""
 27        super().__init__(namespace, name, EventsView.type, tables)
 28
 29    @classmethod
 30    def from_db_views(
 31        klass,
 32        namespace: str,
 33        is_glean: bool,
 34        channels: List[Dict[str, str]],
 35        db_views: dict,
 36    ) -> Iterator[EventsView]:
 37        """Get Events Views from db views and app variants."""
 38        # We can guarantee there will always be at least one channel,
 39        # because this comes from the associated _get_glean_repos in
 40        # namespaces.py
 41        dataset = next(
 42            (channel for channel in channels if channel.get("channel") == "release"),
 43            channels[0],
 44        )["dataset"]
 45
 46        for view_id, references in db_views[dataset].items():
 47            if view_id == "events_unnested":
 48                yield EventsView(
 49                    namespace,
 50                    "events",
 51                    [
 52                        {
 53                            "events_table_view": "events_unnested_table",
 54                            "base_table": f"mozdata.{dataset}.{view_id}",
 55                        }
 56                    ],
 57                )
 58
 59    @classmethod
 60    def from_dict(klass, namespace: str, name: str, _dict: ViewDict) -> EventsView:
 61        """Get a view from a name and dict definition."""
 62        return EventsView(namespace, name, _dict["tables"])
 63
 64    def to_lookml(self, v1_name: Optional[str], dryrun) -> Dict[str, Any]:
 65        """Generate LookML for this view."""
 66        view_defn: Dict[str, Any] = {
 67            "extends": [self.tables[0]["events_table_view"]],
 68            "name": self.name,
 69        }
 70
 71        # add measures
 72        dimensions = lookml_utils._generate_dimensions(
 73            self.tables[0]["base_table"], dryrun=dryrun
 74        )
 75        view_defn["measures"] = self.get_measures(dimensions)
 76
 77        # set document_id as primary key if it exists in the underlying table
 78        # this will allow one_to_many joins
 79        event_id_dimension = self.generate_event_id_dimension(dimensions)
 80        if event_id_dimension is not None:
 81            view_defn["dimensions"] = [event_id_dimension]
 82
 83        return {
 84            "includes": [f"{self.tables[0]['events_table_view']}.view.lkml"],
 85            "views": [view_defn],
 86        }
 87
 88    def get_measures(self, dimensions) -> List[Dict[str, str]]:
 89        """Generate measures for Events Views."""
 90        measures = deepcopy(EventsView.default_measures)
 91        client_id_field = self.get_client_id(dimensions, "events")
 92        if client_id_field is not None:
 93            measures.append(
 94                {
 95                    "name": "client_count",
 96                    "type": "count_distinct",
 97                    "sql": f"${{{client_id_field}}}",
 98                    "description": (
 99                        "The number of clients that completed the event(s)."
100                    ),
101                }
102            )
103
104        return measures
105
106    def generate_event_id_dimension(
107        self, dimensions: list[dict]
108    ) -> Optional[Dict[str, str]]:
109        """Generate the event_id dimension to be used as a primary key for a one to many join."""
110        event_id = self.select_dimension("event_id", dimensions, "events")
111        if event_id:
112            return {
113                "name": "event_id",
114                "primary_key": "yes",
115            }
116        return None
class EventsView(generator.views.view.View):
 13class EventsView(View):
 14    """A view for querying events data, with one row per-event."""
 15
 16    type: str = "events_view"
 17
 18    default_measures: List[Dict[str, str]] = [
 19        {
 20            "name": "event_count",
 21            "type": "count",
 22            "description": ("The number of times the event(s) occurred."),
 23        },
 24    ]
 25
 26    def __init__(self, namespace: str, name: str, tables: List[Dict[str, str]]):
 27        """Get an instance of an EventsView."""
 28        super().__init__(namespace, name, EventsView.type, tables)
 29
 30    @classmethod
 31    def from_db_views(
 32        klass,
 33        namespace: str,
 34        is_glean: bool,
 35        channels: List[Dict[str, str]],
 36        db_views: dict,
 37    ) -> Iterator[EventsView]:
 38        """Get Events Views from db views and app variants."""
 39        # We can guarantee there will always be at least one channel,
 40        # because this comes from the associated _get_glean_repos in
 41        # namespaces.py
 42        dataset = next(
 43            (channel for channel in channels if channel.get("channel") == "release"),
 44            channels[0],
 45        )["dataset"]
 46
 47        for view_id, references in db_views[dataset].items():
 48            if view_id == "events_unnested":
 49                yield EventsView(
 50                    namespace,
 51                    "events",
 52                    [
 53                        {
 54                            "events_table_view": "events_unnested_table",
 55                            "base_table": f"mozdata.{dataset}.{view_id}",
 56                        }
 57                    ],
 58                )
 59
 60    @classmethod
 61    def from_dict(klass, namespace: str, name: str, _dict: ViewDict) -> EventsView:
 62        """Get a view from a name and dict definition."""
 63        return EventsView(namespace, name, _dict["tables"])
 64
 65    def to_lookml(self, v1_name: Optional[str], dryrun) -> Dict[str, Any]:
 66        """Generate LookML for this view."""
 67        view_defn: Dict[str, Any] = {
 68            "extends": [self.tables[0]["events_table_view"]],
 69            "name": self.name,
 70        }
 71
 72        # add measures
 73        dimensions = lookml_utils._generate_dimensions(
 74            self.tables[0]["base_table"], dryrun=dryrun
 75        )
 76        view_defn["measures"] = self.get_measures(dimensions)
 77
 78        # set document_id as primary key if it exists in the underlying table
 79        # this will allow one_to_many joins
 80        event_id_dimension = self.generate_event_id_dimension(dimensions)
 81        if event_id_dimension is not None:
 82            view_defn["dimensions"] = [event_id_dimension]
 83
 84        return {
 85            "includes": [f"{self.tables[0]['events_table_view']}.view.lkml"],
 86            "views": [view_defn],
 87        }
 88
 89    def get_measures(self, dimensions) -> List[Dict[str, str]]:
 90        """Generate measures for Events Views."""
 91        measures = deepcopy(EventsView.default_measures)
 92        client_id_field = self.get_client_id(dimensions, "events")
 93        if client_id_field is not None:
 94            measures.append(
 95                {
 96                    "name": "client_count",
 97                    "type": "count_distinct",
 98                    "sql": f"${{{client_id_field}}}",
 99                    "description": (
100                        "The number of clients that completed the event(s)."
101                    ),
102                }
103            )
104
105        return measures
106
107    def generate_event_id_dimension(
108        self, dimensions: list[dict]
109    ) -> Optional[Dict[str, str]]:
110        """Generate the event_id dimension to be used as a primary key for a one to many join."""
111        event_id = self.select_dimension("event_id", dimensions, "events")
112        if event_id:
113            return {
114                "name": "event_id",
115                "primary_key": "yes",
116            }
117        return None

A view for querying events data, with one row per-event.

EventsView(namespace: str, name: str, tables: List[Dict[str, str]])
26    def __init__(self, namespace: str, name: str, tables: List[Dict[str, str]]):
27        """Get an instance of an EventsView."""
28        super().__init__(namespace, name, EventsView.type, tables)

Get an instance of an EventsView.

type: str = 'events_view'
default_measures: List[Dict[str, str]] = [{'name': 'event_count', 'type': 'count', 'description': 'The number of times the event(s) occurred.'}]
@classmethod
def from_db_views( klass, namespace: str, is_glean: bool, channels: List[Dict[str, str]], db_views: dict) -> Iterator[EventsView]:
30    @classmethod
31    def from_db_views(
32        klass,
33        namespace: str,
34        is_glean: bool,
35        channels: List[Dict[str, str]],
36        db_views: dict,
37    ) -> Iterator[EventsView]:
38        """Get Events Views from db views and app variants."""
39        # We can guarantee there will always be at least one channel,
40        # because this comes from the associated _get_glean_repos in
41        # namespaces.py
42        dataset = next(
43            (channel for channel in channels if channel.get("channel") == "release"),
44            channels[0],
45        )["dataset"]
46
47        for view_id, references in db_views[dataset].items():
48            if view_id == "events_unnested":
49                yield EventsView(
50                    namespace,
51                    "events",
52                    [
53                        {
54                            "events_table_view": "events_unnested_table",
55                            "base_table": f"mozdata.{dataset}.{view_id}",
56                        }
57                    ],
58                )

Get Events Views from db views and app variants.

@classmethod
def from_dict( klass, namespace: str, name: str, _dict: generator.views.view.ViewDict) -> EventsView:
60    @classmethod
61    def from_dict(klass, namespace: str, name: str, _dict: ViewDict) -> EventsView:
62        """Get a view from a name and dict definition."""
63        return EventsView(namespace, name, _dict["tables"])

Get a view from a name and dict definition.

def to_lookml(self, v1_name: Optional[str], dryrun) -> Dict[str, Any]:
65    def to_lookml(self, v1_name: Optional[str], dryrun) -> Dict[str, Any]:
66        """Generate LookML for this view."""
67        view_defn: Dict[str, Any] = {
68            "extends": [self.tables[0]["events_table_view"]],
69            "name": self.name,
70        }
71
72        # add measures
73        dimensions = lookml_utils._generate_dimensions(
74            self.tables[0]["base_table"], dryrun=dryrun
75        )
76        view_defn["measures"] = self.get_measures(dimensions)
77
78        # set document_id as primary key if it exists in the underlying table
79        # this will allow one_to_many joins
80        event_id_dimension = self.generate_event_id_dimension(dimensions)
81        if event_id_dimension is not None:
82            view_defn["dimensions"] = [event_id_dimension]
83
84        return {
85            "includes": [f"{self.tables[0]['events_table_view']}.view.lkml"],
86            "views": [view_defn],
87        }

Generate LookML for this view.

def get_measures(self, dimensions) -> List[Dict[str, str]]:
 89    def get_measures(self, dimensions) -> List[Dict[str, str]]:
 90        """Generate measures for Events Views."""
 91        measures = deepcopy(EventsView.default_measures)
 92        client_id_field = self.get_client_id(dimensions, "events")
 93        if client_id_field is not None:
 94            measures.append(
 95                {
 96                    "name": "client_count",
 97                    "type": "count_distinct",
 98                    "sql": f"${{{client_id_field}}}",
 99                    "description": (
100                        "The number of clients that completed the event(s)."
101                    ),
102                }
103            )
104
105        return measures

Generate measures for Events Views.

def generate_event_id_dimension(self, dimensions: list[dict]) -> Optional[Dict[str, str]]:
107    def generate_event_id_dimension(
108        self, dimensions: list[dict]
109    ) -> Optional[Dict[str, str]]:
110        """Generate the event_id dimension to be used as a primary key for a one to many join."""
111        event_id = self.select_dimension("event_id", dimensions, "events")
112        if event_id:
113            return {
114                "name": "event_id",
115                "primary_key": "yes",
116            }
117        return None

Generate the event_id dimension to be used as a primary key for a one to many join.