-
Notifications
You must be signed in to change notification settings - Fork 96
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1152 from dbt-labs/plypaul--12--saved-query-resolver
Add a Resolver for Saved-Query Dependencies
- Loading branch information
Showing
111 changed files
with
2,347 additions
and
1,254 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
kind: Features | ||
body: Add a Dependency Resolver for Saved Queries | ||
time: 2024-04-26T14:41:19.27946-07:00 | ||
custom: | ||
Author: plypaul | ||
Issue: "1155" |
Empty file.
Empty file.
75 changes: 75 additions & 0 deletions
75
metricflow-semantics/metricflow_semantics/api/v0_1/saved_query_dependency_resolver.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
from __future__ import annotations | ||
|
||
import logging | ||
from dataclasses import dataclass | ||
from typing import Tuple | ||
|
||
from dbt_semantic_interfaces.protocols import SemanticManifest | ||
from dbt_semantic_interfaces.references import ( | ||
SemanticModelReference, | ||
) | ||
|
||
from metricflow_semantics.model.semantic_manifest_lookup import SemanticManifestLookup | ||
from metricflow_semantics.query.query_parser import MetricFlowQueryParser | ||
from metricflow_semantics.specs.query_param_implementations import SavedQueryParameter | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
@dataclass(frozen=True) | ||
class SavedQueryDependencySet: | ||
"""The dependencies of a saved query. | ||
The primary use case is to handle creation of the cache item associated with the saved query. The dependencies | ||
listed in this class must be up-to-date before the cache associated with the saved query can be created. Otherwise, | ||
running the export / creating the cache may create a cache item that is out-of-date / unusable. | ||
""" | ||
|
||
# The semantic models that the saved query depends on. | ||
semantic_model_references: Tuple[SemanticModelReference, ...] | ||
|
||
|
||
class SavedQueryDependencyResolver: | ||
"""Resolves the dependencies of a saved query. Also see `SavedQueryDependencySet`.""" | ||
|
||
def __init__(self, semantic_manifest: SemanticManifest) -> None: # noqa: D107 | ||
self._semantic_manifest = semantic_manifest | ||
self._query_parser = MetricFlowQueryParser(SemanticManifestLookup(semantic_manifest)) | ||
|
||
def _resolve_dependencies(self, saved_query_name: str) -> SavedQueryDependencySet: | ||
parse_result = self._query_parser.parse_and_validate_saved_query( | ||
saved_query_parameter=SavedQueryParameter(saved_query_name), | ||
where_filter=None, | ||
limit=None, | ||
time_constraint_start=None, | ||
time_constraint_end=None, | ||
order_by_names=None, | ||
order_by_parameters=None, | ||
) | ||
|
||
return SavedQueryDependencySet( | ||
semantic_model_references=tuple( | ||
sorted( | ||
parse_result.queried_semantic_models, | ||
key=lambda reference: reference.semantic_model_name, | ||
) | ||
), | ||
) | ||
|
||
def resolve_dependencies(self, saved_query_name: str) -> SavedQueryDependencySet: | ||
"""Return the dependencies of the given saved query in the manifest.""" | ||
try: | ||
return self._resolve_dependencies(saved_query_name) | ||
except Exception: | ||
logger.exception( | ||
f"Got an exception while getting the dependencies of saved-query {repr(saved_query_name)}. " | ||
f"All semantic models will be returned instead for safety." | ||
) | ||
return SavedQueryDependencySet( | ||
semantic_model_references=tuple( | ||
sorted( | ||
(semantic_model.reference for semantic_model in self._semantic_manifest.semantic_models), | ||
key=lambda reference: reference.semantic_model_name, | ||
) | ||
), | ||
) |
15 changes: 15 additions & 0 deletions
15
metricflow-semantics/metricflow_semantics/collection_helpers/dedupe.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
from __future__ import annotations | ||
|
||
from typing import Dict, Iterable, Tuple, TypeVar | ||
|
||
IterableT = TypeVar("IterableT") | ||
|
||
|
||
def ordered_dedupe(*iterables: Iterable[IterableT]) -> Tuple[IterableT, ...]: | ||
"""De-duplicates the items in the iterables while preserving the order.""" | ||
ordered_results: Dict[IterableT, None] = {} | ||
for iterable in iterables: | ||
for item in iterable: | ||
ordered_results[item] = None | ||
|
||
return tuple(ordered_results.keys()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
metricflow-semantics/metricflow_semantics/model/linkable_element_property.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
from __future__ import annotations | ||
|
||
from enum import Enum | ||
from typing import FrozenSet | ||
|
||
|
||
class LinkableElementProperty(Enum): | ||
"""The properties associated with a valid linkable element. | ||
Local means an element that is defined within the same semantic model as the measure. This definition is used | ||
throughout the related classes. | ||
""" | ||
|
||
# A local element as per above definition. | ||
LOCAL = "local" | ||
# A local dimension that is prefixed with a local primary entity. | ||
LOCAL_LINKED = "local_linked" | ||
# An element that was joined to the measure semantic model by an entity. | ||
JOINED = "joined" | ||
# An element that was joined to the measure semantic model by joining multiple semantic models. | ||
MULTI_HOP = "multi_hop" | ||
# A time dimension that is a version of a time dimension in a semantic model, but at a different granularity. | ||
DERIVED_TIME_GRANULARITY = "derived_time_granularity" | ||
# Refers to an entity, not a dimension. | ||
ENTITY = "entity" | ||
# See metric_time in DataSet | ||
METRIC_TIME = "metric_time" | ||
# Refers to a metric, not a dimension. | ||
METRIC = "metric" | ||
|
||
@staticmethod | ||
def all_properties() -> FrozenSet[LinkableElementProperty]: # noqa: D102 | ||
return frozenset( | ||
{ | ||
LinkableElementProperty.LOCAL, | ||
LinkableElementProperty.LOCAL_LINKED, | ||
LinkableElementProperty.JOINED, | ||
LinkableElementProperty.MULTI_HOP, | ||
LinkableElementProperty.DERIVED_TIME_GRANULARITY, | ||
LinkableElementProperty.METRIC_TIME, | ||
LinkableElementProperty.METRIC, | ||
} | ||
) |
19 changes: 19 additions & 0 deletions
19
metricflow-semantics/metricflow_semantics/model/semantic_model_derivation.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from __future__ import annotations | ||
|
||
from abc import ABC, abstractmethod | ||
from typing import Sequence | ||
|
||
from dbt_semantic_interfaces.references import SemanticModelReference | ||
|
||
|
||
class SemanticModelDerivation(ABC): | ||
"""Interface for an object that can be described as derived from a semantic model.""" | ||
|
||
@property | ||
@abstractmethod | ||
def derived_from_semantic_models(self) -> Sequence[SemanticModelReference]: | ||
"""The semantic models that this was derived from. | ||
The returned sequence should be ordered and not contain duplicates. | ||
""" | ||
raise NotImplementedError |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.