dvt-core 0.52.2__cp310-cp310-macosx_10_9_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dvt-core might be problematic. Click here for more details.
- dbt/__init__.py +7 -0
- dbt/_pydantic_shim.py +26 -0
- dbt/artifacts/__init__.py +0 -0
- dbt/artifacts/exceptions/__init__.py +1 -0
- dbt/artifacts/exceptions/schemas.py +31 -0
- dbt/artifacts/resources/__init__.py +116 -0
- dbt/artifacts/resources/base.py +67 -0
- dbt/artifacts/resources/types.py +93 -0
- dbt/artifacts/resources/v1/analysis.py +10 -0
- dbt/artifacts/resources/v1/catalog.py +23 -0
- dbt/artifacts/resources/v1/components.py +274 -0
- dbt/artifacts/resources/v1/config.py +277 -0
- dbt/artifacts/resources/v1/documentation.py +11 -0
- dbt/artifacts/resources/v1/exposure.py +51 -0
- dbt/artifacts/resources/v1/function.py +52 -0
- dbt/artifacts/resources/v1/generic_test.py +31 -0
- dbt/artifacts/resources/v1/group.py +21 -0
- dbt/artifacts/resources/v1/hook.py +11 -0
- dbt/artifacts/resources/v1/macro.py +29 -0
- dbt/artifacts/resources/v1/metric.py +172 -0
- dbt/artifacts/resources/v1/model.py +145 -0
- dbt/artifacts/resources/v1/owner.py +10 -0
- dbt/artifacts/resources/v1/saved_query.py +111 -0
- dbt/artifacts/resources/v1/seed.py +41 -0
- dbt/artifacts/resources/v1/semantic_layer_components.py +72 -0
- dbt/artifacts/resources/v1/semantic_model.py +314 -0
- dbt/artifacts/resources/v1/singular_test.py +14 -0
- dbt/artifacts/resources/v1/snapshot.py +91 -0
- dbt/artifacts/resources/v1/source_definition.py +84 -0
- dbt/artifacts/resources/v1/sql_operation.py +10 -0
- dbt/artifacts/resources/v1/unit_test_definition.py +77 -0
- dbt/artifacts/schemas/__init__.py +0 -0
- dbt/artifacts/schemas/base.py +191 -0
- dbt/artifacts/schemas/batch_results.py +24 -0
- dbt/artifacts/schemas/catalog/__init__.py +11 -0
- dbt/artifacts/schemas/catalog/v1/__init__.py +0 -0
- dbt/artifacts/schemas/catalog/v1/catalog.py +59 -0
- dbt/artifacts/schemas/freshness/__init__.py +1 -0
- dbt/artifacts/schemas/freshness/v3/__init__.py +0 -0
- dbt/artifacts/schemas/freshness/v3/freshness.py +158 -0
- dbt/artifacts/schemas/manifest/__init__.py +2 -0
- dbt/artifacts/schemas/manifest/v12/__init__.py +0 -0
- dbt/artifacts/schemas/manifest/v12/manifest.py +211 -0
- dbt/artifacts/schemas/results.py +147 -0
- dbt/artifacts/schemas/run/__init__.py +2 -0
- dbt/artifacts/schemas/run/v5/__init__.py +0 -0
- dbt/artifacts/schemas/run/v5/run.py +184 -0
- dbt/artifacts/schemas/upgrades/__init__.py +4 -0
- dbt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
- dbt/artifacts/schemas/upgrades/upgrade_manifest_dbt_version.py +2 -0
- dbt/artifacts/utils/validation.py +153 -0
- dbt/cli/__init__.py +1 -0
- dbt/cli/context.py +17 -0
- dbt/cli/exceptions.py +57 -0
- dbt/cli/flags.py +560 -0
- dbt/cli/main.py +2039 -0
- dbt/cli/option_types.py +121 -0
- dbt/cli/options.py +80 -0
- dbt/cli/params.py +804 -0
- dbt/cli/requires.py +490 -0
- dbt/cli/resolvers.py +50 -0
- dbt/cli/types.py +40 -0
- dbt/clients/__init__.py +0 -0
- dbt/clients/checked_load.py +83 -0
- dbt/clients/git.py +164 -0
- dbt/clients/jinja.py +206 -0
- dbt/clients/jinja_static.py +245 -0
- dbt/clients/registry.py +192 -0
- dbt/clients/yaml_helper.py +68 -0
- dbt/compilation.py +876 -0
- dbt/compute/__init__.py +14 -0
- dbt/compute/engines/__init__.py +12 -0
- dbt/compute/engines/spark_engine.py +624 -0
- dbt/compute/federated_executor.py +837 -0
- dbt/compute/filter_pushdown.cpython-310-darwin.so +0 -0
- dbt/compute/filter_pushdown.py +273 -0
- dbt/compute/jar_provisioning.cpython-310-darwin.so +0 -0
- dbt/compute/jar_provisioning.py +255 -0
- dbt/compute/java_compat.cpython-310-darwin.so +0 -0
- dbt/compute/java_compat.py +689 -0
- dbt/compute/jdbc_utils.cpython-310-darwin.so +0 -0
- dbt/compute/jdbc_utils.py +678 -0
- dbt/compute/smart_selector.cpython-310-darwin.so +0 -0
- dbt/compute/smart_selector.py +311 -0
- dbt/compute/strategies/__init__.py +54 -0
- dbt/compute/strategies/base.py +165 -0
- dbt/compute/strategies/dataproc.py +207 -0
- dbt/compute/strategies/emr.py +203 -0
- dbt/compute/strategies/local.py +364 -0
- dbt/compute/strategies/standalone.py +262 -0
- dbt/config/__init__.py +4 -0
- dbt/config/catalogs.py +94 -0
- dbt/config/compute.cpython-310-darwin.so +0 -0
- dbt/config/compute.py +547 -0
- dbt/config/dvt_profile.cpython-310-darwin.so +0 -0
- dbt/config/dvt_profile.py +342 -0
- dbt/config/profile.py +422 -0
- dbt/config/project.py +873 -0
- dbt/config/project_utils.py +28 -0
- dbt/config/renderer.py +231 -0
- dbt/config/runtime.py +553 -0
- dbt/config/selectors.py +208 -0
- dbt/config/utils.py +77 -0
- dbt/constants.py +28 -0
- dbt/context/__init__.py +0 -0
- dbt/context/base.py +745 -0
- dbt/context/configured.py +135 -0
- dbt/context/context_config.py +382 -0
- dbt/context/docs.py +82 -0
- dbt/context/exceptions_jinja.py +178 -0
- dbt/context/macro_resolver.py +195 -0
- dbt/context/macros.py +171 -0
- dbt/context/manifest.py +72 -0
- dbt/context/providers.py +2249 -0
- dbt/context/query_header.py +13 -0
- dbt/context/secret.py +58 -0
- dbt/context/target.py +74 -0
- dbt/contracts/__init__.py +0 -0
- dbt/contracts/files.py +413 -0
- dbt/contracts/graph/__init__.py +0 -0
- dbt/contracts/graph/manifest.py +1904 -0
- dbt/contracts/graph/metrics.py +97 -0
- dbt/contracts/graph/model_config.py +70 -0
- dbt/contracts/graph/node_args.py +42 -0
- dbt/contracts/graph/nodes.py +1806 -0
- dbt/contracts/graph/semantic_manifest.py +232 -0
- dbt/contracts/graph/unparsed.py +811 -0
- dbt/contracts/project.py +417 -0
- dbt/contracts/results.py +53 -0
- dbt/contracts/selection.py +23 -0
- dbt/contracts/sql.py +85 -0
- dbt/contracts/state.py +68 -0
- dbt/contracts/util.py +46 -0
- dbt/deprecations.py +346 -0
- dbt/deps/__init__.py +0 -0
- dbt/deps/base.py +152 -0
- dbt/deps/git.py +195 -0
- dbt/deps/local.py +79 -0
- dbt/deps/registry.py +130 -0
- dbt/deps/resolver.py +149 -0
- dbt/deps/tarball.py +120 -0
- dbt/docs/source/_ext/dbt_click.py +119 -0
- dbt/docs/source/conf.py +32 -0
- dbt/env_vars.py +64 -0
- dbt/event_time/event_time.py +40 -0
- dbt/event_time/sample_window.py +60 -0
- dbt/events/__init__.py +15 -0
- dbt/events/base_types.py +36 -0
- dbt/events/core_types_pb2.py +2 -0
- dbt/events/logging.py +108 -0
- dbt/events/types.py +2516 -0
- dbt/exceptions.py +1486 -0
- dbt/flags.py +89 -0
- dbt/graph/__init__.py +11 -0
- dbt/graph/cli.py +247 -0
- dbt/graph/graph.py +172 -0
- dbt/graph/queue.py +214 -0
- dbt/graph/selector.py +374 -0
- dbt/graph/selector_methods.py +975 -0
- dbt/graph/selector_spec.py +222 -0
- dbt/graph/thread_pool.py +18 -0
- dbt/hooks.py +21 -0
- dbt/include/README.md +49 -0
- dbt/include/__init__.py +3 -0
- dbt/include/starter_project/.gitignore +4 -0
- dbt/include/starter_project/README.md +15 -0
- dbt/include/starter_project/__init__.py +3 -0
- dbt/include/starter_project/analyses/.gitkeep +0 -0
- dbt/include/starter_project/dbt_project.yml +36 -0
- dbt/include/starter_project/macros/.gitkeep +0 -0
- dbt/include/starter_project/models/example/my_first_dbt_model.sql +27 -0
- dbt/include/starter_project/models/example/my_second_dbt_model.sql +6 -0
- dbt/include/starter_project/models/example/schema.yml +21 -0
- dbt/include/starter_project/seeds/.gitkeep +0 -0
- dbt/include/starter_project/snapshots/.gitkeep +0 -0
- dbt/include/starter_project/tests/.gitkeep +0 -0
- dbt/internal_deprecations.py +26 -0
- dbt/jsonschemas/__init__.py +3 -0
- dbt/jsonschemas/jsonschemas.py +309 -0
- dbt/jsonschemas/project/0.0.110.json +4717 -0
- dbt/jsonschemas/project/0.0.85.json +2015 -0
- dbt/jsonschemas/resources/0.0.110.json +2636 -0
- dbt/jsonschemas/resources/0.0.85.json +2536 -0
- dbt/jsonschemas/resources/latest.json +6773 -0
- dbt/links.py +4 -0
- dbt/materializations/__init__.py +0 -0
- dbt/materializations/incremental/__init__.py +0 -0
- dbt/materializations/incremental/microbatch.py +236 -0
- dbt/mp_context.py +8 -0
- dbt/node_types.py +37 -0
- dbt/parser/__init__.py +23 -0
- dbt/parser/analysis.py +21 -0
- dbt/parser/base.py +548 -0
- dbt/parser/common.py +266 -0
- dbt/parser/docs.py +52 -0
- dbt/parser/fixtures.py +51 -0
- dbt/parser/functions.py +30 -0
- dbt/parser/generic_test.py +100 -0
- dbt/parser/generic_test_builders.py +333 -0
- dbt/parser/hooks.py +118 -0
- dbt/parser/macros.py +137 -0
- dbt/parser/manifest.py +2204 -0
- dbt/parser/models.py +573 -0
- dbt/parser/partial.py +1178 -0
- dbt/parser/read_files.py +445 -0
- dbt/parser/schema_generic_tests.py +422 -0
- dbt/parser/schema_renderer.py +111 -0
- dbt/parser/schema_yaml_readers.py +935 -0
- dbt/parser/schemas.py +1466 -0
- dbt/parser/search.py +149 -0
- dbt/parser/seeds.py +28 -0
- dbt/parser/singular_test.py +20 -0
- dbt/parser/snapshots.py +44 -0
- dbt/parser/sources.py +558 -0
- dbt/parser/sql.py +62 -0
- dbt/parser/unit_tests.py +621 -0
- dbt/plugins/__init__.py +20 -0
- dbt/plugins/contracts.py +9 -0
- dbt/plugins/exceptions.py +2 -0
- dbt/plugins/manager.py +163 -0
- dbt/plugins/manifest.py +21 -0
- dbt/profiler.py +20 -0
- dbt/py.typed +1 -0
- dbt/query_analyzer.cpython-310-darwin.so +0 -0
- dbt/query_analyzer.py +410 -0
- dbt/runners/__init__.py +2 -0
- dbt/runners/exposure_runner.py +7 -0
- dbt/runners/no_op_runner.py +45 -0
- dbt/runners/saved_query_runner.py +7 -0
- dbt/selected_resources.py +8 -0
- dbt/task/__init__.py +0 -0
- dbt/task/base.py +503 -0
- dbt/task/build.py +197 -0
- dbt/task/clean.py +56 -0
- dbt/task/clone.py +161 -0
- dbt/task/compile.py +150 -0
- dbt/task/compute.py +454 -0
- dbt/task/debug.py +505 -0
- dbt/task/deps.py +280 -0
- dbt/task/docs/__init__.py +3 -0
- dbt/task/docs/generate.py +660 -0
- dbt/task/docs/index.html +250 -0
- dbt/task/docs/serve.py +29 -0
- dbt/task/freshness.py +322 -0
- dbt/task/function.py +121 -0
- dbt/task/group_lookup.py +46 -0
- dbt/task/init.py +553 -0
- dbt/task/java.py +316 -0
- dbt/task/list.py +236 -0
- dbt/task/printer.py +175 -0
- dbt/task/retry.py +175 -0
- dbt/task/run.py +1306 -0
- dbt/task/run_operation.py +141 -0
- dbt/task/runnable.py +758 -0
- dbt/task/seed.py +103 -0
- dbt/task/show.py +149 -0
- dbt/task/snapshot.py +56 -0
- dbt/task/spark.py +414 -0
- dbt/task/sql.py +110 -0
- dbt/task/target_sync.py +759 -0
- dbt/task/test.py +464 -0
- dbt/tests/fixtures/__init__.py +1 -0
- dbt/tests/fixtures/project.py +620 -0
- dbt/tests/util.py +651 -0
- dbt/tracking.py +529 -0
- dbt/utils/__init__.py +3 -0
- dbt/utils/artifact_upload.py +151 -0
- dbt/utils/utils.py +408 -0
- dbt/version.py +268 -0
- dvt_cli/__init__.py +72 -0
- dvt_core-0.52.2.dist-info/METADATA +286 -0
- dvt_core-0.52.2.dist-info/RECORD +275 -0
- dvt_core-0.52.2.dist-info/WHEEL +5 -0
- dvt_core-0.52.2.dist-info/entry_points.txt +2 -0
- dvt_core-0.52.2.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import enum
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Dict, List, Literal, Optional
|
|
5
|
+
|
|
6
|
+
from dbt.artifacts.resources.types import AccessType, NodeType, TimePeriod
|
|
7
|
+
from dbt.artifacts.resources.v1.components import (
|
|
8
|
+
CompiledResource,
|
|
9
|
+
DeferRelation,
|
|
10
|
+
NodeVersion,
|
|
11
|
+
)
|
|
12
|
+
from dbt.artifacts.resources.v1.config import NodeConfig
|
|
13
|
+
from dbt_common.contracts.config.base import MergeBehavior
|
|
14
|
+
from dbt_common.contracts.constraints import ModelLevelConstraint
|
|
15
|
+
from dbt_common.contracts.util import Mergeable
|
|
16
|
+
from dbt_common.dataclass_schema import (
|
|
17
|
+
ExtensibleDbtClassMixin,
|
|
18
|
+
ValidationError,
|
|
19
|
+
dbtClassMixin,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ModelFreshnessUpdatesOnOptions(enum.Enum):
|
|
24
|
+
all = "all"
|
|
25
|
+
any = "any"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class ModelBuildAfter(ExtensibleDbtClassMixin):
|
|
30
|
+
count: Optional[int] = None
|
|
31
|
+
period: Optional[TimePeriod] = None
|
|
32
|
+
updates_on: ModelFreshnessUpdatesOnOptions = ModelFreshnessUpdatesOnOptions.any
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class ModelFreshness(ExtensibleDbtClassMixin, Mergeable):
|
|
37
|
+
build_after: ModelBuildAfter
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def merge_model_freshness(*thresholds: Optional[ModelFreshness]) -> Optional[ModelFreshness]:
|
|
41
|
+
if not thresholds:
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
current_merged_value: Optional[ModelFreshness] = thresholds[0]
|
|
45
|
+
|
|
46
|
+
for i in range(1, len(thresholds)):
|
|
47
|
+
base = current_merged_value
|
|
48
|
+
update = thresholds[i]
|
|
49
|
+
|
|
50
|
+
if base is not None and update is not None:
|
|
51
|
+
# When both base and update freshness are defined,
|
|
52
|
+
# create a new ModelFreshness instance using the build_after from the 'update'.
|
|
53
|
+
# This effectively means 'update's build_after configuration takes precedence.
|
|
54
|
+
merged_freshness_obj = base.merged(update)
|
|
55
|
+
if (
|
|
56
|
+
base.build_after.updates_on == ModelFreshnessUpdatesOnOptions.all
|
|
57
|
+
or update.build_after.updates_on == ModelFreshnessUpdatesOnOptions.all
|
|
58
|
+
):
|
|
59
|
+
merged_freshness_obj.build_after.updates_on = ModelFreshnessUpdatesOnOptions.all
|
|
60
|
+
current_merged_value = merged_freshness_obj
|
|
61
|
+
elif base is None and update is not None:
|
|
62
|
+
# If the current merged value is None but the new update is defined,
|
|
63
|
+
# take the update.
|
|
64
|
+
current_merged_value = update
|
|
65
|
+
else:
|
|
66
|
+
# This covers cases where 'update' is None (regardless of 'base'),
|
|
67
|
+
# or both 'base' and 'update' are None.
|
|
68
|
+
# The result of the pair-merge is None.
|
|
69
|
+
current_merged_value = base
|
|
70
|
+
|
|
71
|
+
return current_merged_value
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass
|
|
75
|
+
class ModelConfig(NodeConfig):
|
|
76
|
+
access: AccessType = field(
|
|
77
|
+
default=AccessType.Protected,
|
|
78
|
+
metadata=MergeBehavior.Clobber.meta(),
|
|
79
|
+
)
|
|
80
|
+
freshness: Optional[ModelFreshness] = None
|
|
81
|
+
|
|
82
|
+
def __post_init__(self):
|
|
83
|
+
super().__post_init__()
|
|
84
|
+
if (
|
|
85
|
+
self.freshness
|
|
86
|
+
and self.freshness.build_after.period
|
|
87
|
+
and self.freshness.build_after.count is None
|
|
88
|
+
):
|
|
89
|
+
raise ValidationError(
|
|
90
|
+
"`freshness.build_after` must have a value for `count` if a `period` is provided"
|
|
91
|
+
)
|
|
92
|
+
elif (
|
|
93
|
+
self.freshness
|
|
94
|
+
and self.freshness.build_after.count is not None
|
|
95
|
+
and not self.freshness.build_after.period
|
|
96
|
+
):
|
|
97
|
+
raise ValidationError(
|
|
98
|
+
"`freshness.build_after` must have a value for `period` if a `count` is provided"
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
@classmethod
|
|
102
|
+
def __pre_deserialize__(cls, data):
|
|
103
|
+
data = super().__pre_deserialize__(data)
|
|
104
|
+
# scrub out model configs where "build_after" is not defined
|
|
105
|
+
if (
|
|
106
|
+
"freshness" in data
|
|
107
|
+
and isinstance(data["freshness"], dict)
|
|
108
|
+
and "build_after" in data["freshness"]
|
|
109
|
+
):
|
|
110
|
+
data["freshness"] = ModelFreshness.from_dict(data["freshness"]).to_dict()
|
|
111
|
+
else:
|
|
112
|
+
data.pop("freshness", None)
|
|
113
|
+
return data
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@dataclass
|
|
117
|
+
class CustomGranularity(dbtClassMixin):
|
|
118
|
+
name: str
|
|
119
|
+
column_name: Optional[str] = None
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@dataclass
|
|
123
|
+
class TimeSpine(dbtClassMixin):
|
|
124
|
+
standard_granularity_column: str
|
|
125
|
+
custom_granularities: List[CustomGranularity] = field(default_factory=list)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@dataclass
|
|
129
|
+
class Model(CompiledResource):
|
|
130
|
+
resource_type: Literal[NodeType.Model]
|
|
131
|
+
access: AccessType = AccessType.Protected
|
|
132
|
+
config: ModelConfig = field(default_factory=ModelConfig)
|
|
133
|
+
constraints: List[ModelLevelConstraint] = field(default_factory=list)
|
|
134
|
+
version: Optional[NodeVersion] = None
|
|
135
|
+
latest_version: Optional[NodeVersion] = None
|
|
136
|
+
deprecation_date: Optional[datetime] = None
|
|
137
|
+
defer_relation: Optional[DeferRelation] = None
|
|
138
|
+
primary_key: List[str] = field(default_factory=list)
|
|
139
|
+
time_spine: Optional[TimeSpine] = None
|
|
140
|
+
|
|
141
|
+
def __post_serialize__(self, dct: Dict, context: Optional[Dict] = None):
|
|
142
|
+
dct = super().__post_serialize__(dct, context)
|
|
143
|
+
if context and context.get("artifact") and "defer_relation" in dct:
|
|
144
|
+
del dct["defer_relation"]
|
|
145
|
+
return dct
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import List, Optional, Union
|
|
3
|
+
|
|
4
|
+
from dbt_common.contracts.config.properties import AdditionalPropertiesAllowed
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class Owner(AdditionalPropertiesAllowed):
|
|
9
|
+
email: Union[str, List[str], None] = None
|
|
10
|
+
name: Optional[str] = None
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import Any, Dict, List, Literal, Optional, Union
|
|
6
|
+
|
|
7
|
+
from dbt.artifacts.resources.base import GraphResource
|
|
8
|
+
from dbt.artifacts.resources.types import NodeType
|
|
9
|
+
from dbt.artifacts.resources.v1.components import DependsOn, RefArgs
|
|
10
|
+
from dbt.artifacts.resources.v1.config import list_str, metas
|
|
11
|
+
from dbt.artifacts.resources.v1.semantic_layer_components import (
|
|
12
|
+
SourceFileMetadata,
|
|
13
|
+
WhereFilterIntersection,
|
|
14
|
+
)
|
|
15
|
+
from dbt_common.contracts.config.base import BaseConfig, CompareBehavior, MergeBehavior
|
|
16
|
+
from dbt_common.contracts.config.metadata import ShowBehavior
|
|
17
|
+
from dbt_common.dataclass_schema import dbtClassMixin
|
|
18
|
+
from dbt_semantic_interfaces.type_enums.export_destination_type import (
|
|
19
|
+
ExportDestinationType,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class ExportConfig(dbtClassMixin):
|
|
25
|
+
"""Nested configuration attributes for exports."""
|
|
26
|
+
|
|
27
|
+
export_as: ExportDestinationType
|
|
28
|
+
schema_name: Optional[str] = None
|
|
29
|
+
alias: Optional[str] = None
|
|
30
|
+
database: Optional[str] = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class Export(dbtClassMixin):
|
|
35
|
+
"""Configuration for writing query results to a table."""
|
|
36
|
+
|
|
37
|
+
name: str
|
|
38
|
+
config: ExportConfig
|
|
39
|
+
unrendered_config: Dict[str, str] = field(default_factory=dict)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class QueryParams(dbtClassMixin):
|
|
44
|
+
"""The query parameters for the saved query"""
|
|
45
|
+
|
|
46
|
+
metrics: List[str]
|
|
47
|
+
group_by: List[str]
|
|
48
|
+
where: Optional[WhereFilterIntersection]
|
|
49
|
+
order_by: List[str] = field(default_factory=list)
|
|
50
|
+
limit: Optional[int] = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class SavedQueryCache(dbtClassMixin):
|
|
55
|
+
enabled: bool = False
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class SavedQueryConfig(BaseConfig):
|
|
60
|
+
"""Where config options for SavedQueries are stored.
|
|
61
|
+
|
|
62
|
+
This class is much like many other node config classes. It's likely that
|
|
63
|
+
this class will expand in the direction of what's in the `NodeAndTestConfig`
|
|
64
|
+
class. It might make sense to clean the various *Config classes into one at
|
|
65
|
+
some point.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
enabled: bool = True
|
|
69
|
+
group: Optional[str] = field(
|
|
70
|
+
default=None,
|
|
71
|
+
metadata=CompareBehavior.Exclude.meta(),
|
|
72
|
+
)
|
|
73
|
+
meta: Dict[str, Any] = field(
|
|
74
|
+
default_factory=dict,
|
|
75
|
+
metadata=MergeBehavior.Update.meta(),
|
|
76
|
+
)
|
|
77
|
+
export_as: Optional[ExportDestinationType] = None
|
|
78
|
+
schema: Optional[str] = None
|
|
79
|
+
cache: SavedQueryCache = field(default_factory=SavedQueryCache)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@dataclass
|
|
83
|
+
class SavedQueryMandatory(GraphResource):
|
|
84
|
+
query_params: QueryParams
|
|
85
|
+
exports: List[Export]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@dataclass
|
|
89
|
+
class SavedQuery(SavedQueryMandatory):
|
|
90
|
+
resource_type: Literal[NodeType.SavedQuery]
|
|
91
|
+
description: Optional[str] = None
|
|
92
|
+
label: Optional[str] = None
|
|
93
|
+
metadata: Optional[SourceFileMetadata] = None
|
|
94
|
+
config: SavedQueryConfig = field(default_factory=SavedQueryConfig)
|
|
95
|
+
unrendered_config: Dict[str, Any] = field(default_factory=dict)
|
|
96
|
+
group: Optional[str] = None
|
|
97
|
+
depends_on: DependsOn = field(default_factory=DependsOn)
|
|
98
|
+
created_at: float = field(default_factory=lambda: time.time())
|
|
99
|
+
refs: List[RefArgs] = field(default_factory=list)
|
|
100
|
+
tags: Union[List[str], str] = field(
|
|
101
|
+
default_factory=list_str,
|
|
102
|
+
metadata=metas(ShowBehavior.Hide, MergeBehavior.Append, CompareBehavior.Exclude),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def metrics(self) -> List[str]:
|
|
107
|
+
return self.query_params.metrics
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def depends_on_nodes(self):
|
|
111
|
+
return self.depends_on.nodes
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Dict, Literal, Optional
|
|
3
|
+
|
|
4
|
+
from dbt.artifacts.resources.types import NodeType
|
|
5
|
+
from dbt.artifacts.resources.v1.components import (
|
|
6
|
+
DeferRelation,
|
|
7
|
+
MacroDependsOn,
|
|
8
|
+
ParsedResource,
|
|
9
|
+
)
|
|
10
|
+
from dbt.artifacts.resources.v1.config import NodeConfig
|
|
11
|
+
from dbt_common.dataclass_schema import ValidationError
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class SeedConfig(NodeConfig):
|
|
16
|
+
materialized: str = "seed"
|
|
17
|
+
delimiter: str = ","
|
|
18
|
+
quote_columns: Optional[bool] = None
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def validate(cls, data):
|
|
22
|
+
super().validate(data)
|
|
23
|
+
if data.get("materialized") and data.get("materialized") != "seed":
|
|
24
|
+
raise ValidationError("A seed must have a materialized value of 'seed'")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class Seed(ParsedResource): # No SQLDefaults!
|
|
29
|
+
resource_type: Literal[NodeType.Seed]
|
|
30
|
+
config: SeedConfig = field(default_factory=SeedConfig)
|
|
31
|
+
# seeds need the root_path because the contents are not loaded initially
|
|
32
|
+
# and we need the root_path to load the seed later
|
|
33
|
+
root_path: Optional[str] = None
|
|
34
|
+
depends_on: MacroDependsOn = field(default_factory=MacroDependsOn)
|
|
35
|
+
defer_relation: Optional[DeferRelation] = None
|
|
36
|
+
|
|
37
|
+
def __post_serialize__(self, dct: Dict, context: Optional[Dict] = None):
|
|
38
|
+
dct = super().__post_serialize__(dct, context)
|
|
39
|
+
if context and context.get("artifact") and "defer_relation" in dct:
|
|
40
|
+
del dct["defer_relation"]
|
|
41
|
+
return dct
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import List, Optional, Sequence, Tuple
|
|
3
|
+
|
|
4
|
+
from dbt_common.dataclass_schema import dbtClassMixin
|
|
5
|
+
from dbt_semantic_interfaces.call_parameter_sets import JinjaCallParameterSets
|
|
6
|
+
from dbt_semantic_interfaces.parsing.where_filter.jinja_object_parser import (
|
|
7
|
+
JinjaObjectParser,
|
|
8
|
+
QueryItemLocation,
|
|
9
|
+
)
|
|
10
|
+
from dbt_semantic_interfaces.type_enums import AggregationType
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class WhereFilter(dbtClassMixin):
|
|
15
|
+
where_sql_template: str
|
|
16
|
+
|
|
17
|
+
def call_parameter_sets(
|
|
18
|
+
self, custom_granularity_names: Sequence[str]
|
|
19
|
+
) -> JinjaCallParameterSets:
|
|
20
|
+
return JinjaObjectParser.parse_call_parameter_sets(
|
|
21
|
+
self.where_sql_template,
|
|
22
|
+
custom_granularity_names=custom_granularity_names,
|
|
23
|
+
query_item_location=QueryItemLocation.NON_ORDER_BY,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class WhereFilterIntersection(dbtClassMixin):
|
|
29
|
+
where_filters: List[WhereFilter]
|
|
30
|
+
|
|
31
|
+
def filter_expression_parameter_sets(
|
|
32
|
+
self, custom_granularity_names: Sequence[str]
|
|
33
|
+
) -> Sequence[Tuple[str, JinjaCallParameterSets]]:
|
|
34
|
+
raise NotImplementedError
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class FileSlice(dbtClassMixin):
|
|
39
|
+
"""Provides file slice level context about what something was created from.
|
|
40
|
+
|
|
41
|
+
Implementation of the dbt-semantic-interfaces `FileSlice` protocol
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
filename: str
|
|
45
|
+
content: str
|
|
46
|
+
start_line_number: int
|
|
47
|
+
end_line_number: int
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class SourceFileMetadata(dbtClassMixin):
|
|
52
|
+
"""Provides file context about what something was created from.
|
|
53
|
+
|
|
54
|
+
Implementation of the dbt-semantic-interfaces `Metadata` protocol
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
repo_file_path: str
|
|
58
|
+
file_slice: FileSlice
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class MeasureAggregationParameters(dbtClassMixin):
|
|
63
|
+
percentile: Optional[float] = None
|
|
64
|
+
use_discrete_percentile: bool = False
|
|
65
|
+
use_approximate_percentile: bool = False
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class NonAdditiveDimension(dbtClassMixin):
|
|
70
|
+
name: str
|
|
71
|
+
window_choice: AggregationType
|
|
72
|
+
window_groupings: List[str]
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import Any, Dict, List, Optional, Sequence
|
|
4
|
+
|
|
5
|
+
from dbt.artifacts.resources import SourceFileMetadata
|
|
6
|
+
from dbt.artifacts.resources.base import GraphResource
|
|
7
|
+
from dbt.artifacts.resources.v1.components import DependsOn, RefArgs
|
|
8
|
+
from dbt.artifacts.resources.v1.metric import Metric
|
|
9
|
+
from dbt.artifacts.resources.v1.semantic_layer_components import (
|
|
10
|
+
MeasureAggregationParameters,
|
|
11
|
+
NonAdditiveDimension,
|
|
12
|
+
)
|
|
13
|
+
from dbt_common.contracts.config.base import BaseConfig, CompareBehavior, MergeBehavior
|
|
14
|
+
from dbt_common.dataclass_schema import dbtClassMixin
|
|
15
|
+
from dbt_semantic_interfaces.references import (
|
|
16
|
+
DimensionReference,
|
|
17
|
+
EntityReference,
|
|
18
|
+
LinkableElementReference,
|
|
19
|
+
MeasureReference,
|
|
20
|
+
SemanticModelReference,
|
|
21
|
+
TimeDimensionReference,
|
|
22
|
+
)
|
|
23
|
+
from dbt_semantic_interfaces.type_enums import (
|
|
24
|
+
AggregationType,
|
|
25
|
+
DimensionType,
|
|
26
|
+
EntityType,
|
|
27
|
+
MetricType,
|
|
28
|
+
TimeGranularity,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
"""
|
|
32
|
+
The classes in this file are dataclasses which are used to construct the Semantic
|
|
33
|
+
Model node in dbt-core. Additionally, these classes need to at a minimum support
|
|
34
|
+
what is specified in their protocol definitions in dbt-semantic-interfaces.
|
|
35
|
+
Their protocol definitions can be found here:
|
|
36
|
+
https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/dbt_semantic_interfaces/protocols/semantic_model.py
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class SemanticLayerElementConfig(dbtClassMixin):
|
|
42
|
+
meta: Dict[str, Any] = field(
|
|
43
|
+
default_factory=dict,
|
|
44
|
+
metadata=MergeBehavior.Update.meta(),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class Defaults(dbtClassMixin):
|
|
50
|
+
agg_time_dimension: Optional[str] = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class NodeRelation(dbtClassMixin):
|
|
55
|
+
alias: str
|
|
56
|
+
schema_name: str # TODO: Could this be called simply "schema" so we could reuse StateRelation?
|
|
57
|
+
database: Optional[str] = None
|
|
58
|
+
relation_name: Optional[str] = ""
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# ====================================
|
|
62
|
+
# Dimension objects
|
|
63
|
+
# Dimension protocols: https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/dbt_semantic_interfaces/protocols/dimension.py
|
|
64
|
+
# ====================================
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass
|
|
68
|
+
class DimensionValidityParams(dbtClassMixin):
|
|
69
|
+
is_start: bool = False
|
|
70
|
+
is_end: bool = False
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass
|
|
74
|
+
class DimensionTypeParams(dbtClassMixin):
|
|
75
|
+
time_granularity: TimeGranularity
|
|
76
|
+
validity_params: Optional[DimensionValidityParams] = None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass
|
|
80
|
+
class Dimension(dbtClassMixin):
|
|
81
|
+
name: str
|
|
82
|
+
type: DimensionType
|
|
83
|
+
description: Optional[str] = None
|
|
84
|
+
label: Optional[str] = None
|
|
85
|
+
is_partition: bool = False
|
|
86
|
+
type_params: Optional[DimensionTypeParams] = None
|
|
87
|
+
expr: Optional[str] = None
|
|
88
|
+
metadata: Optional[SourceFileMetadata] = None
|
|
89
|
+
config: Optional[SemanticLayerElementConfig] = None
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def reference(self) -> DimensionReference:
|
|
93
|
+
return DimensionReference(element_name=self.name)
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def time_dimension_reference(self) -> Optional[TimeDimensionReference]:
|
|
97
|
+
if self.type == DimensionType.TIME:
|
|
98
|
+
return TimeDimensionReference(element_name=self.name)
|
|
99
|
+
else:
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def validity_params(self) -> Optional[DimensionValidityParams]:
|
|
104
|
+
if self.type_params:
|
|
105
|
+
return self.type_params.validity_params
|
|
106
|
+
else:
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
# ====================================
|
|
111
|
+
# Entity objects
|
|
112
|
+
# Entity protocols: https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/dbt_semantic_interfaces/protocols/entity.py
|
|
113
|
+
# ====================================
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@dataclass
|
|
117
|
+
class Entity(dbtClassMixin):
|
|
118
|
+
name: str
|
|
119
|
+
type: EntityType
|
|
120
|
+
description: Optional[str] = None
|
|
121
|
+
label: Optional[str] = None
|
|
122
|
+
role: Optional[str] = None
|
|
123
|
+
expr: Optional[str] = None
|
|
124
|
+
config: Optional[SemanticLayerElementConfig] = None
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def reference(self) -> EntityReference:
|
|
128
|
+
return EntityReference(element_name=self.name)
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def is_linkable_entity_type(self) -> bool:
|
|
132
|
+
return self.type in (EntityType.PRIMARY, EntityType.UNIQUE, EntityType.NATURAL)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
# ====================================
|
|
136
|
+
# Measure object
|
|
137
|
+
# Measure protocols: https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/dbt_semantic_interfaces/protocols/measure.py
|
|
138
|
+
# ====================================
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@dataclass
|
|
142
|
+
class Measure(dbtClassMixin):
|
|
143
|
+
name: str
|
|
144
|
+
agg: AggregationType
|
|
145
|
+
description: Optional[str] = None
|
|
146
|
+
label: Optional[str] = None
|
|
147
|
+
create_metric: bool = False
|
|
148
|
+
expr: Optional[str] = None
|
|
149
|
+
agg_params: Optional[MeasureAggregationParameters] = None
|
|
150
|
+
non_additive_dimension: Optional[NonAdditiveDimension] = None
|
|
151
|
+
agg_time_dimension: Optional[str] = None
|
|
152
|
+
config: Optional[SemanticLayerElementConfig] = None
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def reference(self) -> MeasureReference:
|
|
156
|
+
return MeasureReference(element_name=self.name)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
# ====================================
|
|
160
|
+
# SemanticModel final parts
|
|
161
|
+
# ====================================
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@dataclass
|
|
165
|
+
class SemanticModelConfig(BaseConfig):
|
|
166
|
+
enabled: bool = True
|
|
167
|
+
group: Optional[str] = field(
|
|
168
|
+
default=None,
|
|
169
|
+
metadata=CompareBehavior.Exclude.meta(),
|
|
170
|
+
)
|
|
171
|
+
meta: Dict[str, Any] = field(
|
|
172
|
+
default_factory=dict,
|
|
173
|
+
metadata=MergeBehavior.Update.meta(),
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@dataclass
|
|
178
|
+
class SemanticModel(GraphResource):
|
|
179
|
+
model: str
|
|
180
|
+
node_relation: Optional[NodeRelation]
|
|
181
|
+
description: Optional[str] = None
|
|
182
|
+
label: Optional[str] = None
|
|
183
|
+
defaults: Optional[Defaults] = None
|
|
184
|
+
entities: Sequence[Entity] = field(default_factory=list)
|
|
185
|
+
measures: Sequence[Measure] = field(default_factory=list)
|
|
186
|
+
dimensions: Sequence[Dimension] = field(default_factory=list)
|
|
187
|
+
metadata: Optional[SourceFileMetadata] = None
|
|
188
|
+
depends_on: DependsOn = field(default_factory=DependsOn)
|
|
189
|
+
refs: List[RefArgs] = field(default_factory=list)
|
|
190
|
+
created_at: float = field(default_factory=lambda: time.time())
|
|
191
|
+
config: SemanticModelConfig = field(default_factory=SemanticModelConfig)
|
|
192
|
+
unrendered_config: Dict[str, Any] = field(default_factory=dict)
|
|
193
|
+
primary_entity: Optional[str] = None
|
|
194
|
+
group: Optional[str] = None
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def entity_references(self) -> List[LinkableElementReference]:
|
|
198
|
+
return [entity.reference for entity in self.entities]
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def dimension_references(self) -> List[LinkableElementReference]:
|
|
202
|
+
return [dimension.reference for dimension in self.dimensions]
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def measure_references(self) -> List[MeasureReference]:
|
|
206
|
+
return [measure.reference for measure in self.measures]
|
|
207
|
+
|
|
208
|
+
@property
|
|
209
|
+
def has_validity_dimensions(self) -> bool:
|
|
210
|
+
return any([dim.validity_params is not None for dim in self.dimensions])
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def validity_start_dimension(self) -> Optional[Dimension]:
|
|
214
|
+
validity_start_dims = [
|
|
215
|
+
dim for dim in self.dimensions if dim.validity_params and dim.validity_params.is_start
|
|
216
|
+
]
|
|
217
|
+
if not validity_start_dims:
|
|
218
|
+
return None
|
|
219
|
+
return validity_start_dims[0]
|
|
220
|
+
|
|
221
|
+
@property
|
|
222
|
+
def validity_end_dimension(self) -> Optional[Dimension]:
|
|
223
|
+
validity_end_dims = [
|
|
224
|
+
dim for dim in self.dimensions if dim.validity_params and dim.validity_params.is_end
|
|
225
|
+
]
|
|
226
|
+
if not validity_end_dims:
|
|
227
|
+
return None
|
|
228
|
+
return validity_end_dims[0]
|
|
229
|
+
|
|
230
|
+
@property
|
|
231
|
+
def partitions(self) -> List[Dimension]: # noqa: D
|
|
232
|
+
return [dim for dim in self.dimensions or [] if dim.is_partition]
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def partition(self) -> Optional[Dimension]:
|
|
236
|
+
partitions = self.partitions
|
|
237
|
+
if not partitions:
|
|
238
|
+
return None
|
|
239
|
+
return partitions[0]
|
|
240
|
+
|
|
241
|
+
@property
|
|
242
|
+
def reference(self) -> SemanticModelReference:
|
|
243
|
+
return SemanticModelReference(semantic_model_name=self.name)
|
|
244
|
+
|
|
245
|
+
def checked_agg_time_dimension_for_measure(
|
|
246
|
+
self, measure_reference: MeasureReference
|
|
247
|
+
) -> TimeDimensionReference:
|
|
248
|
+
measure: Optional[Measure] = None
|
|
249
|
+
for measure in self.measures:
|
|
250
|
+
if measure.reference == measure_reference:
|
|
251
|
+
measure = measure
|
|
252
|
+
|
|
253
|
+
assert (
|
|
254
|
+
measure is not None
|
|
255
|
+
), f"No measure with name ({measure_reference.element_name}) in semantic_model with name ({self.name})"
|
|
256
|
+
|
|
257
|
+
default_agg_time_dimension = (
|
|
258
|
+
self.defaults.agg_time_dimension if self.defaults is not None else None
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
agg_time_dimension_name = measure.agg_time_dimension or default_agg_time_dimension
|
|
262
|
+
assert agg_time_dimension_name is not None, (
|
|
263
|
+
f"Aggregation time dimension for measure {measure.name} on semantic model {self.name} is not set! "
|
|
264
|
+
"To fix this either specify a default `agg_time_dimension` for the semantic model or define an "
|
|
265
|
+
"`agg_time_dimension` on the measure directly."
|
|
266
|
+
)
|
|
267
|
+
return TimeDimensionReference(element_name=agg_time_dimension_name)
|
|
268
|
+
|
|
269
|
+
def checked_agg_time_dimension_for_simple_metric(
|
|
270
|
+
self, metric: Metric
|
|
271
|
+
) -> TimeDimensionReference:
|
|
272
|
+
assert (
|
|
273
|
+
metric.type == MetricType.SIMPLE
|
|
274
|
+
), "Only simple metrics can have an agg time dimension."
|
|
275
|
+
metric_agg_params = metric.type_params.metric_aggregation_params
|
|
276
|
+
# There are validations elsewhere to check this for metrics and provide messaging for it.
|
|
277
|
+
assert metric_agg_params, "Simple metrics must have metric_aggregation_params."
|
|
278
|
+
# This indicates a validation bug / dev error, not a user error that should appear
|
|
279
|
+
# in a user's YAML.
|
|
280
|
+
assert (
|
|
281
|
+
metric_agg_params.semantic_model == self.name
|
|
282
|
+
), "Cannot retrieve the agg time dimension for a metric from a different model "
|
|
283
|
+
f"than the one that the metric belongs to. Metric `{metric.name}` belongs to model "
|
|
284
|
+
f"`{metric_agg_params.semantic_model}`, but we requested the agg time dimension from model `{self.name}`."
|
|
285
|
+
|
|
286
|
+
metric_time_dimension_name = None
|
|
287
|
+
if (
|
|
288
|
+
metric.type_params
|
|
289
|
+
and metric.type_params.metric_aggregation_params
|
|
290
|
+
and metric.type_params.metric_aggregation_params.agg_time_dimension
|
|
291
|
+
):
|
|
292
|
+
metric_time_dimension_name = (
|
|
293
|
+
metric.type_params.metric_aggregation_params.agg_time_dimension
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
default_agg_time_dimension = (
|
|
297
|
+
self.defaults.agg_time_dimension if self.defaults is not None else None
|
|
298
|
+
)
|
|
299
|
+
agg_time_dimension_name = metric_time_dimension_name or default_agg_time_dimension
|
|
300
|
+
|
|
301
|
+
assert agg_time_dimension_name is not None, (
|
|
302
|
+
f"Aggregation time dimension for metric {metric.name} is not set! This should either be set directly on "
|
|
303
|
+
f"the metric specification in the model, or else defaulted to the time dimension in the data "
|
|
304
|
+
f"source containing the metric."
|
|
305
|
+
)
|
|
306
|
+
return TimeDimensionReference(element_name=agg_time_dimension_name)
|
|
307
|
+
|
|
308
|
+
@property
|
|
309
|
+
def primary_entity_reference(self) -> Optional[EntityReference]:
|
|
310
|
+
return (
|
|
311
|
+
EntityReference(element_name=self.primary_entity)
|
|
312
|
+
if self.primary_entity is not None
|
|
313
|
+
else None
|
|
314
|
+
)
|