sqlmesh 0.205.1.dev7__py3-none-any.whl → 0.205.1.dev8__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.
@@ -0,0 +1,404 @@
1
+ import typing as t
2
+ from pathlib import Path
3
+
4
+ from pydantic import Field
5
+
6
+ from sqlmesh.core.dialect import normalize_model_name
7
+ from sqlmesh.core.linter.helpers import (
8
+ TokenPositionDetails,
9
+ )
10
+ from sqlmesh.core.linter.rule import Range, Position
11
+ from sqlmesh.core.model.definition import SqlModel, ExternalModel, PythonModel, SeedModel
12
+ from sqlglot import exp
13
+ from sqlglot.optimizer.scope import build_scope
14
+
15
+ from sqlglot.optimizer.normalize_identifiers import normalize_identifiers
16
+ from ruamel.yaml import YAML
17
+
18
+ from sqlmesh.utils.pydantic import PydanticModel
19
+
20
+ if t.TYPE_CHECKING:
21
+ from sqlmesh.core.context import Context
22
+ from sqlmesh.core.context import GenericContext
23
+
24
+
25
+ class ModelReference(PydanticModel):
26
+ """A reference to a model, excluding external models."""
27
+
28
+ type: t.Literal["model"] = "model"
29
+ path: Path
30
+ range: Range
31
+ markdown_description: t.Optional[str] = None
32
+
33
+
34
+ class ExternalModelReference(PydanticModel):
35
+ """A reference to an external model."""
36
+
37
+ type: t.Literal["external_model"] = "external_model"
38
+ range: Range
39
+ target_range: t.Optional[Range] = None
40
+ path: t.Optional[Path] = None
41
+ """The path of the external model, typically a YAML file, it is optional because
42
+ external models can be unregistered and so the path is not available."""
43
+
44
+ markdown_description: t.Optional[str] = None
45
+
46
+
47
+ class CTEReference(PydanticModel):
48
+ """A reference to a CTE."""
49
+
50
+ type: t.Literal["cte"] = "cte"
51
+ path: Path
52
+ range: Range
53
+ target_range: Range
54
+
55
+
56
+ class MacroReference(PydanticModel):
57
+ """A reference to a macro."""
58
+
59
+ type: t.Literal["macro"] = "macro"
60
+ path: Path
61
+ range: Range
62
+ target_range: Range
63
+ markdown_description: t.Optional[str] = None
64
+
65
+
66
+ Reference = t.Annotated[
67
+ t.Union[ModelReference, CTEReference, MacroReference, ExternalModelReference],
68
+ Field(discriminator="type"),
69
+ ]
70
+
71
+
72
+ def extract_references_from_query(
73
+ query: exp.Expression,
74
+ context: t.Union["Context", "GenericContext[t.Any]"],
75
+ document_path: Path,
76
+ read_file: t.List[str],
77
+ depends_on: t.Set[str],
78
+ dialect: t.Optional[str] = None,
79
+ ) -> t.List[Reference]:
80
+ # Build a scope tree to properly handle nested CTEs
81
+ try:
82
+ query = normalize_identifiers(query.copy(), dialect=dialect)
83
+ root_scope = build_scope(query)
84
+ except Exception:
85
+ root_scope = None
86
+
87
+ references: t.List[Reference] = []
88
+ if not root_scope:
89
+ return references
90
+
91
+ # Traverse all scopes to find CTE definitions and table references
92
+ for scope in root_scope.traverse():
93
+ for table in scope.tables:
94
+ table_name = table.name
95
+
96
+ # Check if this table reference is a CTE in the current scope
97
+ if cte_scope := scope.cte_sources.get(table_name):
98
+ cte = cte_scope.expression.parent
99
+ alias = cte.args["alias"]
100
+ if isinstance(alias, exp.TableAlias):
101
+ identifier = alias.this
102
+ if isinstance(identifier, exp.Identifier):
103
+ target_range_sqlmesh = TokenPositionDetails.from_meta(
104
+ identifier.meta
105
+ ).to_range(read_file)
106
+ table_range_sqlmesh = TokenPositionDetails.from_meta(
107
+ table.this.meta
108
+ ).to_range(read_file)
109
+
110
+ references.append(
111
+ CTEReference(
112
+ path=document_path, # Same file
113
+ range=table_range_sqlmesh,
114
+ target_range=target_range_sqlmesh,
115
+ )
116
+ )
117
+
118
+ column_references = _process_column_references(
119
+ scope=scope,
120
+ reference_name=table.name,
121
+ read_file=read_file,
122
+ referenced_model_path=document_path,
123
+ description="",
124
+ reference_type="cte",
125
+ cte_target_range=target_range_sqlmesh,
126
+ )
127
+ references.extend(column_references)
128
+ continue
129
+
130
+ # For non-CTE tables, process these as before (external model references)
131
+ # Normalize the table reference
132
+ unaliased = table.copy()
133
+ if unaliased.args.get("alias") is not None:
134
+ unaliased.set("alias", None)
135
+ reference_name = unaliased.sql(dialect=dialect)
136
+ try:
137
+ normalized_reference_name = normalize_model_name(
138
+ reference_name,
139
+ default_catalog=context.default_catalog,
140
+ dialect=dialect,
141
+ )
142
+ if normalized_reference_name not in depends_on:
143
+ continue
144
+ except Exception:
145
+ # Skip references that cannot be normalized
146
+ continue
147
+
148
+ # Get the referenced model uri
149
+ referenced_model = context.get_model(
150
+ model_or_snapshot=normalized_reference_name, raise_if_missing=False
151
+ )
152
+ if referenced_model is None:
153
+ # Extract metadata for positioning
154
+ table_meta = TokenPositionDetails.from_meta(table.this.meta)
155
+ table_range_sqlmesh = table_meta.to_range(read_file)
156
+ start_pos_sqlmesh = table_range_sqlmesh.start
157
+ end_pos_sqlmesh = table_range_sqlmesh.end
158
+
159
+ # If there's a catalog or database qualifier, adjust the start position
160
+ catalog_or_db = table.args.get("catalog") or table.args.get("db")
161
+ if catalog_or_db is not None:
162
+ catalog_or_db_meta = TokenPositionDetails.from_meta(catalog_or_db.meta)
163
+ catalog_or_db_range_sqlmesh = catalog_or_db_meta.to_range(read_file)
164
+ start_pos_sqlmesh = catalog_or_db_range_sqlmesh.start
165
+
166
+ references.append(
167
+ ExternalModelReference(
168
+ range=Range(
169
+ start=start_pos_sqlmesh,
170
+ end=end_pos_sqlmesh,
171
+ ),
172
+ markdown_description="Unregistered external model",
173
+ )
174
+ )
175
+ continue
176
+ referenced_model_path = referenced_model._path
177
+ if referenced_model_path is None:
178
+ continue
179
+ # Check whether the path exists
180
+ if not referenced_model_path.is_file():
181
+ continue
182
+
183
+ # Extract metadata for positioning
184
+ table_meta = TokenPositionDetails.from_meta(table.this.meta)
185
+ table_range_sqlmesh = table_meta.to_range(read_file)
186
+ start_pos_sqlmesh = table_range_sqlmesh.start
187
+ end_pos_sqlmesh = table_range_sqlmesh.end
188
+
189
+ # If there's a catalog or database qualifier, adjust the start position
190
+ catalog_or_db = table.args.get("catalog") or table.args.get("db")
191
+ if catalog_or_db is not None:
192
+ catalog_or_db_meta = TokenPositionDetails.from_meta(catalog_or_db.meta)
193
+ catalog_or_db_range_sqlmesh = catalog_or_db_meta.to_range(read_file)
194
+ start_pos_sqlmesh = catalog_or_db_range_sqlmesh.start
195
+
196
+ description = generate_markdown_description(referenced_model)
197
+
198
+ # For external models in YAML files, find the specific model block
199
+ if isinstance(referenced_model, ExternalModel):
200
+ yaml_target_range: t.Optional[Range] = None
201
+ if (
202
+ referenced_model_path.suffix in (".yaml", ".yml")
203
+ and referenced_model_path.is_file()
204
+ ):
205
+ yaml_target_range = _get_yaml_model_range(
206
+ referenced_model_path, referenced_model.name
207
+ )
208
+ references.append(
209
+ ExternalModelReference(
210
+ path=referenced_model_path,
211
+ range=Range(
212
+ start=start_pos_sqlmesh,
213
+ end=end_pos_sqlmesh,
214
+ ),
215
+ markdown_description=description,
216
+ target_range=yaml_target_range,
217
+ )
218
+ )
219
+
220
+ column_references = _process_column_references(
221
+ scope=scope,
222
+ reference_name=normalized_reference_name,
223
+ read_file=read_file,
224
+ referenced_model_path=referenced_model_path,
225
+ description=description,
226
+ yaml_target_range=yaml_target_range,
227
+ reference_type="external_model",
228
+ default_catalog=context.default_catalog,
229
+ dialect=dialect,
230
+ )
231
+ references.extend(column_references)
232
+ else:
233
+ references.append(
234
+ ModelReference(
235
+ path=referenced_model_path,
236
+ range=Range(
237
+ start=start_pos_sqlmesh,
238
+ end=end_pos_sqlmesh,
239
+ ),
240
+ markdown_description=description,
241
+ )
242
+ )
243
+
244
+ column_references = _process_column_references(
245
+ scope=scope,
246
+ reference_name=normalized_reference_name,
247
+ read_file=read_file,
248
+ referenced_model_path=referenced_model_path,
249
+ description=description,
250
+ reference_type="model",
251
+ default_catalog=context.default_catalog,
252
+ dialect=dialect,
253
+ )
254
+ references.extend(column_references)
255
+
256
+ return references
257
+
258
+
259
+ def generate_markdown_description(
260
+ model: t.Union[SqlModel, ExternalModel, PythonModel, SeedModel],
261
+ ) -> t.Optional[str]:
262
+ description = model.description
263
+ columns = model.columns_to_types
264
+ column_descriptions = model.column_descriptions
265
+
266
+ if columns is None:
267
+ return description or None
268
+
269
+ columns_table = "\n".join(
270
+ [
271
+ f"| {column} | {column_type} | {column_descriptions.get(column, '')} |"
272
+ for column, column_type in columns.items()
273
+ ]
274
+ )
275
+
276
+ table_header = "| Column | Type | Description |\n|--------|------|-------------|\n"
277
+ columns_text = table_header + columns_table
278
+ return f"{description}\n\n{columns_text}" if description else columns_text
279
+
280
+
281
+ def _process_column_references(
282
+ scope: t.Any,
283
+ reference_name: str,
284
+ read_file: t.List[str],
285
+ referenced_model_path: Path,
286
+ description: t.Optional[str] = None,
287
+ yaml_target_range: t.Optional[Range] = None,
288
+ reference_type: t.Literal["model", "external_model", "cte"] = "model",
289
+ default_catalog: t.Optional[str] = None,
290
+ dialect: t.Optional[str] = None,
291
+ cte_target_range: t.Optional[Range] = None,
292
+ ) -> t.List[Reference]:
293
+ """
294
+ Process column references for a given table and create appropriate reference objects.
295
+
296
+ Args:
297
+ scope: The SQL scope to search for columns
298
+ reference_name: The full reference name (may include database/catalog)
299
+ read_file: The file content as list of lines
300
+ referenced_model_path: Path of the referenced model
301
+ description: Markdown description for the reference
302
+ yaml_target_range: Target range for external models (YAML files)
303
+ reference_type: Type of reference - "model", "external_model", or "cte"
304
+ default_catalog: Default catalog for normalization
305
+ dialect: SQL dialect for normalization
306
+ cte_target_range: Target range for CTE references
307
+
308
+ Returns:
309
+ List of table references for column usages
310
+ """
311
+
312
+ references: t.List[Reference] = []
313
+ for column in scope.find_all(exp.Column):
314
+ if column.table:
315
+ if reference_type == "cte":
316
+ if column.table == reference_name:
317
+ table_range = _get_column_table_range(column, read_file)
318
+ references.append(
319
+ CTEReference(
320
+ path=referenced_model_path,
321
+ range=table_range,
322
+ target_range=cte_target_range,
323
+ )
324
+ )
325
+ else:
326
+ table_parts = [part.sql(dialect) for part in column.parts[:-1]]
327
+ table_ref = ".".join(table_parts)
328
+ normalized_reference_name = normalize_model_name(
329
+ table_ref,
330
+ default_catalog=default_catalog,
331
+ dialect=dialect,
332
+ )
333
+ if normalized_reference_name == reference_name:
334
+ table_range = _get_column_table_range(column, read_file)
335
+ if reference_type == "external_model":
336
+ references.append(
337
+ ExternalModelReference(
338
+ path=referenced_model_path,
339
+ range=table_range,
340
+ markdown_description=description,
341
+ target_range=yaml_target_range,
342
+ )
343
+ )
344
+ else:
345
+ references.append(
346
+ ModelReference(
347
+ path=referenced_model_path,
348
+ range=table_range,
349
+ markdown_description=description,
350
+ )
351
+ )
352
+
353
+ return references
354
+
355
+
356
+ def _get_column_table_range(column: exp.Column, read_file: t.List[str]) -> Range:
357
+ """
358
+ Get the range for a column's table reference, handling both simple and qualified table names.
359
+
360
+ Args:
361
+ column: The column expression
362
+ read_file: The file content as list of lines
363
+
364
+ Returns:
365
+ The Range covering the table reference in the column
366
+ """
367
+
368
+ table_parts = column.parts[:-1]
369
+
370
+ start_range = TokenPositionDetails.from_meta(table_parts[0].meta).to_range(read_file)
371
+ end_range = TokenPositionDetails.from_meta(table_parts[-1].meta).to_range(read_file)
372
+
373
+ return Range(
374
+ start=start_range.start,
375
+ end=end_range.end,
376
+ )
377
+
378
+
379
+ def _get_yaml_model_range(path: Path, model_name: str) -> t.Optional[Range]:
380
+ """
381
+ Find the range of a specific model block in a YAML file.
382
+
383
+ Args:
384
+ yaml_path: Path to the YAML file
385
+ model_name: Name of the model to find
386
+
387
+ Returns:
388
+ The Range of the model block in the YAML file, or None if not found
389
+ """
390
+ yaml = YAML()
391
+ with path.open("r", encoding="utf-8") as f:
392
+ data = yaml.load(f)
393
+
394
+ if not isinstance(data, list):
395
+ return None
396
+
397
+ for item in data:
398
+ if isinstance(item, dict) and item.get("name") == model_name:
399
+ # Get size of block by taking the earliest line/col in the items block and the last line/col of the block
400
+ position_data = item.lc.data["name"] # type: ignore
401
+ start = Position(line=position_data[2], character=position_data[3])
402
+ end = Position(line=position_data[2], character=position_data[3] + len(item["name"]))
403
+ return Range(start=start, end=end)
404
+ return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlmesh
3
- Version: 0.205.1.dev7
3
+ Version: 0.205.1.dev8
4
4
  Summary: Next-generation data transformation framework
