activerecord-count_loader 0.2.2 → 0.3.0

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
  SHA1:
3
- metadata.gz: e96fba115f86ec9df8e6b61b9e46963db8863389
4
- data.tar.gz: c133bf5dbdc42da2033c895edbafb54aad6503d4
3
+ metadata.gz: 515ec56ea17ba5bad414a147aed81f40819a657c
4
+ data.tar.gz: f9466f0bdbe2c07cbf84e0b48a166db145c4af82
5
5
  SHA512:
6
- metadata.gz: 1fb324c9b4c13172114fa47337949bda6a45418e9fe6ebd4ef2d2702c1dc03df576220e014bf05d3069414063b384d17a649b345b48d0cc1f6baaf44afaee783
7
- data.tar.gz: 0d5d2aaa5ebd82d0a60a8fee3b94fbce338072af25333fc173620f4b8f0e28f33725cd67c9656f56a991cdc69507cc5c12139826820f6bd2ad78fc4e0e3cb329
6
+ metadata.gz: 5d0efd9eac050114ada09182e50fc15098fbe5b1dcc8a6c382964433b249a38bb9082d77b87ec8729144cf28f71f0f3da326ab1b017a945584086e47a8129659
7
+ data.tar.gz: 3533abc4b13a3f41d083159442fa0a6a5917c111eb616ecf77db9a129dbf66cbafc9013f063e53c33783dda98510e00d06dc0b13eb4301668f68bad548f6c6a4
data/.travis.yml CHANGED
@@ -1,12 +1,18 @@
1
1
  script: ci/travis.rb
2
2
  language: ruby
3
3
  rvm:
4
- - 2.1.5
4
+ - 2.1
5
+ - 2.2
6
+ sudo: false
5
7
  gemfile:
6
- - ci/Gemfile.activerecord-3.2.x
7
- - ci/Gemfile.activerecord-4.0.x
8
8
  - ci/Gemfile.activerecord-4.1.x
9
+ - ci/Gemfile.activerecord-4.2.x
9
10
  env:
10
- - ARCONN=sqlite3
11
- - ARCONN=mysql2
12
- - ARCONN=postgresql
11
+ - TASK=test ARCONN=sqlite3
12
+ - TASK=test ARCONN=mysql2
13
+ - TASK=test ARCONN=postgresql
14
+ #- TASK=benchmark ARCONN=mysql2
15
+ matrix:
16
+ allow_failures:
17
+ env:
18
+ - TASK=benchmark ARCONN=mysql2
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in activerecord-count_loader.gemspec
4
4
  gemspec
5
+
6
+ gem 'rbench', github: 'miloops/rbench'
data/README.md CHANGED
@@ -46,7 +46,7 @@ end
46
46
  You can eagerly load `count_loader` association by `includes` or `preload`.
47
47
 
48
48
  ```rb
49
- @tweets = Tweet.preload(:favorites_count)
49
+ @tweets = Tweet.all.preload(:favorites_count)
50
50
  @tweets.each do |tweet|
51
51
  p tweets.favorites_count # this line doesn't execute an additional query
52
52
  end
@@ -55,7 +55,7 @@ end
55
55
  Since it is association, you can preload nested `count_loader` association.
56
56
 
57
57
  ```rb
58
- @users = User.preload(tweets: :favorites_count).all
58
+ @users = User.all.preload(tweets: :favorites_count)
59
59
  @users.each do |user|
60
60
  user.tweets.each do |tweet|
61
61
  p tweet.favorites_count # this line doesn't execute an additional query
@@ -66,9 +66,9 @@ end
66
66
  ## Supported Versions
67
67
 
68
68
  - Ruby
69
- - 2.1
69
+ - 2.1, 2.2
70
70
  - Rails
71
- - 3.2, 4.0, 4.1
71
+ - 4.1, 4.2
72
72
 
73
73
  ### Databases
74
74
 
data/Rakefile CHANGED
@@ -1,6 +1,11 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rake/testtask"
3
3
 
4
+ desc 'Run count_loader benchmarks'
5
+ task :benchmark do
6
+ ruby('benchmark.rb')
7
+ end
8
+
4
9
  Rake::TestTask.new do |t|
5
10
  t.libs << "lib" << "test"
6
11
  t.test_files = Dir.glob("test/**/*_test.rb")
@@ -22,8 +22,10 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency "rake"
23
23
  spec.add_development_dependency "erubis"
24
24
  spec.add_development_dependency "bundler"
25
+ spec.add_development_dependency "pry"
25
26
  spec.add_development_dependency "sqlite3"
26
27
  spec.add_development_dependency "mysql2"
27
28
  spec.add_development_dependency "postgres"
28
- spec.add_development_dependency "pry"
29
+ spec.add_development_dependency "rbench"
30
+ spec.add_development_dependency "dalli"
29
31
  end
