diff --git a/.changes/unreleased/Features-20240627-162953.yaml b/.changes/unreleased/Features-20240627-162953.yaml new file mode 100644 index 00000000000..8e385aa6186 --- /dev/null +++ b/.changes/unreleased/Features-20240627-162953.yaml @@ -0,0 +1,6 @@ +kind: Features +body: Add time_granularity to metric spec. +time: 2024-06-27T16:29:53.500917-07:00 +custom: + Author: courtneyholcomb + Issue: "10376" diff --git a/core/dbt/artifacts/resources/v1/metric.py b/core/dbt/artifacts/resources/v1/metric.py index 0679fd3ba82..0c6da764220 100644 --- a/core/dbt/artifacts/resources/v1/metric.py +++ b/core/dbt/artifacts/resources/v1/metric.py @@ -121,6 +121,7 @@ class Metric(GraphResource): type_params: MetricTypeParams filter: Optional[WhereFilterIntersection] = None metadata: Optional[SourceFileMetadata] = None + time_granularity: Optional[TimeGranularity] = None resource_type: Literal[NodeType.Metric] meta: Dict[str, Any] = field(default_factory=dict, metadata=MergeBehavior.Update.meta()) tags: List[str] = field(default_factory=list) diff --git a/core/dbt/contracts/graph/unparsed.py b/core/dbt/contracts/graph/unparsed.py index fd885645313..a64223df3b6 100644 --- a/core/dbt/contracts/graph/unparsed.py +++ b/core/dbt/contracts/graph/unparsed.py @@ -563,6 +563,7 @@ class UnparsedMetric(dbtClassMixin): description: str = "" # Note: `Union` must be the outermost part of the type annotation for serialization to work properly. filter: Union[str, List[str], None] = None + time_granularity: Optional[str] = None # metadata: Optional[Unparsedetadata] = None # TODO meta: Dict[str, Any] = field(default_factory=dict) tags: List[str] = field(default_factory=list) diff --git a/core/dbt/parser/schema_yaml_readers.py b/core/dbt/parser/schema_yaml_readers.py index 86ac10d7545..b4ae3e213b7 100644 --- a/core/dbt/parser/schema_yaml_readers.py +++ b/core/dbt/parser/schema_yaml_readers.py @@ -435,6 +435,9 @@ def parse_metric(self, unparsed: UnparsedMetric, generated: bool = False) -> Non label=unparsed.label, type=MetricType(unparsed.type), type_params=self._get_metric_type_params(unparsed), + time_granularity=( + TimeGranularity(unparsed.time_granularity) if unparsed.time_granularity else None + ), filter=parse_where_filter(unparsed.filter), meta=unparsed.meta, tags=unparsed.tags, diff --git a/core/setup.py b/core/setup.py index 42b60836931..1491204ae3c 100644 --- a/core/setup.py +++ b/core/setup.py @@ -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.6.1,<0.7", + "dbt-semantic-interfaces>=0.6.8,<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", diff --git a/schemas/dbt/manifest/v12.json b/schemas/dbt/manifest/v12.json index 6e125cc0c98..0ec6daae1f1 100644 --- a/schemas/dbt/manifest/v12.json +++ b/schemas/dbt/manifest/v12.json @@ -9044,6 +9044,29 @@ ], "default": null }, + "time_granularity": { + "anyOf": [ + { + "enum": [ + "nanosecond", + "microsecond", + "millisecond", + "second", + "minute", + "hour", + "day", + "week", + "month", + "quarter", + "year" + ] + }, + { + "type": "null" + } + ], + "default": null + }, "meta": { "type": "object", "propertyNames": { @@ -18020,6 +18043,29 @@ ], "default": null }, + "time_granularity": { + "anyOf": [ + { + "enum": [ + "nanosecond", + "microsecond", + "millisecond", + "second", + "minute", + "hour", + "day", + "week", + "month", + "quarter", + "year" + ] + }, + { + "type": "null" + } + ], + "default": null + }, "meta": { "type": "object", "propertyNames": { diff --git a/tests/functional/metrics/fixtures.py b/tests/functional/metrics/fixtures.py index 39d11fb0a95..5614fab8c63 100644 --- a/tests/functional/metrics/fixtures.py +++ b/tests/functional/metrics/fixtures.py @@ -113,6 +113,7 @@ type: simple type_params: measure: people + time_granularity: month config: meta: my_meta_config: 'config' diff --git a/tests/functional/metrics/test_metrics.py b/tests/functional/metrics/test_metrics.py index 9241ea8ceaa..3f8fba2a19c 100644 --- a/tests/functional/metrics/test_metrics.py +++ b/tests/functional/metrics/test_metrics.py @@ -83,6 +83,11 @@ def test_simple_metric( ) == 2 ) + assert ( + manifest.metrics["metric.test.number_of_people"].time_granularity + == TimeGranularity.MONTH + ) + assert manifest.metrics["metric.test.collective_tenure"].time_granularity is None class TestInvalidRefMetrics: