Skip to content

Commit 3cfac50

Browse files
authored
[DCV-3454] Restore custom functionality of old v0.x (#17)
* Override _apply_dbt_builtins to prevent FunctionWrapper errors on config.get() * Strip snapshot tags * Wrap code in subquery to safely apply user's LIMIT * Don't apply default limit if an in-script limit clause is present * [DCV-3454] /health: always return ready if server is running * [DCV-3454] Use env variable for logging level
1 parent 1d61667 commit 3cfac50

File tree

3 files changed

+43
-11
lines changed

3 files changed

+43
-11
lines changed

src/dbt_core_interface/dbt_templater/templater.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ def dbt_version(self) -> str:
4545
"""Gets the dbt version."""
4646
return self._dbt_version.to_version_string()
4747

48+
def _apply_dbt_builtins(self, config: FluffConfig | None) -> bool:
49+
"""DbtTemplater uses actual dbt compilation, not FunctionWrapper placeholders.
50+
51+
Returning False prevents SQLFluff from adding FunctionWrapper objects
52+
(which lack .get() method) to the Jinja environment during slice_file analysis.
53+
"""
54+
return False
55+
4856
@large_file_check
4957
def process( # pyright: ignore[reportIncompatibleMethodOverride]
5058
self,

src/dbt_core_interface/project.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import functools
1010
import gc
1111
import json
12+
import re
1213
import logging
1314
import os
1415
import shlex
@@ -694,6 +695,9 @@ def _create_temp_node(
694695
self, sql: str, node_id: str | None = None
695696
) -> tuple[ManifestNode, t.Callable[[], None]]:
696697
"""Create a temporary node for SQL execution/compilation."""
698+
# Remove only the opening and closing snapshot tags, keep the body
699+
sql = re.sub(r'{%\s*snapshot\b.*?%}', '', sql, flags=re.DOTALL)
700+
sql = re.sub(r'{%\s*endsnapshot\s*%}', '', sql, flags=re.DOTALL)
697701
node_id = node_id or f"temp_node_{uuid.uuid4().hex[:8]}"
698702
sql_node = self.sql_parser.parse_remote(sql, node_id)
699703
process_node(self.runtime_config, self.manifest, sql_node)

src/dbt_core_interface/server.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import json
1010
import logging
1111
import os
12+
import re
1213
import time
1314
import typing as t
1415
import uuid
@@ -284,17 +285,31 @@ def run_sql(
284285
comp_res = runner.compile_sql(raw_sql)
285286
try:
286287
model_context = runner.generate_runtime_model_context(comp_res.node)
287-
query = runner.adapter.execute_macro(
288-
macro_name="get_show_sql",
289-
macro_resolver=runner.manifest,
290-
context_override=model_context,
291-
kwargs={
292-
"compiled_code": model_context["compiled_code"],
293-
"sql_header": model_context["config"].get("sql_header"),
294-
"limit": limit,
295-
},
296-
)
288+
original_code = model_context["compiled_code"]
289+
sql_header = model_context["config"].get("sql_header") or ""
290+
291+
# Check if query already has a LIMIT clause at the end - if so, execute as-is
292+
query: str
293+
has_limit = bool(re.search(r"\slimit\s+\d+(\s+offset\s+\d+)?\s*;?\s*$", original_code, re.IGNORECASE))
294+
295+
if has_limit:
296+
query = f"{sql_header}\n{original_code}" if sql_header else original_code
297+
298+
else:
299+
# Wrap in subquery to safely apply limit
300+
compiled_code = f"select * from ({original_code}) as __server_query"
301+
query = runner.adapter.execute_macro(
302+
macro_name="get_show_sql",
303+
macro_resolver=runner.manifest,
304+
context_override=model_context,
305+
kwargs={
306+
"compiled_code": compiled_code,
307+
"sql_header": sql_header,
308+
"limit": limit,
309+
},
310+
)
297311
exec_res = runner.execute_sql(t.cast(str, query), compile=False) # pyright: ignore[reportInvalidCast]
312+
298313
except Exception as e:
299314
response.status_code = 500
300315
return ServerErrorContainer(
@@ -469,9 +484,14 @@ def parse_project(
469484

470485

471486
@app.get("/health") # legacy extension support
487+
def health() -> dict[str, t.Any]:
488+
"""Health check for vscode-sqlfluff extension. Always returns ready if server is running."""
489+
return {"result": {"status": "ready"}}
490+
491+
472492
@app.get("/api/v1/status")
473493
def status(runner: DbtProject = Depends(_get_runner)) -> dict[str, t.Any]:
474-
"""Health check endpoint to verify server status."""
494+
"""Status endpoint with project details."""
475495
return {
476496
"result": {
477497
"status": "ready",

0 commit comments

Comments
 (0)