5
5
  Author-email: "TobikoData Inc." <engineering@tobikodata.com>
6
6
  License: Apache License
@@ -1,5 +1,5 @@
1
1
  sqlmesh/__init__.py,sha256=QjwaamJIdW7voXoS880yAx7tHm-Im4_mqGA-XJgafos,7631
2
- sqlmesh/_version.py,sha256=2-J210bWQCsO1sdHRz3_eGnoH3f4ilsj-9AVCvDjY8U,528
2
+ sqlmesh/_version.py,sha256=O6HKB0GOTs35eNzv7mkEhoR0RKzZ0ghQEUat1MqXvj4,528
3
3
  sqlmesh/magics.py,sha256=bEzYqXHcM0P3CjyUZ1O9arlmXAdLAhoglKbQ29fD9AE,41842
4
4
  sqlmesh/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  sqlmesh/cicd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -77,10 +77,10 @@ sqlmesh/core/engine_adapter/spark.py,sha256=sYkVOPS0X43UPbI0z7Hh_EpKlI36qkOcr4NN
77
77
  sqlmesh/core/engine_adapter/trino.py,sha256=Tws3GxqnC6BmXFohqru1TDxsgPH-21qV6Oky7FaaLpE,15908
78
78
  sqlmesh/core/linter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
79
  sqlmesh/core/linter/definition.py,sha256=JDJTkhByUw4Tr3nF-BOHKFAx_eASQqEqzX6AUVQUz8I,5659
