counter_culture 3.2.1 → 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d06abb7c02b9c0bd0e9536c04d7ba1f753c944c018fe6f14bc156567567c46c
4
- data.tar.gz: dbda06f156910a7f7a807ecee156cfb36b0ec88a97ecd35cd120be564df571bd
3
+ metadata.gz: ce78ea0f9a3ad552e5cb8b0e230dbc70fc3fcb51f9f0c21676c3ecca7601569a
4
+ data.tar.gz: 840001761832861fbbef2e3d921d553d0ea39c685a8ab16b4096444722bb5d03
5
5
  SHA512:
6
- metadata.gz: 2b95de040d7c944ba43bf103157144bb5cca3bc1ca309f1082189e5015b46f1fd01615296794f3cc8a27f5e0f1b499fe0744ac41e0438f21986926a4b8c38e69
7
- data.tar.gz: 9889708057fbfa61c14291124e4c71bb8f0c8f67cb9bdf24f57865cff8fc27fae5f98576ff5f99d0ada07961a4781b9e943ef0679ce30f55d7e567a1d025f2eb
6
+ metadata.gz: 41e59967d03892c1d0ce48d1c804862bcd0ffb575df9675869fc94fcba13440f8eaf07f4a06b6b5b88a168c79efd06af4a4b88634f8bdc9d8ca0b5c990b0c81f
7
+ data.tar.gz: 1e90fa445eb4972dea2c7ce851719e8fa0a095aa2526b177fd1d2ec5ae9de8d85f4bf9d1b3cc1a112a1186f76add7b7d564efab9bb146085fdf1c1011cda5ebf
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
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: bundle update
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", "3.2"]
46
52
  rails-version: ["5.2", "6.0", "6.1", "7.0"]
47
53
  database: ["postgresql", "sqlite3", "mysql2"]
48
54
  exclude:
@@ -55,6 +61,24 @@ 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.2"
71
+ rails-version: "5.2"
72
+ database: "mysql2"
73
+ - ruby-version: "3.2"
74
+ rails-version: "5.2"
75
+ database: "postgresql"
76
+ - ruby-version: "3.2"
77
+ rails-version: "5.2"
78
+ database: "sqlite3"
79
+ - ruby-version: "3.1"
80
+ rails-version: "5.2"
81
+ database: "mysql2"
58
82
  - ruby-version: "2.6"
59
83
  rails-version: "7.0"
