Skip to content

Commit

Permalink
Add meta to measures, entities, and dimensions (#358)
Browse files Browse the repository at this point in the history
### Description

This PR is modeled off of
[this](#250)
prior PR. This PR adds meta to measures, entities, and dimensions.
 
### Checklist

- [x] I have read [the contributing
guide](https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/CONTRIBUTING.md)
and understand what's expected of me
- [x] I have signed the
[CLA](https://docs.getdbt.com/docs/contributor-license-agreements)
- [x] This PR includes tests, or tests are not required/relevant for
this PR
- [x] I have run `changie new` to [create a changelog
entry](https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/CONTRIBUTING.md#adding-a-changelog-entry)
  • Loading branch information
DevonFulcher authored Nov 12, 2024
1 parent b7ce0aa commit c833632
Show file tree
Hide file tree
Showing 13 changed files with 164 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .changes/unreleased/Features-20241023-113450.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Features
body: Support meta for dimensions, entities, and measures
time: 2024-10-23T11:34:50.577294-05:00
custom:
Author: DevonFulcher
Issue: None
18 changes: 18 additions & 0 deletions dbt_semantic_interfaces/implementations/element_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from typing import Any, Dict

from pydantic import Field
from typing_extensions import override

from dbt_semantic_interfaces.implementations.base import HashableBaseModel
from dbt_semantic_interfaces.protocols.meta import SemanticLayerElementConfig
from dbt_semantic_interfaces.protocols.protocol_hint import ProtocolHint


class PydanticSemanticLayerElementConfig(HashableBaseModel, ProtocolHint[SemanticLayerElementConfig]):
"""PydanticDimension config."""

@override
def _implements_protocol(self) -> SemanticLayerElementConfig: # noqa: D
return self

meta: Dict[str, Any] = Field(default_factory=dict)
4 changes: 4 additions & 0 deletions dbt_semantic_interfaces/implementations/elements/dimension.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
HashableBaseModel,
ModelWithMetadataParsing,
)
from dbt_semantic_interfaces.implementations.element_config import (
PydanticSemanticLayerElementConfig,
)
from dbt_semantic_interfaces.implementations.metadata import PydanticMetadata
from dbt_semantic_interfaces.references import (
DimensionReference,
Expand Down Expand Up @@ -48,6 +51,7 @@ class PydanticDimension(HashableBaseModel, ModelWithMetadataParsing):
expr: Optional[str] = None
metadata: Optional[PydanticMetadata]
label: Optional[str] = None
config: Optional[PydanticSemanticLayerElementConfig]

@property
def reference(self) -> DimensionReference: # noqa: D
Expand Down
4 changes: 4 additions & 0 deletions dbt_semantic_interfaces/implementations/elements/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
HashableBaseModel,
ModelWithMetadataParsing,
)
from dbt_semantic_interfaces.implementations.element_config import (
PydanticSemanticLayerElementConfig,
)
from dbt_semantic_interfaces.implementations.metadata import PydanticMetadata
from dbt_semantic_interfaces.references import EntityReference
from dbt_semantic_interfaces.type_enums import EntityType
Expand All @@ -21,6 +24,7 @@ class PydanticEntity(HashableBaseModel, ModelWithMetadataParsing):
expr: Optional[str] = None
metadata: Optional[PydanticMetadata] = None
label: Optional[str] = None
config: Optional[PydanticSemanticLayerElementConfig]

@property
def reference(self) -> EntityReference: # noqa: D
Expand Down
4 changes: 4 additions & 0 deletions dbt_semantic_interfaces/implementations/elements/measure.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
HashableBaseModel,
ModelWithMetadataParsing,
)
from dbt_semantic_interfaces.implementations.element_config import (
PydanticSemanticLayerElementConfig,
)
from dbt_semantic_interfaces.implementations.metadata import PydanticMetadata
from dbt_semantic_interfaces.references import MeasureReference
from dbt_semantic_interfaces.type_enums import AggregationType
Expand Down Expand Up @@ -46,6 +49,7 @@ class PydanticMeasure(HashableBaseModel, ModelWithMetadataParsing):
non_additive_dimension: Optional[PydanticNonAdditiveDimensionParameters] = None
agg_time_dimension: Optional[str] = None
label: Optional[str] = None
config: Optional[PydanticSemanticLayerElementConfig] = None

@property
def reference(self) -> MeasureReference: # noqa: D
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,19 @@
],
"type": "object"
},
"dimension_config_schema": {
"$id": "dimension_config_schema",
"additionalProperties": false,
"properties": {
"meta": {
"propertyNames": {
"type": "string"
},
"type": "object"
}
},
"type": "object"
},
"dimension_schema": {
"$id": "dimension_schema",
"additionalProperties": false,
Expand All @@ -128,6 +141,9 @@
}
],
"properties": {
"config": {
"$ref": "#/definitions/dimension_config_schema"
},
"description": {
"type": "string"
},
Expand Down Expand Up @@ -204,10 +220,26 @@
],
"type": "object"
},
"entity_config_schema": {
"$id": "entity_config_schema",
"additionalProperties": false,
"properties": {
"meta": {
"propertyNames": {
"type": "string"
},
"type": "object"
}
},
"type": "object"
},
"entity_schema": {
"$id": "entity_schema",
"additionalProperties": false,
"properties": {
"config": {
"$ref": "#/definitions/entity_config_schema"
},
"entity": {
"type": "string"
},
Expand Down Expand Up @@ -314,6 +346,19 @@
"type"
]
},
"measure_config_schema": {
"$id": "measure_config_schema",
"additionalProperties": false,
"properties": {
"meta": {
"propertyNames": {
"type": "string"
},
"type": "object"
}
},
"type": "object"
},
"measure_schema": {
"$id": "measure_schema",
"additionalProperties": false,
Expand Down Expand Up @@ -347,6 +392,9 @@
"pattern": "(?!.*__).*^[a-z][a-z0-9_]*[a-z0-9]$",
"type": "string"
},
"config": {
"$ref": "#/definitions/measure_config_schema"
},
"create_metric": {
"type": "boolean"
},
Expand Down
34 changes: 34 additions & 0 deletions dbt_semantic_interfaces/parsing/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,16 @@
"additionalProperties": False,
}


