counter_culture 3.10.2 → 3.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/lib/counter_culture/configuration.rb +4 -0
- data/lib/counter_culture/counter.rb +21 -10
- data/lib/counter_culture/reconciler.rb +34 -8
- data/lib/counter_culture/version.rb +1 -1
- data/lib/counter_culture.rb +8 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 593e3704f40322fade2c263f93bb6d88749b397d641586b30f4d616ee5c9ed0c
|
4
|
+
data.tar.gz: b183412de943dbe2390a4eef636ca8aae9fea6aeac6ac298177545d26b08413e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0a74d87a9d56ec4b19d7fe9a7aaf9bd2698d527387251a52b866e534117386005e830eef556b96bbc67122a125ebf942a4531be5b6f2d35a075b55b3133b052
|
7
|
+
data.tar.gz: 4cd891261ed5402cffa7eea851e2400f3b6d7ec8c4d617b36a3b0dd680e00f17b9b1a909a55bb94db1dbe636ca4b5d2d929d02df851e00869bb316a703fa8928
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 3.11.1 (June 27, 2025)
|
2
|
+
|
3
|
+
Bugfixes:
|
4
|
+
- Don't attempt to modify frozen association object (#416)
|
5
|
+
|
6
|
+
## 3.11.0 (June 26, 2025)
|
7
|
+
|
8
|
+
New features:
|
9
|
+
- Support for composite primary keys in Rails v7.2+ (#413)
|
10
|
+
|
1
11
|
## 3.10.2 (June 24, 2025)
|
2
12
|
|
3
13
|
Bugfixes:
|
@@ -113,7 +113,9 @@ module CounterCulture
|
|
113
113
|
end
|
114
114
|
|
115
115
|
if @with_papertrail
|
116
|
-
|
116
|
+
conditions = primary_key_conditions(primary_key, id_to_change)
|
117
|
+
instance = klass.where(conditions).first
|
118
|
+
|
117
119
|
if instance
|
118
120
|
if instance.paper_trail.respond_to?(:save_with_version)
|
119
121
|
# touch_with_version is deprecated starting in PaperTrail 9.0.0
|
@@ -137,7 +139,8 @@ module CounterCulture
|
|
137
139
|
|
138
140
|
unless Thread.current[:aggregate_counter_updates]
|
139
141
|
execute_now_or_after_commit(obj) do
|
140
|
-
|
142
|
+
conditions = primary_key_conditions(primary_key, id_to_change)
|
143
|
+
klass.where(conditions).update_all updates.join(', ')
|
141
144
|
unless options[:was]
|
142
145
|
assign_to_associated_object(obj, relation, change_counter_column, operator, delta_magnitude)
|
143
146
|
end
|
@@ -174,7 +177,7 @@ module CounterCulture
|
|
174
177
|
|
175
178
|
# the string to pass to order() in order to sort by primary key
|
176
179
|
def full_primary_key(klass)
|
177
|
-
"#{klass.quoted_table_name}.#{
|
180
|
+
Array.wrap(klass.quoted_primary_key).map { |pk| "#{klass.quoted_table_name}.#{pk}" }.join(', ')
|
178
181
|
end
|
179
182
|
|
180
183
|
# gets the value of the foreign key on the given relation
|
@@ -188,23 +191,24 @@ module CounterCulture
|
|
188
191
|
original_relation = relation
|
189
192
|
relation = relation.is_a?(Enumerable) ? relation.dup : [relation]
|
190
193
|
|
191
|
-
if was
|
194
|
+
value = if was
|
192
195
|
first = relation.shift
|
193
196
|
foreign_key_value = attribute_was(obj, relation_foreign_key(first))
|
194
197
|
klass = relation_klass(first, source: obj, was: was)
|
195
198
|
if foreign_key_value
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
+
primary_key = relation_primary_key(first, source: obj, was: was)
|
200
|
+
conditions = primary_key_conditions(primary_key, foreign_key_value)
|
201
|
+
klass.where(conditions).first
|
199
202
|
end
|
200
203
|
else
|
201
|
-
|
204
|
+
obj
|
202
205
|
end
|
203
206
|
while !value.nil? && relation.size > 0
|
204
207
|
value = value.send(relation.shift)
|
205
208
|
end
|
206
209
|
|
207
|
-
|
210
|
+
primary_key = relation_primary_key(original_relation, source: obj, was: was)
|
211
|
+
Array.wrap(primary_key).map { |pk| value.try(pk&.to_sym) }.compact.presence
|
208
212
|
end
|
209
213
|
|
210
214
|
# gets the reflect object on the given relation
|
@@ -310,6 +314,7 @@ module CounterCulture
|
|
310
314
|
return reflect.options[:primary_key] if reflect.options.key?(:primary_key)
|
311
315
|
return relation_klass(relation, source: source, was: was).try(:primary_key)
|
312
316
|
end
|
317
|
+
|
313
318
|
reflect.association_primary_key(klass)
|
314
319
|
end
|
315
320
|
|
@@ -373,7 +378,7 @@ module CounterCulture
|
|
373
378
|
association_name = relation_reflect(relation).name
|
374
379
|
|
375
380
|
association_object = association_object_for_assign(obj, association_name)
|
376
|
-
return if association_object.blank?
|
381
|
+
return if association_object.blank? || association_object.frozen?
|
377
382
|
|
378
383
|
association_object.assign_attributes(
|
379
384
|
change_counter_column =>
|
@@ -441,6 +446,12 @@ module CounterCulture
|
|
441
446
|
end
|
442
447
|
end
|
443
448
|
|
449
|
+
def primary_key_conditions(primary_key, fk_value)
|
450
|
+
Array.wrap(primary_key)
|
451
|
+
.zip(Array.wrap(fk_value))
|
452
|
+
.to_h
|
453
|
+
end
|
454
|
+
|
444
455
|
def counter_update_snippet(update, klass, id_to_change, operator, delta_magnitude)
|
445
456
|
if Thread.current[:aggregate_counter_updates]
|
446
457
|
remember_counter_update(
|
@@ -111,8 +111,8 @@ module CounterCulture
|
|
111
111
|
|
112
112
|
# select join column and count (from above) as well as cache column ('column_name') for later comparison
|
113
113
|
counts_query = scope.select(
|
114
|
-
"#{
|
115
|
-
"#{
|
114
|
+
"#{primary_key_select}, " \
|
115
|
+
"#{association_primary_key_select}, " \
|
116
116
|
"#{count_select} AS count, " \
|
117
117
|
"MAX(#{relation_class_table_name}.#{column_name}) AS #{column_name}"
|
118
118
|
)
|
@@ -173,7 +173,8 @@ module CounterCulture
|
|
173
173
|
end
|
174
174
|
|
175
175
|
with_writing_db_connection do
|
176
|
-
|
176
|
+
conditions = Array.wrap(relation_class.primary_key).map { |key| [key, record.send(key)] }.to_h
|
177
|
+
relation_class.where(conditions).update_all(updates.join(', '))
|
177
178
|
end
|
178
179
|
end
|
179
180
|
end
|
@@ -199,11 +200,12 @@ module CounterCulture
|
|
199
200
|
def track_change(record, column_name, count)
|
200
201
|
@changes_holder << {
|
201
202
|
:entity => relation_class.name,
|
202
|
-
relation_class.primary_key.to_sym => record.send(relation_class.primary_key),
|
203
203
|
:what => column_name,
|
204
204
|
:wrong => record.send(column_name),
|
205
205
|
:right => count
|
206
|
-
}
|
206
|
+
}.tap do |h|
|
207
|
+
Array.wrap(relation_class.primary_key).each { |pk| h[pk.to_sym] = record.send(pk) }
|
208
|
+
end
|
207
209
|
end
|
208
210
|
|
209
211
|
def count_select
|
@@ -217,10 +219,23 @@ module CounterCulture
|
|
217
219
|
@count_select = "SUM(COALESCE(#{self_table_name}.#{delta_column}, 0))"
|
218
220
|
end
|
219
221
|
else
|
220
|
-
|
222
|
+
primary_key = Array.wrap(model.primary_key).first
|
223
|
+
count_column = "#{self_table_name}.#{primary_key}"
|
224
|
+
@count_select = "COUNT(#{count_column})*#{delta_magnitude}"
|
221
225
|
end
|
222
226
|
end
|
223
227
|
|
228
|
+
def primary_key_select
|
229
|
+
relation_class_table_name = quote_table_name(relation_class.table_name)
|
230
|
+
Array.wrap(relation_class.primary_key).map { |pk| "#{relation_class_table_name}.#{pk}" }.join(', ')
|
231
|
+
end
|
232
|
+
|
233
|
+
def association_primary_key_select
|
234
|
+
relation_class_table_name = quote_table_name(relation_class.table_name)
|
235
|
+
association_primary_key = relation_reflect(relation).association_primary_key(relation_class)
|
236
|
+
Array.wrap(association_primary_key).map { |apk| "#{relation_class_table_name}.#{apk}" }.join(', ')
|
237
|
+
end
|
238
|
+
|
224
239
|
def self_table_name
|
225
240
|
return @self_table_name if @self_table_name
|
226
241
|
|
@@ -271,8 +286,17 @@ module CounterCulture
|
|
271
286
|
[target_table_key, source_table_key]
|
272
287
|
end
|
273
288
|
|
289
|
+
source_table_key = Array.wrap(source_table_key)
|
290
|
+
target_table_key = Array.wrap(target_table_key)
|
291
|
+
|
292
|
+
join_conditions =
|
293
|
+
source_table_key
|
294
|
+
.zip(target_table_key).map do |source_key, target_key|
|
295
|
+
"#{source_table}.#{source_key} = #{target_table_alias}.#{target_key}"
|
296
|
+
end.join(' AND ')
|
274
297
|
joins_sql = "LEFT JOIN #{target_table} AS #{target_table_alias} "\
|
275
|
-
"ON #{
|
298
|
+
"ON #{join_conditions}"
|
299
|
+
|
276
300
|
# adds 'type' condition to JOIN clause if the current model is a
|
277
301
|
# child in a Single Table Inheritance
|
278
302
|
if reflect.active_record.column_names.include?('type') &&
|
@@ -289,7 +313,9 @@ module CounterCulture
|
|
289
313
|
# conditions must be applied to the join on which we are counting
|
290
314
|
if where
|
291
315
|
if where.respond_to?(:to_sql)
|
292
|
-
|
316
|
+
model_primary_key = Array.wrap(model.primary_key)
|
317
|
+
where_select = model_primary_key.map { |pk| "#{model.table_name}.#{pk}" }.join(', ')
|
318
|
+
joins_sql += " AND (#{target_table_alias}.#{model_primary_key.first}) IN (#{where.select(where_select).to_sql})"
|
293
319
|
else
|
294
320
|
joins_sql += " AND (#{model.send(:sanitize_sql_for_conditions, where)})"
|
295
321
|
end
|
data/lib/counter_culture.rb
CHANGED
@@ -35,9 +35,14 @@ module CounterCulture
|
|
35
35
|
end.compact
|
36
36
|
|
37
37
|
if update_snippets.any?
|
38
|
-
klass
|
39
|
-
|
40
|
-
|
38
|
+
primary_key = Thread.current[:primary_key_map][klass]
|
39
|
+
|
40
|
+
conditions =
|
41
|
+
Array.wrap(primary_key)
|
42
|
+
.zip(Array.wrap(rec_id))
|
43
|
+
.to_h
|
44
|
+
|
45
|
+
klass.where(conditions).update_all(update_snippets.join(', '))
|
41
46
|
end
|
42
47
|
end
|
43
48
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: counter_culture
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.11.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Magnus von Koeller
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-06-
|
11
|
+
date: 2025-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|