counter_culture 3.2.1 → 3.3.0
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/.circleci/config.yml +18 -3
- data/CHANGELOG.md +10 -0
- data/README.md +15 -1
- data/lib/counter_culture/extensions.rb +6 -12
- data/lib/counter_culture/reconciler.rb +28 -6
- data/lib/counter_culture/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5ab4a286fa35aeed4f39a89653ed55be5da8c2ea6255a84f8f5c60c3002a4e75
|
|
4
|
+
data.tar.gz: 910213339a5c0815679736c77e72b8964a678fb58495fdfd9882157b3fdaaf5b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d42e4460ea4ad61e3ee12bdc430d9cb833772a32d02bdfe9c2fd8b78f7f06d157f06e9f50dec1efb5df6bf6c917b624f4c9c626ac43ea541a9faef3422fbc5b8
|
|
7
|
+
data.tar.gz: 50166340b9db761bcdf4a198d21d8c1580b26d09cf4928082885175441ef260758d909e321d30c7204e2f782730833e8153db8a3d28c879dd55d8de3d2ceb453
|
data/.circleci/config.yml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
version: 2.1
|
|
2
2
|
|
|
3
3
|
orbs:
|
|
4
|
-
ruby: circleci/ruby@1.
|
|
4
|
+
ruby: circleci/ruby@1.8
|
|
5
5
|
|
|
6
6
|
jobs:
|
|
7
7
|
test:
|
|
@@ -19,7 +19,13 @@ jobs:
|
|
|
19
19
|
steps:
|
|
20
20
|
- checkout
|
|
21
21
|
- run:
|
|
22
|
-
name:
|
|
22
|
+
name: gem update --system --no-ri --no-rdoc
|
|
23
|
+
# bundles sporadically fail with a weird Psych error if I don't do
|
|
24
|
+
# this. It's annoying since it's slow but it's better than
|
|
25
|
+
# non-deterministic build failures.
|
|
26
|
+
command: sudo gem update --system
|
|
27
|
+
- run:
|
|
28
|
+
name: bundle update --no-ri --no-rdoc
|
|
23
29
|
command: BUNDLE_GEMFILE=gemfiles/rails_<< parameters.rails-version >>.gemfile bundle update
|
|
24
30
|
- run:
|
|
25
31
|
name: install dockerize
|
|
@@ -42,7 +48,7 @@ workflows:
|
|
|
42
48
|
- test:
|
|
43
49
|
matrix:
|
|
44
50
|
parameters:
|
|
45
|
-
ruby-version: ["2.6", "2.7", "3.0"]
|
|
51
|
+
ruby-version: ["2.6", "2.7", "3.0", "3.1"]
|
|
46
52
|
rails-version: ["5.2", "6.0", "6.1", "7.0"]
|
|
47
53
|
database: ["postgresql", "sqlite3", "mysql2"]
|
|
48
54
|
exclude:
|
|
@@ -55,6 +61,15 @@ workflows:
|
|
|
55
61
|
- ruby-version: "3.0"
|
|
56
62
|
rails-version: "5.2"
|
|
57
63
|
database: "mysql2"
|
|
64
|
+
- ruby-version: "3.1"
|
|
65
|
+
rails-version: "5.2"
|
|
66
|
+
database: "postgresql"
|
|
67
|
+
- ruby-version: "3.1"
|
|
68
|
+
rails-version: "5.2"
|
|
69
|
+
database: "sqlite3"
|
|
70
|
+
- ruby-version: "3.1"
|
|
71
|
+
rails-version: "5.2"
|
|
72
|
+
database: "mysql2"
|
|
58
73
|
- ruby-version: "2.6"
|
|
59
74
|
rails-version: "7.0"
|
|
60
75
|
database: "postgresql"
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## 3.3.0 (October 11, 2022)
|
|
2
|
+
|
|
3
|
+
Improvements:
|
|
4
|
+
- Allow reading from replica in `counter_culture_fix_counts` (#330)
|
|
5
|
+
- Test against Ruby 3.1 (#357)
|
|
6
|
+
|
|
7
|
+
Bugfixes:
|
|
8
|
+
- Don't decrement counter cache when calling `.destroy` on an already-destroyed model (#351)
|
|
9
|
+
- Don't immediately call `Proc` passed to `column_names` to avoid startup issue (#352)
|
|
10
|
+
|
|
1
11
|
## 3.2.1 (February 24, 2022)
|
|
2
12
|
|
|
3
13
|
Bugfixes:
|
data/README.md
CHANGED
|
@@ -20,7 +20,7 @@ product.categories_count # => will use counter cache without query
|
|
|
20
20
|
Add counter_culture to your Gemfile:
|
|
21
21
|
|
|
22
22
|
```ruby
|
|
23
|
-
gem 'counter_culture', '~> 2
|
|
23
|
+
gem 'counter_culture', '~> 3.2'
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
Then run `bundle install`
|
|
@@ -359,6 +359,20 @@ Product.counter_culture_fix_counts start: 2001, finish: 3000
|
|
|
359
359
|
# In worker 2, lets process from 2001 to 3000
|
|
360
360
|
```
|
|
361
361
|
|
|
362
|
+
#### Fix counter cache using a replica database
|
|
363
|
+
|
|
364
|
+
When fixing counter caches the number of reads usually vastly exceeds the number of writes. It can make sense to offload the road load to a replica database in this case. Rails 6 introduced [native handling of multiple database connections](https://guides.rubyonrails.org/v6.0/active_record_multiple_databases.html). You can use this to send read traffic to a read-only repliace using the option `db_connection_builder`:
|
|
365
|
+
|
|
366
|
+
```ruby
|
|
367
|
+
Product.counter_culture_fix_counts db_connection_builder: proc{|reading, block|
|
|
368
|
+
if reading # Count calls will request a reading connection
|
|
369
|
+
Product.connected_to(role: :reading, &block)
|
|
370
|
+
else # Update all calls will request a non-reading connection
|
|
371
|
+
Product.connected_to(role: :writing, &block)
|
|
372
|
+
end
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
362
376
|
#### Handling dynamic column names
|
|
363
377
|
|
|
364
378
|
Manually populating counter caches with dynamic column names requires additional configuration:
|
|
@@ -45,15 +45,7 @@ module CounterCulture
|
|
|
45
45
|
@after_commit_counter_cache = []
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
!options[:column_names] ||
|
|
50
|
-
options[:column_names].is_a?(Hash) ||
|
|
51
|
-
(
|
|
52
|
-
options[:column_names].is_a?(Proc) &&
|
|
53
|
-
options[:column_names].call.is_a?(Hash)
|
|
54
|
-
)
|
|
55
|
-
)
|
|
56
|
-
unless column_names_valid
|
|
48
|
+
if options[:column_names] && !(options[:column_names].is_a?(Hash) || options[:column_names].is_a?(Proc))
|
|
57
49
|
raise ArgumentError.new(
|
|
58
50
|
":column_names must be a Hash of conditions and column names, " \
|
|
59
51
|
"or a Proc that when called returns such a Hash"
|
|
@@ -92,7 +84,7 @@ module CounterCulture
|
|
|
92
84
|
next if options[:exclude] && options[:exclude].include?(counter.relation)
|
|
93
85
|
next if options[:only] && !options[:only].include?(counter.relation)
|
|
94
86
|
|
|
95
|
-
reconciler_options = %i(batch_size column_name finish skip_unsupported start touch verbose where polymorphic_classes)
|
|
87
|
+
reconciler_options = %i(batch_size column_name db_connection_builder finish skip_unsupported start touch verbose where polymorphic_classes)
|
|
96
88
|
|
|
97
89
|
reconciler = CounterCulture::Reconciler.new(counter, options.slice(*reconciler_options))
|
|
98
90
|
reconciler.reconcile!
|
|
@@ -113,8 +105,10 @@ module CounterCulture
|
|
|
113
105
|
# called by after_destroy callback
|
|
114
106
|
def _update_counts_after_destroy
|
|
115
107
|
self.class.after_commit_counter_cache.each do |counter|
|
|
116
|
-
|
|
117
|
-
|
|
108
|
+
unless destroyed?
|
|
109
|
+
# decrement counter cache
|
|
110
|
+
counter.change_counter_cache(self, :increment => false)
|
|
111
|
+
end
|
|
118
112
|
end
|
|
119
113
|
end
|
|
120
114
|
|
|
@@ -84,6 +84,8 @@ module CounterCulture
|
|
|
84
84
|
{ nil => counter_cache_name }
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
+
raise ArgumentError, ":column_names must be a Hash of conditions and column names" unless counter_column_names.is_a?(Hash)
|
|
88
|
+
|
|
87
89
|
if options[:column_name]
|
|
88
90
|
counter_column_names = counter_column_names.select do |_, v|
|
|
89
91
|
options[:column_name].to_s == v.to_s
|
|
@@ -123,11 +125,13 @@ module CounterCulture
|
|
|
123
125
|
find_in_batches_args[:start] = options[:start] if options[:start].present?
|
|
124
126
|
find_in_batches_args[:finish] = options[:finish] if options[:finish].present?
|
|
125
127
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
with_reading_db_connection do
|
|
129
|
+
counts_query.find_in_batches(**find_in_batches_args).with_index(1) do |records, index|
|
|
130
|
+
log "Processing batch ##{index}."
|
|
131
|
+
# now iterate over all the models and see whether their counts are right
|
|
132
|
+
update_count_for_batch(column_name, records)
|
|
133
|
+
log "Finished batch ##{index}."
|
|
134
|
+
end
|
|
131
135
|
end
|
|
132
136
|
end
|
|
133
137
|
log_without_newline "\n"
|
|
@@ -161,7 +165,9 @@ module CounterCulture
|
|
|
161
165
|
end
|
|
162
166
|
end
|
|
163
167
|
|
|
164
|
-
|
|
168
|
+
with_writing_db_connection do
|
|
169
|
+
relation_class.where(relation_class.primary_key => record.send(relation_class.primary_key)).update_all(updates.join(', '))
|
|
170
|
+
end
|
|
165
171
|
end
|
|
166
172
|
end
|
|
167
173
|
end
|
|
@@ -312,6 +318,22 @@ module CounterCulture
|
|
|
312
318
|
string.parameterize(separator: '_')
|
|
313
319
|
end
|
|
314
320
|
end
|
|
321
|
+
|
|
322
|
+
def with_reading_db_connection(&block)
|
|
323
|
+
if builder = options[:db_connection_builder]
|
|
324
|
+
builder.call(true, block)
|
|
325
|
+
else
|
|
326
|
+
yield
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def with_writing_db_connection(&block)
|
|
331
|
+
if builder = options[:db_connection_builder]
|
|
332
|
+
builder.call(false, block)
|
|
333
|
+
else
|
|
334
|
+
yield
|
|
335
|
+
end
|
|
336
|
+
end
|
|
315
337
|
end
|
|
316
338
|
end
|
|
317
339
|
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.3.0
|
|
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: 2022-
|
|
11
|
+
date: 2022-10-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -344,7 +344,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
344
344
|
- !ruby/object:Gem::Version
|
|
345
345
|
version: '0'
|
|
346
346
|
requirements: []
|
|
347
|
-
rubygems_version: 3.
|
|
347
|
+
rubygems_version: 3.3.7
|
|
348
348
|
signing_key:
|
|
349
349
|
specification_version: 4
|
|
350
350
|
summary: Turbo-charged counter caches for your Rails app.
|