feat: Update deletion trigger to run on statement - BED-8796#100
feat: Update deletion trigger to run on statement - BED-8796#100StephenHinck wants to merge 2 commits into
Conversation
WalkthroughThe PostgreSQL ChangesStatement-level cascade delete trigger
Go dependency updates
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@integration/pgsql_delete_cascade_test.go`:
- Around line 105-107: The cascade-delete assertion is currently querying via
countByCypher on CascadeDeleteNode/CascadeDeleteEdge, which only sees
relationships whose endpoints still exist. Update the pgsql_delete_cascade_test
check to count the edge table directly with a SQL count(*) against the edge
storage so orphaned CascadeDeleteEdge rows are detected; keep the existing
expectation and adjust the helper usage in this test block accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 71bb1960-c899-4331-b423-44347be4b163
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (3)
drivers/pg/query/sql/schema_up.sqlgo.modintegration/pgsql_delete_cascade_test.go
| if edgeCount := countByCypher(t, ctx, db, "MATCH (:CascadeDeleteNode)-[r:CascadeDeleteEdge]->(:CascadeDeleteNode) RETURN count(r)"); edgeCount != 1 { | ||
| t.Fatalf("surviving edge count: got %d, want 1", edgeCount) | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm Cypher MATCH translation joins edges to existing nodes (excluding orphans),
# which would make the current edge assertion blind to failed cascades.
rg -nP --type=go -C3 'func .*Query\(' drivers/pg
rg -nP --type=go -C3 'start_id|end_id|join .*node' drivers/pg/queryRepository: SpecterOps/DAWGS
Length of output: 3121
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== Files ==\n'
git ls-files integration/pgsql_delete_cascade_test.go drivers/pg/query.go drivers/pg/query/format.go drivers/pg/transaction.go | cat
printf '\n== Outline: integration/pgsql_delete_cascade_test.go ==\n'
ast-grep outline integration/pgsql_delete_cascade_test.go --view expanded || true
printf '\n== Outline: drivers/pg/query.go ==\n'
ast-grep outline drivers/pg/query.go --view expanded || true
printf '\n== Outline: drivers/pg/query/format.go ==\n'
ast-grep outline drivers/pg/query/format.go --view expanded || true
printf '\n== Outline: drivers/pg/transaction.go ==\n'
ast-grep outline drivers/pg/transaction.go --view expanded || true
printf '\n== Relevant snippets ==\n'
for f in integration/pgsql_delete_cascade_test.go drivers/pg/query.go drivers/pg/query/format.go drivers/pg/transaction.go; do
printf '\n--- %s ---\n' "$f"
wc -l "$f"
done
printf '\n== test file excerpt ==\n'
sed -n '1,220p' integration/pgsql_delete_cascade_test.go
printf '\n== query.go excerpt ==\n'
sed -n '1,220p' drivers/pg/query.go
printf '\n== query/format.go excerpt around relationship upsert ==\n'
sed -n '130,220p' drivers/pg/query/format.go
printf '\n== transaction.go excerpt around Query ==\n'
sed -n '250,340p' drivers/pg/transaction.goRepository: SpecterOps/DAWGS
Length of output: 17875
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== translate package files ==\n'
git ls-files 'cypher/models/pgsql/translate/**/*.go' 'cypher/models/pgsql/translate/*.go' | cat
printf '\n== outlines ==\n'
for f in $(git ls-files 'cypher/models/pgsql/translate/**/*.go' 'cypher/models/pgsql/translate/*.go'); do
printf '\n--- %s ---\n' "$f"
ast-grep outline "$f" --view expanded || true
done
printf '\n== search for relationship joins ==\n'
rg -n -C 3 'start_id|end_id|join .*node|relationship|pattern' cypher/models/pgsql/translate
printf '\n== search for MATCH/relationship translation tests ==\n'
rg -n -C 2 'MATCH \(.*\)-\[.*\]->\(.*\)|count\(r\)|start_id|end_id' cypher/models/pgsql/translate test integration cypher || trueRepository: SpecterOps/DAWGS
Length of output: 50375
Count the edge table directly here. MATCH (:CascadeDeleteNode)-[r:CascadeDeleteEdge]->(:CascadeDeleteNode) only matches relationships whose endpoints still exist, so orphaned rows left behind by a broken cascade can be missed. Use a direct select count(*) from edge check instead.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@integration/pgsql_delete_cascade_test.go` around lines 105 - 107, The
cascade-delete assertion is currently querying via countByCypher on
CascadeDeleteNode/CascadeDeleteEdge, which only sees relationships whose
endpoints still exist. Update the pgsql_delete_cascade_test check to count the
edge table directly with a SQL count(*) against the edge storage so orphaned
CascadeDeleteEdge rows are detected; keep the existing expectation and adjust
the helper usage in this test block accordingly.
Description
BloodHound primarily works with PG in batch data, it is rare for the application to delete a single node or edge. By moving the table trigger to delete edges associated with nodes to
FOR EACH STATEMENT, batch node deletes will call a single edge deletion, rather than running for every deleted node, improving DB performance across all deletions.Resolves: BED-8796
Type of Change
Testing
make test_allwithCONNECTION_STRINGset)Screenshots (if appropriate):
Driver Impact
drivers/pg)drivers/neo4j)Checklist
go.mod/go.sumare up to date if dependencies changedSummary by CodeRabbit