Delete Strategies
This notebook demonstrates the three deletion strategies supported by deleteNode():
``”cascade”`` (default): ON DELETE CASCADE — delete the node and all connected edges.
``”restrict”``: ON DELETE RESTRICT — refuse to delete if the node has connected edges.
``”set_null”``: ON DELETE SET NULL — delete the node and its edges, but keep neighbor nodes.
It also covers cascade delete through WeakNode hierarchies via the propagation flag.
[ ]:
import importlib.util
package_to_check = 'drm'
spec = importlib.util.find_spec(package_to_check)
if spec is None:
print(f'⚠️ {package_to_check} no està instal·lat. Iniciant instal·lació...')
%pip install -q --upgrade drm-tools
print("✅ Instal·lació completada. L'estat del kernel PODRIA requerir un reinici.")
else:
print(f'✅ {package_to_check} ja està present al sistema. Saltant instal·lació.')
[ ]:
from drm import NetworkXGraph, Node, WeakNode, Relation
graph = NetworkXGraph()
# Create a small graph:
# Alice --WROTE--> Paper1 --CITES--> Paper2
# Bob --WROTE--> Paper1
#
# Document1
# |--CONTAINS--> Section1 (WeakNode)
# |--CONTAINS--> Page1 (WeakNode of Section1)
doc = Node(pk={"doc": "DOC-001"}, main_label="Document")
section = WeakNode(parent=doc, pk={"section": 1}, main_label="Section")
page = WeakNode(parent=section, pk={"page": 1}, main_label="Page")
alice = Node(pk={"name": "Alice"}, main_label="Author")
bob = Node(pk={"name": "Bob"}, main_label="Author")
paper1 = Node(pk={"title": "P1"}, main_label="Paper")
paper2 = Node(pk={"title": "P2"}, main_label="Paper")
# Insert all nodes
graph.insertNode(doc)
graph.insertNode(section, insert_parent=True)
graph.insertNode(page, insert_parent=True)
graph.insertNode(alice)
graph.insertNode(bob)
graph.insertNode(paper1)
graph.insertNode(paper2)
# Create relations
graph.insertRelation(Relation(alice, paper1, "WROTE"))
graph.insertRelation(Relation(bob, paper1, "WROTE"))
graph.insertRelation(Relation(paper1, paper2, "CITES"))
def show_state(label):
print(f"\n=== {label} ===")
print(f"Nodes: {graph.get_node_ids()}")
print(f"Edges: {graph.get_edges()}")
show_state("Initial state")
Strategy 1: CASCADE (default)
on_delete="cascade" deletes the node and all connected edges. Neighbor nodes remain as standalone entities.
[ ]:
print("Before deleting paper1:")
show_state("Before CASCADE delete of paper1")
# Delete paper1 with cascade (default)
result = graph.deleteNode(paper1, on_delete="cascade")
print(f"deleteNode returned: {result}")
print("\nAfter deleting paper1 (CASCADE):")
show_state("After CASCADE delete of paper1")
print("Note: Alice, Bob, and paper2 still exist, but edges are gone.")
Strategy 2: RESTRICT
on_delete="restrict" refuses to delete if the node has any connected edges. This is useful for enforcing referential integrity.
[ ]:
print("Before trying to delete alice (who has edges):")
show_state("Before RESTRICT delete attempt on alice")
try:
graph.deleteNode(alice, on_delete="restrict")
print("ERROR: Should have raised RuntimeError!")
except RuntimeError as e:
print(f"Caught expected error: {e}")
print("\nGraph unchanged (alice was not deleted):")
show_state("After RESTRICT attempt (unchanged)")
Strategy 3: SET NULL
on_delete="set_null" deletes the node and its edges, but keeps neighbor nodes as standalone entities. Functionally similar to cascade for the graph structure, but with a different semantic meaning.
[ ]:
print("Before deleting bob:")
show_state("Before SET NULL delete of bob")
result = graph.deleteNode(bob, on_delete="set_null")
print(f"deleteNode returned: {result}")
print("\nAfter deleting bob (SET NULL):")
show_state("After SET NULL delete of bob")
print("Note: alice and paper1 still exist, edges removed.")
Cascade delete through WeakNode hierarchies
When propagation=True, deleting a parent node also deletes all child WeakNodes connected via edges with _propagate=True. This is the default behavior for WeakNode relations.
[ ]:
# Reset: create a fresh graph with a WeakNode hierarchy
graph2 = NetworkXGraph()
doc2 = Node(pk={"doc": "DOC-002"}, main_label="Document")
section2 = WeakNode(parent=doc2, pk={"section": 1}, main_label="Section")
page2 = WeakNode(parent=section2, pk={"page": 1}, main_label="Page")
graph2.insertNode(doc2)
graph2.insertNode(section2, insert_parent=True)
graph2.insertNode(page2, insert_parent=True)
print("Before deleting the document:")
show_state("Before cascade delete of Document")
print("Hierarchy: Document -> Section -> Page")
# Delete the parent document with propagation
# This cascades to Section and Page
result = graph2.deleteNode(doc2, propagation=True, detach=True)
print(f"\ndeleteNode returned: {result}")
print("\nAfter deleting Document with propagation=True:")
show_state("After cascade delete of Document")
print("All nodes (Document, Section, Page) were deleted.")
Summary table
Strategy |
Deletes node |
Deletes edges |
Keeps neighbors |
Raises on edges |
|---|---|---|---|---|
|
✅ |
✅ |
✅ (standalone) |
❌ |
|
❌ |
❌ |
— |
✅ (RuntimeError) |
|
✅ |
✅ |
✅ (standalone) |
❌ |
With propagation=True, cascade/delete also removes child WeakNodes.
Cleanup
[ ]:
graph.close()
graph2.close()
print("All graphs closed.")