80
- sqlmesh/core/linter/helpers.py,sha256=Fc_rh5earww0V8oKSEPVnUEY0bnpEmK88O4FLV3W-QE,5022
80
+ sqlmesh/core/linter/helpers.py,sha256=HNNSiuKB2o4Z2AGbwgrGr9hE0lQnIR7VHQfj8D8M_Jw,5202
81
81
  sqlmesh/core/linter/rule.py,sha256=cyGoAz9HuhBYRfbgow_MZhzmDvQE7NK1gzzKsAN0cwY,3694
82
82
  sqlmesh/core/linter/rules/__init__.py,sha256=gevzfb67vFqckTCoVAe_TBGf6hQ-YtE1_YuGuXyh1L0,77
83
- sqlmesh/core/linter/rules/builtin.py,sha256=UNelGDGuzE-gPc6DsFw9h0BUbzmwx-Xyrx8wZh61Qq8,5163
83
+ sqlmesh/core/linter/rules/builtin.py,sha256=rOZoNGB-TOuUgOXLdxhhHbSe-0CU4XG5iGY-UeFJyu0,8069
84
84
  sqlmesh/core/metric/__init__.py,sha256=H1HmoD5IwN4YWe9iJXyueLYNmTQFZwok5nSWNJcZIBQ,237
