class CollectiveIdea::Acts::NestedSet::Move

Attributes

instance[R]
position[R]
target[R]

Public Class Methods

new(target, position, instance) click to toggle source
# File lib/awesome_nested_set/move.rb, line 7
def initialize(target, position, instance)
  @target = target
  @position = position
  @instance = instance
end

Public Instance Methods

move() click to toggle source
# File lib/awesome_nested_set/move.rb, line 13
def move
  prevent_impossible_move

  bound, other_bound = get_boundaries

  # there would be no change
  return if bound == right || bound == left

  # we have defined the boundaries of two non-overlapping intervals,
  # so sorting puts both the intervals and their boundaries in order
  a, b, c, d = [left, right, bound, other_bound].sort

  lock_nodes_between! a, d

  nested_set_scope_without_default_scope.where(where_statement(a, d)).update_all(
    conditions(a, b, c, d)
  )
end

Private Instance Methods

case_condition_for_direction(column_name) click to toggle source
# File lib/awesome_nested_set/move.rb, line 69
def case_condition_for_direction(column_name)
  column = send(column_name)
  "#{column} = CASE " +
    "WHEN #{column} BETWEEN :a AND :b " +
    "THEN #{column} + :d - :b " +
    "WHEN #{column} BETWEEN :c AND :d " +
    "THEN #{column} + :a - :c " +
    "ELSE #{column} END, "
end
case_condition_for_parent() click to toggle source
# File lib/awesome_nested_set/move.rb, line 79
def case_condition_for_parent
  "#{quoted_parent_column_name} = CASE " +
    "WHEN #{quoted_primary_column_name} = :primary_id THEN :new_parent_id " +
    "ELSE #{quoted_parent_column_name} END"
end
conditions(a, b, c, d) click to toggle source
# File lib/awesome_nested_set/move.rb, line 48
def conditions(a, b, c, d)
  _conditions = case_condition_for_direction(:quoted_left_column_name) +
                case_condition_for_direction(:quoted_right_column_name) +
                case_condition_for_parent

  # We want the record to be 'touched' if it timestamps.
  if @instance.respond_to?(:updated_at)
    _conditions << ", updated_at = :timestamp"
  end

  [
    _conditions,
    {
      :a => a, :b => b, :c => c, :d => d,
      :primary_id => instance.primary_id,
      :new_parent_id => new_parent_id,
      :timestamp => Time.now.utc
    }
  ]
end
get_boundaries() click to toggle source
# File lib/awesome_nested_set/move.rb, line 103
def get_boundaries
  if (bound = target_bound) > right
    bound -= 1
    other_bound = right + 1
  else
    other_bound = left - 1
  end
  [bound, other_bound]
end
lock_nodes_between!(left_bound, right_bound) click to toggle source
# File lib/awesome_nested_set/move.rb, line 85
def lock_nodes_between!(left_bound, right_bound)
  # select the rows in the model between a and d, and apply a lock
  instance_base_class.right_of(left_bound).left_of_right_side(right_bound).
                      select(primary_column_name).lock(true)
end
new_parent_id() click to toggle source
# File lib/awesome_nested_set/move.rb, line 95
def new_parent_id
  case position
  when :child then target.primary_id
  when :root  then nil
  else target[parent_column_name]
  end
end
prevent_impossible_move() click to toggle source
# File lib/awesome_nested_set/move.rb, line 116
def prevent_impossible_move
  if !root && !instance.move_possible?(target)
    raise ImpossibleMove, "Impossible move, target node cannot be inside moved tree."
  end
end
root() click to toggle source
# File lib/awesome_nested_set/move.rb, line 91
def root
  position == :root
end
target_bound() click to toggle source
# File lib/awesome_nested_set/move.rb, line 122
def target_bound
  case position
  when :child then right(target)
  when :left  then left(target)
  when :right then right(target) + 1
  when :root  then nested_set_scope_without_default_scope.pluck(right_column_name).max + 1
  else raise ActiveRecord::ActiveRecordError, "Position should be :child, :left, :right or :root ('#{position}' received)."
  end
end
where_statement(left_bound, right_bound) click to toggle source
# File lib/awesome_nested_set/move.rb, line 43
def where_statement(left_bound, right_bound)
  instance_arel_table[left_column_name].in(left_bound..right_bound).
    or(instance_arel_table[right_column_name].in(left_bound..right_bound))
end