Skip to content

Commit d92bf84

Browse files
authored
Fix: Quote columns when getting column level lineage (#2907)
1 parent 1fa1a4c commit d92bf84

File tree

2 files changed

+47
-2
lines changed

2 files changed

+47
-2
lines changed

tests/web/test_lineage.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,3 +697,41 @@ def test_get_lineage_constants(project_context: Context) -> None:
697697
response_json = response.json()
698698
assert response_json['"foo"']["col"]["models"] == {'"bar"': ["col"]}
699699
assert response_json['"bar"']["col"]["models"] == {'"external_table"': ["col"]}
700+
701+
702+
def test_get_lineage_quoted_columns(project_context: Context) -> None:
703+
project_tmp_path = project_context.path
704+
models_dir = project_tmp_path / "models"
705+
models_dir.mkdir()
706+
foo_sql_file = models_dir / "foo.sql"
707+
foo_sql_file.write_text(
708+
"""MODEL (name foo);
709+
WITH my_cte AS (
710+
SELECT col as "@col" FROM bar
711+
UNION
712+
SELECT NULL::TIMESTAMP as "@col" FROM bar
713+
UNION
714+
SELECT 1 as "@col" FROM external_table
715+
)
716+
SELECT "@col" FROM my_cte;"""
717+
)
718+
bar_sql_file = models_dir / "bar.sql"
719+
bar_sql_file.write_text(
720+
"""MODEL (name bar);
721+
SELECT col FROM external_table;"""
722+
)
723+
project_context.load()
724+
725+
response = client.get("/api/lineage/foo/@col")
726+
assert response.status_code == 200, response.json()
727+
response_json = response.json()
728+
assert response_json['"foo"']["@col"]["models"] == {'"foo": my_cte': ["@col"]}
729+
assert response_json['"foo": my_cte']["@col"]["models"] == {'"bar"': ["col"]}
730+
assert response_json['"bar"']["col"]["models"] == {'"external_table"': ["col"]}
731+
732+
# Models only
733+
response = client.get("/api/lineage/foo/@col?models_only=1")
734+
assert response.status_code == 200, response.json()
735+
response_json = response.json()
736+
assert response_json['"foo"']["@col"]["models"] == {'"bar"': ["col"]}
737+
assert response_json['"bar"']["col"]["models"] == {'"external_table"': ["col"]}

web/server/api/endpoints/lineage.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
router = APIRouter()
2121

2222

23+
def quote_column(column: str, dialect: str) -> str:
24+
return exp.to_identifier(column, quoted=True).sql(dialect=dialect)
25+
26+
2327
def get_source_name(
2428
node: Node, default_catalog: t.Optional[str], dialect: str, model_name: str
2529
) -> str:
@@ -57,7 +61,8 @@ def create_lineage_adjacency_list(
5761
models={},
5862
)
5963
continue
60-
root = lineage(column, model)
64+
65+
root = lineage(quote_column(column, model.dialect), model)
6166

6267
for node in root.walk():
6368
if root.name == "UNION" and node is root:
@@ -109,7 +114,9 @@ def create_models_only_lineage_adjacency_list(
109114
model = context.get_model(model_name)
110115
dependencies = defaultdict(set)
111116
if model:
112-
for table, column_names in column_dependencies(context, model_name, column).items():
117+
for table, column_names in column_dependencies(
118+
context, model_name, quote_column(column, model.dialect)
119+
).items():
113120
for column_name in column_names:
114121
dependencies[table].add(column_name)
115122
nodes.append((table, column_name))

0 commit comments

Comments
 (0)