sqlmesh 0.189.2.dev3__py3-none-any.whl → 0.189.2.dev5__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 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.189.2.dev3'
21
- __version_tuple__ = version_tuple = (0, 189, 2, 'dev3')
20
+ __version__ = version = '0.189.2.dev5'
21
+ __version_tuple__ = version_tuple = (0, 189, 2, 'dev5')
@@ -7,14 +7,25 @@ from sqlmesh.lsp.uri import URI
7
7
 
8
8
 
9
9
  def get_sql_completions(
10
- context: t.Optional[LSPContext], file_uri: t.Optional[URI]
10
+ context: t.Optional[LSPContext], file_uri: t.Optional[URI], content: t.Optional[str] = None
11
11
  ) -> AllModelsResponse:
12
12
  """
13
13
  Return a list of completions for a given file.
14
14
  """
15
+ # Get SQL keywords for the dialect
16
+ sql_keywords = get_keywords(context, file_uri)
17
+
18
+ # Get keywords from file content if provided
19
+ file_keywords = set()
20
+ if content:
21
+ file_keywords = extract_keywords_from_content(content, get_dialect(context, file_uri))
22
+
23
+ # Combine keywords - SQL keywords first, then file keywords
24
+ all_keywords = list(sql_keywords) + list(file_keywords - sql_keywords)
25
+
15
26
  return AllModelsResponse(
16
27
  models=list(get_models(context, file_uri)),
17
- keywords=list(get_keywords(context, file_uri)),
28
+ keywords=all_keywords,
18
29
  )
19
30
 
20
31
 
@@ -97,3 +108,54 @@ def get_keywords_from_tokenizer(dialect: t.Optional[str] = None) -> t.Set[str]:
97
108
  parts = keyword.split(" ")
98
109
  expanded_keywords.update(parts)
99
110
  return expanded_keywords
111
+
112
+
113
+ def get_dialect(context: t.Optional[LSPContext], file_uri: t.Optional[URI]) -> t.Optional[str]:
114
+ """
115
+ Get the dialect for a given file.
116
+ """
117
+ if file_uri is not None and context is not None and file_uri.to_path() in context.map:
118
+ file_info = context.map[file_uri.to_path()]
119
+
120
+ # Handle ModelInfo objects
121
+ if isinstance(file_info, ModelTarget) and file_info.names:
122
+ model_name = file_info.names[0]
123
+ model_from_context = context.context.get_model(model_name)
124
+ return model_from_context.dialect
125
+
126
+ # Handle AuditInfo objects
127
+ if isinstance(file_info, AuditTarget) and file_info.name:
128
+ audit = context.context.standalone_audits.get(file_info.name)
129
+ if audit is not None and audit.dialect:
130
+ return audit.dialect
131
+
132
+ if context is not None:
133
+ return context.context.default_dialect
134
+
135
+ return None
136
+
137
+
138
+ def extract_keywords_from_content(content: str, dialect: t.Optional[str] = None) -> t.Set[str]:
139
+ """
140
+ Extract identifiers from SQL content using the tokenizer.
141
+ Only extracts identifiers (variable names, table names, column names, etc.)
142
+ that are not SQL keywords.
143
+ """
144
+ if not content:
145
+ return set()
146
+
147
+ tokenizer_class = Dialect.get_or_raise(dialect).tokenizer_class
148
+ keywords = set()
149
+ try:
150
+ tokenizer = tokenizer_class()
151
+ tokens = tokenizer.tokenize(content)
152
+ for token in tokens:
153
+ # Don't include keywords in the set
154
+ if token.text.upper() not in tokenizer_class.KEYWORDS:
155
+ keywords.add(token.text)
156
+
157
+ except Exception:
158
+ # If tokenization fails, return empty set
159
+ pass
160
+
161
+ return keywords
sqlmesh/lsp/context.py CHANGED
@@ -176,15 +176,18 @@ class LSPContext:
176
176
  if audit._path is not None
177
177
  ]
178
178
 
179
- def get_autocomplete(self, uri: t.Optional[URI]) -> AllModelsResponse:
179
+ def get_autocomplete(
180
+ self, uri: t.Optional[URI], content: t.Optional[str] = None
181
+ ) -> AllModelsResponse:
180
182
  """Get autocomplete suggestions for a file.
181
183
 
182
184
  Args:
183
185
  uri: The URI of the file to get autocomplete suggestions for.
186
+ content: The content of the file (optional).
184
187
 
185
188
  Returns:
186
189
  AllModelsResponse containing models and keywords.
187
190
  """
