Class: SimpleNestedSet::Move::ToTarget

Inherits:
Object
  • Object
show all
Includes:
Protection
Defined in:
lib/simple_nested_set/move/to_target.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Protection

#impossible_move!, #inconsistent_move!, #protect_impossible_move!, #protect_inconsistent_move!

Constructor Details

#initialize(node, target, position) ⇒ ToTarget

Returns a new instance of ToTarget.



10
11
12
13
14
# File 'lib/simple_nested_set/move/to_target.rb', line 10

def initialize(node, target, position)
  @node, @target, @position = node, target, position
  @target = nested_set.find(target) if target && !target.is_a?(ActiveRecord::Base)
  protect_impossible_move!
end

Instance Attribute Details

#nodeObject (readonly)

Returns the value of attribute node.



6
7
8
# File 'lib/simple_nested_set/move/to_target.rb', line 6

def node
  @node
end

#positionObject (readonly)

Returns the value of attribute position.



6
7
8
# File 'lib/simple_nested_set/move/to_target.rb', line 6

def position
  @position
end

#targetObject (readonly)

Returns the value of attribute target.



6
7
8
# File 'lib/simple_nested_set/move/to_target.rb', line 6

def target
  @target
end

Instance Method Details

#boundObject



68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/simple_nested_set/move/to_target.rb', line 68

def bound
  @bound ||= begin
    bound = case position
      when :child ; target.rgt
      when :left  ; target.lft
      when :right ; target.rgt + 1
      when :root 
        r = roots.where('id <> ?', node.id)
        r.empty?? 1 : r.last.rgt + 1
    end
    bound > node.rgt ? bound - 1 : bound
  end
end

#boundariesObject



62
63
64
65
66
# File 'lib/simple_nested_set/move/to_target.rb', line 62

def boundaries
  # we have defined the boundaries of two non-overlapping intervals,
  # so sorting puts both the intervals and their boundaries in order
  @boundaries ||= [node.lft, node.rgt, bound, other_bound].sort
end

#other_boundObject

TODO name other_bound in a more reasonable way



83
84
85
# File 'lib/simple_nested_set/move/to_target.rb', line 83

def other_bound
  @other_bound ||= bound > node.rgt ? node.rgt + 1 : node.lft - 1
end

#parent_idObject



54
55
56
57
58
59
60
# File 'lib/simple_nested_set/move/to_target.rb', line 54

def parent_id
  @parent_id ||= case position
    when :child;  target.id
    when :root;   nil
    else          target.parent_id
  end
end

#performObject



16
17
18
19
20
21
22
23
# File 'lib/simple_nested_set/move/to_target.rb', line 16

def perform
  node.run_callbacks(:move) do
    unless bound == node.rgt || bound == node.lft # there would be no change
      nested_set.transaction { update_structure! }
    end
    reload
  end
end

#reloadObject



49
50
51
52
# File 'lib/simple_nested_set/move/to_target.rb', line 49

def reload
  target.nested_set.reload if target
  node.nested_set.reload
end

#rootsObject



87
88
89
# File 'lib/simple_nested_set/move/to_target.rb', line 87

def roots
  @roots ||= node.nested_set.roots
end

#table_nameObject



91
92
93
# File 'lib/simple_nested_set/move/to_target.rb', line 91

def table_name
  node.class.quoted_table_name
end

#update_structure!Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/simple_nested_set/move/to_target.rb', line 25

def update_structure!
  sql = <<-sql
    lft = CASE
      WHEN lft BETWEEN :a AND :b THEN lft + :d - :b
      WHEN lft BETWEEN :c AND :d THEN lft + :a - :c
      ELSE lft END,

    rgt = CASE
      WHEN rgt BETWEEN :a AND :b THEN rgt + :d - :b
      WHEN rgt BETWEEN :c AND :d THEN rgt + :a - :c
      ELSE rgt END,

    parent_id = CASE
      WHEN id = :id THEN :parent_id
      ELSE parent_id END
  sql

  a, b, c, d = boundaries
  sql = [sql, { :a => a, :b => b, :c => c, :d => d, :id => id, :parent_id => parent_id }]

  # puts ActiveRecord::Base.send(:sanitize_sql_array, sql)
  nested_set.update_all(sql)
end