60
84
  database: "postgresql"
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## 3.3.1 (June 26, 2023)
2
+
3
+ Bugfixes:
4
+ - Read primary key on polymorphic associations if it's explicitly set (#370)
5
+
6
+ ## 3.3.0 (October 11, 2022)
7
+
8
+ Improvements:
9
+ - Allow reading from replica in `counter_culture_fix_counts` (#330)
10
+ - Test against Ruby 3.1 (#357)
11
+
12
+ Bugfixes:
13
+ - Don't decrement counter cache when calling `.destroy` on an already-destroyed model (#351)
14
+ - Don't immediately call `Proc` passed to `column_names` to avoid startup issue (#352)
15
+
1
16
  ## 3.2.1 (February 24, 2022)
2
17
 
3
18
  Bugfixes:
data/README.md CHANGED
@@ -7,10 +7,11 @@ Turbo-charged counter caches for your Rails app. Huge improvements over the Rail
7
7
  * Supports dynamic column names, making it possible to split up the counter cache for different types of objects
8
8
  * Can keep a running count, or a running total
9
9
 
10
- Tested against Ruby 2.6, 2.7 and 3.0, and against the latest patch releases of Rails 5.2, 6.0, 6.1 and 7.0.
10
+ Tested against Ruby 2.6, 2.7, 3.0, 3.1 and 3.2, and against the latest patch releases of Rails 5.2, 6.0, 6.1 and 7.0.
11
11
 
12
12
  Please note that -- unlike Rails' built-in counter-caches -- counter_culture does not currently change the behavior of the `.size` method on ActiveRecord associations. If you want to avoid a database query and read the cached value, please use the attribute name containing the counter cache directly.
13
- ```
13
+
14
+ ```ruby
14
15
  product.categories.size # => will lead to a SELECT COUNT(*) query
15
16
  product.categories_count # => will use counter cache without query
16
17
  ```
@@ -20,7 +21,7 @@ product.categories_count # => will use counter cache without query
20
21
  Add counter_culture to your Gemfile:
21
22
 
22
23
  ```ruby
23
- gem 'counter_culture', '~> 2.0'
24
+ gem 'counter_culture', '~> 3.2'
24
25
  ```
25
26
 
26
27
  Then run `bundle install`
@@ -359,6 +360,20 @@ Product.counter_culture_fix_counts start: 2001, finish: 3000
359
360
  # In worker 2, lets process from 2001 to 3000
360
361
  ```
361
362
 
363
+ #### Fix counter cache using a replica database
364
+
365
+ 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`:
366
+
367
+ ```ruby
368
+ Product.counter_culture_fix_counts db_connection_builder: proc{|reading, block|
369
+ if reading # Count calls will request a reading connection
370
+ Product.connected_to(role: :reading, &block)
371
+ else # Update all calls will request a non-reading connection
372
+ Product.connected_to(role: :writing, &block)
373
+ end
374
+ }
375
+ ```
376
+
362
377
  #### Handling dynamic column names
363
378
 
364
379
  Manually populating counter caches with dynamic column names requires additional configuration:
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = 'https://github.com/magnusvk/counter_culture'
14
14
  spec.license = 'MIT'
15
15
 
16
- spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
16
+ spec.required_ruby_version = '>= 2.6'
17
17
 
18
18
  # Specify which files should be added to the gem when it is released.
19
19
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -284,6 +284,8 @@ module CounterCulture
284
284
  if reflect.options.key?(:polymorphic)
285
285
  raise "can't handle multiple keys with polymorphic associations" unless (relation.is_a?(Symbol) || relation.length == 1)
286
286
  raise "must specify source for polymorphic associations..." unless source
287
+
288
+ return reflect.options[:primary_key] if reflect.options.key?(:primary_key)
287
289
  return relation_klass(relation, source: source, was: was).try(:primary_key)
288
290
  end
289
291
  reflect.association_primary_key(klass)
@@ -45,15 +45,7 @@ module CounterCulture
45
45
  @after_commit_counter_cache = []
46
46
  end
47
47
 
48
- column_names_valid = (
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
- # decrement counter cache
117
- counter.change_counter_cache(self, :increment => false)
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
- counts_query.find_in_batches(**find_in_batches_args).with_index(1) do |records, index|
127
- log "Processing batch ##{index}."
128
- # now iterate over all the models and see whether their counts are right
129
- update_count_for_batch(column_name, records)
130
- log "Finished batch ##{index}."
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
- relation_class.where(relation_class.primary_key => record.send(relation_class.primary_key)).update_all(updates.join(', '))
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
@@ -1,3 +1,3 @@
1
1
  module CounterCulture
2
- VERSION = '3.2.1'.freeze
2
+ VERSION = '3.3.1'.freeze
3
3
  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.2.1
4
+ version: 3.3.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: 2022-02-25 00:00:00.000000000 Z
11
+ date: 2023-06-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -312,7 +312,6 @@ files:
312
312
  - LICENSE.txt
313
313
  - README.md
314
314
  - Rakefile
315
- - circle.yml
316
315
  - counter_culture.gemspec
317
316
  - gemfiles/rails_5.2.gemfile
318
317
  - gemfiles/rails_6.0.gemfile
@@ -337,14 +336,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
337
336
  requirements:
338
337
  - - ">="
339
338
  - !ruby/object:Gem::Version
340
- version: 2.3.0
339
+ version: '2.6'
341
340
  required_rubygems_version: !ruby/object:Gem::Requirement
342
341
  requirements:
343
342
  - - ">="
344
343
  - !ruby/object:Gem::Version
345
344
  version: '0'
346
345
  requirements: []
347
- rubygems_version: 3.1.4
346
+ rubygems_version: 3.4.2
348
347
  signing_key:
349
348
  specification_version: 4
350
349
  summary: Turbo-charged counter caches for your Rails app.
data/circle.yml DELETED
@@ -1,12 +0,0 @@
1
- machine:
2
- ruby:
3
- version: 2.3.1
4
- database:
5
- override:
6
- - echo "No database setup required..."
7
- dependencies:
8
- post:
9
- - cd spec/rails_app && bundle install
10
- test:
11
- override:
12
- - bundle exec rspec spec