sqlmesh 0.194.2.dev2__py3-none-any.whl → 0.194.2.dev4__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/config/common.py +17 -0
- sqlmesh/core/config/root.py +9 -0
- sqlmesh/core/constants.py +1 -0
- sqlmesh/core/engine_adapter/base.py +17 -0
- sqlmesh/core/engine_adapter/duckdb.py +14 -0
- sqlmesh/core/engine_adapter/shared.py +7 -0
- sqlmesh/core/engine_adapter/snowflake.py +33 -0
- sqlmesh/core/environment.py +4 -0
- sqlmesh/core/snapshot/definition.py +9 -9
- sqlmesh/core/snapshot/evaluator.py +14 -0
- sqlmesh/core/state_sync/common.py +26 -2
- sqlmesh/lsp/reference.py +134 -0
- {sqlmesh-0.194.2.dev2.dist-info → sqlmesh-0.194.2.dev4.dist-info}/METADATA +1 -1
- {sqlmesh-0.194.2.dev2.dist-info → sqlmesh-0.194.2.dev4.dist-info}/RECORD +19 -19
- {sqlmesh-0.194.2.dev2.dist-info → sqlmesh-0.194.2.dev4.dist-info}/WHEEL +0 -0
- {sqlmesh-0.194.2.dev2.dist-info → sqlmesh-0.194.2.dev4.dist-info}/entry_points.txt +0 -0
- {sqlmesh-0.194.2.dev2.dist-info → sqlmesh-0.194.2.dev4.dist-info}/licenses/LICENSE +0 -0
- {sqlmesh-0.194.2.dev2.dist-info → sqlmesh-0.194.2.dev4.dist-info}/top_level.txt +0 -0
sqlmesh/_version.py
CHANGED
|
@@ -17,5 +17,5 @@ __version__: str
|
|
|
17
17
|
__version_tuple__: VERSION_TUPLE
|
|
18
18
|
version_tuple: VERSION_TUPLE
|
|
19
19
|
|
|
20
|
-
__version__ = version = '0.194.2.
|
|
21
|
-
__version_tuple__ = version_tuple = (0, 194, 2, '
|
|
20
|
+
__version__ = version = '0.194.2.dev4'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 194, 2, 'dev4')
|
sqlmesh/core/config/common.py
CHANGED
|
@@ -10,9 +10,22 @@ from sqlmesh.utils.pydantic import field_validator
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class EnvironmentSuffixTarget(str, Enum):
|
|
13
|
+
# Intended to create virtual environments in their own schemas, with names like "<model_schema_name>__<env name>". The view name is untouched.
|
|
14
|
+
# For example, a model named 'sqlmesh_example.full_model' created in an environment called 'dev'
|
|
15
|
+
# would have its virtual layer view created as 'sqlmesh_example__dev.full_model'
|
|
13
16
|
SCHEMA = "schema"
|
|
17
|
+
|
|
18
|
+
# Intended to create virtual environments in the same schema as their production counterparts by adjusting the table name.
|
|
19
|
+
# For example, a model named 'sqlmesh_example.full_model' created in an environment called 'dev'
|
|
20
|
+
# would have its virtual layer view created as "sqlmesh_example.full_model__dev"
|
|
14
21
|
TABLE = "table"
|
|
15
22
|
|
|
23
|
+
# Intended to create virtual environments in their own catalogs to preserve the schema and view name of the models
|
|
24
|
+
# For example, a model named 'sqlmesh_example.full_model' created in an environment called 'dev'
|
|
25
|
+
# with a default catalog of "warehouse" would have its virtual layer view created as "warehouse__dev.sqlmesh_example.full_model"
|
|
26
|
+
# note: this only works for engines that can query across catalogs
|
|
27
|
+
CATALOG = "catalog"
|
|
28
|
+
|
|
16
29
|
@property
|
|
17
30
|
def is_schema(self) -> bool:
|
|
18
31
|
return self == EnvironmentSuffixTarget.SCHEMA
|
|
@@ -21,6 +34,10 @@ class EnvironmentSuffixTarget(str, Enum):
|
|
|
21
34
|
def is_table(self) -> bool:
|
|
22
35
|
return self == EnvironmentSuffixTarget.TABLE
|
|
23
36
|
|
|
37
|
+
@property
|
|
38
|
+
def is_catalog(self) -> bool:
|
|
39
|
+
return self == EnvironmentSuffixTarget.CATALOG
|
|
40
|
+
|
|
24
41
|
@classproperty
|
|
25
42
|
def default(cls) -> EnvironmentSuffixTarget:
|
|
26
43
|
return EnvironmentSuffixTarget.SCHEMA
|
sqlmesh/core/config/root.py
CHANGED
|
@@ -242,6 +242,15 @@ class Config(BaseConfig):
|
|
|
242
242
|
},
|
|
243
243
|
)
|
|
244
244
|
|
|
245
|
+
if (
|
|
246
|
+
self.environment_suffix_target == EnvironmentSuffixTarget.CATALOG
|
|
247
|
+
and self.environment_catalog_mapping
|
|
248
|
+
):
|
|
249
|
+
raise ConfigError(
|
|
250
|
+
f"'environment_suffix_target: catalog' is mutually exclusive with 'environment_catalog_mapping'.\n"
|
|
251
|
+
"Please specify one or the other"
|
|
252
|
+
)
|
|
253
|
+
|
|
245
254
|
if self.environment_catalog_mapping:
|
|
246
255
|
_normalize_identifiers("environment_catalog_mapping")
|
|
247
256
|
if self.physical_schema_mapping:
|
sqlmesh/core/constants.py
CHANGED
|
@@ -101,6 +101,7 @@ class EngineAdapter:
|
|
|
101
101
|
SUPPORTS_VIEW_SCHEMA = True
|
|
102
102
|
SUPPORTS_CLONING = False
|
|
103
103
|
SUPPORTS_MANAGED_MODELS = False
|
|
104
|
+
SUPPORTS_CREATE_DROP_CATALOG = False
|
|
104
105
|
SCHEMA_DIFFER = SchemaDiffer()
|
|
105
106
|
SUPPORTS_TUPLE_IN = True
|
|
106
107
|
HAS_VIEW_BINDING = False
|
|
@@ -1217,6 +1218,22 @@ class EngineAdapter:
|
|
|
1217
1218
|
**kwargs,
|
|
1218
1219
|
)
|
|
1219
1220
|
|
|
1221
|
+
def create_catalog(self, catalog_name: str | exp.Identifier) -> None:
|
|
1222
|
+
return self._create_catalog(exp.parse_identifier(catalog_name, dialect=self.dialect))
|
|
1223
|
+
|
|
1224
|
+
def _create_catalog(self, catalog_name: exp.Identifier) -> None:
|
|
1225
|
+
raise SQLMeshError(
|
|
1226
|
+
f"Unable to create catalog '{catalog_name.sql(dialect=self.dialect)}' as automatic catalog management is not implemented in the {self.dialect} engine."
|
|
1227
|
+
)
|
|
1228
|
+
|
|
1229
|
+
def drop_catalog(self, catalog_name: str | exp.Identifier) -> None:
|
|
1230
|
+
return self._drop_catalog(exp.parse_identifier(catalog_name, dialect=self.dialect))
|
|
1231
|
+
|
|
1232
|
+
def _drop_catalog(self, catalog_name: exp.Identifier) -> None:
|
|
1233
|
+
raise SQLMeshError(
|
|
1234
|
+
f"Unable to drop catalog '{catalog_name.sql(dialect=self.dialect)}' as automatic catalog management is not implemented in the {self.dialect} engine."
|
|
1235
|
+
)
|
|
1236
|
+
|
|
1220
1237
|
def columns(
|
|
1221
1238
|
self, table_name: TableName, include_pseudo_columns: bool = False
|
|
1222
1239
|
) -> t.Dict[str, exp.DataType]:
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import typing as t
|
|
4
4
|
from sqlglot import exp
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
from sqlmesh.core.engine_adapter.mixins import (
|
|
7
8
|
GetCurrentCatalogFromFunctionMixin,
|
|
@@ -35,6 +36,7 @@ class DuckDBEngineAdapter(LogicalMergeMixin, GetCurrentCatalogFromFunctionMixin,
|
|
|
35
36
|
)
|
|
36
37
|
COMMENT_CREATION_TABLE = CommentCreationTable.COMMENT_COMMAND_ONLY
|
|
37
38
|
COMMENT_CREATION_VIEW = CommentCreationView.COMMENT_COMMAND_ONLY
|
|
39
|
+
SUPPORTS_CREATE_DROP_CATALOG = True
|
|
38
40
|
|
|
39
41
|
@property
|
|
40
42
|
def catalog_support(self) -> CatalogSupport:
|
|
@@ -44,6 +46,18 @@ class DuckDBEngineAdapter(LogicalMergeMixin, GetCurrentCatalogFromFunctionMixin,
|
|
|
44
46
|
"""Sets the catalog name of the current connection."""
|
|
45
47
|
self.execute(exp.Use(this=exp.to_identifier(catalog)))
|
|
46
48
|
|
|
49
|
+
def _create_catalog(self, catalog_name: exp.Identifier) -> None:
|
|
50
|
+
db_filename = f"{catalog_name.output_name}.db"
|
|
51
|
+
self.execute(
|
|
52
|
+
exp.Attach(this=exp.alias_(exp.Literal.string(db_filename), catalog_name), exists=True)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
def _drop_catalog(self, catalog_name: exp.Identifier) -> None:
|
|
56
|
+
db_file_path = Path(f"{catalog_name.output_name}.db")
|
|
57
|
+
self.execute(exp.Detach(this=catalog_name, exists=True))
|
|
58
|
+
if db_file_path.exists():
|
|
59
|
+
db_file_path.unlink()
|
|
60
|
+
|
|
47
61
|
def _df_to_source_queries(
|
|
48
62
|
self,
|
|
49
63
|
df: DF,
|
|
@@ -173,9 +173,16 @@ class DataObject(PydanticModel):
|
|
|
173
173
|
|
|
174
174
|
|
|
175
175
|
class CatalogSupport(Enum):
|
|
176
|
+
# The engine has no concept of catalogs
|
|
176
177
|
UNSUPPORTED = 1
|
|
178
|
+
|
|
179
|
+
# The engine has a concept of catalogs, but they are isolated from each other and cannot reference each others tables
|
|
177
180
|
SINGLE_CATALOG_ONLY = 2
|
|
181
|
+
|
|
182
|
+
# The engine supports multiple catalogs but some operations require a SET CATALOG query to set the active catalog before proceeding
|
|
178
183
|
REQUIRES_SET_CATALOG = 3
|
|
184
|
+
|
|
185
|
+
# The engine supports multiple catalogs and can unambiguously target a specific catalog when performing operations (without running SET CATALOG first)
|
|
179
186
|
FULL_SUPPORT = 4
|
|
180
187
|
|
|
181
188
|
@property
|
|
@@ -9,6 +9,7 @@ from sqlglot.helper import ensure_list
|
|
|
9
9
|
from sqlglot.optimizer.normalize_identifiers import normalize_identifiers
|
|
10
10
|
from sqlglot.optimizer.qualify_columns import quote_identifiers
|
|
11
11
|
|
|
12
|
+
import sqlmesh.core.constants as c
|
|
12
13
|
from sqlmesh.core.dialect import to_schema
|
|
13
14
|
from sqlmesh.core.engine_adapter.mixins import (
|
|
14
15
|
GetCurrentCatalogFromFunctionMixin,
|
|
@@ -43,6 +44,7 @@ if t.TYPE_CHECKING:
|
|
|
43
44
|
"_get_data_objects": CatalogSupport.REQUIRES_SET_CATALOG,
|
|
44
45
|
"create_schema": CatalogSupport.REQUIRES_SET_CATALOG,
|
|
45
46
|
"drop_schema": CatalogSupport.REQUIRES_SET_CATALOG,
|
|
47
|
+
"drop_catalog": CatalogSupport.REQUIRES_SET_CATALOG, # needs a catalog to issue a query to information_schema.databases even though the result is global
|
|
46
48
|
}
|
|
47
49
|
)
|
|
48
50
|
class SnowflakeEngineAdapter(GetCurrentCatalogFromFunctionMixin, ClusteredByMixin, RowDiffMixin):
|
|
@@ -52,6 +54,7 @@ class SnowflakeEngineAdapter(GetCurrentCatalogFromFunctionMixin, ClusteredByMixi
|
|
|
52
54
|
SUPPORTS_CLONING = True
|
|
53
55
|
SUPPORTS_MANAGED_MODELS = True
|
|
54
56
|
CURRENT_CATALOG_EXPRESSION = exp.func("current_database")
|
|
57
|
+
SUPPORTS_CREATE_DROP_CATALOG = True
|
|
55
58
|
SCHEMA_DIFFER = SchemaDiffer(
|
|
56
59
|
parameterized_type_defaults={
|
|
57
60
|
exp.DataType.build("BINARY", dialect=DIALECT).this: [(8388608,)],
|
|
@@ -123,6 +126,36 @@ class SnowflakeEngineAdapter(GetCurrentCatalogFromFunctionMixin, ClusteredByMixi
|
|
|
123
126
|
def catalog_support(self) -> CatalogSupport:
|
|
124
127
|
return CatalogSupport.FULL_SUPPORT
|
|
125
128
|
|
|
129
|
+
def _create_catalog(self, catalog_name: exp.Identifier) -> None:
|
|
130
|
+
props = exp.Properties(
|
|
131
|
+
expressions=[exp.SchemaCommentProperty(this=exp.Literal.string(c.SQLMESH_MANAGED))]
|
|
132
|
+
)
|
|
133
|
+
self.execute(
|
|
134
|
+
exp.Create(
|
|
135
|
+
this=exp.Table(this=catalog_name), kind="DATABASE", exists=True, properties=props
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
def _drop_catalog(self, catalog_name: exp.Identifier) -> None:
|
|
140
|
+
# only drop the catalog if it was created by SQLMesh, which is indicated by its comment matching {c.SQLMESH_MANAGED}
|
|
141
|
+
exists_check = (
|
|
142
|
+
exp.select(exp.Literal.number(1))
|
|
143
|
+
.from_(exp.to_table("information_schema.databases"))
|
|
144
|
+
.where(
|
|
145
|
+
exp.and_(
|
|
146
|
+
exp.column("database_name").eq(exp.Literal.string(catalog_name)),
|
|
147
|
+
exp.column("comment").eq(exp.Literal.string(c.SQLMESH_MANAGED)),
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
)
|
|
151
|
+
normalize_identifiers(exists_check, dialect=self.dialect)
|
|
152
|
+
if self.fetchone(exists_check, quote_identifiers=True) is not None:
|
|
153
|
+
self.execute(exp.Drop(this=exp.Table(this=catalog_name), kind="DATABASE", exists=True))
|
|
154
|
+
else:
|
|
155
|
+
logger.warning(
|
|
156
|
+
f"Not dropping database {catalog_name.sql(dialect=self.dialect)} because there is no indication it is '{c.SQLMESH_MANAGED}'"
|
|
157
|
+
)
|
|
158
|
+
|
|
126
159
|
def _create_table(
|
|
127
160
|
self,
|
|
128
161
|
table_name_or_schema: t.Union[exp.Schema, TableName],
|
sqlmesh/core/environment.py
CHANGED
|
@@ -43,6 +43,10 @@ class EnvironmentNamingInfo(PydanticModel):
|
|
|
43
43
|
normalize_name: bool = True
|
|
44
44
|
gateway_managed: bool = False
|
|
45
45
|
|
|
46
|
+
@property
|
|
47
|
+
def is_dev(self) -> bool:
|
|
48
|
+
return self.name.lower() != c.PROD
|
|
49
|
+
|
|
46
50
|
@field_validator("name", mode="before")
|
|
47
51
|
@classmethod
|
|
48
52
|
def _sanitize_name(cls, v: str) -> str:
|
|
@@ -274,13 +274,19 @@ class QualifiedViewName(PydanticModel, frozen=True):
|
|
|
274
274
|
def catalog_for_environment(
|
|
275
275
|
self, environment_naming_info: EnvironmentNamingInfo, dialect: DialectType = None
|
|
276
276
|
) -> t.Optional[str]:
|
|
277
|
-
|
|
277
|
+
catalog_name: t.Optional[str] = None
|
|
278
|
+
if environment_naming_info.is_dev and environment_naming_info.suffix_target.is_catalog:
|
|
279
|
+
catalog_name = f"{self.catalog}__{environment_naming_info.name}"
|
|
280
|
+
elif environment_naming_info.catalog_name_override:
|
|
278
281
|
catalog_name = environment_naming_info.catalog_name_override
|
|
282
|
+
|
|
283
|
+
if catalog_name:
|
|
279
284
|
return (
|
|
280
285
|
normalize_identifiers(catalog_name, dialect=dialect).name
|
|
281
286
|
if environment_naming_info.normalize_name
|
|
282
287
|
else catalog_name
|
|
283
288
|
)
|
|
289
|
+
|
|
284
290
|
return self.catalog
|
|
285
291
|
|
|
286
292
|
def schema_for_environment(
|
|
@@ -295,10 +301,7 @@ class QualifiedViewName(PydanticModel, frozen=True):
|
|
|
295
301
|
if normalize:
|
|
296
302
|
schema = normalize_identifiers(schema, dialect=dialect).name
|
|
297
303
|
|
|
298
|
-
if
|
|
299
|
-
environment_naming_info.name.lower() != c.PROD
|
|
300
|
-
and environment_naming_info.suffix_target.is_schema
|
|
301
|
-
):
|
|
304
|
+
if environment_naming_info.is_dev and environment_naming_info.suffix_target.is_schema:
|
|
302
305
|
env_name = environment_naming_info.name
|
|
303
306
|
if normalize:
|
|
304
307
|
env_name = normalize_identifiers(env_name, dialect=dialect).name
|
|
@@ -311,10 +314,7 @@ class QualifiedViewName(PydanticModel, frozen=True):
|
|
|
311
314
|
self, environment_naming_info: EnvironmentNamingInfo, dialect: DialectType = None
|
|
312
315
|
) -> str:
|
|
313
316
|
table = self.table
|
|
314
|
-
if
|
|
315
|
-
environment_naming_info.name.lower() != c.PROD
|
|
316
|
-
and environment_naming_info.suffix_target.is_table
|
|
317
|
-
):
|
|
317
|
+
if environment_naming_info.is_dev and environment_naming_info.suffix_target.is_table:
|
|
318
318
|
env_name = environment_naming_info.name
|
|
319
319
|
if environment_naming_info.normalize_name:
|
|
320
320
|
env_name = normalize_identifiers(env_name, dialect=dialect).name
|
|
@@ -251,6 +251,8 @@ class SnapshotEvaluator:
|
|
|
251
251
|
|
|
252
252
|
# A schema can be shared across multiple engines, so we need to group by gateway
|
|
253
253
|
for gateway, tables in tables_by_gateway.items():
|
|
254
|
+
if environment_naming_info.suffix_target.is_catalog:
|
|
255
|
+
self._create_catalogs(tables=tables, gateway=gateway)
|
|
254
256
|
self._create_schemas(tables=tables, gateway=gateway)
|
|
255
257
|
|
|
256
258
|
deployability_index = deployability_index or DeployabilityIndex.all_deployable()
|
|
@@ -1114,6 +1116,18 @@ class SnapshotEvaluator:
|
|
|
1114
1116
|
blocking=blocking,
|
|
1115
1117
|
)
|
|
1116
1118
|
|
|
1119
|
+
def _create_catalogs(
|
|
1120
|
+
self,
|
|
1121
|
+
tables: t.Iterable[t.Union[exp.Table, str]],
|
|
1122
|
+
gateway: t.Optional[str] = None,
|
|
1123
|
+
) -> None:
|
|
1124
|
+
# attempt to create catalogs for the virtual layer if possible
|
|
1125
|
+
adapter = self.get_adapter(gateway)
|
|
1126
|
+
if adapter.SUPPORTS_CREATE_DROP_CATALOG:
|
|
1127
|
+
unique_catalogs = {t.catalog for t in [exp.to_table(maybe_t) for maybe_t in tables]}
|
|
1128
|
+
for catalog_name in unique_catalogs:
|
|
1129
|
+
adapter.create_catalog(catalog_name)
|
|
1130
|
+
|
|
1117
1131
|
def _create_schemas(
|
|
1118
1132
|
self,
|
|
1119
1133
|
tables: t.Iterable[t.Union[exp.Table, str]],
|
|
@@ -30,7 +30,9 @@ def cleanup_expired_views(
|
|
|
30
30
|
console: t.Optional[Console] = None,
|
|
31
31
|
) -> None:
|
|
32
32
|
expired_schema_environments = [
|
|
33
|
-
environment
|
|
33
|
+
environment
|
|
34
|
+
for environment in environments
|
|
35
|
+
if environment.suffix_target.is_schema or environment.suffix_target.is_catalog
|
|
34
36
|
]
|
|
35
37
|
expired_table_environments = [
|
|
36
38
|
environment for environment in environments if environment.suffix_target.is_table
|
|
@@ -42,8 +44,10 @@ def cleanup_expired_views(
|
|
|
42
44
|
return engine_adapters.get(gateway, default_adapter)
|
|
43
45
|
return default_adapter
|
|
44
46
|
|
|
47
|
+
catalogs_to_drop: t.Set[t.Tuple[EngineAdapter, str]] = set()
|
|
48
|
+
|
|
45
49
|
# Drop the schemas for the expired environments
|
|
46
|
-
for engine_adapter, expired_catalog, expired_schema in {
|
|
50
|
+
for engine_adapter, expired_catalog, expired_schema, suffix_target in {
|
|
47
51
|
(
|
|
48
52
|
(engine_adapter := get_adapter(environment.gateway_managed, snapshot.model_gateway)),
|
|
49
53
|
snapshot.qualified_view_name.catalog_for_environment(
|
|
@@ -52,6 +56,7 @@ def cleanup_expired_views(
|
|
|
52
56
|
snapshot.qualified_view_name.schema_for_environment(
|
|
53
57
|
environment.naming_info, dialect=engine_adapter.dialect
|
|
54
58
|
),
|
|
59
|
+
environment.suffix_target,
|
|
55
60
|
)
|
|
56
61
|
for environment in expired_schema_environments
|
|
57
62
|
for snapshot in environment.snapshots
|
|
@@ -64,6 +69,10 @@ def cleanup_expired_views(
|
|
|
64
69
|
ignore_if_not_exists=True,
|
|
65
70
|
cascade=True,
|
|
66
71
|
)
|
|
72
|
+
|
|
73
|
+
if suffix_target.is_catalog and expired_catalog:
|
|
74
|
+
catalogs_to_drop.add((engine_adapter, expired_catalog))
|
|
75
|
+
|
|
67
76
|
if console:
|
|
68
77
|
console.update_cleanup_progress(schema.sql(dialect=engine_adapter.dialect))
|
|
69
78
|
except Exception as e:
|
|
@@ -96,6 +105,21 @@ def cleanup_expired_views(
|
|
|
96
105
|
else:
|
|
97
106
|
raise SQLMeshError(message) from e
|
|
98
107
|
|
|
108
|
+
# Drop any catalogs that were associated with a snapshot where the engine adapter supports dropping catalogs
|
|
109
|
+
# catalogs_to_drop is only populated when environment_suffix_target is set to 'catalog'
|
|
110
|
+
for engine_adapter, catalog in catalogs_to_drop:
|
|
111
|
+
if engine_adapter.SUPPORTS_CREATE_DROP_CATALOG:
|
|
112
|
+
try:
|
|
113
|
+
engine_adapter.drop_catalog(catalog)
|
|
114
|
+
if console:
|
|
115
|
+
console.update_cleanup_progress(catalog)
|
|
116
|
+
except Exception as e:
|
|
117
|
+
message = f"Failed to drop the expired environment catalog '{catalog}': {e}"
|
|
118
|
+
if warn_on_delete_failure:
|
|
119
|
+
logger.warning(message)
|
|
120
|
+
else:
|
|
121
|
+
raise SQLMeshError(message) from e
|
|
122
|
+
|
|
99
123
|
|
|
100
124
|
def transactional() -> t.Callable[[t.Callable], t.Callable]:
|
|
101
125
|
def decorator(func: t.Callable) -> t.Callable:
|
sqlmesh/lsp/reference.py
CHANGED
|
@@ -208,6 +208,17 @@ def get_model_definitions_for_a_path(
|
|
|
208
208
|
target_range=target_range,
|
|
209
209
|
)
|
|
210
210
|
)
|
|
211
|
+
|
|
212
|
+
column_references = _process_column_references(
|
|
213
|
+
scope=scope,
|
|
214
|
+
reference_name=table.name,
|
|
215
|
+
read_file=read_file,
|
|
216
|
+
referenced_model_uri=document_uri,
|
|
217
|
+
description="",
|
|
218
|
+
reference_type="cte",
|
|
219
|
+
cte_target_range=target_range,
|
|
220
|
+
)
|
|
221
|
+
references.extend(column_references)
|
|
211
222
|
continue
|
|
212
223
|
|
|
213
224
|
# For non-CTE tables, process as before (external model references)
|
|
@@ -276,6 +287,19 @@ def get_model_definitions_for_a_path(
|
|
|
276
287
|
target_range=yaml_target_range,
|
|
277
288
|
)
|
|
278
289
|
)
|
|
290
|
+
|
|
291
|
+
column_references = _process_column_references(
|
|
292
|
+
scope=scope,
|
|
293
|
+
reference_name=normalized_reference_name,
|
|
294
|
+
read_file=read_file,
|
|
295
|
+
referenced_model_uri=referenced_model_uri,
|
|
296
|
+
description=description,
|
|
297
|
+
yaml_target_range=yaml_target_range,
|
|
298
|
+
reference_type="external_model",
|
|
299
|
+
default_catalog=lint_context.context.default_catalog,
|
|
300
|
+
dialect=dialect,
|
|
301
|
+
)
|
|
302
|
+
references.extend(column_references)
|
|
279
303
|
else:
|
|
280
304
|
references.append(
|
|
281
305
|
LSPModelReference(
|
|
@@ -288,6 +312,18 @@ def get_model_definitions_for_a_path(
|
|
|
288
312
|
)
|
|
289
313
|
)
|
|
290
314
|
|
|
315
|
+
column_references = _process_column_references(
|
|
316
|
+
scope=scope,
|
|
317
|
+
reference_name=normalized_reference_name,
|
|
318
|
+
read_file=read_file,
|
|
319
|
+
referenced_model_uri=referenced_model_uri,
|
|
320
|
+
description=description,
|
|
321
|
+
reference_type="model",
|
|
322
|
+
default_catalog=lint_context.context.default_catalog,
|
|
323
|
+
dialect=dialect,
|
|
324
|
+
)
|
|
325
|
+
references.extend(column_references)
|
|
326
|
+
|
|
291
327
|
return references
|
|
292
328
|
|
|
293
329
|
|
|
@@ -735,6 +771,104 @@ def _position_within_range(position: Position, range: Range) -> bool:
|
|
|
735
771
|
)
|
|
736
772
|
|
|
737
773
|
|
|
774
|
+
def _get_column_table_range(column: exp.Column, read_file: t.List[str]) -> Range:
|
|
775
|
+
"""
|
|
776
|
+
Get the range for a column's table reference, handling both simple and qualified table names.
|
|
777
|
+
|
|
778
|
+
Args:
|
|
779
|
+
column: The column expression
|
|
780
|
+
read_file: The file content as list of lines
|
|
781
|
+
|
|
782
|
+
Returns:
|
|
783
|
+
The Range covering the table reference in the column
|
|
784
|
+
"""
|
|
785
|
+
|
|
786
|
+
table_parts = column.parts[:-1]
|
|
787
|
+
|
|
788
|
+
start_range = TokenPositionDetails.from_meta(table_parts[0].meta).to_range(read_file)
|
|
789
|
+
end_range = TokenPositionDetails.from_meta(table_parts[-1].meta).to_range(read_file)
|
|
790
|
+
|
|
791
|
+
return Range(
|
|
792
|
+
start=to_lsp_position(start_range.start),
|
|
793
|
+
end=to_lsp_position(end_range.end),
|
|
794
|
+
)
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
def _process_column_references(
|
|
798
|
+
scope: t.Any,
|
|
799
|
+
reference_name: str,
|
|
800
|
+
read_file: t.List[str],
|
|
801
|
+
referenced_model_uri: URI,
|
|
802
|
+
description: t.Optional[str] = None,
|
|
803
|
+
yaml_target_range: t.Optional[Range] = None,
|
|
804
|
+
reference_type: t.Literal["model", "external_model", "cte"] = "model",
|
|
805
|
+
default_catalog: t.Optional[str] = None,
|
|
806
|
+
dialect: t.Optional[str] = None,
|
|
807
|
+
cte_target_range: t.Optional[Range] = None,
|
|
808
|
+
) -> t.List[Reference]:
|
|
809
|
+
"""
|
|
810
|
+
Process column references for a given table and create appropriate reference objects.
|
|
811
|
+
|
|
812
|
+
Args:
|
|
813
|
+
scope: The SQL scope to search for columns
|
|
814
|
+
reference_name: The full reference name (may include database/catalog)
|
|
815
|
+
read_file: The file content as list of lines
|
|
816
|
+
referenced_model_uri: URI of the referenced model
|
|
817
|
+
description: Markdown description for the reference
|
|
818
|
+
yaml_target_range: Target range for external models (YAML files)
|
|
819
|
+
reference_type: Type of reference - "model", "external_model", or "cte"
|
|
820
|
+
default_catalog: Default catalog for normalization
|
|
821
|
+
dialect: SQL dialect for normalization
|
|
822
|
+
cte_target_range: Target range for CTE references
|
|
823
|
+
|
|
824
|
+
Returns:
|
|
825
|
+
List of table references for column usages
|
|
826
|
+
"""
|
|
827
|
+
|
|
828
|
+
references: t.List[Reference] = []
|
|
829
|
+
for column in scope.find_all(exp.Column):
|
|
830
|
+
if column.table:
|
|
831
|
+
if reference_type == "cte":
|
|
832
|
+
if column.table == reference_name:
|
|
833
|
+
table_range = _get_column_table_range(column, read_file)
|
|
834
|
+
references.append(
|
|
835
|
+
LSPCteReference(
|
|
836
|
+
uri=referenced_model_uri.value,
|
|
837
|
+
range=table_range,
|
|
838
|
+
target_range=cte_target_range,
|
|
839
|
+
)
|
|
840
|
+
)
|
|
841
|
+
else:
|
|
842
|
+
table_parts = [part.sql(dialect) for part in column.parts[:-1]]
|
|
843
|
+
table_ref = ".".join(table_parts)
|
|
844
|
+
normalized_reference_name = normalize_model_name(
|
|
845
|
+
table_ref,
|
|
846
|
+
default_catalog=default_catalog,
|
|
847
|
+
dialect=dialect,
|
|
848
|
+
)
|
|
849
|
+
if normalized_reference_name == reference_name:
|
|
850
|
+
table_range = _get_column_table_range(column, read_file)
|
|
851
|
+
if reference_type == "external_model":
|
|
852
|
+
references.append(
|
|
853
|
+
LSPExternalModelReference(
|
|
854
|
+
uri=referenced_model_uri.value,
|
|
855
|
+
range=table_range,
|
|
856
|
+
markdown_description=description,
|
|
857
|
+
target_range=yaml_target_range,
|
|
858
|
+
)
|
|
859
|
+
)
|
|
860
|
+
else:
|
|
861
|
+
references.append(
|
|
862
|
+
LSPModelReference(
|
|
863
|
+
uri=referenced_model_uri.value,
|
|
864
|
+
range=table_range,
|
|
865
|
+
markdown_description=description,
|
|
866
|
+
)
|
|
867
|
+
)
|
|
868
|
+
|
|
869
|
+
return references
|
|
870
|
+
|
|
871
|
+
|
|
738
872
|
def _get_yaml_model_range(path: Path, model_name: str) -> t.Optional[Range]:
|
|
739
873
|
"""
|
|
740
874
|
Find the range of a specific model block in a YAML file.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
sqlmesh/__init__.py,sha256=QjwaamJIdW7voXoS880yAx7tHm-Im4_mqGA-XJgafos,7631
|
|
2
|
-
sqlmesh/_version.py,sha256=
|
|
2
|
+
sqlmesh/_version.py,sha256=4AXoTdklMBMT8Jjx_8JGYvr6SI6W51xe_eIQYgKEEdg,528
|
|
3
3
|
sqlmesh/magics.py,sha256=ysPC5ohXpgQ8IHQPwtQtwGoVypmVq_YBlm1noUueDIw,40448
|
|
4
4
|
sqlmesh/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
sqlmesh/cicd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -12,11 +12,11 @@ sqlmesh/cli/options.py,sha256=aC_L5WnMScKzMU55BD1Y-8R-QzqCkPSYrlCI-payHRA,1333
|
|
|
12
12
|
sqlmesh/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
sqlmesh/core/_typing.py,sha256=e1f7xO2aZCy38M_3VoDy-XI3shyd99-IFctgIFSgXWM,497
|
|
14
14
|
sqlmesh/core/console.py,sha256=pMIkBjaigneVqGkoGxOKVmT423RPfbDKX8TQ8D1SzpU,153466
|
|
15
|
-
sqlmesh/core/constants.py,sha256=
|
|
15
|
+
sqlmesh/core/constants.py,sha256=gUABXWYgH_XOSbaZAJsR5o1dmA61JDCvBDyxqqXX3LM,2630
|
|
16
16
|
sqlmesh/core/context.py,sha256=LyPmWyUjHhW415_yoH4IQ5KLEV8cY6gF2znjMewx4yY,118131
|
|
17
17
|
sqlmesh/core/context_diff.py,sha256=TCzM8egBE35DskpouOB-GQM2Qf5iUHWbRgiB5yZ6tzg,21552
|
|
18
18
|
sqlmesh/core/dialect.py,sha256=93cXYVuNoZ9CvJNTVn2Yz7WDOdHINwVXflbn0eZ-p14,49764
|
|
19
|
-
sqlmesh/core/environment.py,sha256=
|
|
19
|
+
sqlmesh/core/environment.py,sha256=7DbJX0r5nZRU3LhcgIxbSV-JosQYDjAt3V5Wc2Fpns8,13005
|
|
20
20
|
sqlmesh/core/lineage.py,sha256=zjB0Zfamo2Fja2r5SSZPMbrEKTXr1WjozZPVqvxdybI,3143
|
|
21
21
|
sqlmesh/core/loader.py,sha256=XVUd1UwK8jlJUaZdFBghSslipH2L80YVykjFzdGMCYA,40474
|
|
22
22
|
sqlmesh/core/macros.py,sha256=L_UlI4kysfDiYYpv78kODZw8kYbC9-FdBx7nHm1hBjs,60584
|
|
@@ -40,7 +40,7 @@ sqlmesh/core/audit/definition.py,sha256=QXXObhR_jHgjWLu0qXxPuIXm0GlFQq33rhp11m_x
|
|
|
40
40
|
sqlmesh/core/config/__init__.py,sha256=b4gFb04tpeZpowqJD-7h3U3TLgxrpQhZahVEAo6VW2Y,2009
|
|
41
41
|
sqlmesh/core/config/base.py,sha256=t8NQmsgQoZSc-k0dlDiCb8t1jj0AMYdGZ-6se9q_Pks,4898
|
|
42
42
|
sqlmesh/core/config/categorizer.py,sha256=6vzUoNLjR6GOEb_2mYVz2TwmMv2BfldgHX2u-Le5HZs,1975
|
|
43
|
-
sqlmesh/core/config/common.py,sha256
|
|
43
|
+
sqlmesh/core/config/common.py,sha256=rsb2uVFqPEX3DMsWG_hApwztCuRJP-FAmaQ_5L3-S8g,4006
|
|
44
44
|
sqlmesh/core/config/connection.py,sha256=sxRPhP0q088kInXtZinEK2FbkQHkzJZrGMDF-VnWmtA,82137
|
|
45
45
|
sqlmesh/core/config/feature_flag.py,sha256=JRcD31OG_t2cYc24meKbHDGB0iVID0P07V2oOeB_mgA,203
|
|
46
46
|
sqlmesh/core/config/format.py,sha256=6CXFbvnor56xbldKE-Vrm9k_ABRoY4v6vgIb3mCihiQ,1355
|
|
@@ -52,27 +52,27 @@ sqlmesh/core/config/migration.py,sha256=3lZIlmIcQH3_hIEm3Y3jFtvpw0YXzRzAnk4Odikl
|
|
|
52
52
|
sqlmesh/core/config/model.py,sha256=GIz9kAfKD2NEXNzCZCQ17-CK2OtqN6WgeG1fvibcChM,3650
|
|
53
53
|
sqlmesh/core/config/naming.py,sha256=KVGaxUgswoQajXR_cHFJvgkmEFcU1V182GkOH1SJxuE,326
|
|
54
54
|
sqlmesh/core/config/plan.py,sha256=wJEDfocMcKSMN0-5gVojjIcmJZ0376LJU3tkGMTm-Zc,1558
|
|
55
|
-
sqlmesh/core/config/root.py,sha256=
|
|
55
|
+
sqlmesh/core/config/root.py,sha256=tZxArC4kjPqrt43R9uErH_awwwNQVaNIaTAb-ot9WiU,15529
|
|
56
56
|
sqlmesh/core/config/run.py,sha256=rIK0QnN_vArrwps2TXGVEbvao2AnGZgzXo7EliJa42E,852
|
|
57
57
|
sqlmesh/core/config/scheduler.py,sha256=k3BVMpy5ZrC05ZlyE3vec8ZGfTjUjWyfsKZtYgflbyA,7029
|
|
58
58
|
sqlmesh/core/config/ui.py,sha256=jsO-S6_d9NkLZGG5pT4mgKgxMF34KzkDociZAMvCX3U,278
|
|
59
59
|
sqlmesh/core/engine_adapter/__init__.py,sha256=two_WTs4UnSNp-fscJh8vOunJq0Xi37EuDuMjKsKuNE,2281
|
|
60
60
|
sqlmesh/core/engine_adapter/_typing.py,sha256=_63pYCThfC39UtPVHY3N0H6qJ1YBT32OqwwR3swolGM,1037
|
|
61
61
|
sqlmesh/core/engine_adapter/athena.py,sha256=WBVAB_YzBJXdiqq51LTd2jmYoMtGrLmtsA8IrIFVnQ0,26199
|
|
62
|
-
sqlmesh/core/engine_adapter/base.py,sha256=
|
|
62
|
+
sqlmesh/core/engine_adapter/base.py,sha256=R90ZhxpVb58Vl-zVse9fkNVbm3eD3lqi1PhW_WBOtAQ,102263
|
|
63
63
|
sqlmesh/core/engine_adapter/base_postgres.py,sha256=DOsOdCJyQAVfA9S0GznuH0J1bonMqYVP_yJLDYcxFYM,6772
|
|
64
64
|
sqlmesh/core/engine_adapter/bigquery.py,sha256=qJE8vHLKKAeWMvltmYaUvWS95jM_UEZ6UzYLlr58sGo,50424
|
|
65
65
|
sqlmesh/core/engine_adapter/clickhouse.py,sha256=LoPdm_s_s-ZxS1XJPA3Et0iOHeJ1LgqTAFbwBdiqE7A,34912
|
|
66
66
|
sqlmesh/core/engine_adapter/databricks.py,sha256=8ZExPIeT3dDh9MTJW8udvmh9LiY-f9HkRAN1Q5Qebhs,14541
|
|
67
|
-
sqlmesh/core/engine_adapter/duckdb.py,sha256=
|
|
67
|
+
sqlmesh/core/engine_adapter/duckdb.py,sha256=TlSFSWNzUfjGdhuMyCi1CLwhBaEKyNKtasub9OsYwrc,5199
|
|
68
68
|
sqlmesh/core/engine_adapter/mixins.py,sha256=HMB0Z9O3p5jaTZMolKiWKqpVDZokf5GoI99YXwEJ8bc,22470
|
|
69
69
|
sqlmesh/core/engine_adapter/mssql.py,sha256=e-PElz8RAUwD-fGCx-2oleg3UGxFH-f0AzXODR3hpm0,14140
|
|
70
70
|
sqlmesh/core/engine_adapter/mysql.py,sha256=lVC-siXZK3iSfqCmBjZNw8uy09Z8la8v8_oUZ-E2OwI,6966
|
|
71
71
|
sqlmesh/core/engine_adapter/postgres.py,sha256=fdQrsBodfGlNf8lZYkS99U_gjoDyaYKEVKLgScduv3I,4601
|
|
72
72
|
sqlmesh/core/engine_adapter/redshift.py,sha256=B4GsPggz-xyvBpx5qubvVwEeKF3vk7n5SMExL-Q5Ysw,16754
|
|
73
73
|
sqlmesh/core/engine_adapter/risingwave.py,sha256=YYCQ0EJaSrR9_P1_2_LmElQ6zSxqkZzhvhdm-2WtWWg,969
|
|
74
|
-
sqlmesh/core/engine_adapter/shared.py,sha256=
|
|
75
|
-
sqlmesh/core/engine_adapter/snowflake.py,sha256=
|
|
74
|
+
sqlmesh/core/engine_adapter/shared.py,sha256=zL2W2t9af9mo80aSO0fz5TqV6mY8_kI5VYLswbKdZyk,13369
|
|
75
|
+
sqlmesh/core/engine_adapter/snowflake.py,sha256=IEEzepxNpfqBIMe4ziz2k8fjOcJPeQPZyM3XljymAj0,28874
|
|
76
76
|
sqlmesh/core/engine_adapter/spark.py,sha256=sYkVOPS0X43UPbI0z7Hh_EpKlI36qkOcr4NNFOTQlLs,21045
|
|
77
77
|
sqlmesh/core/engine_adapter/trino.py,sha256=7WdLFlT0AyD5NF0EDP7GqX0SHF8sTm7cafBZxk84cmY,15798
|
|
78
78
|
sqlmesh/core/linter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -102,12 +102,12 @@ sqlmesh/core/plan/stages.py,sha256=9BtcCgHYSvELrAkrOEhTuR1POAJNknLn_n4CmkqAC-4,2
|
|
|
102
102
|
sqlmesh/core/snapshot/__init__.py,sha256=Z5HTetNCZGoKF1WAKXk4LWL9dc8EC8lwS2O4TtoBmt4,1317
|
|
103
103
|
sqlmesh/core/snapshot/cache.py,sha256=bgqCR2hyf6r2A_8QP1EnXFK25gDX37-Zg0YeMuETWxg,3934
|
|
104
104
|
sqlmesh/core/snapshot/categorizer.py,sha256=qGG5870mu1jR2whKisSBH_GFbsyh96RnzJDgkN7DV9g,2482
|
|
105
|
-
sqlmesh/core/snapshot/definition.py,sha256
|
|
106
|
-
sqlmesh/core/snapshot/evaluator.py,sha256=
|
|
105
|
+
sqlmesh/core/snapshot/definition.py,sha256=mjGZBpzhKI9gYLmuYhSAs0IBKEo_JdfX66EcR9yRcig,84359
|
|
106
|
+
sqlmesh/core/snapshot/evaluator.py,sha256=zuxNnEKCyImFIT_hWLNc7xtKv4uflkKXOLprkD_hCJE,90132
|
|
107
107
|
sqlmesh/core/state_sync/__init__.py,sha256=B60xj-_Xk-4jas3UphLvwkuf04G-9AyGckcblXE0aRg,869
|
|
108
108
|
sqlmesh/core/state_sync/base.py,sha256=WLlwcbF53BHsX1jCsVjWewO9Ht7QUsn2ktJ3-q5iK8g,18346
|
|
109
109
|
sqlmesh/core/state_sync/cache.py,sha256=0AsYdQyBqbLdJvkBQ-hDAipsvnn_jSps-nya-Q4XeL0,5337
|
|
110
|
-
sqlmesh/core/state_sync/common.py,sha256=
|
|
110
|
+
sqlmesh/core/state_sync/common.py,sha256=x8Nkox6VmkD-lYZkjRcNe3iVsChR1HBroTorf1kATpQ,7609
|
|
111
111
|
sqlmesh/core/state_sync/export_import.py,sha256=WJ7sFX2b_RPAFE4yspJRi_4JQnaO23xpJgRxwXD0agA,8709
|
|
112
112
|
sqlmesh/core/state_sync/db/__init__.py,sha256=jGCqKYB7npq4eh6H2LyfBAJWdOP-IFu0DC4CMiQgYvw,107
|
|
113
113
|
sqlmesh/core/state_sync/db/environment.py,sha256=RKaP71CDI7YFhLYuyYVbtyBEWfwvNd2_XsDvjtrQq2Q,13645
|
|
@@ -173,7 +173,7 @@ sqlmesh/lsp/description.py,sha256=PjguwyVw5YeYSgT0JMhkf5U1Jry-sDPLvQ2caIR9JPQ,85
|
|
|
173
173
|
sqlmesh/lsp/helpers.py,sha256=EFc1u3-b7kSv5-tNwmKUDxId72RCLDBnN2lLTgRSzzQ,1020
|
|
174
174
|
sqlmesh/lsp/hints.py,sha256=j-blccBUil94yRoDjWfkSM0HqMmsKD6hP2TaWdWWVk4,3734
|
|
175
175
|
sqlmesh/lsp/main.py,sha256=EanNAS5ArBRc2oYsS3jhL46pfzXLn78xwSW-9R4RQ3o,33731
|
|
176
|
-
sqlmesh/lsp/reference.py,sha256=
|
|
176
|
+
sqlmesh/lsp/reference.py,sha256=NyfpK12TouDuy5-G7KOhvifkJItMfrakKwnMoU6SiVk,32088
|
|
177
177
|
sqlmesh/lsp/uri.py,sha256=mvSLbZGmMTHPpliThOtVWiFcHnfJzp1w39q9l-xD2SI,802
|
|
178
178
|
sqlmesh/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
179
179
|
sqlmesh/migrations/v0001_init.py,sha256=h8FwMYJj9_O8yGpk12guaSaGwX5A3we2GiKeHrXi15o,2048
|
|
@@ -282,7 +282,7 @@ sqlmesh/utils/pydantic.py,sha256=I898jAFqa3qU6lG2uPpRebVFncOUo8ZrLWM_R3K3DHU,116
|
|
|
282
282
|
sqlmesh/utils/rich.py,sha256=BpB47G0-JcU41LkGkeGKroexj4NOV5fox4-GOIXPgIc,3545
|
|
283
283
|
sqlmesh/utils/windows.py,sha256=r7Yin4WEwbvH7sKA3hOJtRsclmscNuBeCklCfVPvtQs,611
|
|
284
284
|
sqlmesh/utils/yaml.py,sha256=np-WVcwmwsKghCgAj1OBBMsK1SXSRn4wR-H37cGiFr8,2282
|
|
285
|
-
sqlmesh-0.194.2.
|
|
285
|
+
sqlmesh-0.194.2.dev4.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
|
|
286
286
|
web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
287
287
|
web/client/dist/index.html,sha256=w71qWSLmp-xwmVJO8m41k8Rtni3iZlF0hmhiTr-NeCI,5472
|
|
288
288
|
web/client/dist/assets/Audits-sYYNn2gO.js,sha256=zSAKkif2kU0JuPH05xjNYITNPmsbDlvLKUc2-orr8AY,1041
|
|
@@ -400,8 +400,8 @@ web/server/api/endpoints/models.py,sha256=ud-lRwriyI_OYg9tZchrBgeiXELiRTLNEodraf
|
|
|
400
400
|
web/server/api/endpoints/modules.py,sha256=8hqqgonGay_mJmpCw0IdbjsPhWlQH2VLdKAqha-myac,468
|
|
401
401
|
web/server/api/endpoints/plan.py,sha256=OYuQ_4dgbhG9ibTcX1a8mvYgH3ANxw9Fhbb4wg6QWqc,9222
|
|
402
402
|
web/server/api/endpoints/table_diff.py,sha256=SCy3-pr5x6bEEiOaZGCDbiHQhpgxwmnz3Acqa2Ie6jI,2090
|
|
403
|
-
sqlmesh-0.194.2.
|
|
404
|
-
sqlmesh-0.194.2.
|
|
405
|
-
sqlmesh-0.194.2.
|
|
406
|
-
sqlmesh-0.194.2.
|
|
407
|
-
sqlmesh-0.194.2.
|
|
403
|
+
sqlmesh-0.194.2.dev4.dist-info/METADATA,sha256=pevBdvNfo9E_J4tgKi3OEpgwh1snIDvFiV1molPT_04,26690
|
|
404
|
+
sqlmesh-0.194.2.dev4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
405
|
+
sqlmesh-0.194.2.dev4.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
|
|
406
|
+
sqlmesh-0.194.2.dev4.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
|
|
407
|
+
sqlmesh-0.194.2.dev4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|