188
191
  from sqlmesh.lsp.completions import get_sql_completions
189
192
 
190
- return get_sql_completions(self, uri)
193
+ return get_sql_completions(self, uri, content)
sqlmesh/lsp/main.py CHANGED
@@ -36,9 +36,7 @@ from sqlmesh.lsp.custom import (
36
36
  RenderModelRequest,
37
37
  RenderModelResponse,
38
38
  )
39
- from sqlmesh.lsp.reference import (
40
- get_references,
41
- )
39
+ from sqlmesh.lsp.reference import get_references, get_cte_references
42
40
  from sqlmesh.lsp.uri import URI
43
41
  from web.server.api.endpoints.lineage import column_lineage, model_lineage
44
42
  from web.server.api.endpoints.models import get_models
@@ -114,13 +112,22 @@ class SQLMeshLanguageServer:
114
112
  @self.server.feature(ALL_MODELS_FEATURE)
115
113
  def all_models(ls: LanguageServer, params: AllModelsRequest) -> AllModelsResponse:
116
114
  uri = URI(params.textDocument.uri)
115
+
116
+ # Get the document content
117
+ content = None
118
+ try:
119
+ document = ls.workspace.get_text_document(params.textDocument.uri)
120
+ content = document.source
121
+ except Exception:
122
+ pass
123
+
117
124
  try:
118
125
  context = self._context_get_or_load(uri)
119
- return context.get_autocomplete(uri)
126
+ return context.get_autocomplete(uri, content)
120
127
  except Exception as e:
121
128
  from sqlmesh.lsp.completions import get_sql_completions
122
129
 
123
- return get_sql_completions(None, URI(params.textDocument.uri))
130
+ return get_sql_completions(None, URI(params.textDocument.uri), content)
124
131
 
125
132
  @self.server.feature(RENDER_MODEL_FEATURE)
126
133
  def render_model(ls: LanguageServer, params: RenderModelRequest) -> RenderModelResponse:
@@ -369,6 +376,28 @@ class SQLMeshLanguageServer:
369
376
  ls.show_message(f"Error getting references: {e}", types.MessageType.Error)
370
377
  return []
371
378
 
379
+ @self.server.feature(types.TEXT_DOCUMENT_REFERENCES)
380
+ def find_references(
381
+ ls: LanguageServer, params: types.ReferenceParams
382
+ ) -> t.Optional[t.List[types.Location]]:
383
+ """Find all references of a symbol (currently supporting CTEs)"""
384
+ try:
385
+ uri = URI(params.text_document.uri)
386
+ self._ensure_context_for_document(uri)
387
+ document = ls.workspace.get_text_document(params.text_document.uri)
388
+ if self.lsp_context is None:
389
+ raise RuntimeError(f"No context found for document: {document.path}")
390
+
391
+ cte_references = get_cte_references(self.lsp_context, uri, params.position)
392
+
393
+ # Convert references to Location objects
394
+ locations = [types.Location(uri=ref.uri, range=ref.range) for ref in cte_references]
395
+
396
+ return locations if locations else None
397
+ except Exception as e:
398
+ ls.show_message(f"Error getting locations: {e}", types.MessageType.Error)
399
+ return None
400
+
372
401
  @self.server.feature(types.TEXT_DOCUMENT_DIAGNOSTIC)