85
85
  sqlmesh/core/metric/definition.py,sha256=Yd5aVgsZCDPJ43aGP7WqtzZOuuSUtB8uJGVA6Jw9x9M,7201
86
86
  sqlmesh/core/metric/rewriter.py,sha256=GiSTHfn2kinqCfNPYgZPRk93JFLzVaaejHtHDQ0yXZI,7326
@@ -164,16 +164,15 @@ sqlmesh/integrations/github/cicd/command.py,sha256=w3oWhvR4utEurB5UABXj4iVBIojkC
164
164
  sqlmesh/integrations/github/cicd/config.py,sha256=n4KyNv65y1gpys82iLAQZUb6g2pnzywyV_7cOrQXsnI,3669
165
165
  sqlmesh/integrations/github/cicd/controller.py,sha256=XZIh8y7527sBcTMCyXyVxulieFGa90Uz5Uq0wfLPjOY,54857
166
166
  sqlmesh/lsp/api.py,sha256=_lA_buSPZFIoLJuINbS53LbNOOaHp3orb0uFTE3aCqI,2328
167
- sqlmesh/lsp/completions.py,sha256=Nt1XpFL_-QAIRM8BBBC6Ia6YG0hMZriiNJra7nGfD4Q,6676
167
+ sqlmesh/lsp/completions.py,sha256=7Lhboh6xyoMJ3kkHG3aZz1xVbDwKiXeQKdIRj5xlUOA,6674
168
168
  sqlmesh/lsp/context.py,sha256=7zkDu1J4OyeFgWM_q96_zSqI057Ei_dExx-zcBVADNs,14850
