Skip to content

Commit

Permalink
Add CumulativeTypeParams & sub-daily granularities to semantic mani…
Browse files Browse the repository at this point in the history
…fest (#10350)
  • Loading branch information
courtneyholcomb authored Jul 1, 2024
1 parent b59c907 commit a94027a
Show file tree
Hide file tree
Showing 14 changed files with 521 additions and 81 deletions.
6 changes: 6 additions & 0 deletions .changes/unreleased/Features-20240625-095107.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Features
body: Support cumulative_type_params & sub-daily granularities in semantic manifest.
time: 2024-06-25T09:51:07.983248-07:00
custom:
Author: courtneyholcomb
Issue: "10360"
1 change: 1 addition & 0 deletions core/dbt/artifacts/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from dbt.artifacts.resources.v1.metric import (
ConstantPropertyInput,
ConversionTypeParams,
CumulativeTypeParams,
Metric,
MetricConfig,
MetricInput,
Expand Down
9 changes: 9 additions & 0 deletions core/dbt/artifacts/resources/v1/metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from dbt_semantic_interfaces.type_enums import (
ConversionCalculationType,
MetricType,
PeriodAggregation,
TimeGranularity,
)

Expand Down Expand Up @@ -80,6 +81,13 @@ class ConversionTypeParams(dbtClassMixin):
constant_properties: Optional[List[ConstantPropertyInput]] = None


@dataclass
class CumulativeTypeParams(dbtClassMixin):
window: Optional[MetricTimeWindow] = None
grain_to_date: Optional[TimeGranularity] = None
period_agg: PeriodAggregation = PeriodAggregation.FIRST


@dataclass
class MetricTypeParams(dbtClassMixin):
measure: Optional[MetricInputMeasure] = None
Expand All @@ -91,6 +99,7 @@ class MetricTypeParams(dbtClassMixin):
grain_to_date: Optional[TimeGranularity] = None
metrics: Optional[List[MetricInput]] = None
conversion_type_params: Optional[ConversionTypeParams] = None
cumulative_type_params: Optional[CumulativeTypeParams] = None


@dataclass
Expand Down
2 changes: 1 addition & 1 deletion core/dbt/contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
## Artifacts

### Generating JSON schemas
A helper script, `sripts/collect-artifact-schema.py` is available to generate json schemas corresponding to versioned artifacts (`ArtifactMixin`s).
A helper script, `scripts/collect-artifact-schema.py` is available to generate json schemas corresponding to versioned artifacts (`ArtifactMixin`s).

This script is necessary to run when a new artifact schema version is created, or when changes are made to existing artifact versions, and writes json schema to `schema/dbt/<artifact>/v<version>.json`.

Expand Down
13 changes: 12 additions & 1 deletion core/dbt/contracts/graph/unparsed.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
from pathlib import Path
from typing import Any, Dict, List, Literal, Optional, Sequence, Union

from dbt_semantic_interfaces.type_enums import ConversionCalculationType
from dbt_semantic_interfaces.type_enums import (
ConversionCalculationType,
PeriodAggregation,
)

# trigger the PathEncoder
import dbt_common.helper_types # noqa:F401
Expand Down Expand Up @@ -532,6 +535,13 @@ class UnparsedConversionTypeParams(dbtClassMixin):
constant_properties: Optional[List[ConstantPropertyInput]] = None


@dataclass
class UnparsedCumulativeTypeParams(dbtClassMixin):
window: Optional[str] = None
grain_to_date: Optional[str] = None
period_agg: str = PeriodAggregation.FIRST.value


@dataclass
class UnparsedMetricTypeParams(dbtClassMixin):
measure: Optional[Union[UnparsedMetricInputMeasure, str]] = None
Expand All @@ -542,6 +552,7 @@ class UnparsedMetricTypeParams(dbtClassMixin):
grain_to_date: Optional[str] = None # str is really a TimeGranularity Enum
metrics: Optional[List[Union[UnparsedMetricInput, str]]] = None
conversion_type_params: Optional[UnparsedConversionTypeParams] = None
cumulative_type_params: Optional[UnparsedCumulativeTypeParams] = None


@dataclass
Expand Down
71 changes: 62 additions & 9 deletions core/dbt/parser/schema_yaml_readers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
DimensionType,
EntityType,
MetricType,
PeriodAggregation,
TimeGranularity,
)

from dbt.artifacts.resources import (
ConversionTypeParams,
CumulativeTypeParams,
Dimension,
DimensionTypeParams,
Entity,
Expand Down Expand Up @@ -42,6 +44,7 @@
from dbt.contracts.graph.nodes import Exposure, Group, Metric, SavedQuery, SemanticModel
from dbt.contracts.graph.unparsed import (
UnparsedConversionTypeParams,
UnparsedCumulativeTypeParams,
UnparsedDimension,
UnparsedDimensionTypeParams,
UnparsedEntity,
Expand Down Expand Up @@ -221,9 +224,19 @@ def _get_input_measures(

return input_measures

def _get_time_window(
self,
unparsed_window: Optional[str],
def _get_period_agg(self, unparsed_period_agg: str) -> PeriodAggregation:
return PeriodAggregation(unparsed_period_agg)

def _get_optional_grain_to_date(
self, unparsed_grain_to_date: Optional[str]
) -> Optional[TimeGranularity]:
if not unparsed_grain_to_date:
return None

return TimeGranularity(unparsed_grain_to_date)

def _get_optional_time_window(
self, unparsed_window: Optional[str]
) -> Optional[MetricTimeWindow]:
if unparsed_window is not None:
parts = unparsed_window.split(" ")
Expand Down Expand Up @@ -277,7 +290,7 @@ def _get_metric_input(self, unparsed: Union[UnparsedMetricInput, str]) -> Metric
name=unparsed.name,
filter=parse_where_filter(unparsed.filter),
alias=unparsed.alias,
offset_window=self._get_time_window(unparsed.offset_window),
offset_window=self._get_optional_time_window(unparsed.offset_window),
offset_to_grain=offset_to_grain,
)

Expand Down Expand Up @@ -311,11 +324,48 @@ def _get_optional_conversion_type_params(
conversion_measure=self._get_input_measure(unparsed.conversion_measure),
entity=unparsed.entity,
calculation=ConversionCalculationType(unparsed.calculation),
window=self._get_time_window(unparsed.window),
window=self._get_optional_time_window(unparsed.window),
constant_properties=unparsed.constant_properties,
)

def _get_metric_type_params(self, type_params: UnparsedMetricTypeParams) -> MetricTypeParams:
def _get_optional_cumulative_type_params(
self, unparsed_metric: UnparsedMetric
) -> Optional[CumulativeTypeParams]:
unparsed_type_params = unparsed_metric.type_params
if unparsed_metric.type.lower() == MetricType.CUMULATIVE.value:
if not unparsed_type_params.cumulative_type_params:
unparsed_type_params.cumulative_type_params = UnparsedCumulativeTypeParams()

if (
unparsed_type_params.window
and not unparsed_type_params.cumulative_type_params.window
):
unparsed_type_params.cumulative_type_params.window = unparsed_type_params.window
if (
unparsed_type_params.grain_to_date
and not unparsed_type_params.cumulative_type_params.grain_to_date
):
unparsed_type_params.cumulative_type_params.grain_to_date = (
unparsed_type_params.grain_to_date
)

return CumulativeTypeParams(
window=self._get_optional_time_window(
unparsed_type_params.cumulative_type_params.window
),
grain_to_date=self._get_optional_grain_to_date(
unparsed_type_params.cumulative_type_params.grain_to_date
),
period_agg=self._get_period_agg(
unparsed_type_params.cumulative_type_params.period_agg
),
)

return None

def _get_metric_type_params(self, unparsed_metric: UnparsedMetric) -> MetricTypeParams:
type_params = unparsed_metric.type_params

grain_to_date: Optional[TimeGranularity] = None
if type_params.grain_to_date is not None:
grain_to_date = TimeGranularity(type_params.grain_to_date)
Expand All @@ -325,12 +375,15 @@ def _get_metric_type_params(self, type_params: UnparsedMetricTypeParams) -> Metr
numerator=self._get_optional_metric_input(type_params.numerator),
denominator=self._get_optional_metric_input(type_params.denominator),
expr=str(type_params.expr) if type_params.expr is not None else None,
window=self._get_time_window(type_params.window),
window=self._get_optional_time_window(type_params.window),
grain_to_date=grain_to_date,
metrics=self._get_metric_inputs(type_params.metrics),
conversion_type_params=self._get_optional_conversion_type_params(
type_params.conversion_type_params
)
),
cumulative_type_params=self._get_optional_cumulative_type_params(
unparsed_metric=unparsed_metric,
),
# input measures are calculated via metric processing post parsing
# input_measures=?,
)
Expand Down Expand Up @@ -380,7 +433,7 @@ def parse_metric(self, unparsed: UnparsedMetric, generated: bool = False):
description=unparsed.description,
label=unparsed.label,
type=MetricType(unparsed.type),
type_params=self._get_metric_type_params(unparsed.type_params),
type_params=self._get_metric_type_params(unparsed),
filter=parse_where_filter(unparsed.filter),
meta=unparsed.meta,
tags=unparsed.tags,
Expand Down
2 changes: 1 addition & 1 deletion core/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
# Accept patches but avoid automatically updating past a set minor version range.
"dbt-extractor>=0.5.0,<=0.6",
"minimal-snowplow-tracker>=0.0.2,<0.1",
"dbt-semantic-interfaces>=0.5.1,<0.7",
"dbt-semantic-interfaces>=0.6.1,<0.7",
# Minor versions for these are expected to be backwards-compatible
"dbt-common>=1.3.0,<2.0",
"dbt-adapters>=1.1.1,<2.0",
Expand Down
2 changes: 1 addition & 1 deletion schemas/dbt/catalog/v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
"dbt_version": {
"type": "string",
"default": "1.8.0a1"
"default": "1.9.0a1"
},
"generated_at": {
"type": "string"
Expand Down
Loading

0 comments on commit a94027a

Please sign in to comment.