373
402
  def diagnostic(
374
403
  ls: LanguageServer, params: types.DocumentDiagnosticParams
@@ -471,8 +500,16 @@ class SQLMeshLanguageServer:
471
500
  uri = URI(params.text_document.uri)
472
501
  context = self._context_get_or_load(uri)
473
502
 
503
+ # Get the document content
504
+ content = None
505
+ try:
506
+ document = ls.workspace.get_text_document(params.text_document.uri)
507
+ content = document.source
508
+ except Exception:
509
+ pass
510
+
474
511
  # Get completions using the existing completions module
475
- completion_response = context.get_autocomplete(uri)
512
+ completion_response = context.get_autocomplete(uri, content)
476
513
 
477
514
  completion_items = []
478
515
  # Add model completions
sqlmesh/lsp/reference.py CHANGED
@@ -47,16 +47,7 @@ def by_position(position: Position) -> t.Callable[[Reference], bool]:
47
47
  """
48
48
 
49
49
  def contains_position(r: Reference) -> bool:
50
- return (
51
- r.range.start.line < position.line
52
- or (
53
- r.range.start.line == position.line
54
- and r.range.start.character <= position.character
55
- )
56
- ) and (
57
- r.range.end.line > position.line
58
- or (r.range.end.line == position.line and r.range.end.character >= position.character)
59
- )
50
+ return _position_within_range(position, r.range)
60
51
 
61
52
  return contains_position
62
53
 
@@ -478,3 +469,78 @@ def get_built_in_macro_reference(macro_name: str, macro_range: Range) -> t.Optio
478
469
  ),
479
470
  markdown_description=func.__doc__ if func.__doc__ else None,
480
471
  )
472
+
473
+
474
+ def get_cte_references(
475
+ lint_context: LSPContext, document_uri: URI, position: Position
476
+ ) -> t.List[Reference]:
477
+ """
478
+ Get all references to a CTE at a specific position in a document.
479
+
480
+ This function finds both the definition and all usages of a CTE within the same file.
481
+
482
+ Args:
483
+ lint_context: The LSP context
484
+ document_uri: The URI of the document
485
+ position: The position to check for CTE references
486
+
487
+ Returns:
488
+ A list of references to the CTE (including its definition and all usages)
489
+ """
490
+ references = get_model_definitions_for_a_path(lint_context, document_uri)
491
+
492
+ # Filter for CTE references (those with target_range set and same URI)
493
+ # TODO: Consider extending Reference class to explicitly indicate reference type instead
494
+ cte_references = [
495
+ ref for ref in references if ref.target_range is not None and ref.uri == document_uri.value
496
+ ]
497
+
498
+ if not cte_references:
499
+ return []
500
+
501
+ target_cte_definition_range = None
502
+ for ref in cte_references:
503
+ # Check if cursor is on a CTE usage
504
+ if _position_within_range(position, ref.range):
505
+ target_cte_definition_range = ref.target_range
506
+ break
507
+ # Check if cursor is on the CTE definition
508
+ elif ref.target_range and _position_within_range(position, ref.target_range):
509
+ target_cte_definition_range = ref.target_range
510
+ break
511
+
512
+ if target_cte_definition_range is None:
513
+ return []
514
+
515
+ # Add the CTE definition
516
+ matching_references = [
517
+ Reference(
518
+ uri=document_uri.value,
519
+ range=target_cte_definition_range,
520
+ markdown_description="CTE definition",
521
+ )
522
+ ]
523
+
524
+ # Add all usages
525
+ for ref in cte_references:
526
+ if ref.target_range == target_cte_definition_range:
527
+ matching_references.append(
528
+ Reference(
529
+ uri=document_uri.value,
530
+ range=ref.range,
531
+ markdown_description="CTE usage",
532
+ )
533
+ )
534
+
535
+ return matching_references
536
+
537
+
538
+ def _position_within_range(position: Position, range: Range) -> bool:
539
+ """Check if a position is within a given range."""
540
+ return (
541
+ range.start.line < position.line
542
+ or (range.start.line == position.line and range.start.character <= position.character)
543
+ ) and (
544
+ range.end.line > position.line
545
+ or (range.end.line == position.line and range.end.character >= position.character)
546
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlmesh
3
- Version: 0.189.2.dev3
3
+ Version: 0.189.2.dev5
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=VWAfzT3JO6WSHdQvc3FuaKghdPUBtqn5G9xsaKStfHk,528
2
+ sqlmesh/_version.py,sha256=UCkyVwo8pASnW_g9KnP7JuTaDH8HiF1OwE6T433YP3A,528
3
3
  sqlmesh/magics.py,sha256=fu7-OeT_0_TAkWZOLoiioE3-3iFpvTRxFCbQUlRnfuw,39944
4
4
  sqlmesh/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  sqlmesh/cicd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -158,12 +158,12 @@ sqlmesh/integrations/github/cicd/command.py,sha256=rNWb-aMOA9R23YumD5vPwR0PgPGGj
158
158
  sqlmesh/integrations/github/cicd/config.py,sha256=tRhMZaLf1p6AWXvi67n85Q-lptJNGt1Wk_Jr61ytpiM,2104
159
159
  sqlmesh/integrations/github/cicd/controller.py,sha256=IgUWK9orYSMiElO3GaL6Ja-osFgA7je3RDcLChWUi5s,43769
160
160
  sqlmesh/lsp/api.py,sha256=LJdECSaEZoPbu_Xl4KscVG-WLt7_g4dY-zKGO68dH14,2162
161
- sqlmesh/lsp/completions.py,sha256=Ufe5XyqmT8ttXqQDbhH2RtuGC0cVuVfSnGqDMl6KmB4,3601
162
- sqlmesh/lsp/context.py,sha256=ozkrw-897_Scbbn4AnKdeTQhrUb0CI0e34vcV-5U2DA,6158
161
+ sqlmesh/lsp/completions.py,sha256=Y6zNKNne91tzRm5vRk82JmhIpo7dIBUoK8GGQesGlT8,5746
162
+ sqlmesh/lsp/context.py,sha256=RVFGjKWv1o509su80izZL-Wqy8vWElqUDnv2XWvBsgs,6271
163
163
  sqlmesh/lsp/custom.py,sha256=Mml6V1nYAHdP4Zt8gxly1ZLKYALtxGeAVzPrrYpc7m8,1426
164
164
  sqlmesh/lsp/description.py,sha256=4QIGC9ix8IzmWF6DVUNhY4m1Crk3sNQA6hZ1RbyqU78,827
165
- sqlmesh/lsp/main.py,sha256=Y1ISd75Ax09cNkSHw-Z0w_56IQXmmGxoGDWFT6KLs6g,30564
166
- sqlmesh/lsp/reference.py,sha256=-HkMMzRzq4ike5mSkoWajanYNMAwhQhlPaqw62451ac,16887
165
+ sqlmesh/lsp/main.py,sha256=GlqGFQgI1e23UaOQmeFr9jbSCC3zcbQiM_EEMSCiE90,32237
166
+ sqlmesh/lsp/reference.py,sha256=_fXzPDjyDy1AgWtDUMpN9PWk7h98LZt0uMW-llbNl7g,19083
167
167
  sqlmesh/lsp/uri.py,sha256=mvSLbZGmMTHPpliThOtVWiFcHnfJzp1w39q9l-xD2SI,802
168
168
  sqlmesh/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
169
169
  sqlmesh/migrations/v0001_init.py,sha256=h8FwMYJj9_O8yGpk12guaSaGwX5A3we2GiKeHrXi15o,2048
@@ -272,7 +272,7 @@ sqlmesh/utils/pydantic.py,sha256=I898jAFqa3qU6lG2uPpRebVFncOUo8ZrLWM_R3K3DHU,116
272
272
  sqlmesh/utils/rich.py,sha256=xNZyPCqEc4TAlJlsEthg-5eYUWpaizz0QjBzO7a1Yv4,1509
273
273
  sqlmesh/utils/windows.py,sha256=r7Yin4WEwbvH7sKA3hOJtRsclmscNuBeCklCfVPvtQs,611
274
274
  sqlmesh/utils/yaml.py,sha256=np-WVcwmwsKghCgAj1OBBMsK1SXSRn4wR-H37cGiFr8,2282
275
- sqlmesh-0.189.2.dev3.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
275
+ sqlmesh-0.189.2.dev5.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
276
276
  web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
277
277
  web/client/dist/index.html,sha256=LbR9XrOXE77otBPoDnaomssYz6h2TBwLANs6hUJ0p2M,5472
278
278
  web/client/dist/assets/Audits-DB1HcP9M.js,sha256=eGI_Soj69Jntsixw1NqQpdwG94N5jipQZv7T1Y7WUSs,1041
@@ -390,8 +390,8 @@ web/server/api/endpoints/models.py,sha256=ud-lRwriyI_OYg9tZchrBgeiXELiRTLNEodraf
390
390
  web/server/api/endpoints/modules.py,sha256=8hqqgonGay_mJmpCw0IdbjsPhWlQH2VLdKAqha-myac,468
391
391
  web/server/api/endpoints/plan.py,sha256=OYuQ_4dgbhG9ibTcX1a8mvYgH3ANxw9Fhbb4wg6QWqc,9222
392
392
  web/server/api/endpoints/table_diff.py,sha256=SCy3-pr5x6bEEiOaZGCDbiHQhpgxwmnz3Acqa2Ie6jI,2090
393
- sqlmesh-0.189.2.dev3.dist-info/METADATA,sha256=ZwPwvUMCBO1AXjzzXTD-G8hWjrg47KJ7O28aw9_yPF4,26540
394
- sqlmesh-0.189.2.dev3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
395
- sqlmesh-0.189.2.dev3.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
396
- sqlmesh-0.189.2.dev3.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
397
- sqlmesh-0.189.2.dev3.dist-info/RECORD,,
393
+ sqlmesh-0.189.2.dev5.dist-info/METADATA,sha256=f4UGuR824Wi94aH6tQXKt6YbvnTjINkev0MqnYB5-PM,26540
394
+ sqlmesh-0.189.2.dev5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
395
+ sqlmesh-0.189.2.dev5.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
396
+ sqlmesh-0.189.2.dev5.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
397
+ sqlmesh-0.189.2.dev5.dist-info/RECORD,,