169
169
  sqlmesh/lsp/custom.py,sha256=3gfN_z9IXKOhTGkaZX7V5I8WUmI4z1GWe1sViOo92pw,3980
170
- sqlmesh/lsp/description.py,sha256=PjguwyVw5YeYSgT0JMhkf5U1Jry-sDPLvQ2caIR9JPQ,856
171
170
  sqlmesh/lsp/errors.py,sha256=3NMim_5J00Eypz7t8b7XbkBfy8gIsRkeq-VcjD4COtc,1489
172
171
  sqlmesh/lsp/helpers.py,sha256=EFc1u3-b7kSv5-tNwmKUDxId72RCLDBnN2lLTgRSzzQ,1020
173
172
  sqlmesh/lsp/hints.py,sha256=j-blccBUil94yRoDjWfkSM0HqMmsKD6hP2TaWdWWVk4,3734
174
- sqlmesh/lsp/main.py,sha256=CnirmB_vXkYZRy0poBftKbKums6ciL9ih3Q43kCo5KI,42345
175
- sqlmesh/lsp/reference.py,sha256=ucyvi52bmmmD5XGC_On0JDvQefwPrgX41KNuamjyOPQ,32624
176
- sqlmesh/lsp/rename.py,sha256=DPnxrYXT5gSECbX3q9lzWYl-5xnQMw-jlMOkiKgxjxg,4674
173
+ sqlmesh/lsp/main.py,sha256=IW6Om8yGWBkKywBjKxFYhGe4UXa-iWlKcPCkyOgYKD0,42460
174
+ sqlmesh/lsp/reference.py,sha256=-TTT5NIIGDQoEDCzH8RNgEINt0p9DYclzEn4rBjreRI,18475
175
+ sqlmesh/lsp/rename.py,sha256=AFj-zJGWiBgHSj1jx1rOx4yJmmw1QpEcob648epM8gk,4668
177
176
  sqlmesh/lsp/tests_ranges.py,sha256=YO5w534J5_y2NWxj9t637wHLbFDJdXBvM7i5F4C-P0I,2308