entity_config_schema = {
"$id": "entity_config_schema",
"type": "object",
"properties": {
"meta": {"type": "object", "propertyNames": {"type": "string"}},
},
"additionalProperties": False,
}

entity_schema = {
"$id": "entity_schema",
"type": "object",
Expand All @@ -174,6 +184,7 @@
"expr": {"type": ["string", "boolean"]},
"entity": {"type": "string"},
"label": {"type": "string"},
"config": {"$ref": "entity_config_schema"},
},
"additionalProperties": False,
"required": ["name", "type"],
Expand Down Expand Up @@ -226,6 +237,15 @@
"additionalProperties": False,
}

measure_config_schema = {
"$id": "measure_config_schema",
"type": "object",
"properties": {
"meta": {"type": "object", "propertyNames": {"type": "string"}},
},
"additionalProperties": False,
}

measure_schema = {
"$id": "measure_schema",
"type": "object",
Expand All @@ -248,11 +268,21 @@
},
"description": {"type": "string"},
"label": {"type": "string"},
"config": {"$ref": "measure_config_schema"},
},
"additionalProperties": False,
"required": ["name", "agg"],
}

dimension_config_schema = {
"$id": "dimension_config_schema",
"type": "object",
"properties": {
"meta": {"type": "object", "propertyNames": {"type": "string"}},
},
"additionalProperties": False,
}

dimension_schema = {
"$id": "dimension_schema",
"type": "object",
Expand All @@ -267,6 +297,7 @@
"expr": {"type": ["string", "boolean"]},
"type_params": {"$ref": "dimension_type_params_schema"},
"label": {"type": "string"},
"config": {"$ref": "dimension_config_schema"},
},
# dimension must have type_params if its a time dimension
"anyOf": [{"not": {"$ref": "#/definitions/is-time-dimension"}}, {"required": ["type_params"]}],
Expand Down Expand Up @@ -529,6 +560,9 @@
saved_query_query_params_schema["$id"]: saved_query_query_params_schema,
semantic_model_config_schema["$id"]: semantic_model_config_schema,
metric_config_schema["$id"]: metric_config_schema,
dimension_config_schema["$id"]: dimension_config_schema,
entity_config_schema["$id"]: entity_config_schema,
measure_config_schema["$id"]: measure_config_schema,
}

resources: List[Tuple[str, Resource]] = [(str(k), DRAFT7.create_resource(v)) for k, v in schema_store.items()]
Expand Down
6 changes: 6 additions & 0 deletions dbt_semantic_interfaces/protocols/dimension.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from abc import abstractmethod
from typing import Optional, Protocol

