From ff012cc23d989625e839e4a9f36865bde463921f Mon Sep 17 00:00:00 2001 From: Thomas Lento Date: Thu, 23 May 2024 18:09:36 -0700 Subject: [PATCH] Add element type property to LinkableElement interface (#1226) The LinkableElement interface is used in cases where we have a set of LinkableElements undifferentiated by underlying type. In predicate pushdown, this happens with where specs that reference some set of linkable elements but store them in an undifferentiated collection. In practice, we need to know not just the object type, but the more refined LinkableElementType in order to apply the pushdown evaluation logic, as time dimensions and categorical dimensions need to be considered in a distinct way. This makes the relevant property available in the parent interface so we can access it directly. --- .../model/semantics/linkable_element.py | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/metricflow-semantics/metricflow_semantics/model/semantics/linkable_element.py b/metricflow-semantics/metricflow_semantics/model/semantics/linkable_element.py index f7d6b56706..82ad6c1f30 100644 --- a/metricflow-semantics/metricflow_semantics/model/semantics/linkable_element.py +++ b/metricflow-semantics/metricflow_semantics/model/semantics/linkable_element.py @@ -1,7 +1,7 @@ from __future__ import annotations import logging -from abc import ABC +from abc import ABC, abstractmethod from dataclasses import dataclass from enum import Enum from typing import FrozenSet, Optional, Sequence, Tuple @@ -98,7 +98,11 @@ class SemanticModelJoinPathElement: class LinkableElement(SemanticModelDerivation, SerializableDataclass, ABC): """An entity / dimension that may have been joined by entities.""" - pass + @property + @abstractmethod + def element_type(self) -> LinkableElementType: + """The LinkableElementType describing what this instance represents.""" + raise NotImplementedError @dataclass(frozen=True) @@ -116,15 +120,19 @@ class LinkableDimension(LinkableElement, SerializableDataclass): date_part: Optional[DatePart] @property - def path_key(self) -> ElementPathKey: # noqa: D102 - if self.dimension_type is DimensionType.CATEGORICAL: - element_type = LinkableElementType.DIMENSION - else: - element_type = LinkableElementType.TIME_DIMENSION + @override + def element_type(self) -> LinkableElementType: + return ( + LinkableElementType.DIMENSION + if self.dimension_type is DimensionType.CATEGORICAL + else LinkableElementType.TIME_DIMENSION + ) + @property + def path_key(self) -> ElementPathKey: # noqa: D102 return ElementPathKey( element_name=self.element_name, - element_type=element_type, + element_type=self.element_type, entity_links=self.entity_links, time_granularity=self.time_granularity, date_part=self.date_part, @@ -156,10 +164,15 @@ class LinkableEntity(LinkableElement, SerializableDataclass): entity_links: Tuple[EntityReference, ...] join_path: SemanticModelJoinPath + @property + @override + def element_type(self) -> LinkableElementType: + return LinkableElementType.ENTITY + @property def path_key(self) -> ElementPathKey: # noqa: D102 return ElementPathKey( - element_name=self.element_name, element_type=LinkableElementType.ENTITY, entity_links=self.entity_links + element_name=self.element_name, element_type=self.element_type, entity_links=self.entity_links ) @property @@ -199,6 +212,11 @@ def __post_init__(self) -> None: """ assert {LinkableElementProperty.METRIC, LinkableElementProperty.JOINED}.issubset(self.properties) + @property + @override + def element_type(self) -> LinkableElementType: + return LinkableElementType.METRIC + @property def element_name(self) -> str: # noqa: D102 return self.reference.element_name @@ -207,7 +225,7 @@ def element_name(self) -> str: # noqa: D102 def path_key(self) -> ElementPathKey: # noqa: D102 return ElementPathKey( element_name=self.element_name, - element_type=LinkableElementType.METRIC, + element_type=self.element_type, entity_links=self.join_path.entity_links, metric_subquery_entity_links=self.metric_subquery_entity_links, )