counter_culture 3.0.0 → 3.2.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: 6e21168dbc07960cbb457996e275fe225426b9e96cd4b78a7dcd65ac13a0e006
4
- data.tar.gz: 655b861dbd102fd40c0be44fc9f12c5a3a8b21682a8951597c7b4d2bcde3ea5e
3
+ metadata.gz: 8d06abb7c02b9c0bd0e9536c04d7ba1f753c944c018fe6f14bc156567567c46c
4
+ data.tar.gz: dbda06f156910a7f7a807ecee156cfb36b0ec88a97ecd35cd120be564df571bd
5
5
  SHA512:
6
- metadata.gz: 42ae36d35f8ad486b25477a89e87477a40909fb08ffd627c6441c2c4ce17ef038c5f92f3514bd2cc993fd01996f3e49ab2470481f2ab778dc620c2aa7f65d59c
7
- data.tar.gz: 48ad4871eb41b4a97e5f53f41a671e4fef455fa2c70d475002de69bda1db8b1e8cc4af91b0c251d6ac1a4fba961ba5ab3eb2e821f9e9c8735a577728f7270338
6
+ metadata.gz: 2b95de040d7c944ba43bf103157144bb5cca3bc1ca309f1082189e5015b46f1fd01615296794f3cc8a27f5e0f1b499fe0744ac41e0438f21986926a4b8c38e69
7
+ data.tar.gz: 9889708057fbfa61c14291124e4c71bb8f0c8f67cb9bdf24f57865cff8fc27fae5f98576ff5f99d0ada07961a4781b9e943ef0679ce30f55d7e567a1d025f2eb
@@ -0,0 +1,66 @@
1
+ version: 2.1
2
+
3
+ orbs:
4
+ ruby: circleci/ruby@1.4
5
+
6
+ jobs:
7
+ test:
8
+ parameters:
9
+ ruby-version:
10
+ type: string
11
+ rails-version:
12
+ type: string
13
+ database:
14
+ type: string
15
+ docker:
16
+ - image: cimg/ruby:<< parameters.ruby-version >>
17
+ - image: cimg/postgres:14.1
18
+ - image: cimg/mysql:8.0
19
+ steps:
20
+ - checkout
21
+ - run:
22
+ name: bundle update
23
+ command: BUNDLE_GEMFILE=gemfiles/rails_<< parameters.rails-version >>.gemfile bundle update
24
+ - run:
25
+ name: install dockerize
26
+ command: wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && sudo tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
27
+ environment:
28
+ DOCKERIZE_VERSION: v0.3.0
29
+ - run:
30
+ name: Wait for Postgres
31
+ command: dockerize -wait tcp://localhost:5432 -timeout 1m
32
+ - run:
33
+ name: Wait for MySQL
34
+ command: dockerize -wait tcp://localhost:3306 -timeout 1m
35
+ - run:
36
+ name: rspec
37
+ command: DB=<< parameters.database >> rspec spec
38
+
39
+ workflows:
40
+ test:
41
+ jobs:
42
+ - test:
43
+ matrix:
44
+ parameters:
45
+ ruby-version: ["2.6", "2.7", "3.0"]
46
+ rails-version: ["5.2", "6.0", "6.1", "7.0"]
47
+ database: ["postgresql", "sqlite3", "mysql2"]
48
+ exclude:
49
+ - ruby-version: "3.0"
50
+ rails-version: "5.2"
51
+ database: "postgresql"
52
+ - ruby-version: "3.0"
53
+ rails-version: "5.2"
54
+ database: "sqlite3"
55
+ - ruby-version: "3.0"
56
+ rails-version: "5.2"
57
+ database: "mysql2"
58
+ - ruby-version: "2.6"
59
+ rails-version: "7.0"
60
+ database: "postgresql"
61
+ - ruby-version: "2.6"
62
+ rails-version: "7.0"
63
+ database: "sqlite3"
64
+ - ruby-version: "2.6"
65
+ rails-version: "7.0"
66
+ database: "mysql2"
data/Appraisals CHANGED
@@ -2,30 +2,9 @@
2
2
  5.2