from dbt_semantic_interfaces.protocols.meta import SemanticLayerElementConfig
from dbt_semantic_interfaces.protocols.metadata import Metadata
from dbt_semantic_interfaces.references import (
DimensionReference,
Expand Down Expand Up @@ -107,3 +108,8 @@ def validity_params(self) -> Optional[DimensionValidityParams]:
def label(self) -> Optional[str]:
"""Returns a string representing a human readable label for the dimension."""
pass

@property
@abstractmethod
def config(self) -> Optional[SemanticLayerElementConfig]: # noqa: D
pass
6 changes: 6 additions & 0 deletions dbt_semantic_interfaces/protocols/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from abc import abstractmethod
from typing import Optional, Protocol

from dbt_semantic_interfaces.protocols.meta import SemanticLayerElementConfig
from dbt_semantic_interfaces.references import EntityReference
from dbt_semantic_interfaces.type_enums import EntityType

Expand Down Expand Up @@ -60,3 +61,8 @@ def is_linkable_entity_type(self) -> bool:
def label(self) -> Optional[str]:
"""Returns a string representing a human readable label for the entity."""
pass

@property
@abstractmethod
def config(self) -> Optional[SemanticLayerElementConfig]: # noqa: D
pass
6 changes: 6 additions & 0 deletions dbt_semantic_interfaces/protocols/measure.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from abc import abstractmethod
from typing import Optional, Protocol, Sequence

from dbt_semantic_interfaces.protocols.meta import SemanticLayerElementConfig
from dbt_semantic_interfaces.references import MeasureReference
from dbt_semantic_interfaces.type_enums import AggregationType

Expand Down Expand Up @@ -98,3 +99,8 @@ def reference(self) -> MeasureReference:
def label(self) -> Optional[str]:
"""Returns a string representing a human readable label for the measure."""
pass

@property
@abstractmethod
def config(self) -> Optional[SemanticLayerElementConfig]: # noqa: D
pass
12 changes: 12 additions & 0 deletions dbt_semantic_interfaces/protocols/meta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from abc import abstractmethod
from typing import Any, Dict, Protocol


class SemanticLayerElementConfig(Protocol): # noqa: D
"""The config property allows you to configure additional resources/metadata."""

@property
@abstractmethod
def meta(self) -> Dict[str, Any]:
"""The meta field can be used to set metadata for a resource."""
pass
11 changes: 9 additions & 2 deletions tests/parsing/test_semantic_model_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ def test_base_semantic_model_entity_parsing() -> None:
role: test_role
expr: example_id
label: {label}
config:
meta:
random: metadata
"""
)
file = YamlConfigFile(filepath="test_dir/inline_for_test", contents=yaml_contents)
Expand Down Expand Up @@ -206,7 +208,9 @@ def test_base_semantic_model_measure_parsing() -> None:
expr: example_input
description: {description}
label: {label}
config:
meta:
random: metadata
"""
)
file = YamlConfigFile(filepath="test_dir/inline_for_test", contents=yaml_contents)
Expand Down Expand Up @@ -325,6 +329,9 @@ def test_semantic_model_categorical_dimension_parsing() -> None:
- name: example_categorical_dimension
type: categorical
expr: dimension_input
config:
meta:
random: metadata
"""
)
file = YamlConfigFile(filepath="inline_for_test", contents=yaml_contents)
Expand Down
7 changes: 7 additions & 0 deletions tests/test_implements_satisfy_protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
from hypothesis import given
from hypothesis.strategies import booleans, builds, from_type, just, lists, none, text

from dbt_semantic_interfaces.implementations.element_config import (
PydanticSemanticLayerElementConfig,
)
from dbt_semantic_interfaces.implementations.elements.dimension import (
PydanticDimension,
PydanticDimensionTypeParams,
Expand Down Expand Up @@ -66,6 +69,7 @@
expr=OPTIONAL_STR_STRATEGY,
metadata=OPTIONAL_METADATA_STRATEGY,
label=OPTIONAL_STR_STRATEGY,
config=builds(PydanticSemanticLayerElementConfig),
)

DIMENSION_VALIDITY_PARAMS_STRATEGY = builds(
Expand All @@ -82,6 +86,7 @@
expr=OPTIONAL_STR_STRATEGY,
metadata=OPTIONAL_METADATA_STRATEGY,
label=OPTIONAL_STR_STRATEGY,
config=builds(PydanticSemanticLayerElementConfig),
)

DIMENSION_STRATEGY = TIME_DIMENSION_STRATEGY | CATEGORICAL_DIMENSION_STRATEGY
Expand All @@ -93,6 +98,7 @@
expr=OPTIONAL_STR_STRATEGY,
metadata=OPTIONAL_METADATA_STRATEGY,
label=OPTIONAL_STR_STRATEGY,
config=builds(PydanticSemanticLayerElementConfig),
)

MEASURE_STRATEGY = builds(
Expand All @@ -104,6 +110,7 @@
non_additive_dimesnion=builds(PydanticNonAdditiveDimensionParameters) | none(),
agg_time_dimension=OPTIONAL_STR_STRATEGY,
label=OPTIONAL_STR_STRATEGY,
config=builds(PydanticSemanticLayerElementConfig),
)

SEMANTIC_MODEL_STRATEGY = builds(
Expand Down

0 comments on commit c833632

Please sign in to comment.