Skip to content

fix edge table delete cascade to preserve shared children (#5)#44

Open
stalep wants to merge 1 commit intoHyperfoil:mainfrom
stalep:issue_5
Open

fix edge table delete cascade to preserve shared children (#5)#44
stalep wants to merge 1 commit intoHyperfoil:mainfrom
stalep:issue_5

Conversation

@stalep
Copy link
Copy Markdown
Member

@stalep stalep commented Apr 7, 2026

When deleting a node/value with references in edge tables (node_edge, value_edge), shared children are now preserved if they have other parents. Fixes the entity/query mismatch in getDependentValues, adds parent count checks before cascading deletes, and cleans up inverse edge rows.

@stalep stalep requested review from barreiro and willr3 April 7, 2026 10:02
…il#5)

When deleting a node/value with references in edge tables, shared
children are now preserved if they have other parents. Fixes the
entity/query mismatch in getDependentValues, adds parent count
checks before cascading deletes, and cleans up inverse edge rows.
@willr3
Copy link
Copy Markdown
Collaborator

willr3 commented Apr 10, 2026

This PR claims to fix closure table delete cascade in the main branch but I don't see where the main branch is using a closure table and this PR does not re-introduce a closure table.

@stalep
Copy link
Copy Markdown
Member Author

stalep commented Apr 13, 2026

yeah, the fix itself is about preserving shared children in these edge tables during delete cascades (checking parent count before removing), but the PR title/description should have said "edge table" instead of "closure table". Updating now.

@stalep stalep changed the title fix closure table delete cascade to preserve shared children (#5) fix edge table delete cascade to preserve shared children (#5) Apr 13, 2026
@stalep stalep requested a review from Copilot April 14, 2026 20:07
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates cascade-delete behavior for node_edge and value_edge relationships so that deleting a parent node/value does not incorrectly delete children that still have other parents, and adds regression tests around shared vs exclusive dependents.

Changes:

  • Fixes getDependentValues to return ValueEntity (previously queried via NodeEntity).
  • Adds parent-count checks and explicit edge-table cleanup to NodeService.delete and ValueService.delete.
  • Reworks deleteDescendantValues and purge to avoid deleting values that still have external parents, plus adds tests for these cases.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/test/java/io/hyperfoil/tools/h5m/svc/ValueServiceTest.java Adds regression tests covering shared/exclusive child behavior for delete, deleteDescendants, and purge.
src/test/java/io/hyperfoil/tools/h5m/svc/NodeServiceTest.java Adds regression test ensuring shared dependent nodes survive deleting one parent.
src/main/java/io/hyperfoil/tools/h5m/svc/ValueService.java Fixes dependent query type and adds edge-aware cascade logic for deletes/purge/descendant deletion.
src/main/java/io/hyperfoil/tools/h5m/svc/NodeService.java Adds parent counting and edge-aware cascading delete for nodes.
src/main/java/io/hyperfoil/tools/h5m/svc/EdgeQueries.java Introduces shared native-query helpers for edge-table parent counts and cleanup deletes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +196 to +204
Map<Long, Long> parentCounts = getNodeParentCounts(dependents.stream().map(n -> n.id).toList());
for(NodeEntity dependent : dependents){
long parentCount = parentCounts.getOrDefault(dependent.id, 0L);
if(parentCount <= 1){
delete(dependent.id);
}
}
// clean up edge rows where this node is a parent (inverse side not managed by JPA)
EdgeQueries.deleteParentEdges(em, "node_edge", nodeId);
Comment on lines +562 to +566
Map<Long, Long> parentCounts = getParentCounts(descendants.stream().map(ValueEntity::getId).toList());
int deleted = 0;
for(ValueEntity v : descendants){
if(parentCounts.getOrDefault(v.id, 0L) <= 1){
EdgeQueries.deleteParentEdges(em, "value_edge", v.id);
Comment on lines +588 to +593
if(!hasExternalParent(d, purgeSet)){
EdgeQueries.deleteParentEdges(em, "value_edge", d.id);
EdgeQueries.deleteChildEdges(em, "value_edge", d.id);
em.createNativeQuery("DELETE FROM value WHERE id = :id")
.setParameter("id", d.id).executeUpdate();
deleted++;
Comment on lines +86 to +88
Map<Long, Long> parentCounts = getParentCounts(dependents.stream().map(ValueEntity::getId).toList());
for(ValueEntity dependent : dependents){
long parentCount = parentCounts.getOrDefault(dependent.id, 0L);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants