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
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.
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.