178
177
  sqlmesh/lsp/uri.py,sha256=mvSLbZGmMTHPpliThOtVWiFcHnfJzp1w39q9l-xD2SI,802
179
178
  sqlmesh/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -278,6 +277,7 @@ sqlmesh/utils/errors.py,sha256=8FE33Eo3KN3Y4s5EZM5t92jZi9BAVGzkr3QCGlrLeDk,5679
278
277
  sqlmesh/utils/git.py,sha256=v1MD4Zwn52UBn_tTfoKn8SAPJVGC6SEFrJ4WEJFbgF0,1868
279
278
  sqlmesh/utils/hashing.py,sha256=nZRKvLNQ83tLG4IoXshVJZf-MbDrXC1HOeNw8Ji-tMM,578
280
279
  sqlmesh/utils/jinja.py,sha256=zulSPIICdFOjN__xkAiMpxbCS7S0--xAFK9d8VG0KvU,27844
280
+ sqlmesh/utils/lineage.py,sha256=r8bmemlZpGq-g2jlEPUnG3qNrg1RCdHC0I8k8x8QvKM,15578
281
281
  sqlmesh/utils/metaprogramming.py,sha256=yDWS3_tkm6Yd5TNHgii2x_VdZ2pVM0vL6oFuwFMMs0A,23554
282
282
  sqlmesh/utils/migration.py,sha256=R7Ck6FX-LfcujGy7sgS0kDWlK-xAEBODr3gqIQ8gC08,835
283
283
  sqlmesh/utils/pandas.py,sha256=FytTSLcRNtO0-YMvpoDBkkut3yoQJR9mBSKpif8lxug,2497
