test: one node per SQL table across files

A table no file defines, read from N files, becomes N per-file stub
nodes, and a schema-qualified read never binds to its definition in
another file. A SQL read of `Orders` also binds to a Python class
Orders. Guards cover same-file binding and different schemas.

(cherry picked from commit 1dfc710497)
This commit is contained in:
Deepjyoti-Sarmah authored and safishamsi committed 2026-10-22 13:49:38 +01:00
1 parent 9ce1404719
commit 8e8a7c3808
1 file changed
+95
+95
View File
@@ -0,0 +1,95 @@
"""A table referenced from several files is one node, bound to its definition when one exists."""
from __future__ import annotations
from pathlib import Path
import pytest
pytest.importorskip("tree_sitter_sql")
from graphify.extract import extract # noqa: E402
def _project(tmp_path: Path, files: dict[str, str]) -> dict:
paths = []
for rel, text in files.items():
p = tmp_path / rel
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text(text)
paths.append(p)
return extract(paths, root=tmp_path)
def _norm(label: str) -> str:
return label.replace("[", "").replace("]", "").lower()
def _ids(result: dict, name: str) -> set[str]:
return {n["id"] for n in result["nodes"] if _norm(n["label"]) == name}
def _read_targets(result: dict, view: str) -> set[str]:
src = _ids(result, view)
return {e["target"] for e in result["edges"] if e["source"] in src and e["relation"] == "reads_from"}
VIEWS = {
"v/a.sql": "CREATE VIEW dbo.VA AS SELECT id FROM {t};\n",
"v/b.sql": "CREATE VIEW dbo.VB AS SELECT id FROM {t};\n",
}
# bug
@pytest.mark.parametrize("table", ["dbo.Orders", "Orders"])
def test_undefined_table_from_two_files_is_one_node(tmp_path, table):
r = _project(tmp_path, {k: v.format(t=table) for k, v in VIEWS.items()})
assert len(_ids(r, table.lower())) == 1
assert _read_targets(r, "dbo.va") == _read_targets(r, "dbo.vb")
# bug
@pytest.mark.parametrize("table", ["dbo.Orders", "Orders"])
def test_reads_bind_to_table_defined_in_another_file(tmp_path, table):
files = {"t/tables.sql": f"CREATE TABLE {table} (id INT);\n"}
files.update({k: v.format(t=table) for k, v in VIEWS.items()})
r = _project(tmp_path, files)
defined = _ids(r, table.lower())
assert len(defined) == 1
assert _read_targets(r, "dbo.va") == defined
assert _read_targets(r, "dbo.vb") == defined
# bug
def test_bracket_and_plain_names_across_files_are_one_table(tmp_path):
r = _project(tmp_path, {
"t/tables.sql": "CREATE TABLE [dbo].[Orders] (id INT);\n",
"v/a.sql": "CREATE VIEW dbo.VA AS SELECT id FROM dbo.Orders;\n",
})
assert _read_targets(r, "dbo.va") == _ids(r, "dbo.orders")
assert len(_ids(r, "dbo.orders")) == 1
# guard
def test_same_file_definition_still_binds(tmp_path):
r = _project(tmp_path, {"a.sql": "CREATE TABLE dbo.Orders (id INT);\nCREATE VIEW dbo.VA AS SELECT id FROM dbo.Orders;\n"})
assert _read_targets(r, "dbo.va") == _ids(r, "dbo.orders")
# guard
def test_different_schemas_stay_different_tables(tmp_path):
r = _project(tmp_path, {
"v/a.sql": "CREATE VIEW dbo.VA AS SELECT id FROM dbo.Orders;\n",
"v/b.sql": "CREATE VIEW dbo.VB AS SELECT id FROM sales.Orders;\n",
})
assert _read_targets(r, "dbo.va").isdisjoint(_read_targets(r, "dbo.vb"))
# guard
def test_sql_read_does_not_bind_to_python_class(tmp_path):
r = _project(tmp_path, {
"app/models.py": "class Orders:\n pass\n",
"v/a.sql": "CREATE VIEW dbo.VA AS SELECT id FROM Orders;\n",
})
py = {n["id"] for n in r["nodes"] if n.get("source_file", "").endswith(".py") and n["label"] == "Orders"}
assert py
assert _read_targets(r, "dbo.va").isdisjoint(py)