Skip to content
Draft
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
15 changes: 14 additions & 1 deletion lib/closure_tree/numeric_deterministic_ordering.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ def _ct_reorder_children(minimum_sort_order_value = nil)
_ct.reorder_with_parent_id(_ct_id, minimum_sort_order_value, scope_conditions)
end

def _ct_reorder_prior_parent_or_roots(prior_parent, was_root)
if prior_parent
prior_parent._ct_reorder_children
elsif was_root && !_ct.dont_order_roots
scope_conditions = _ct.scope_values_from_instance(self)
_ct.reorder_with_parent_id(nil, nil, scope_conditions)
end
end

def self_and_descendants_preordered
# TODO: raise NotImplementedError if sort_order is not numeric and not null?
hierarchy_table = self.class.hierarchy_class.arel_table
Expand Down Expand Up @@ -130,11 +139,14 @@ def append_child(child_node)
end

def prepend_child(child_node)
prior_parent = child_node.parent
was_root = prior_parent.nil? && child_node.persisted?
child_node.order_value = -1
child_node.parent = self
child_node._ct_skip_sort_order_maintenance!
if child_node.save
_ct_reorder_children
_ct_reorder_prior_parent_or_roots(prior_parent, was_root)
child_node.reload
else
child_node
Expand All @@ -161,6 +173,7 @@ def add_sibling(sibling, add_after = true)

_ct.with_advisory_lock do
prior_sibling_parent = sibling.parent
sibling_was_root = prior_sibling_parent.nil? && sibling.persisted?
reorder_from_value = if prior_sibling_parent == parent
[order_value, sibling.order_value].compact.min
else
Expand All @@ -184,7 +197,7 @@ def add_sibling(sibling, add_after = true)
sibling.update_order_value(self_ov)
end

prior_sibling_parent.try(:_ct_reorder_children) if prior_sibling_parent != parent
sibling._ct_reorder_prior_parent_or_roots(prior_sibling_parent, sibling_was_root) if prior_sibling_parent != parent
sibling
end
end
Expand Down
65 changes: 65 additions & 0 deletions test/closure_tree/label_order_value_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,69 @@ def setup
assert_equal 1, b.order_value
assert_equal 2, c.order_value
end

test 'should reorder remaining root nodes when a root node becomes a child via prepend_child' do
node_1 = Label.create(name: 'node_1')
node_2 = Label.create(name: 'node_2')
node_3 = Label.create(name: 'node_3')
node_4 = Label.create(name: 'node_4')

# Verify initial positions
assert_equal 0, node_1.order_value
assert_equal 1, node_2.order_value
assert_equal 2, node_3.order_value
assert_equal 3, node_4.order_value

# Move node_2 as a child of node_3 using prepend_child
node_3.prepend_child(node_2)

# Reload all nodes to get updated positions
node_1.reload
node_2.reload
node_3.reload
node_4.reload

# Verify node_2 is now a child of node_3 with position 0
assert_equal node_3.id, node_2._ct_parent_id
assert_equal 0, node_2.order_value

# Verify remaining root nodes have sequential positions without gaps
assert_equal 0, node_1.order_value
assert_equal 1, node_3.order_value
assert_equal 2, node_4.order_value
end

test 'should reorder remaining root nodes when a root node becomes a child via add_sibling' do
node_1 = Label.create(name: 'node_1')
node_2 = Label.create(name: 'node_2')
node_3 = Label.create(name: 'node_3')
node_4 = Label.create(name: 'node_4')

# Create a child under node_3
child = Label.create(name: 'child', parent: node_3)

# Verify initial positions
assert_equal 0, node_1.order_value
assert_equal 1, node_2.order_value
assert_equal 2, node_3.order_value
assert_equal 3, node_4.order_value
assert_equal 0, child.order_value

# Move node_2 as a sibling of child (making it a child of node_3)
child.add_sibling(node_2)

# Reload all nodes to get updated positions
node_1.reload
node_2.reload
node_3.reload
node_4.reload

# Verify node_2 is now a child of node_3
assert_equal node_3.id, node_2._ct_parent_id

# Verify remaining root nodes have sequential positions without gaps
assert_equal 0, node_1.order_value
assert_equal 1, node_3.order_value
assert_equal 2, node_4.order_value
end
end