@@ -286,7 +286,7 @@ sqlmesh/utils/pydantic.py,sha256=o_NsXbIpDqNpUA1Uc5xF0ZzoXQYYB0DfHwdRxBwXPNk,120
286
286
  sqlmesh/utils/rich.py,sha256=cwQ5nJ6sgz64xHtoh6_ec7ReV5YpsOGhMtUJnwoRfEI,3549
287
287
  sqlmesh/utils/windows.py,sha256=r7Yin4WEwbvH7sKA3hOJtRsclmscNuBeCklCfVPvtQs,611
288
288
  sqlmesh/utils/yaml.py,sha256=hvo5lmybYLcIx4p6CQwufS8X4MbwS60lEBnCmYJCXmU,2336
289
- sqlmesh-0.205.1.dev7.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
289
+ sqlmesh-0.205.1.dev8.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
290
290
  web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
291
291
  web/client/dist/index.html,sha256=SXykdSRNgrT1k6I2dPZPEfpxPjIsi8-yVFijt-naSA4,5472
292
292
  web/client/dist/assets/Audits-Jm353fhk.js,sha256=ry6b5IKT3hLAfD5C3T2BqxulfauEV0n0YZ2vsP4eQ_U,1041
@@ -404,8 +404,8 @@ web/server/api/endpoints/models.py,sha256=kwj0s7uve3iZSMfmjkoPVMFMeY1sD0peTeyrWf
404
404
  web/server/api/endpoints/modules.py,sha256=8hqqgonGay_mJmpCw0IdbjsPhWlQH2VLdKAqha-myac,468
405
405
  web/server/api/endpoints/plan.py,sha256=bbbY50W_2MsZSTxOHWMKz0tbIm75nsRSlPy8GI2fg9Q,9306
406
406
  web/server/api/endpoints/table_diff.py,sha256=SCy3-pr5x6bEEiOaZGCDbiHQhpgxwmnz3Acqa2Ie6jI,2090
407
- sqlmesh-0.205.1.dev7.dist-info/METADATA,sha256=wc7uuI_P71gBrxywdUTb6QPOzxSJMbZa7L9GNJAT9v4,26678
408
- sqlmesh-0.205.1.dev7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
409
- sqlmesh-0.205.1.dev7.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
410
- sqlmesh-0.205.1.dev7.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
411
- sqlmesh-0.205.1.dev7.dist-info/RECORD,,
407
+ sqlmesh-0.205.1.dev8.dist-info/METADATA,sha256=6LQWBfLHBvtcA5WdLBE9jJ5zBPxCpYxt_AqZYw9y0_M,26678
408
+ sqlmesh-0.205.1.dev8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
409
+ sqlmesh-0.205.1.dev8.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
410
+ sqlmesh-0.205.1.dev8.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
411
+ sqlmesh-0.205.1.dev8.dist-info/RECORD,,
@@ -1,29 +0,0 @@
1
- from sqlmesh.core.model.definition import (
2
- ExternalModel,
3
- PythonModel,
4
- SeedModel,
5
- SqlModel,
6
- )
7
- import typing as t
8
-
9
-
10
- def generate_markdown_description(
11
- model: t.Union[SqlModel, ExternalModel, PythonModel, SeedModel],
12
- ) -> t.Optional[str]:
13
- description = model.description
14
- columns = model.columns_to_types
15
- column_descriptions = model.column_descriptions
16
-
17
- if columns is None:
18
- return description or None
19
-
20
- columns_table = "\n".join(
21
- [
22
- f"| {column} | {column_type} | {column_descriptions.get(column, '')} |"
23
- for column, column_type in columns.items()
24
- ]
25
- )
26
-
27
- table_header = "| Column | Type | Description |\n|--------|------|-------------|\n"
28
- columns_text = table_header + columns_table
29
- return f"{description}\n\n{columns_text}" if description else columns_text