Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/codegraphcontext/tools/indexing/persistence/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1265,6 +1265,17 @@ def _work(session):
)
parent_paths = [record["path"] for record in parents_res]

# Module nodes are shared by their name: a module definition can be
# contained by this file while other files keep INCLUDES or IMPORTS
# edges to the same node. Remove only this file's containment edge
# before deleting the file-owned graph elements.
session.run(
"""
MATCH (f:File {path: $path})-[r:CONTAINS]->(:Module)
DELETE r
""",
path=file_path_str,
)
session.run(
"""
MATCH (f:File {path: $path})
Expand All @@ -1287,6 +1298,7 @@ def _work(session):
)

execute_write_operation(self.driver, backend, _work)
self._purge_dangling_pathless_nodes()
def write_cpp_class_function_links(self, repo_path_str: str) -> None:
"""Post-pass: create Class-[:CONTAINS]->Function edges for C++ files.

Expand Down
60 changes: 60 additions & 0 deletions tests/unit/tools/test_kuzu_import_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,66 @@ def test_kuzu_indexes_import_rows_with_missing_optional_fields(tmp_path):
manager.close_driver()


def test_kuzu_file_deletion_preserves_module_included_by_other_files(tmp_path):
"""Deleting a defining file must not detach other files from its Module."""
repo = tmp_path / "repo"
repo.mkdir()
module_file = repo / "shared.rb"
alpha_file = repo / "alpha.rb"
beta_file = repo / "beta.rb"
for path in (module_file, alpha_file, beta_file):
path.write_text("# fixture\n", encoding="utf-8")

manager, driver = _new_kuzu_driver(tmp_path)
try:
writer = GraphWriter(driver)
writer.add_repository_to_graph(repo)
writer.add_file_to_graph(
{
"path": str(module_file),
"repo_path": str(repo),
"lang": "ruby",
"modules": [{"name": "Shared", "line_number": 1}],
"functions": [],
"classes": [],
"variables": [],
},
repo.name,
{},
repo_path_str=str(repo.resolve()),
)
for path, class_name in ((alpha_file, "Alpha"), (beta_file, "Beta")):
writer.add_file_to_graph(
{
"path": str(path),
"repo_path": str(repo),
"lang": "ruby",
"classes": [{"name": class_name, "line_number": 1}],
"module_inclusions": [{"class": class_name, "module": "Shared"}],
"functions": [],
"variables": [],
},
repo.name,
{},
repo_path_str=str(repo.resolve()),
)

writer.delete_file_from_graph(str(module_file))

with driver.session() as session:
rows = session.run(
"""
MATCH (c:Class)-[:INCLUDES]->(m:Module {name: 'Shared'})
RETURN c.name AS class_name
ORDER BY class_name
"""
).data()

assert rows == [{"class_name": "Alpha"}, {"class_name": "Beta"}]
finally:
manager.close_driver()


def test_kuzu_migrates_existing_module_schema_without_full_import_name(tmp_path):
db_path = tmp_path / "db"
db = kuzu.Database(str(db_path))
Expand Down
Loading