3
3
  6.0
4
4
  6.1
5
+ 7.0
5
6
  ].each do |rails_version|
6
- gem_rails_version = Gem::Version.new(rails_version)
7
- if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.5.0') &&
8
- gem_rails_version >= Gem::Version.new('6.0.0.beta')
9
-
10
- # Rails 6 requires Ruby >= 2.5
11
- next
12
- end
13
7
  appraise "rails-#{rails_version}" do
14
8
  gem 'rails', "~> #{rails_version}.0"
15
-
16
- if gem_rails_version < Gem::Version.new('5.0')
17
- gem 'pg', '~> 0.15'
18
- else
19
- gem 'pg'
20
- end
21
- gem 'mysql2'
22
- if gem_rails_version < Gem::Version.new('5.2')
23
- gem 'sqlite3', '~> 1.3.0'
24
- else
25
- gem 'sqlite3'
26
- end
27
- if gem_rails_version < Gem::Version.new('5.0')
28
- gem 'bigdecimal', '~> 1.3.5'
29
- end
30
9
  end
31
10
  end
data/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## 3.2.1 (February 24, 2022)
2
+
3
+ Bugfixes:
4
+ - Fix `counter_culture_fix_counts` when passing it symbols for column names (#341)
5
+
6
+ ## 3.2.0 (January 24, 2022)
7
+
8
+ Improvements:
9
+ - Allow specifiying `polymorphic_classes` to avoid a potentially expensive
10
+ `DISTINCT` query when calling `counter_culture_fix_counts` (#336)
11
+
12
+ Bugfixes:
13
+ - Fix primary key name for enumerable relations (#337)
14
+
15
+ ## 3.1.0 (November 29, 2021)
16
+
17
+ Improvements:
18
+ - Allow specifiying a `Proc` to `column_names` to avoid loading a scope on
19
+ startup (#335)
20
+
1
21
  ## 3.0.0 (October 26, 2021)
2
22
 
3
23
  Breaking changes:
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # counter_culture [![Build Status](https://app.travis-ci.com/magnusvk/counter_culture.svg?branch=master)](https://app.travis-ci.com/magnusvk/counter_culture)
1
+ # counter_culture [![Build Status](https://circleci.com/gh/magnusvk/counter_culture/tree/master.svg?style=svg)](https://circleci.com/gh/magnusvk/counter_culture/tree/master)
2
2
 
3
3
  Turbo-charged counter caches for your Rails app. Huge improvements over the Rails standard counter caches:
4
4
 
@@ -7,7 +7,7 @@ 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.5.8, 2.6.6, 2.7.2 and 3.0.0, and against the latest patch releases of Rails 4.2, 5.0, 5.1, 5.2, 6.0 and 6.1.
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.
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
  ```
@@ -376,7 +376,10 @@ class Product < ActiveRecord::Base
376
376
  end
377
377
  ```
378
378
 
379
- You can specify a scope instead of a where condition string for `column_names`:
379
+ You can specify a scope instead of a where condition string for `column_names`. We recommend
380
+ providing a Proc that returns a hash instead of directly providing a hash: If you were to directly
381
+ provide a scope this would load your schema cache on startup which will break things like
382
+ `rake db:migrate`.
380
383
 
381
384
  ```ruby
382
385
  class Product < ActiveRecord::Base
@@ -386,10 +389,10 @@ class Product < ActiveRecord::Base
386
389
 
387
390
  counter_culture :category,
388
391
  column_name: proc {|model| "#{model.product_type}_count" },
389
- column_names: {
392
+ column_names: -> { {
390
393
  Product.awesomes => :awesome_count,
391
394
  Product.suckys => :sucky_count
392
- }
395
+ } }
393
396
  end
394
397
  ```
395
398
 
@@ -456,6 +459,17 @@ end
456
459
 
457
460
  counter_culture now supports polymorphic associations of one level only.
458
461
 
462
+ To discover which models need to be updated via `counter_culture_fix_counts`,
463
+ counter_culture performs a `DISTINCT` query on the polymorphic relationship.
464
+ This query can be expensive so we therefore offer the option
465
+ (`polymorphic_classes`) to specify the models' counts that should be corrected:
466
+
467
+ ```ruby
468
+ Image.counter_culture_fix_counts(polymorphic_classes: Product)
469
+ # or
470
+ Image.counter_culture_fix_counts(polymorphic_classes: [Product, Employee])
471
+ ```
472
+
459
473
  ## Contributing to counter_culture
460
474
 
461
475
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
@@ -38,9 +38,12 @@ Gem::Specification.new do |spec|
38
38
  spec.add_development_dependency 'after_commit_action'
39
39
  spec.add_development_dependency 'rails', '>= 4.2'
40
40
  spec.add_development_dependency 'rake', '>= 10.0'
41
- spec.add_development_dependency 'rdoc', '~> 5.0.0'
41
+ spec.add_development_dependency 'rdoc', ">= 6.3.1"
42
42
  spec.add_development_dependency 'rspec', '~> 3.0'
43
43
  spec.add_development_dependency 'rspec-extra-formatters'
44
44
  spec.add_development_dependency 'simplecov', '~> 0.16.1'
45
45
  spec.add_development_dependency 'timecop'
46
+ spec.add_development_dependency 'sqlite3'
47
+ spec.add_development_dependency 'mysql2'
48
+ spec.add_development_dependency 'pg'
46
49
  end
@@ -2,9 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "sqlite3"
6
5
  gem "rails", "~> 5.2.0"
7
- gem "pg"
8
- gem "mysql2"
9
6
 
10
7
  gemspec path: "../"
@@ -2,9 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "sqlite3"
6
5
  gem "rails", "~> 6.0.0"
7
- gem "pg"
8
- gem "mysql2"
9
6
 
10
7
  gemspec path: "../"
@@ -2,9 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "sqlite3"
6
5
  gem "rails", "~> 6.1.0"
7
- gem "pg"
8
- gem "mysql2"
9
6
 
10
7
  gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 7.0.0"
6
+
7
+ gemspec path: "../"
@@ -163,8 +163,9 @@ module CounterCulture
163
163
  # pass true to get the past value, false or nothing to get the
164
164
  # current value
165
165
  def foreign_key_value(obj, relation, was = false)
166
+ original_relation = relation
166
167
  relation = relation.is_a?(Enumerable) ? relation.dup : [relation]
167
- first_relation = relation.first
168
+
168
169
  if was
169
170
  first = relation.shift
170
171
  foreign_key_value = attribute_was(obj, relation_foreign_key(first))
@@ -180,7 +181,8 @@ module CounterCulture
180
181
  while !value.nil? && relation.size > 0
181
182
  value = value.send(relation.shift)
182
183
  end
183
- return value.try(relation_primary_key(first_relation, source: obj, was: was).try(:to_sym))
184
+
185
+ return value.try(relation_primary_key(original_relation, source: obj, was: was).try(:to_sym))
184
186
  end
185
187
 
186
188
  # gets the reflect object on the given relation
@@ -45,8 +45,19 @@ module CounterCulture
45
45
  @after_commit_counter_cache = []
46
46
  end
47
47
 
48
- if options[:column_names] && !options[:column_names].is_a?(Hash)
49
- raise ":column_names must be a Hash of conditions and column names"
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
57
+ raise ArgumentError.new(
58
+ ":column_names must be a Hash of conditions and column names, " \
59
+ "or a Proc that when called returns such a Hash"
60
+ )
50
61
  end
51
62
 
52
63
  # add the counter to our collection
@@ -60,7 +71,8 @@ module CounterCulture
60
71
  # options:
61
72
  # { :exclude => list of relations to skip when fixing counts,
62
73
  # :only => only these relations will have their counts fixed,
63
- # :column_name => only this column will have its count fixed }
74
+ # :column_name => only this column will have its count fixed
75
+ # :polymorphic_classes => specify the class(es) to update in polymorphic associations }
64
76
  # returns: a list of fixed record as an array of hashes of the form:
65
77
  # { :entity => which model the count was fixed on,
66
78
  # :id => the id of the model that had the incorrect count,
@@ -80,7 +92,7 @@ module CounterCulture
80
92
  next if options[:exclude] && options[:exclude].include?(counter.relation)
81
93
  next if options[:only] && !options[:only].include?(counter.relation)
82
94
 
83
- reconciler_options = %i(batch_size column_name finish skip_unsupported start touch verbose where)
95
+ reconciler_options = %i(batch_size column_name finish skip_unsupported start touch verbose where polymorphic_classes)
84
96
 
85
97
  reconciler = CounterCulture::Reconciler.new(counter, options.slice(*reconciler_options))
86
98
  reconciler.reconcile!
@@ -28,7 +28,7 @@ module CounterCulture
28
28
  raise "Fixing counter caches is not supported when :delta_magnitude is a Proc; you may skip this relation with :skip_unsupported => true" if delta_magnitude.is_a?(Proc)
29
29
  end
30
30
 
31
- associated_model_classes.each do |associated_model_class|
31
+ Array(associated_model_classes).each do |associated_model_class|
32
32
  Reconciliation.new(counter, changes, options, associated_model_class).perform
33
33
  end
34
34
 
@@ -39,7 +39,7 @@ module CounterCulture
39
39
 
40
40
  def associated_model_classes
41
41
  if polymorphic?
42
- polymorphic_associated_model_classes
42
+ options[:polymorphic_classes].presence || polymorphic_associated_model_classes
43
43
  else
44
44
  [associated_model_class]
45
45
  end
@@ -74,10 +74,20 @@ module CounterCulture
74
74
 
75
75
  scope = relation_class
76
76
 
77
- counter_column_names = column_names || {nil => counter_cache_name}
77
+ counter_column_names =
78
+ case column_names
79
+ when Proc
80
+ column_names.call
81
+ when Hash
82
+ column_names
83
+ else
84
+ { nil => counter_cache_name }
85
+ end
78
86
 
79
87
  if options[:column_name]
80
- counter_column_names = counter_column_names.select{ |_, v| options[:column_name].to_s == v }
88
+ counter_column_names = counter_column_names.select do |_, v|
89
+ options[:column_name].to_s == v.to_s
90
+ end
81
91
  end
82
92
 
83
93
  # iterate over all the possible counter cache column names
@@ -1,3 +1,3 @@
1
1
  module CounterCulture
2
- VERSION = '3.0.0'.freeze
2
+ VERSION = '3.2.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.0.0
4
+ version: 3.2.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: 2021-10-26 00:00:00.000000000 Z
11
+ date: 2022-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -182,16 +182,16 @@ dependencies:
182
182
  name: rdoc
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
- - - "~>"
185
+ - - ">="
186
186
  - !ruby/object:Gem::Version
187
- version: 5.0.0
187
+ version: 6.3.1
188
188
  type: :development
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
- - - "~>"
192
+ - - ">="
193
193
  - !ruby/object:Gem::Version
194
- version: 5.0.0
194
+ version: 6.3.1
195
195
  - !ruby/object:Gem::Dependency
196
196
  name: rspec
197
197
  requirement: !ruby/object:Gem::Requirement
@@ -248,6 +248,48 @@ dependencies:
248
248
  - - ">="
249
249
  - !ruby/object:Gem::Version
250
250
  version: '0'
251
+ - !ruby/object:Gem::Dependency
252
+ name: sqlite3
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - ">="
256
+ - !ruby/object:Gem::Version
257
+ version: '0'
258
+ type: :development
259
+ prerelease: false
260
+ version_requirements: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - ">="
263
+ - !ruby/object:Gem::Version
264
+ version: '0'
265
+ - !ruby/object:Gem::Dependency
266
+ name: mysql2
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - ">="
270
+ - !ruby/object:Gem::Version
271
+ version: '0'
272
+ type: :development
273
+ prerelease: false
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - ">="
277
+ - !ruby/object:Gem::Version
278
+ version: '0'
279
+ - !ruby/object:Gem::Dependency
280
+ name: pg
281
+ requirement: !ruby/object:Gem::Requirement
282
+ requirements:
283
+ - - ">="
284
+ - !ruby/object:Gem::Version
285
+ version: '0'
286
+ type: :development
287
+ prerelease: false
288
+ version_requirements: !ruby/object:Gem::Requirement
289
+ requirements:
290
+ - - ">="
291
+ - !ruby/object:Gem::Version
292
+ version: '0'
251
293
  description: counter_culture provides turbo-charged counter caches that are kept up-to-date
252
294
  not just on create and destroy, that support multiple levels of indirection through
253
295
  relationships, allow dynamic column names and that avoid deadlocks by updating in
@@ -260,10 +302,10 @@ extra_rdoc_files:
260
302
  - LICENSE.txt
261
303
  - README.md
262
304
  files:
305
+ - ".circleci/config.yml"
263
306
  - ".document"
264
307
  - ".gitignore"
265
308
  - ".rspec"
266
- - ".travis.yml"
267
309
  - Appraisals
268
310
  - CHANGELOG.md
269
311
  - Gemfile
@@ -275,6 +317,7 @@ files:
275
317
  - gemfiles/rails_5.2.gemfile
276
318
  - gemfiles/rails_6.0.gemfile
277
319
  - gemfiles/rails_6.1.gemfile
320
+ - gemfiles/rails_7.0.gemfile
278
321
  - lib/counter_culture.rb
279
322
  - lib/counter_culture/counter.rb
280
323
  - lib/counter_culture/extensions.rb
data/.travis.yml DELETED
@@ -1,50 +0,0 @@
1
- dist: focal
2
- language: ruby
3
- cache:
4
- directories:
5
- - ~/.rvm/gems
6
- services:
7
- - postgresql
8
- - mysql
9
- branches:
10
- only:
11
- - master
12
- addons:
13
- postgresql: '12'
14
- apt:
15
- packages:
16
- - postgresql-12
17
- - postgresql-client-12
18
- rvm:
19
- - "2.6.8"
20
- - "2.7.4"
21
- - "3.0.2"
22
- gemfile:
23
- - gemfiles/rails_5.2.gemfile
24
- - gemfiles/rails_6.0.gemfile
25
- - gemfiles/rails_6.1.gemfile
26
- matrix:
27
- exclude:
28
- - rvm: "3.0.2"
29
- gemfile: gemfiles/rails_5.2.gemfile
30
- env:
31
- global:
32
- - PGUSER=postgres
33
- - PGPORT=5432
34
- - PGHOST=localhost
35
- jobs:
36
- - DB=postgresql
37
- - DB=sqlite3
38
- - DB=mysql2
39
- before_install:
40
- - sudo sed -i -e '/local.*peer/s/postgres/all/' -e 's/peer\|md5/trust/g' /etc/postgresql/*/main/pg_hba.conf
41
- - sudo service postgresql restart
42
- - sleep 1
43
- - postgres --version
44
- - if [ "$BUNDLE_GEMFILE" = "$PWD/gemfiles/rails_4.2.gemfile" ]; then gem install bundler -v '1.17.3'; else gem install bundler -v '> 2'; fi
45
- install:
46
- - if [ "$BUNDLE_GEMFILE" = "$PWD/gemfiles/rails_4.2.gemfile" ]; then bundle _1.17.3_ update; else bundle update; fi
47
- before_script:
48
- - psql -c 'create database counter_culture_test;' -U postgres
49
- - mysql -e 'CREATE DATABASE counter_culture_test;'
50
- script: TRAVIS=true bundle exec rake spec