data/benchmark.rb ADDED
@@ -0,0 +1,42 @@
1
+ $LOAD_PATH.unshift File.expand_path('../test', __FILE__)
2
+
3
+ require 'rbench'
4
+ require 'cases/db_config'
5
+ require 'models/favorite'
6
+ require 'models/tweet'
7
+
8
+ RBench.run(50) do
9
+ column :counter_cache, title: 'counter_cache'
10
+ column :left_join, title: 'LEFT JOIN'
11
+ column :count_loader, title: 'activerecord-count_loader'
12
+ column :has_many, title: 'preload has_many'
13
+ column :count_query, title: 'N+1 COUNT'
14
+
15
+ join_relation = Tweet.joins('LEFT JOIN favorites ON tweets.id = favorites.tweet_id').
16
+ select('tweets.*, COUNT(favorites.id) AS joined_count').group('tweets.id')
17
+
18
+ def prepare_records(tweets_count, favorites_count)
19
+ tweets_count.times do
20
+ t = Tweet.create(favorites_count_cache: 0)
21
+ favorites_count.times { Favorite.create(tweet: t) }
22
+ end
23
+ end
24
+
25
+ test_cases = [
26
+ [10, 5],
27
+ [20, 20],
28
+ [30, 100],
29
+ ]
30
+
31
+ test_cases.each do |tweets_count, favorites_count|
32
+ prepare_records(tweets_count, favorites_count)
33
+
34
+ report "N = #{tweets_count}, count = #{favorites_count}" do
35
+ counter_cache { Tweet.first(tweets_count).map(&:favorites_count_cache) }
36
+ left_join { join_relation.first(tweets_count).map(&:joined_count) }
37
+ count_loader { Tweet.preload(:favorites_count).first(tweets_count).map(&:favorites_count) }
38
+ has_many { Tweet.preload(:favorites).first(tweets_count).map{ |t| t.favorites.size } }
39
+ count_query { Tweet.first(tweets_count).map{ |t| t.favorites.count } }
40
+ end
41
+ end
42
+ end
@@ -1,4 +1,4 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gem 'rails', '~> 4.2.0.beta4'
3
+ gem 'rails', '~> 4.2.0'
4
4
  gemspec path: '..'
