sqlmesh 0.205.1.dev7__py3-none-any.whl → 0.205.1.dev9__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/lsp/reference.py CHANGED
@@ -1,74 +1,27 @@
1
1
  import typing as t
2
2
  from pathlib import Path
3
- from pydantic import Field
4
3
 
5
4
  from sqlmesh.core.audit import StandaloneAudit
6
- from sqlmesh.core.dialect import normalize_model_name
7
5
  from sqlmesh.core.linter.helpers import (
8
6
  TokenPositionDetails,
9
7
  )
10
8
  from sqlmesh.core.linter.rule import Range, Position
11
- from sqlmesh.core.model.definition import SqlModel, ExternalModel
9
+ from sqlmesh.core.model.definition import SqlModel
12
10
  from sqlmesh.lsp.context import LSPContext, ModelTarget, AuditTarget
13
11
  from sqlglot import exp
14
- from sqlmesh.lsp.description import generate_markdown_description
15
- from sqlglot.optimizer.scope import build_scope
16
12
 
17
13
  from sqlmesh.lsp.uri import URI
18
- from sqlmesh.utils.pydantic import PydanticModel
19
- from sqlglot.optimizer.normalize_identifiers import normalize_identifiers
14
+ from sqlmesh.utils.lineage import (
15
+ MacroReference,
16
+ CTEReference,
17
+ Reference,
18
+ ModelReference,
19
+ extract_references_from_query,
20
+ )
20
21
  import ast
21
22
  from sqlmesh.core.model import Model
22
23
  from sqlmesh import macro
23
24
  import inspect
24
- from ruamel.yaml import YAML
25
-
26
-
27
- class LSPModelReference(PydanticModel):
28
- """A LSP reference to a model, excluding external models."""
29
-
30
- type: t.Literal["model"] = "model"
31
- path: Path
32
- range: Range
33
- markdown_description: t.Optional[str] = None
34
-
35
-
36
- class LSPExternalModelReference(PydanticModel):
37
- """A LSP reference to an external model."""
38
-
39
- type: t.Literal["external_model"] = "external_model"
40
- range: Range
41
- target_range: t.Optional[Range] = None
42
- path: t.Optional[Path] = None
43
- """The path of the external model, typically a YAML file, it is optional because
44
- external models can be unregistered and so the path is not available."""
45
-
46
- markdown_description: t.Optional[str] = None
47
-
48
-
49
- class LSPCteReference(PydanticModel):
50
- """A LSP reference to a CTE."""
51
-
52
- type: t.Literal["cte"] = "cte"
53
- path: Path
54
- range: Range
55
- target_range: Range
56
-
57
-
58
- class LSPMacroReference(PydanticModel):
59
- """A LSP reference to a macro."""
60
-
61
- type: t.Literal["macro"] = "macro"
62
- path: Path
63
- range: Range
64
- target_range: Range
65
- markdown_description: t.Optional[str] = None
66
-
67
-
68
- Reference = t.Annotated[
69
- t.Union[LSPModelReference, LSPCteReference, LSPMacroReference, LSPExternalModelReference],
70
- Field(discriminator="type"),
71
- ]
72
25
 
73
26
 
74
27
  def by_position(position: Position) -> t.Callable[[Reference], bool]:
@@ -158,7 +111,6 @@ def get_model_definitions_for_a_path(
158
111
  audit = lint_context.context.standalone_audits.get(file_info.name)
159
112
  if audit is None:
160
113
  return []
161
-
162
114
  query = audit.query
163
115
  dialect = audit.dialect
164
116
  depends_on = audit.depends_on
@@ -169,177 +121,17 @@ def get_model_definitions_for_a_path(
169
121
  if file_path is None:
170
122
  return []
171
123
 
172
- # Find all possible references
173
- references: t.List[Reference] = []
174
-
175
124
  with open(file_path, "r", encoding="utf-8") as file:
176
125
  read_file = file.readlines()
177
126
 
178
- # Build a scope tree to properly handle nested CTEs
179
- try:
180
- query = normalize_identifiers(query.copy(), dialect=dialect)
181
- root_scope = build_scope(query)
182
- except Exception:
183
- root_scope = None
184
-
185
- if root_scope:
186
- # Traverse all scopes to find CTE definitions and table references
187
- for scope in root_scope.traverse():
188
- for table in scope.tables:
189
- table_name = table.name
190
-
191
- # Check if this table reference is a CTE in the current scope
192
- if cte_scope := scope.cte_sources.get(table_name):
193
- cte = cte_scope.expression.parent
194
- alias = cte.args["alias"]
195
- if isinstance(alias, exp.TableAlias):
196
- identifier = alias.this
197
- if isinstance(identifier, exp.Identifier):
198
- target_range_sqlmesh = TokenPositionDetails.from_meta(
199
- identifier.meta
200
- ).to_range(read_file)
201
- table_range_sqlmesh = TokenPositionDetails.from_meta(
202
- table.this.meta
203
- ).to_range(read_file)
204
-
205
- references.append(
206
- LSPCteReference(
207
- path=document_uri.to_path(), # Same file
208
- range=table_range_sqlmesh,
209
- target_range=target_range_sqlmesh,
210
- )
211
- )
212
-
213
- column_references = _process_column_references(
214
- scope=scope,
215
- reference_name=table.name,
216
- read_file=read_file,
217
- referenced_model_path=document_uri.to_path(),
218
- description="",
219
- reference_type="cte",
220
- cte_target_range=target_range_sqlmesh,
221
- )
222
- references.extend(column_references)
223
- continue
224
-
225
- # For non-CTE tables, process these as before (external model references)
226
- # Normalize the table reference
227
- unaliased = table.copy()
228
- if unaliased.args.get("alias") is not None:
229
- unaliased.set("alias", None)
230
- reference_name = unaliased.sql(dialect=dialect)
231
- try:
232
- normalized_reference_name = normalize_model_name(
233
- reference_name,
234
- default_catalog=lint_context.context.default_catalog,
235
- dialect=dialect,
236
- )
237
- if normalized_reference_name not in depends_on:
238
- continue
239
- except Exception:
240
- # Skip references that cannot be normalized
241
- continue
242
-
243
- # Get the referenced model uri
244
- referenced_model = lint_context.context.get_model(
245
- model_or_snapshot=normalized_reference_name, raise_if_missing=False
246
- )
247
- if referenced_model is None:
248
- table_meta = TokenPositionDetails.from_meta(table.this.meta)
249
- table_range_sqlmesh = table_meta.to_range(read_file)
250
- start_pos_sqlmesh = table_range_sqlmesh.start
251
- end_pos_sqlmesh = table_range_sqlmesh.end
252
- references.append(
253
- LSPExternalModelReference(
254
- range=Range(
255
- start=start_pos_sqlmesh,
256
- end=end_pos_sqlmesh,
257
- ),
258
- markdown_description="Unregistered external model",
259
- )
260
- )
261
- continue
262
- referenced_model_path = referenced_model._path
263
- if referenced_model_path is None:
264
- continue
265
- # Check whether the path exists
266
- if not referenced_model_path.is_file():
267
- continue
268
-
269
- # Extract metadata for positioning
270
- table_meta = TokenPositionDetails.from_meta(table.this.meta)
271
- table_range_sqlmesh = table_meta.to_range(read_file)
272
- start_pos_sqlmesh = table_range_sqlmesh.start
273
- end_pos_sqlmesh = table_range_sqlmesh.end
274
-
275
- # If there's a catalog or database qualifier, adjust the start position
276
- catalog_or_db = table.args.get("catalog") or table.args.get("db")
277
- if catalog_or_db is not None:
278
- catalog_or_db_meta = TokenPositionDetails.from_meta(catalog_or_db.meta)
279
- catalog_or_db_range_sqlmesh = catalog_or_db_meta.to_range(read_file)
280
- start_pos_sqlmesh = catalog_or_db_range_sqlmesh.start
281
-
282
- description = generate_markdown_description(referenced_model)
283
-
284
- # For external models in YAML files, find the specific model block
285
- if isinstance(referenced_model, ExternalModel):
286
- yaml_target_range: t.Optional[Range] = None
287
- if (
288
- referenced_model_path.suffix in (".yaml", ".yml")
289
- and referenced_model_path.is_file()
290
- ):
291
- yaml_target_range = _get_yaml_model_range(
292
- referenced_model_path, referenced_model.name
293
- )
294
- references.append(
295
- LSPExternalModelReference(
296
- path=referenced_model_path,
297
- range=Range(
298
- start=start_pos_sqlmesh,
299
- end=end_pos_sqlmesh,
300
- ),
301
- markdown_description=description,
302
- target_range=yaml_target_range,
303
- )
304
- )
305
-
306
- column_references = _process_column_references(
307
- scope=scope,
308
- reference_name=normalized_reference_name,
309
- read_file=read_file,
310
- referenced_model_path=referenced_model_path,
311
- description=description,
312
- yaml_target_range=yaml_target_range,
313
- reference_type="external_model",
314
- default_catalog=lint_context.context.default_catalog,
315
- dialect=dialect,
316
- )
317
- references.extend(column_references)
318
- else:
319
- references.append(
320
- LSPModelReference(
321
- path=referenced_model_path,
322
- range=Range(
323
- start=start_pos_sqlmesh,
324
- end=end_pos_sqlmesh,
325
- ),
326
- markdown_description=description,
327
- )
328
- )
329
-
330
- column_references = _process_column_references(
331
- scope=scope,
332
- reference_name=normalized_reference_name,
333
- read_file=read_file,
334
- referenced_model_path=referenced_model_path,
335
- description=description,
336
- reference_type="model",
337
- default_catalog=lint_context.context.default_catalog,
338
- dialect=dialect,
339
- )
340
- references.extend(column_references)
341
-
342
- return references
127
+ return extract_references_from_query(
128
+ query=query,
129
+ context=lint_context.context,
130
+ document_path=document_uri.to_path(),
131
+ read_file=read_file,
132
+ depends_on=depends_on,
133
+ dialect=dialect,
134
+ )
343
135
 
344
136
 
345
137
  def get_macro_definitions_for_a_path(
@@ -476,7 +268,7 @@ def get_macro_reference(
476
268
 
477
269
  # Create a reference to the macro definition
478
270
 
479
- return LSPMacroReference(
271
+ return MacroReference(
480
272
  path=path,
481
273
  range=macro_range,
482
274
  target_range=Range(
@@ -509,7 +301,7 @@ def get_built_in_macro_reference(macro_name: str, macro_range: Range) -> t.Optio
509
301
  # Calculate the end line number by counting the number of source lines
510
302
  end_line_number = line_number + len(source_lines) - 1
511
303
 
512
- return LSPMacroReference(
304
+ return MacroReference(
513
305
  path=Path(filename),
514
306
  range=macro_range,
515
307
  target_range=Range(
@@ -522,7 +314,7 @@ def get_built_in_macro_reference(macro_name: str, macro_range: Range) -> t.Optio
522
314
 
523
315
  def get_model_find_all_references(
524
316
  lint_context: LSPContext, document_uri: URI, position: Position
525
- ) -> t.List[LSPModelReference]:
317
+ ) -> t.List[ModelReference]:
526
318
  """
527
319
  Get all references to a model across the entire project.
528
320
 
@@ -540,7 +332,7 @@ def get_model_find_all_references(
540
332
  # Find the model reference at the cursor position
541
333
  model_at_position = next(
542
334
  filter(
543
- lambda ref: isinstance(ref, LSPModelReference)
335
+ lambda ref: isinstance(ref, ModelReference)
544
336
  and _position_within_range(position, ref.range),
545
337
  get_model_definitions_for_a_path(lint_context, document_uri),
546
338
  ),
@@ -550,13 +342,13 @@ def get_model_find_all_references(
550
342
  if not model_at_position:
551
343
  return []
552
344
 
553
- assert isinstance(model_at_position, LSPModelReference) # for mypy
345
+ assert isinstance(model_at_position, ModelReference) # for mypy
554
346
 
555
347
  target_model_path = model_at_position.path
556
348
 
557
349
  # Start with the model definition
558
- all_references: t.List[LSPModelReference] = [
559
- LSPModelReference(
350
+ all_references: t.List[ModelReference] = [
351
+ ModelReference(
560
352
  path=model_at_position.path,
561
353
  range=Range(
562
354
  start=Position(line=0, character=0),
@@ -568,15 +360,15 @@ def get_model_find_all_references(
568
360
 
569
361
  # Then add references from the current file
570
362
  current_file_refs = filter(
571
- lambda ref: isinstance(ref, LSPModelReference) and ref.path == target_model_path,
363
+ lambda ref: isinstance(ref, ModelReference) and ref.path == target_model_path,
572
364
  get_model_definitions_for_a_path(lint_context, document_uri),
573
365
  )
574
366
 
575
367
  for ref in current_file_refs:
576
- assert isinstance(ref, LSPModelReference) # for mypy
368
+ assert isinstance(ref, ModelReference) # for mypy
577
369
 
578
370
  all_references.append(
579
- LSPModelReference(
371
+ ModelReference(
580
372
  path=document_uri.to_path(),
581
373
  range=ref.range,
582
374
  markdown_description=ref.markdown_description,
@@ -593,15 +385,15 @@ def get_model_find_all_references(
593
385
 
594
386
  # Get model references that point to the target model
595
387
  matching_refs = filter(
596
- lambda ref: isinstance(ref, LSPModelReference) and ref.path == target_model_path,
388
+ lambda ref: isinstance(ref, ModelReference) and ref.path == target_model_path,
597
389
  get_model_definitions_for_a_path(lint_context, file_uri),
598
390
  )
599
391
 
600
392
  for ref in matching_refs:
601
- assert isinstance(ref, LSPModelReference) # for mypy
393
+ assert isinstance(ref, ModelReference) # for mypy
602
394
 
603
395
  all_references.append(
604
- LSPModelReference(
396
+ ModelReference(
605
397
  path=path,
606
398
  range=ref.range,
607
399
  markdown_description=ref.markdown_description,
@@ -613,7 +405,7 @@ def get_model_find_all_references(
613
405
 
614
406
  def get_cte_references(
615
407
  lint_context: LSPContext, document_uri: URI, position: Position
616
- ) -> t.List[LSPCteReference]:
408
+ ) -> t.List[CTEReference]:
617
409
  """
618
410
  Get all references to a CTE at a specific position in a document.
619
411
 
@@ -629,10 +421,10 @@ def get_cte_references(
629
421
  """
630
422
 
631
423
  # Filter to get the CTE references
632
- cte_references: t.List[LSPCteReference] = [
424
+ cte_references: t.List[CTEReference] = [
633
425
  ref
634
426
  for ref in get_model_definitions_for_a_path(lint_context, document_uri)
635
- if isinstance(ref, LSPCteReference)
427
+ if isinstance(ref, CTEReference)
636
428
  ]
637
429
 
638
430
  if not cte_references:
@@ -654,7 +446,7 @@ def get_cte_references(
654
446
 
655
447
  # Add the CTE definition
656
448
  matching_references = [
657
- LSPCteReference(
449
+ CTEReference(
658
450
  path=document_uri.to_path(),
659
451
  range=target_cte_definition_range,
660
452
  target_range=target_cte_definition_range,
@@ -665,7 +457,7 @@ def get_cte_references(
665
457
  for ref in cte_references:
666
458
  if ref.target_range == target_cte_definition_range:
667
459
  matching_references.append(
668
- LSPCteReference(
460
+ CTEReference(
669
461
  path=document_uri.to_path(),
670
462
  range=ref.range,
671
463
  target_range=ref.target_range,
@@ -677,7 +469,7 @@ def get_cte_references(
677
469
 
678
470
  def get_macro_find_all_references(
679
471
  lsp_context: LSPContext, document_uri: URI, position: Position
680
- ) -> t.List[LSPMacroReference]:
472
+ ) -> t.List[MacroReference]:
681
473
  """
682
474
  Get all references to a macro at a specific position in a document.
683
475
 
@@ -694,7 +486,7 @@ def get_macro_find_all_references(
694
486
  # Find the macro reference at the cursor position
695
487
  macro_at_position = next(
696
488
  filter(
697
- lambda ref: isinstance(ref, LSPMacroReference)
489
+ lambda ref: isinstance(ref, MacroReference)
698
490
  and _position_within_range(position, ref.range),
699
491
  get_macro_definitions_for_a_path(lsp_context, document_uri),
700
492
  ),
@@ -704,14 +496,14 @@ def get_macro_find_all_references(
704
496
  if not macro_at_position:
705
497
  return []
706
498
 
707
- assert isinstance(macro_at_position, LSPMacroReference) # for mypy
499
+ assert isinstance(macro_at_position, MacroReference) # for mypy
708
500
 
709
501
  target_macro_path = macro_at_position.path
710
502
  target_macro_target_range = macro_at_position.target_range
711
503
 
712
504
  # Start with the macro definition
713
- all_references: t.List[LSPMacroReference] = [
714
- LSPMacroReference(
505
+ all_references: t.List[MacroReference] = [
506
+ MacroReference(
715
507
  path=target_macro_path,
716
508
  range=target_macro_target_range,
717
509
  target_range=target_macro_target_range,
@@ -725,16 +517,16 @@ def get_macro_find_all_references(
725
517
 
726
518
  # Get macro references that point to the same macro definition
727
519
  matching_refs = filter(
728
- lambda ref: isinstance(ref, LSPMacroReference)
520
+ lambda ref: isinstance(ref, MacroReference)
729
521
  and ref.path == target_macro_path
730
522
  and ref.target_range == target_macro_target_range,
731
523
  get_macro_definitions_for_a_path(lsp_context, file_uri),
732
524
  )
733
525
 
734
526
  for ref in matching_refs:
735
- assert isinstance(ref, LSPMacroReference) # for mypy
527
+ assert isinstance(ref, MacroReference) # for mypy
736
528
  all_references.append(
737
- LSPMacroReference(
529
+ MacroReference(
738
530
  path=path,
739
531
  range=ref.range,
740
532
  target_range=ref.target_range,
@@ -786,129 +578,3 @@ def _position_within_range(position: Position, range: Range) -> bool:
786
578
  range.end.line > position.line
787
579
  or (range.end.line == position.line and range.end.character >= position.character)
788
580
  )
789
-
790
-
791
- def _get_column_table_range(column: exp.Column, read_file: t.List[str]) -> Range:
792
- """
793
- Get the range for a column's table reference, handling both simple and qualified table names.
794
-
795
- Args:
796
- column: The column expression
797
- read_file: The file content as list of lines
798
-
799
- Returns:
800
- The Range covering the table reference in the column
801
- """
802
-
803
- table_parts = column.parts[:-1]
804
-
805
- start_range = TokenPositionDetails.from_meta(table_parts[0].meta).to_range(read_file)
806
- end_range = TokenPositionDetails.from_meta(table_parts[-1].meta).to_range(read_file)
807
-
808
- return Range(
809
- start=start_range.start,
810
- end=end_range.end,
811
- )
812
-
813
-
814
- def _process_column_references(
815
- scope: t.Any,
816
- reference_name: str,
817
- read_file: t.List[str],
818
- referenced_model_path: Path,
819
- description: t.Optional[str] = None,
820
- yaml_target_range: t.Optional[Range] = None,
821
- reference_type: t.Literal["model", "external_model", "cte"] = "model",
822
- default_catalog: t.Optional[str] = None,
823
- dialect: t.Optional[str] = None,
824
- cte_target_range: t.Optional[Range] = None,
825
- ) -> t.List[Reference]:
826
- """
827
- Process column references for a given table and create appropriate reference objects.
828
-
829
- Args:
830
- scope: The SQL scope to search for columns
831
- reference_name: The full reference name (may include database/catalog)
832
- read_file: The file content as list of lines
833
- referenced_model_path: Path of the referenced model
834
- description: Markdown description for the reference
835
- yaml_target_range: Target range for external models (YAML files)
836
- reference_type: Type of reference - "model", "external_model", or "cte"
837
- default_catalog: Default catalog for normalization
838
- dialect: SQL dialect for normalization
839
- cte_target_range: Target range for CTE references
840
-
841
- Returns:
842
- List of table references for column usages
843
- """
844
-
845
- references: t.List[Reference] = []
846
- for column in scope.find_all(exp.Column):
847
- if column.table:
848
- if reference_type == "cte":
849
- if column.table == reference_name:
850
- table_range = _get_column_table_range(column, read_file)
851
- references.append(
852
- LSPCteReference(
853
- path=referenced_model_path,
854
- range=table_range,
855
- target_range=cte_target_range,
856
- )
857
- )
858
- else:
859
- table_parts = [part.sql(dialect) for part in column.parts[:-1]]
860
- table_ref = ".".join(table_parts)
861
- normalized_reference_name = normalize_model_name(
862
- table_ref,
863
- default_catalog=default_catalog,
864
- dialect=dialect,
865
- )
866
- if normalized_reference_name == reference_name:
867
- table_range = _get_column_table_range(column, read_file)
868
- if reference_type == "external_model":
869
- references.append(
870
- LSPExternalModelReference(
871
- path=referenced_model_path,
872
- range=table_range,
873
- markdown_description=description,
874
- target_range=yaml_target_range,
875
- )
876
- )
877
- else:
878
- references.append(
879
- LSPModelReference(
880
- path=referenced_model_path,
881
- range=table_range,
882
- markdown_description=description,
883
- )
884
- )
885
-
886
- return references
887
-
888
-
889
- def _get_yaml_model_range(path: Path, model_name: str) -> t.Optional[Range]:
890
- """
891
- Find the range of a specific model block in a YAML file.
892
-
893
- Args:
894
- yaml_path: Path to the YAML file
895
- model_name: Name of the model to find
896
-
897
- Returns:
898
- The Range of the model block in the YAML file, or None if not found
899
- """
900
- yaml = YAML()
901
- with path.open("r", encoding="utf-8") as f:
902
- data = yaml.load(f)
903
-
904
- if not isinstance(data, list):
905
- return None
906
-
907
- for item in data:
908
- if isinstance(item, dict) and item.get("name") == model_name:
909
- # Get size of block by taking the earliest line/col in the items block and the last line/col of the block
910
- position_data = item.lc.data["name"] # type: ignore
911
- start = Position(line=position_data[2], character=position_data[3])
912
- end = Position(line=position_data[2], character=position_data[3] + len(item["name"]))
913
- return Range(start=start, end=end)
914
- return None
sqlmesh/lsp/rename.py CHANGED
@@ -13,7 +13,7 @@ from sqlmesh.lsp.helpers import to_sqlmesh_position, to_lsp_range
13
13
  from sqlmesh.lsp.reference import (
14
14
  _position_within_range,
15
15
  get_cte_references,
16
- LSPCteReference,
16
+ CTEReference,
17
17
  )
18
18
  from sqlmesh.lsp.uri import URI
19
19
 
@@ -82,7 +82,7 @@ def rename_symbol(
82
82
  return None
83
83
 
84
84
 
85
- def _rename_cte(cte_references: t.List[LSPCteReference], new_name: str) -> WorkspaceEdit:
85
+ def _rename_cte(cte_references: t.List[CTEReference], new_name: str) -> WorkspaceEdit:
86
86
  """
87
87
  Create a WorkspaceEdit for renaming a CTE.
88
88