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 +2 -2
- sqlmesh/lsp/completions.py +64 -2
- sqlmesh/lsp/context.py +5 -2
- sqlmesh/lsp/main.py +43 -6
- sqlmesh/lsp/reference.py +76 -10
- {sqlmesh-0.189.2.dev3.dist-info → sqlmesh-0.189.2.dev5.dist-info}/METADATA +1 -1
- {sqlmesh-0.189.2.dev3.dist-info → sqlmesh-0.189.2.dev5.dist-info}/RECORD +11 -11
- {sqlmesh-0.189.2.dev3.dist-info → sqlmesh-0.189.2.dev5.dist-info}/WHEEL +0 -0
- {sqlmesh-0.189.2.dev3.dist-info → sqlmesh-0.189.2.dev5.dist-info}/entry_points.txt +0 -0
- {sqlmesh-0.189.2.dev3.dist-info → sqlmesh-0.189.2.dev5.dist-info}/licenses/LICENSE +0 -0
- {sqlmesh-0.189.2.dev3.dist-info → sqlmesh-0.189.2.dev5.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.189.2.
|
|
21
|
-
__version_tuple__ = version_tuple = (0, 189, 2, '
|
|
20
|
+
__version__ = version = '0.189.2.dev5'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 189, 2, 'dev5')
|
sqlmesh/lsp/completions.py
CHANGED
|
@@ -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=
|
|
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(
|
|
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,5 +1,5 @@
|
|
|
1
1
|
sqlmesh/__init__.py,sha256=QjwaamJIdW7voXoS880yAx7tHm-Im4_mqGA-XJgafos,7631
|
|
2
|
-
sqlmesh/_version.py,sha256=
|
|
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=
|
|
162
|
-
sqlmesh/lsp/context.py,sha256=
|
|
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=
|
|
166
|
-
sqlmesh/lsp/reference.py,sha256
|
|
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.
|
|
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.
|
|
394
|
-
sqlmesh-0.189.2.
|
|
395
|
-
sqlmesh-0.189.2.
|
|
396
|
-
sqlmesh-0.189.2.
|
|
397
|
-
sqlmesh-0.189.2.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|