data/ci/travis.rb CHANGED
@@ -10,3 +10,5 @@ commands = [
10
10
  commands.each do |command|
11
11
  system("#{command} > /dev/null 2>&1")
12
12
  end
13
+
14
+ exit system("bundle exec rake $TASK")
@@ -14,4 +14,14 @@ module ActiveRecord
14
14
  end
15
15
  end
16
16
  end
17
+
18
+ module Reflection
19
+ class CountLoaderReflection < AssociationReflection
20
+ def initialize(name, scope, options, active_record)
21
+ super(name, scope, options, active_record)
22
+ end
23
+
24
+ def macro; :count_loader; end
25
+ end
26
+ end
17
27
  end
@@ -1,9 +1,9 @@
1
1
  ActiveSupport.on_load(:active_record) do
2
2
  module ActiveRecord
3
- Reflection.prepend(CountLoader::ReflectionExtension)
4
- Associations::Preloader.prepend(CountLoader::PreloaderExtension)
5
- Associations::JoinDependency.prepend(CountLoader::JoinDependencyExtension)
6
- Associations::Builder::HasMany.prepend(CountLoader::Builder::HasManyExtension)
7
- Reflection::AssociationReflection.prepend(CountLoader::AssociationReflectionExtension)
3
+ Reflection.send(:prepend, CountLoader::ReflectionExtension)
4
+ Associations::Preloader.send(:prepend, CountLoader::PreloaderExtension)
5
+ Associations::JoinDependency.send(:prepend, CountLoader::JoinDependencyExtension)
6
+ Associations::Builder::HasMany.send(:prepend, CountLoader::Builder::HasManyExtension)
7
+ Reflection::AssociationReflection.send(:prepend, CountLoader::AssociationReflectionExtension)
8
8
  end
9
9
  end
@@ -11,7 +11,11 @@ module ActiveRecord
11
11
  def create(macro, name, scope, options, ar)
12
12
  case macro
13
13
  when :count_loader
14
- Reflection::AssociationReflection.new(macro, name, scope, options, ar)
14
+ if ActiveRecord::VERSION::MAJOR >= 4 && ActiveRecord::VERSION::MINOR >= 2
15
+ Reflection::CountLoaderReflection.new(name, scope, options, ar)
16
+ else
17
+ Reflection::AssociationReflection.new(macro, name, scope, options, ar)
18
+ end
15
19
  else
16
20
  super(macro, name, scope, options, ar)
17
21
  end
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module CountLoader
3
- VERSION = "0.2.2"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
data/sample/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'rails', '4.1.5'
3
+ gem 'rails', '4.2.0'
4
4
  gem 'mysql2'
5
5
  gem 'sass-rails', '~> 4.0.3'
6
6
  gem 'uglifier', '>= 1.3.0'
@@ -13,7 +13,7 @@ gem 'sdoc', '~> 0.4.0', group: :doc
13
13
  gem 'activerecord-count_loader', path: '..'
14
14
 
15
15
  group :development do
16
- gem 'pry'
16
+ gem 'pry-rails'
17
17
  gem 'spring'
18
18
  gem 'silencer'
19
19
  end
@@ -0,0 +1,24 @@
1
+ require 'config'
2
+
3
+ require 'active_record'
4
+ require 'activerecord-count_loader'
5
+
6
+ require 'support/config'
7
+ require 'support/connection'
8
+
9
+ # Connect to the database
10
+ ARTest.connect
11
+
12
+ def load_schema
13
+ # silence verbose schema loading
14
+ original_stdout = $stdout
15
+ $stdout = StringIO.new
16
+
17
+ adapter_name = ActiveRecord::Base.connection.adapter_name.downcase
18
+
19
+ load SCHEMA_ROOT + "/schema.rb"
20
+ ensure
21
+ $stdout = original_stdout
22
+ end
23
+
24
+ load_schema
data/test/cases/helper.rb CHANGED
@@ -1,27 +1,4 @@
1
- require 'config'
1
+ require 'cases/db_config'
2
2
 
3
3
  require 'support/autorun'
4
-
5
- require 'active_record'
6
- require 'activerecord-count_loader'
7
4
  require 'cases/test_case'
8
-
9
- require 'support/config'
10
- require 'support/connection'
11
-
12
- # Connect to the database
13
- ARTest.connect
14
-
15
- def load_schema
16
- # silence verbose schema loading
17
- original_stdout = $stdout
18
- $stdout = StringIO.new
19
-
20
- adapter_name = ActiveRecord::Base.connection.adapter_name.downcase
21
-
22
- load SCHEMA_ROOT + "/schema.rb"
23
- ensure
24
- $stdout = original_stdout
25
- end
26
-
27
- load_schema
@@ -1,3 +1,3 @@
1
1
  class Favorite < ActiveRecord::Base
2
- belongs_to :tweet
2
+ belongs_to :tweet, counter_cache: :favorites_count_cache
3
3
  end
@@ -2,13 +2,15 @@ ActiveRecord::Schema.define do
2
2
  create_table :favorites, force: true do |t|
3
3
  t.integer :tweet_id
4
4
  t.integer :user_id
5
- t.datetime :created_at
6
5
  t.timestamps
7
6
  end
7
+ add_index :favorites, :tweet_id
8
8
 
9
9
  create_table :tweets, force: true do |t|
10
10
  t.integer :in_reply_to_tweet_id
11
11
  t.integer :user_id
12
+ t.integer :favorites_count_cache
12
13
  t.timestamps
13
14
  end
15
+ add_index :tweets, :in_reply_to_tweet_id
14
16
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-count_loader
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Takashi Kokubun
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-23 00:00:00.000000000 Z
11
+ date: 2015-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: sqlite3
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -123,7 +137,21 @@ dependencies:
123
137
  - !ruby/object:Gem::Version
124
138
  version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
- name: pry
140
+ name: rbench
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: dalli
127
155
  requirement: !ruby/object:Gem::Requirement
128
156
  requirements:
129
157
  - - ">="
@@ -150,8 +178,7 @@ files:
150
178
  - README.md
151
179
  - Rakefile
152
180
  - activerecord-count_loader.gemspec
153
- - ci/Gemfile.activerecord-3.2.x
154
- - ci/Gemfile.activerecord-4.0.x
181
+ - benchmark.rb
155
182
  - ci/Gemfile.activerecord-4.1.x
156
183
  - ci/Gemfile.activerecord-4.2.x
157
184
  - ci/travis.rb
@@ -224,6 +251,7 @@ files:
224
251
  - test/cases/associations/eager_load_test.rb
225
252
  - test/cases/associations/includes_test.rb
226
253
  - test/cases/associations/preload_test.rb
254
+ - test/cases/db_config.rb
227
255
  - test/cases/helper.rb
228
256
  - test/cases/test_case.rb
229
257
  - test/config.example.yml
@@ -254,8 +282,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
254
282
  version: '0'
255
283
  requirements: []
256
284
  rubyforge_project:
257
- rubygems_version: 2.2.2
285
+ rubygems_version: 2.4.5
258
286
  signing_key:
259
287
  specification_version: 4
260
288
  summary: N+1 count query killer for ActiveRecord
261
289
  test_files: []
290
+ has_rdoc:
@@ -1,4 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem 'activerecord', '~> 3.2.0'
4
- gemspec path: '..'
@@ -1,4 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem 'activerecord', '~> 4.0.0'
4
- gemspec path: '..'