34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
# File 'lib/mover.rb', line 34
def move_to(to_class, conditions, instance=nil, copy = false)
from_class = self
add_conditions! where = '', conditions
insert = from_class.column_names & to_class.column_names
insert -= [ 'moved_at' ]
insert.collect! { |col| connection.quote_column_name(col) }
select = insert.clone
if to_class.column_names.include?('moved_at')
insert << connection.quote_column_name('moved_at')
select << connection.quote(Time.now.utc)
end
collector = lambda do |(classes, block)|
classes.collect! { |c| eval(c.to_s) }
block if classes.include?(to_class) || classes.empty?
end
if copy
before = (@before_copy || []).collect(&collector).compact
after = (@after_copy || []).collect(&collector).compact
else before = (@before_move || []).collect(&collector).compact
after = (@after_move || []).collect(&collector).compact
end
instances =
if instance
[ instance ]
elsif before.empty? && after.empty?
[]
else
self.find(:all, :conditions => where[5..-1])
end
exec_callbacks = lambda do |callbacks|
callbacks.each do |block|
instances.each { |instance| instance.instance_eval(&block) }
end
end
transaction do
exec_callbacks.call before
if copy
from_ids = from_class.find(:all, :select => "id", :conditions => where[5..-1]).collect(&:id)
to_ids = to_class.find(:all, :select => "id", :conditions => where[5..-1]).collect(&:id)
trash_ids = to_ids - from_ids
insert_ids = from_ids - to_ids - trash_ids
update_ids = to_ids - insert_ids - trash_ids
unless update_ids.empty?
update = []
insert.each_with_index{|col, i|
to = insert[i].include?('`') ? "#{to_class.table_name}.#{insert[i]}" : insert[i]
from = select[i].include?('`') ? "#{from_class.table_name}.#{select[i]}" : select[i]
update << "#{to} = #{from}"
}
where_ids = update_ids.collect{|x| "#{from_class.table_name}.id = #{x}"}
connection.execute(<<-SQL)
UPDATE #{to_class.table_name}
INNER JOIN #{from_class.table_name}
ON #{to_class.table_name}.id = #{from_class.table_name}.id
AND (#{where_ids.join(' AND ')})
SET #{update.join(', ')}
SQL
end
unless insert_ids.empty?
where_ids = insert_ids.collect{|x| "#{from_class.table_name}.id = #{x}"}
sql =<<-SQL
INSERT INTO #{to_class.table_name} (#{insert.join(', ')})
SELECT #{select.join(', ')}
FROM #{from_class.table_name}
WHERE (#{where_ids.join(' OR ')})
SQL
connection.execute(sql)
end
else
connection.execute(<<-SQL)
INSERT INTO #{to_class.table_name} (#{insert.join(', ')})
SELECT #{select.join(', ')}
FROM #{from_class.table_name}
#{where}
SQL
connection.execute("DELETE FROM #{from_class.table_name} #{where}")
end
exec_callbacks.call after
end
end
|