activerecord-batch_touching 1.0.pre.beta3 → 1.0.pre.beta4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/activerecord/batch_touching.rb +45 -20
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e3ae09116c725e745e467afa1d834b6b2a28bcae4f01d5346e598235bb7d0a8
|
4
|
+
data.tar.gz: 842acced5ccc6df3149f4ae60b2b7f574f1bf04a553a67b54d6832c1501b94ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5339c3f783b5b4e8f667a47437fa26e507353d648fd99f637ea73925c28d07d626c7eeb9a8850552ae4182ebb1d36ae9acb5acbe0e2d42e7b0d9f1664a0d86d7
|
7
|
+
data.tar.gz: bf5025309b66d19d7571ef34a3701eb23d9d8c054b68619bb6ad1f881439b37eb99e2a6fdd67e53dbadccf585ea41ae2703ee09fe10d3a81dd9e422675aa8b56
|
@@ -55,6 +55,28 @@ module ActiveRecord
|
|
55
55
|
end
|
56
56
|
|
57
57
|
class << self
|
58
|
+
# Disable batch touching globally
|
59
|
+
def disable!
|
60
|
+
@disabled = true
|
61
|
+
end
|
62
|
+
|
63
|
+
# Enable batch touching globally
|
64
|
+
def enable!
|
65
|
+
@disabled = false
|
66
|
+
end
|
67
|
+
|
68
|
+
# Disable batch touching for a block
|
69
|
+
def disable
|
70
|
+
Thread.current[:batch_touching_disabled] = false
|
71
|
+
yield
|
72
|
+
ensure
|
73
|
+
Thread.current[:batch_touching_disabled] = false
|
74
|
+
end
|
75
|
+
|
76
|
+
def disabled?
|
77
|
+
Thread.current[:batch_touching_disabled] || @disabled
|
78
|
+
end
|
79
|
+
|
58
80
|
def states
|
59
81
|
Thread.current[:batch_touching_states] ||= []
|
60
82
|
end
|
@@ -66,7 +88,7 @@ module ActiveRecord
|
|
66
88
|
delegate :add_record, to: :current_state
|
67
89
|
|
68
90
|
def batch_touching?
|
69
|
-
states.present?
|
91
|
+
states.present? && !disabled?
|
70
92
|
end
|
71
93
|
|
72
94
|
# Start batching all touches. When done, apply them. (Unless nested.)
|
@@ -91,20 +113,15 @@ module ActiveRecord
|
|
91
113
|
|
92
114
|
# Apply the touches that were batched. We're in a transaction already so there's no need to open one.
|
93
115
|
def apply_touches
|
116
|
+
current_time = ActiveRecord::Base.current_time_from_proper_timezone
|
94
117
|
callbacks_run = Set.new
|
95
118
|
all_states = State.new
|
96
119
|
while current_state.more_records?
|
97
120
|
all_states.merge!(current_state)
|
98
121
|
state_records = current_state.records
|
99
122
|
current_state.clear_records!
|
100
|
-
state_records.each do |
|
101
|
-
|
102
|
-
records.each do |record|
|
103
|
-
unless callbacks_run.include?(record)
|
104
|
-
record._run_touch_callbacks
|
105
|
-
callbacks_run.add(record)
|
106
|
-
end
|
107
|
-
end
|
123
|
+
state_records.each do |(_klass, columns), records|
|
124
|
+
soft_touch_records(columns, records, current_time, callbacks_run)
|
108
125
|
end
|
109
126
|
end
|
110
127
|
|
@@ -112,30 +129,38 @@ module ActiveRecord
|
|
112
129
|
sorted_records = all_states.records.keys.sort_by { |k| k.first.name }.map { |k| [k, all_states.records[k]] }.to_h
|
113
130
|
sorted_records.each do |(klass, columns), records|
|
114
131
|
records.reject!(&:destroyed?)
|
115
|
-
touch_records klass, columns, records if records.present?
|
132
|
+
touch_records klass, columns, records, current_time if records.present?
|
116
133
|
end
|
117
134
|
end
|
118
135
|
|
119
|
-
#
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
columns.each { |column| write_attribute column, current_time }
|
136
|
+
# Only set new timestamp in memory.
|
137
|
+
# Running callbacks also allows us to collect more touches (i.e. touch: true for associations).
|
138
|
+
def soft_touch_records(columns, records, time, callbacks_run)
|
139
|
+
records.each do |record|
|
140
|
+
record.instance_eval do
|
141
|
+
unless destroyed?
|
142
|
+
columns.each { |column| write_attribute column, time }
|
127
143
|
if locking_enabled?
|
128
144
|
self[self.class.locking_column] += 1
|
129
145
|
clear_attribute_change(self.class.locking_column)
|
130
146
|
end
|
131
147
|
clear_attribute_changes(columns)
|
132
148
|
end
|
149
|
+
unless callbacks_run.include?(record)
|
150
|
+
record._run_touch_callbacks
|
151
|
+
callbacks_run.add(record)
|
152
|
+
end
|
133
153
|
end
|
154
|
+
end
|
155
|
+
end
|
134
156
|
|
135
|
-
|
157
|
+
# Touch the specified records--non-empty set of instances of the same class.
|
158
|
+
def touch_records(klass, columns, records, time)
|
159
|
+
if columns.present?
|
160
|
+
sql = columns.map { |column| "#{klass.connection.quote_column_name(column)} = :time" }.join(", ")
|
136
161
|
sql += ", #{klass.locking_column} = #{klass.locking_column} + 1" if klass.locking_enabled?
|
137
162
|
|
138
|
-
klass.unscoped.where(klass.primary_key => records.to_a).update_all([sql,
|
163
|
+
klass.unscoped.where(klass.primary_key => records.to_a).update_all([sql, time: time])
|
139
164
|
end
|
140
165
|
end
|
141
166
|
end
|