sqlmesh 0.209.1.dev12__py3-none-any.whl → 0.209.1.dev14__py3-none-any.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.
- sqlmesh/_version.py +2 -2
- sqlmesh/core/audit/definition.py +5 -3
- sqlmesh/core/config/common.py +29 -0
- sqlmesh/core/config/root.py +14 -7
- sqlmesh/core/constants.py +2 -0
- sqlmesh/core/context.py +7 -4
- sqlmesh/core/engine_adapter/base.py +73 -5
- sqlmesh/core/engine_adapter/redshift.py +6 -1
- sqlmesh/core/engine_adapter/shared.py +3 -0
- sqlmesh/core/loader.py +2 -0
- sqlmesh/core/macros.py +16 -3
- sqlmesh/core/model/common.py +198 -41
- sqlmesh/core/model/decorator.py +3 -0
- sqlmesh/core/model/definition.py +20 -11
- sqlmesh/core/model/meta.py +2 -0
- sqlmesh/core/plan/builder.py +40 -67
- sqlmesh/core/plan/common.py +19 -0
- sqlmesh/core/plan/stages.py +47 -8
- sqlmesh/core/snapshot/definition.py +49 -15
- sqlmesh/core/snapshot/evaluator.py +25 -4
- sqlmesh/core/state_sync/db/snapshot.py +3 -4
- sqlmesh/dbt/basemodel.py +5 -1
- sqlmesh/dbt/loader.py +5 -1
- sqlmesh/dbt/model.py +6 -1
- sqlmesh/dbt/seed.py +6 -1
- sqlmesh/migrations/v0088_add_virtual_environment_mode.py +5 -0
- sqlmesh/migrations/v0088_warn_about_variable_python_env_diffs.py +74 -0
- sqlmesh/utils/jinja.py +1 -1
- sqlmesh/utils/metaprogramming.py +12 -5
- {sqlmesh-0.209.1.dev12.dist-info → sqlmesh-0.209.1.dev14.dist-info}/METADATA +1 -1
- {sqlmesh-0.209.1.dev12.dist-info → sqlmesh-0.209.1.dev14.dist-info}/RECORD +35 -32
- {sqlmesh-0.209.1.dev12.dist-info → sqlmesh-0.209.1.dev14.dist-info}/WHEEL +0 -0
- {sqlmesh-0.209.1.dev12.dist-info → sqlmesh-0.209.1.dev14.dist-info}/entry_points.txt +0 -0
- {sqlmesh-0.209.1.dev12.dist-info → sqlmesh-0.209.1.dev14.dist-info}/licenses/LICENSE +0 -0
- {sqlmesh-0.209.1.dev12.dist-info → sqlmesh-0.209.1.dev14.dist-info}/top_level.txt +0 -0
sqlmesh/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.209.1.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 209, 1, '
|
|
31
|
+
__version__ = version = '0.209.1.dev14'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 209, 1, 'dev14')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
sqlmesh/core/audit/definition.py
CHANGED
|
@@ -438,13 +438,15 @@ def load_audit(
|
|
|
438
438
|
|
|
439
439
|
extra_kwargs: t.Dict[str, t.Any] = {}
|
|
440
440
|
if is_standalone:
|
|
441
|
-
jinja_macro_refrences,
|
|
441
|
+
jinja_macro_refrences, referenced_variables = extract_macro_references_and_variables(
|
|
442
442
|
*(gen(s) for s in statements),
|
|
443
443
|
gen(query),
|
|
444
444
|
)
|
|
445
445
|
jinja_macros = (jinja_macros or JinjaMacroRegistry()).trim(jinja_macro_refrences)
|
|
446
446
|
for jinja_macro in jinja_macros.root_macros.values():
|
|
447
|
-
|
|
447
|
+
referenced_variables.update(
|
|
448
|
+
extract_macro_references_and_variables(jinja_macro.definition)[1]
|
|
449
|
+
)
|
|
448
450
|
|
|
449
451
|
extra_kwargs["jinja_macros"] = jinja_macros
|
|
450
452
|
extra_kwargs["python_env"] = make_python_env(
|
|
@@ -453,7 +455,7 @@ def load_audit(
|
|
|
453
455
|
module_path,
|
|
454
456
|
macros or macro.get_registry(),
|
|
455
457
|
variables=variables,
|
|
456
|
-
|
|
458
|
+
referenced_variables=referenced_variables,
|
|
457
459
|
)
|
|
458
460
|
extra_kwargs["default_catalog"] = default_catalog
|
|
459
461
|
if project is not None:
|
sqlmesh/core/config/common.py
CHANGED
|
@@ -49,6 +49,35 @@ class EnvironmentSuffixTarget(str, Enum):
|
|
|
49
49
|
return str(self)
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
class VirtualEnvironmentMode(str, Enum):
|
|
53
|
+
"""Mode for virtual environment behavior.
|
|
54
|
+
|
|
55
|
+
FULL: Use full virtual environment functionality with versioned table names and virtual layer updates.
|
|
56
|
+
DEV_ONLY: Bypass virtual environments in production, using original unversioned model names.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
FULL = "full"
|
|
60
|
+
DEV_ONLY = "dev_only"
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def is_full(self) -> bool:
|
|
64
|
+
return self == VirtualEnvironmentMode.FULL
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def is_dev_only(self) -> bool:
|
|
68
|
+
return self == VirtualEnvironmentMode.DEV_ONLY
|
|
69
|
+
|
|
70
|
+
@classproperty
|
|
71
|
+
def default(cls) -> VirtualEnvironmentMode:
|
|
72
|
+
return VirtualEnvironmentMode.FULL
|
|
73
|
+
|
|
74
|
+
def __str__(self) -> str:
|
|
75
|
+
return self.name
|
|
76
|
+
|
|
77
|
+
def __repr__(self) -> str:
|
|
78
|
+
return str(self)
|
|
79
|
+
|
|
80
|
+
|
|
52
81
|
class TableNamingConvention(str, Enum):
|
|
53
82
|
# Causes table names at the physical layer to follow the convention:
|
|
54
83
|
# <schema-name>__<table-name>__<fingerprint>
|
sqlmesh/core/config/root.py
CHANGED
|
@@ -14,7 +14,11 @@ from sqlglot.optimizer.normalize_identifiers import normalize_identifiers
|
|
|
14
14
|
from sqlmesh.cicd.config import CICDBotConfig
|
|
15
15
|
from sqlmesh.core import constants as c
|
|
16
16
|
from sqlmesh.core.console import get_console
|
|
17
|
-
from sqlmesh.core.config import
|
|
17
|
+
from sqlmesh.core.config.common import (
|
|
18
|
+
EnvironmentSuffixTarget,
|
|
19
|
+
TableNamingConvention,
|
|
20
|
+
VirtualEnvironmentMode,
|
|
21
|
+
)
|
|
18
22
|
from sqlmesh.core.config.base import BaseConfig, UpdateStrategy
|
|
19
23
|
from sqlmesh.core.config.common import variables_validator, compile_regex_mapping
|
|
20
24
|
from sqlmesh.core.config.connection import (
|
|
@@ -110,6 +114,7 @@ class Config(BaseConfig):
|
|
|
110
114
|
physical_schema_mapping: A mapping from regular expressions to names of schemas in which physical tables for corresponding models will be placed.
|
|
111
115
|
environment_suffix_target: Indicates whether to append the environment name to the schema or table name.
|
|
112
116
|
physical_table_naming_convention: Indicates how tables should be named at the physical layer
|
|
117
|
+
virtual_environment_mode: Indicates how environments should be handled.
|
|
113
118
|
gateway_managed_virtual_layer: Whether the models' views in the virtual layer are created by the model-specific gateway rather than the default gateway.
|
|
114
119
|
infer_python_dependencies: Whether to statically analyze Python code to automatically infer Python package requirements.
|
|
115
120
|
environment_catalog_mapping: A mapping from regular expressions to catalog names. The catalog name is used to determine the target catalog for a given environment.
|
|
@@ -148,12 +153,9 @@ class Config(BaseConfig):
|
|
|
148
153
|
env_vars: t.Dict[str, str] = {}
|
|
149
154
|
username: str = ""
|
|
150
155
|
physical_schema_mapping: RegexKeyDict = {}
|
|
151
|
-
environment_suffix_target: EnvironmentSuffixTarget =
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
physical_table_naming_convention: TableNamingConvention = Field(
|
|
155
|
-
default=TableNamingConvention.default
|
|
156
|
-
)
|
|
156
|
+
environment_suffix_target: EnvironmentSuffixTarget = EnvironmentSuffixTarget.default
|
|
157
|
+
physical_table_naming_convention: TableNamingConvention = TableNamingConvention.default
|
|
158
|
+
virtual_environment_mode: VirtualEnvironmentMode = VirtualEnvironmentMode.default
|
|
157
159
|
gateway_managed_virtual_layer: bool = False
|
|
158
160
|
infer_python_dependencies: bool = True
|
|
159
161
|
environment_catalog_mapping: RegexKeyDict = {}
|
|
@@ -260,6 +262,11 @@ class Config(BaseConfig):
|
|
|
260
262
|
"Please specify one or the other"
|
|
261
263
|
)
|
|
262
264
|
|
|
265
|
+
if self.plan.use_finalized_state and not self.virtual_environment_mode.is_full:
|
|
266
|
+
raise ConfigError(
|
|
267
|
+
"Using the finalized state is only supported when `virtual_environment_mode` is set to `full`."
|
|
268
|
+
)
|
|
269
|
+
|
|
263
270
|
if self.environment_catalog_mapping:
|
|
264
271
|
_normalize_identifiers("environment_catalog_mapping")
|
|
265
272
|
if self.physical_schema_mapping:
|
sqlmesh/core/constants.py
CHANGED
|
@@ -80,7 +80,9 @@ REQUIREMENTS = "sqlmesh-requirements.lock"
|
|
|
80
80
|
DEFAULT_SCHEMA = "default"
|
|
81
81
|
|
|
82
82
|
SQLMESH_VARS = "__sqlmesh__vars__"
|
|
83
|
+
SQLMESH_VARS_METADATA = "__sqlmesh__vars__metadata__"
|
|
83
84
|
SQLMESH_BLUEPRINT_VARS = "__sqlmesh__blueprint__vars__"
|
|
85
|
+
SQLMESH_BLUEPRINT_VARS_METADATA = "__sqlmesh__blueprint__vars__metadata__"
|
|
84
86
|
|
|
85
87
|
VAR = "var"
|
|
86
88
|
BLUEPRINT_VAR = "blueprint_var"
|
sqlmesh/core/context.py
CHANGED
|
@@ -1616,6 +1616,11 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
1616
1616
|
max_interval_end_per_model,
|
|
1617
1617
|
)
|
|
1618
1618
|
|
|
1619
|
+
if not self.config.virtual_environment_mode.is_full:
|
|
1620
|
+
forward_only = True
|
|
1621
|
+
elif forward_only is None:
|
|
1622
|
+
forward_only = self.config.plan.forward_only
|
|
1623
|
+
|
|
1619
1624
|
return self.PLAN_BUILDER_TYPE(
|
|
1620
1625
|
context_diff=context_diff,
|
|
1621
1626
|
start=start,
|
|
@@ -1628,9 +1633,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
1628
1633
|
skip_backfill=skip_backfill,
|
|
1629
1634
|
empty_backfill=empty_backfill,
|
|
1630
1635
|
is_dev=is_dev,
|
|
1631
|
-
forward_only=
|
|
1632
|
-
forward_only if forward_only is not None else self.config.plan.forward_only
|
|
1633
|
-
),
|
|
1636
|
+
forward_only=forward_only,
|
|
1634
1637
|
allow_destructive_models=expanded_destructive_models,
|
|
1635
1638
|
environment_ttl=environment_ttl,
|
|
1636
1639
|
environment_suffix_target=self.config.environment_suffix_target,
|
|
@@ -2936,7 +2939,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
2936
2939
|
def _plan_preview_enabled(self) -> bool:
|
|
2937
2940
|
if self.config.plan.enable_preview is not None:
|
|
2938
2941
|
return self.config.plan.enable_preview
|
|
2939
|
-
# It is dangerous to enable preview by default for dbt projects that rely on engines that don
|
|
2942
|
+
# It is dangerous to enable preview by default for dbt projects that rely on engines that don't support cloning.
|
|
2940
2943
|
# Enabling previews in such cases can result in unintended full refreshes because dbt incremental models rely on
|
|
2941
2944
|
# the maximum timestamp value in the target table.
|
|
2942
2945
|
return self._project_type == c.NATIVE or self.engine_adapter.SUPPORTS_CLONING
|
|
@@ -32,6 +32,7 @@ from sqlmesh.core.engine_adapter.shared import (
|
|
|
32
32
|
CommentCreationTable,
|
|
33
33
|
CommentCreationView,
|
|
34
34
|
DataObject,
|
|
35
|
+
DataObjectType,
|
|
35
36
|
EngineRunMode,
|
|
36
37
|
InsertOverwriteStrategy,
|
|
37
38
|
SourceQuery,
|
|
@@ -39,13 +40,13 @@ from sqlmesh.core.engine_adapter.shared import (
|
|
|
39
40
|
)
|
|
40
41
|
from sqlmesh.core.model.kind import TimeColumn
|
|
41
42
|
from sqlmesh.core.schema_diff import SchemaDiffer
|
|
42
|
-
from sqlmesh.utils import columns_to_types_all_known, random_id
|
|
43
|
-
from sqlmesh.utils.connection_pool import
|
|
43
|
+
from sqlmesh.utils import CorrelationId, columns_to_types_all_known, random_id
|
|
44
|
+
from sqlmesh.utils.connection_pool import ConnectionPool, create_connection_pool
|
|
44
45
|
from sqlmesh.utils.date import TimeLike, make_inclusive, to_time_column
|
|
45
46
|
from sqlmesh.utils.errors import (
|
|
47
|
+
MissingDefaultCatalogError,
|
|
46
48
|
SQLMeshError,
|
|
47
49
|
UnsupportedCatalogOperationError,
|
|
48
|
-
MissingDefaultCatalogError,
|
|
49
50
|
)
|
|
50
51
|
from sqlmesh.utils.pandas import columns_to_types_from_df
|
|
51
52
|
|
|
@@ -54,8 +55,8 @@ if t.TYPE_CHECKING:
|
|
|
54
55
|
|
|
55
56
|
from sqlmesh.core._typing import SchemaName, SessionProperties, TableName
|
|
56
57
|
from sqlmesh.core.engine_adapter._typing import (
|
|
57
|
-
BigframeSession,
|
|
58
58
|
DF,
|
|
59
|
+
BigframeSession,
|
|
59
60
|
PySparkDataFrame,
|
|
60
61
|
PySparkSession,
|
|
61
62
|
Query,
|
|
@@ -369,6 +370,12 @@ class EngineAdapter:
|
|
|
369
370
|
kwargs: Optional create table properties.
|
|
370
371
|
"""
|
|
371
372
|
target_table = exp.to_table(table_name)
|
|
373
|
+
|
|
374
|
+
target_data_object = self.get_data_object(target_table)
|
|
375
|
+
table_exists = target_data_object is not None
|
|
376
|
+
if self.drop_data_object_on_type_mismatch(target_data_object, DataObjectType.TABLE):
|
|
377
|
+
table_exists = False
|
|
378
|
+
|
|
372
379
|
source_queries, columns_to_types = self._get_source_queries_and_columns_to_types(
|
|
373
380
|
query_or_df, columns_to_types, target_table=target_table
|
|
374
381
|
)
|
|
@@ -390,7 +397,7 @@ class EngineAdapter:
|
|
|
390
397
|
)
|
|
391
398
|
# All engines support `CREATE TABLE AS` so we use that if the table doesn't already exist and we
|
|
392
399
|
# use `CREATE OR REPLACE TABLE AS` if the engine supports it
|
|
393
|
-
if self.SUPPORTS_REPLACE_TABLE or not
|
|
400
|
+
if self.SUPPORTS_REPLACE_TABLE or not table_exists:
|
|
394
401
|
return self._create_table_from_source_queries(
|
|
395
402
|
target_table,
|
|
396
403
|
source_queries,
|
|
@@ -930,6 +937,28 @@ class EngineAdapter:
|
|
|
930
937
|
)
|
|
931
938
|
)
|
|
932
939
|
|
|
940
|
+
def drop_data_object(self, data_object: DataObject, ignore_if_not_exists: bool = True) -> None:
|
|
941
|
+
"""Drops a data object of arbitrary type.
|
|
942
|
+
|
|
943
|
+
Args:
|
|
944
|
+
data_object: The data object to drop.
|
|
945
|
+
ignore_if_not_exists: If True, no error will be raised if the data object does not exist.
|
|
946
|
+
"""
|
|
947
|
+
if data_object.type.is_view:
|
|
948
|
+
self.drop_view(data_object.to_table(), ignore_if_not_exists=ignore_if_not_exists)
|
|
949
|
+
elif data_object.type.is_materialized_view:
|
|
950
|
+
self.drop_view(
|
|
951
|
+
data_object.to_table(), ignore_if_not_exists=ignore_if_not_exists, materialized=True
|
|
952
|
+
)
|
|
953
|
+
elif data_object.type.is_table:
|
|
954
|
+
self.drop_table(data_object.to_table(), exists=ignore_if_not_exists)
|
|
955
|
+
elif data_object.type.is_managed_table:
|
|
956
|
+
self.drop_managed_table(data_object.to_table(), exists=ignore_if_not_exists)
|
|
957
|
+
else:
|
|
958
|
+
raise SQLMeshError(
|
|
959
|
+
f"Can't drop data object '{data_object.to_table().sql(dialect=self.dialect)}' of type '{data_object.type.value}'"
|
|
960
|
+
)
|
|
961
|
+
|
|
933
962
|
def drop_table(self, table_name: TableName, exists: bool = True) -> None:
|
|
934
963
|
"""Drops a table.
|
|
935
964
|
|
|
@@ -1118,6 +1147,12 @@ class EngineAdapter:
|
|
|
1118
1147
|
if properties.expressions:
|
|
1119
1148
|
create_kwargs["properties"] = properties
|
|
1120
1149
|
|
|
1150
|
+
if replace:
|
|
1151
|
+
self.drop_data_object_on_type_mismatch(
|
|
1152
|
+
self.get_data_object(view_name),
|
|
1153
|
+
DataObjectType.VIEW if not materialized else DataObjectType.MATERIALIZED_VIEW,
|
|
1154
|
+
)
|
|
1155
|
+
|
|
1121
1156
|
with source_queries[0] as query:
|
|
1122
1157
|
self.execute(
|
|
1123
1158
|
exp.Create(
|
|
@@ -2022,6 +2057,15 @@ class EngineAdapter:
|
|
|
2022
2057
|
)
|
|
2023
2058
|
self._rename_table(old_table_name, new_table_name)
|
|
2024
2059
|
|
|
2060
|
+
def get_data_object(self, target_name: TableName) -> t.Optional[DataObject]:
|
|
2061
|
+
target_table = exp.to_table(target_name)
|
|
2062
|
+
existing_data_objects = self.get_data_objects(
|
|
2063
|
+
schema_(target_table.db, target_table.catalog), {target_table.name}
|
|
2064
|
+
)
|
|
2065
|
+
if existing_data_objects:
|
|
2066
|
+
return existing_data_objects[0]
|
|
2067
|
+
return None
|
|
2068
|
+
|
|
2025
2069
|
def get_data_objects(
|
|
2026
2070
|
self, schema_name: SchemaName, object_names: t.Optional[t.Set[str]] = None
|
|
2027
2071
|
) -> t.List[DataObject]:
|
|
@@ -2483,6 +2527,30 @@ class EngineAdapter:
|
|
|
2483
2527
|
table = exp.to_table(table_name)
|
|
2484
2528
|
self.execute(f"TRUNCATE TABLE {table.sql(dialect=self.dialect, identify=True)}")
|
|
2485
2529
|
|
|
2530
|
+
def drop_data_object_on_type_mismatch(
|
|
2531
|
+
self, data_object: t.Optional[DataObject], expected_type: DataObjectType
|
|
2532
|
+
) -> bool:
|
|
2533
|
+
"""Drops a data object if it exists and is not of the expected type.
|
|
2534
|
+
|
|
2535
|
+
Args:
|
|
2536
|
+
data_object: The data object to check.
|
|
2537
|
+
expected_type: The expected type of the data object.
|
|
2538
|
+
|
|
2539
|
+
Returns:
|
|
2540
|
+
True if the data object was dropped, False otherwise.
|
|
2541
|
+
"""
|
|
2542
|
+
if data_object is None or data_object.type == expected_type:
|
|
2543
|
+
return False
|
|
2544
|
+
|
|
2545
|
+
logger.warning(
|
|
2546
|
+
"Target data object '%s' is a %s and not a %s, dropping it",
|
|
2547
|
+
data_object.to_table().sql(dialect=self.dialect),
|
|
2548
|
+
data_object.type.value,
|
|
2549
|
+
expected_type.value,
|
|
2550
|
+
)
|
|
2551
|
+
self.drop_data_object(data_object)
|
|
2552
|
+
return True
|
|
2553
|
+
|
|
2486
2554
|
def _replace_by_key(
|
|
2487
2555
|
self,
|
|
2488
2556
|
target_table: TableName,
|
|
@@ -262,7 +262,12 @@ class RedshiftEngineAdapter(
|
|
|
262
262
|
"""
|
|
263
263
|
import pandas as pd
|
|
264
264
|
|
|
265
|
-
|
|
265
|
+
target_data_object = self.get_data_object(table_name)
|
|
266
|
+
table_exists = target_data_object is not None
|
|
267
|
+
if self.drop_data_object_on_type_mismatch(target_data_object, DataObjectType.TABLE):
|
|
268
|
+
table_exists = False
|
|
269
|
+
|
|
270
|
+
if not isinstance(query_or_df, pd.DataFrame) or not table_exists:
|
|
266
271
|
return super().replace_query(
|
|
267
272
|
table_name,
|
|
268
273
|
query_or_df,
|
|
@@ -171,6 +171,9 @@ class DataObject(PydanticModel):
|
|
|
171
171
|
def is_clustered(self) -> bool:
|
|
172
172
|
return bool(self.clustering_key)
|
|
173
173
|
|
|
174
|
+
def to_table(self) -> exp.Table:
|
|
175
|
+
return exp.table_(self.name, db=self.schema_name, catalog=self.catalog, quoted=True)
|
|
176
|
+
|
|
174
177
|
|
|
175
178
|
class CatalogSupport(Enum):
|
|
176
179
|
# The engine has no concept of catalogs
|
sqlmesh/core/loader.py
CHANGED
|
@@ -603,6 +603,7 @@ class SqlMeshLoader(Loader):
|
|
|
603
603
|
infer_names=self.config.model_naming.infer_names,
|
|
604
604
|
signal_definitions=signals,
|
|
605
605
|
default_catalog_per_gateway=self.context.default_catalog_per_gateway,
|
|
606
|
+
virtual_environment_mode=self.config.virtual_environment_mode,
|
|
606
607
|
**loading_default_kwargs or {},
|
|
607
608
|
)
|
|
608
609
|
|
|
@@ -683,6 +684,7 @@ class SqlMeshLoader(Loader):
|
|
|
683
684
|
audit_definitions=audits,
|
|
684
685
|
signal_definitions=signals,
|
|
685
686
|
default_catalog_per_gateway=self.context.default_catalog_per_gateway,
|
|
687
|
+
virtual_environment_mode=self.config.virtual_environment_mode,
|
|
686
688
|
):
|
|
687
689
|
if model.enabled:
|
|
688
690
|
models[model.fqn] = model
|
sqlmesh/core/macros.py
CHANGED
|
@@ -210,7 +210,12 @@ class MacroEvaluator:
|
|
|
210
210
|
self.macros[normalize_macro_name(k)] = self.env[k]
|
|
211
211
|
elif v.is_value:
|
|
212
212
|
value = self.env[k]
|
|
213
|
-
if k in (
|
|
213
|
+
if k in (
|
|
214
|
+
c.SQLMESH_VARS,
|
|
215
|
+
c.SQLMESH_VARS_METADATA,
|
|
216
|
+
c.SQLMESH_BLUEPRINT_VARS,
|
|
217
|
+
c.SQLMESH_BLUEPRINT_VARS_METADATA,
|
|
218
|
+
):
|
|
214
219
|
value = {
|
|
215
220
|
var_name: (
|
|
216
221
|
self.parse_one(var_value.sql)
|
|
@@ -557,17 +562,25 @@ class MacroEvaluator:
|
|
|
557
562
|
|
|
558
563
|
def var(self, var_name: str, default: t.Optional[t.Any] = None) -> t.Optional[t.Any]:
|
|
559
564
|
"""Returns the value of the specified variable, or the default value if it doesn't exist."""
|
|
560
|
-
return
|
|
565
|
+
return {
|
|
566
|
+
**(self.locals.get(c.SQLMESH_VARS) or {}),
|
|
567
|
+
**(self.locals.get(c.SQLMESH_VARS_METADATA) or {}),
|
|
568
|
+
}.get(var_name.lower(), default)
|
|
561
569
|
|
|
562
570
|
def blueprint_var(self, var_name: str, default: t.Optional[t.Any] = None) -> t.Optional[t.Any]:
|
|
563
571
|
"""Returns the value of the specified blueprint variable, or the default value if it doesn't exist."""
|
|
564
|
-
return
|
|
572
|
+
return {
|
|
573
|
+
**(self.locals.get(c.SQLMESH_BLUEPRINT_VARS) or {}),
|
|
574
|
+
**(self.locals.get(c.SQLMESH_BLUEPRINT_VARS_METADATA) or {}),
|
|
575
|
+
}.get(var_name.lower(), default)
|
|
565
576
|
|
|
566
577
|
@property
|
|
567
578
|
def variables(self) -> t.Dict[str, t.Any]:
|
|
568
579
|
return {
|
|
569
580
|
**self.locals.get(c.SQLMESH_VARS, {}),
|
|
581
|
+
**self.locals.get(c.SQLMESH_VARS_METADATA, {}),
|
|
570
582
|
**self.locals.get(c.SQLMESH_BLUEPRINT_VARS, {}),
|
|
583
|
+
**self.locals.get(c.SQLMESH_BLUEPRINT_VARS_METADATA, {}),
|
|
571
584
|
}
|
|
572
585
|
|
|
573
586
|
def _coerce(self, expr: exp.Expression, typ: t.Any, strict: bool = False) -> t.Any:
|