activerecord-precount 0.4.3 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 03bcfbd6e4eeb0e73abd3ba62ce3479ce88be195
4
- data.tar.gz: ed4a627ba81085af77fc6c0fc0c5036d6aed498b
3
+ metadata.gz: b808e109c4ff4e66a60696bef99eb38a78f2c729
4
+ data.tar.gz: abed0c7c35ef630938eec845e4439a7e62f54e90
5
5
  SHA512:
6
- metadata.gz: 9ec150f0c07963351a74c8657673bb14a3afe9e4476c19658ea74a1e489b89e21f5abc876aa097c703460db396069cacf54bfd7a70ab0e536c9a20c953d5a46f
7
- data.tar.gz: 0c50e140ed0cfb414f64c380e3fd95c92083a207e2b2dbf144536d285d24bc1c23ded87944eeb74ecce362aa493c818b5fc0097621e9ea32902b7eb73f8433bf
6
+ metadata.gz: 36e5f8ad70b97aa1d58990791ec8a7de3e075783700d25e8ffc93be693c2d9f39b29da237b46d5159e750654ea3b50b80c99bf32c31118618025e63957aac590
7
+ data.tar.gz: c08a6d413c210e044e609e36c1e297803476ff52e6b54c6bd8be48b89c4aeafc3b2d759da86314b84858d18fdf29ecb0c9fda2b1f8403bbdce44dfa829bd5aa0
data/README.md CHANGED
@@ -15,36 +15,55 @@ Tweet.all.each do |tweet|
15
15
  p tweet.favorites.count
16
16
  end
17
17
  # SELECT `tweets`.* FROM `tweets`
18
- # SELECT COUNT(*) FROM `tweets` WHERE `tweets`.`tweet_id` = 1
19
- # SELECT COUNT(*) FROM `tweets` WHERE `tweets`.`tweet_id` = 2
20
- # SELECT COUNT(*) FROM `tweets` WHERE `tweets`.`tweet_id` = 3
21
- # SELECT COUNT(*) FROM `tweets` WHERE `tweets`.`tweet_id` = 4
22
- # SELECT COUNT(*) FROM `tweets` WHERE `tweets`.`tweet_id` = 5
18
+ # SELECT COUNT(*) FROM `favorites` WHERE `favorites`.`tweet_id` = 1
19
+ # SELECT COUNT(*) FROM `favorites` WHERE `favorites`.`tweet_id` = 2
20
+ # SELECT COUNT(*) FROM `favorites` WHERE `favorites`.`tweet_id` = 3
21
+ # SELECT COUNT(*) FROM `favorites` WHERE `favorites`.`tweet_id` = 4
22
+ # SELECT COUNT(*) FROM `favorites` WHERE `favorites`.`tweet_id` = 5
23
23
  ```
24
24
 
25
25
  ### Count eager loading
26
26
 
27
+ #### precount
28
+
27
29
  With activerecord-precount gem installed, you can use `precount` method
28
30
  to eagerly load counts of associated records.
31
+ Like `preload`, it loads counts by multiple queries
29
32
 
30
33
  ```rb
31
34
  Tweet.all.precount(:favorites).each do |tweet|
32
35
  p tweet.favorites.count
33
36
  end
34
37
  # SELECT `tweets`.* FROM `tweets`
35
- # SELECT COUNT(`tweets`.`tweet_id`), tweet_id FROM `tweets` WHERE `tweets`.`tweet_id` IN (1, 2, 3, 4, 5) GROUP BY tweet_id
38
+ # SELECT COUNT(`favorites`.`tweet_id`), `favorites`.`tweet_id` FROM `favorites` WHERE `favorites`.`tweet_id` IN (1, 2, 3, 4, 5) GROUP BY `favorites`.`tweet_id`
39
+ ```
40
+
41
+ #### eager\_count
42
+
43
+ Like `eager_load`, `eager_count` method allows you to load counts by one JOIN query.
44
+
45
+ ```rb
46
+ Tweet.all.eager_count(:favorites).each do |tweet|
47
+ p tweet.favorites.count
48
+ end
49
+ # SELECT `tweets`.`id` AS t0_r0, `tweets`.`tweet_id` AS t0_r1, `tweets`.`user_id` AS t0_r2, `tweets`.`created_at` AS t0_r3, `tweets`.`updated_at` AS t0_r4, COUNT(`favorites`.`id`) AS t1_r0 FROM `tweets` LEFT OUTER JOIN `favorites` ON `favorites`.`tweet_id` = `tweets`.`id` GROUP BY tweets.id
36
50
  ```
37
51
 
38
52
  ## Benchmark
39
53
 
40
- With [this benchmark](https://github.com/k0kubun/activerecord-precount/blob/079c8fdaaca4e7f08f542f825e296183a3f19c67/benchmark.rb)
41
- ([result](https://travis-ci.org/k0kubun/activerecord-precount/jobs/48996451)),
42
- precounted query is **7.7x faster** than N+1 count query.
54
+ The [result](https://travis-ci.org/k0kubun/activerecord-precount/jobs/49061937) of
55
+ [this benchmark](https://github.com/k0kubun/activerecord-precount/blob/40765d36ff0e0627cd0941b2c0a0f6573290c67e/benchmark.rb).
56
+
57
+ | | N+1 query | precount | eager\_count |
58
+ |:-- |:----------|:---------|:-------------|
59
+ | Time | 1.401 | 0.176 | 0.119 |
60
+ | Ratio | 1.0x | **7.9x faster** | **11.7x faster** |
43
61
 
44
62
  ```rb
45
63
  # Tweet count is 50, and each tweet has 10 favorites
46
- Tweet.precount(:favorites).first(50).map(&:favorites_count) # 0.190
47
- Tweet.first(50).map{ |t| t.favorites.count } # 1.472
64
+ Tweet.all.map{ |t| t.favorites.count } # N+1 query
65
+ Tweet.precount(:favorites).map(&:favorites_count) # precount
66
+ Tweet.eager_count(:favorites).map(&:favorites_count) # eager_count
48
67
  ```
49
68
 
50
69
  ## Installation
@@ -69,8 +88,8 @@ gem 'activerecord-precount'
69
88
  ## Advanced Usage
70
89
 
71
90
  ### Nested eager loading
72
- `Foo.precount(:bars)` automatically defines `bars_count` association for `Foo`.
73
- Thus you can preload the association and call `foo.bars_count`.
91
+ `Foo.precount(:bars)` or `Foo.eager_count(:bars)` automatically defines `bars_count` association for `Foo`.
92
+ That enables you to preload the association and call `foo.bars_count`.
74
93
 
75
94
  You can manually define `bars_count` with follwoing code.
76
95
 
@@ -103,9 +122,11 @@ Though precounted `bars.count` is faster than not-precounted one, the fallback i
103
122
  ```rb
104
123
  # slow
105
124
  Foo.precount(:bars).map { |f| f.bars.count }
125
+ Foo.eager_count(:bars).map { |f| f.bars.count }
106
126
 
107
127
  # fast (recommended)
108
128
  Foo.precount(:bars).map { |f| f.bars_count }
129
+ Foo.eager_count(:bars).map { |f| f.bars_count }
109
130
  ```
110
131
 
111
132
  ## License
data/benchmark.rb CHANGED
@@ -8,8 +8,10 @@ require 'models/tweet'
8
8
  RBench.run(50) do
9
9
  column :counter_cache, title: 'counter_cache'
10
10
  column :left_join, title: 'LEFT JOIN'
11
- column :count_loader, title: 'precount'
12
- column :precount, title: 'slow precount'
11
+ column :eager_count, title: 'eager_count'
12
+ column :precount, title: 'precount'
13
+ column :slow_eager_count, title: 'slow eager_count'
14
+ column :slow_precount, title: 'slow precount'
13
15
  column :has_many, title: 'preload'
14
16
  column :count_query, title: 'N+1 COUNT'
15
17
 
@@ -17,6 +19,9 @@ RBench.run(50) do
17
19
  select('tweets.*, COUNT(favorites.id) AS joined_count').group('tweets.id')
18
20
 
19
21
  def prepare_records(tweets_count, favorites_count)
22
+ Tweet.delete_all
23
+ Favorite.delete_all
24
+
20
25
  tweets_count.times do
21
26
  t = Tweet.create(favorites_count_cache: 0)
22
27
  favorites_count.times { Favorite.create(tweet: t) }
@@ -34,12 +39,16 @@ RBench.run(50) do
34
39
  prepare_records(tweets_count, favorites_count)
35
40
 
36
41
  report "N = #{tweets_count}, count = #{favorites_count}" do
37
- counter_cache { Tweet.first(tweets_count).map(&:favorites_count_cache) }
38
- left_join { join_relation.first(tweets_count).map(&:joined_count) }
39
- count_loader { Tweet.precount(:favorites).first(tweets_count).map(&:favorites_count) }
40
- precount { Tweet.precount(:favorites).first(tweets_count).map { |t| t.favorites.count } }
41
- has_many { Tweet.preload(:favorites).first(tweets_count).map{ |t| t.favorites.size } }
42
- count_query { Tweet.first(tweets_count).map{ |t| t.favorites.count } }
42
+ counter_cache { Tweet.all.map(&:favorites_count_cache) }
43
+ left_join { Tweet.joins('LEFT JOIN favorites ON tweets.id = favorites.tweet_id').
44
+ select('tweets.*, COUNT(favorites.id) AS joined_count').
45
+ group('tweets.id').map(&:joined_count) }
46
+ eager_count { Tweet.eager_count(:favorites).map(&:favorites_count) }
47
+ precount { Tweet.precount(:favorites).map(&:favorites_count) }
48
+ slow_eager_count { Tweet.eager_count(:favorites).map { |t| t.favorites.count } }
49
+ slow_precount { Tweet.precount(:favorites).map { |t| t.favorites.count } }
50
+ has_many { Tweet.preload(:favorites).map{ |t| t.favorites.size } }
51
+ count_query { Tweet.all.map{ |t| t.favorites.count } }
43
52
  end
44
53
  end
45
54
  end
@@ -1,7 +1,7 @@
1
1
  module ActiveRecord
2
2
  module Precount
3
3
  module BaseExtension
4
- delegate :precount, to: :all
4
+ delegate :precount, :eager_count, to: :all
5
5
 
6
6
  def has_reflection?(name)
7
7
  reflection_for(name).present?
@@ -1,22 +1,48 @@
1
1
  module ActiveRecord
2
- # This imitates EagerLoadPolymorphicError
3
- class EagerLoadCountLoaderError < ActiveRecordError
4
- def initialize(reflection)
5
- super("Cannot eagerly load the count_loader association #{reflection.name.inspect}")
6
- end
7
- end
8
-
9
2
  module Precount
10
3
  module JoinDependencyExtension
11
- def build(associations, base_klass)
12
- associations.map do |name, right|
13
- reflection = find_reflection base_klass, name
14
- if reflection.macro == :count_loader
15
- raise EagerLoadCountLoaderError.new(reflection)
4
+ class CountTable < Associations::JoinDependency::Aliases::Table
5
+ def column_aliases
6
+ columns.map { |column| table[column.name].count.as Arel.sql column.alias }
7
+ end
8
+ end
9
+
10
+ def aliases
11
+ Associations::JoinDependency::Aliases.new join_root.each_with_index.map { |join_part,i|
12
+ if join_part.is_a?(Associations::JoinDependency::JoinAssociation) && join_part.reflection.macro == :count_loader
13
+ # select COUNT(primary_key)
14
+ column_name = join_part.reflection.klass.primary_key
15
+ column = Associations::JoinDependency::Aliases::Column.new column_name, "t#{i}_r0"
16
+ CountTable.new(join_part, [column])
17
+ else
18
+ # original aliases' internal function
19
+ columns = join_part.column_names.each_with_index.map { |column_name,j|
20
+ Associations::JoinDependency::Aliases::Column.new column_name, "t#{i}_r#{j}"
21
+ }
22
+ Associations::JoinDependency::Aliases::Table.new(join_part, columns)
16
23
  end
24
+ }
25
+ end
26
+
27
+ private
28
+
29
+ # instantiate only count_loader and pass others to super
30
+ def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
31
+ normal_children = []
32
+
33
+ parent.children.each do |node|
34
+ if node.reflection.macro != :count_loader
35
+ normal_children << node
36
+ next
37
+ end
38
+
39
+ key = aliases.column_alias(node, node.primary_key)
40
+ ar_parent.association(node.reflection.name).target = row[key].to_i
17
41
  end
42
+ return if normal_children.blank?
18
43
 
19
- super(associations, base_klass)
44
+ normal_parent = Associations::JoinDependency::JoinBase.new(parent.base_klass, normal_children)
45
+ super(ar_parent, normal_parent, row, rs, seen, model_cache, aliases)
20
46
  end
21
47
  end
22
48
  end
@@ -13,11 +13,23 @@ module ActiveRecord
13
13
  self
14
14
  end
15
15
 
16
+ def eager_count(*args)
17
+ check_if_method_has_arguments!(:eager_count, args)
18
+ spawn.eager_count!(*args)
19
+ end
20
+
21
+ def eager_count!(*args)
22
+ define_count_loader!(*args)
23
+
24
+ self.eager_load_values += args.map { |arg| :"#{arg}_count" }
25
+ self
26
+ end
27
+
16
28
  private
17
29
 
18
30
  def define_count_loader!(*args)
19
31
  args.each do |arg|
20
- raise ArgumentError, "#{klass} does not have :#{arg} association." unless has_reflection?(arg)
32
+ raise ArgumentError, "Association named '#{arg}' was not found on #{klass.name}." unless has_reflection?(arg)
21
33
  next if has_reflection?(counter_name = :"#{arg}_count")
22
34
 
23
35
  options = reflection_for(arg).options.slice(*Associations::Builder::CountLoader.valid_options)
@@ -25,6 +37,20 @@ module ActiveRecord
25
37
  Reflection.add_reflection(model, counter_name, reflection)
26
38
  end
27
39
  end
40
+
41
+ def apply_join_dependency(relation, join_dependency)
42
+ relation = super(relation, join_dependency)
43
+
44
+ # to count associated records in JOIN query, group scope is necessary
45
+ join_dependency.reflections.each do |reflection|
46
+ if reflection.macro == :count_loader
47
+ ar = reflection.active_record
48
+ relation = relation.group("#{ar.table_name}.#{ar.primary_key}")
49
+ end
50
+ end
51
+
52
+ relation
53
+ end
28
54
  end
29
55
  end
30
56
  end
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module Precount
3
- VERSION = "0.4.3"
3
+ VERSION = "0.5.0"
4
4
  end
5
5
  end
@@ -1,13 +1,33 @@
1
1
  class ApplicationController < ActionController::Base
2
+ AVAILABLE_LOADERS = %w[N+1 precount eager_count].freeze
3
+ DEFAULT_LOADER = 'N+1'
4
+
2
5
  def index
3
6
  @tweets = Tweet.all
4
- if eager_load?
7
+ case loader
8
+ when 'precount'
5
9
  @tweets = @tweets.precount(:replies).preload(in_reply_to: :favorites_count)
10
+ when 'eager_count'
11
+ @tweets = @tweets.eager_count(:replies).eager_load(in_reply_to: :favorites_count)
6
12
  end
7
13
  end
8
14
 
9
- def eager_load?
10
- params[:eager_load] == 'true'
15
+ def precount?
16
+ loader == 'precount'
17
+ end
18
+ helper_method :precount?
19
+
20
+ def eager_count?
21
+ loader == 'eager_count'
22
+ end
23
+ helper_method :eager_count?
24
+
25
+ def loader
26
+ if AVAILABLE_LOADERS.include?(params[:loader])
27
+ params[:loader]
28
+ else
29
+ DEFAULT_LOADER
30
+ end
11
31
  end
12
- helper_method :eager_load?
32
+ helper_method :loader
13
33
  end
@@ -23,7 +23,7 @@
23
23
  <%= tweet.id %>
24
24
  </td>
25
25
  <td>
26
- <%= tweet.replies.count %>
26
+ <%= (precount? || eager_count?) ? tweet.replies_count : tweet.replies.count %>
27
27
  </td>
28
28
  <td>
29
29
  <%= tweet.in_reply_to.try(:id) %>
@@ -38,12 +38,14 @@
38
38
  <% finish = Time.now %>
39
39
 
40
40
  <p>
41
- <%= eager_load? ? 'Eager loaded' : 'N+1 query' %>
41
+ Loader: <%= loader %>
42
42
  </p>
43
43
  <p>
44
44
  Time: <%= "%.1f" % ((finish - start) * 1000) %>ms
45
45
  </p>
46
46
 
47
47
  <p>
48
- <%= link_to 'Swtich', url_for(eager_load: !eager_load?) %>
49
- <p>
48
+ <% ApplicationController::AVAILABLE_LOADERS.each do |ld| %>
49
+ <%= link_to_unless loader == ld, ld, url_for(loader: ld) %>
50
+ <% end %>
51
+ </p>
@@ -6,5 +6,6 @@ class CreateTweets < ActiveRecord::Migration
6
6
 
7
7
  t.timestamps
8
8
  end
9
+ add_index :tweets, :in_reply_to_tweet_id
9
10
  end
10
11
  end
@@ -6,5 +6,6 @@ class CreateFavorites < ActiveRecord::Migration
6
6
 
7
7
  t.timestamps
8
8
  end
9
+ add_index :favorites, :tweet_id
9
10
  end
10
11
  end
data/sample/db/schema.rb CHANGED
@@ -20,6 +20,8 @@ ActiveRecord::Schema.define(version: 20141122002555) do
20
20
  t.datetime "updated_at"
21
21
  end
22
22
 
23
+ add_index "favorites", ["tweet_id"], name: "index_favorites_on_tweet_id", using: :btree
24
+
23
25
  create_table "tweets", force: :cascade do |t|
24
26
  t.integer "in_reply_to_tweet_id", limit: 4
25
27
  t.integer "user_id", limit: 4
@@ -27,6 +29,8 @@ ActiveRecord::Schema.define(version: 20141122002555) do
27
29
  t.datetime "updated_at"
28
30
  end
29
31
 
32
+ add_index "tweets", ["in_reply_to_tweet_id"], name: "index_tweets_on_in_reply_to_tweet_id", using: :btree
33
+
30
34
  create_table "users", force: :cascade do |t|
31
35
  t.datetime "created_at"
32
36
  t.datetime "updated_at"
@@ -0,0 +1,46 @@
1
+ require 'cases/helper'
2
+
3
+ class EagerCountTest < ActiveRecord::CountLoader::TestCase
4
+ def setup
5
+ tweets_count.times.map do |index|
6
+ tweet = Tweet.create
7
+ index.times { Favorite.create(tweet: tweet) }
8
+ end
9
+
10
+ if Tweet.has_reflection?(:favs_count)
11
+ if ActiveRecord::VERSION::MAJOR >= 4 && ActiveRecord::VERSION::MINOR >= 2
12
+ Tweet._reflections.delete('favs_count')
13
+ else
14
+ Tweet._reflections.delete(:favs_count)
15
+ end
16
+ end
17
+ end
18
+
19
+ def teardown
20
+ [Tweet, Favorite].each(&:delete_all)
21
+ end
22
+
23
+ def tweets_count
24
+ 3
25
+ end
26
+
27
+ def test_eager_count_defines_count_loader
28
+ assert_equal(Tweet.has_reflection?(:favs_count), false)
29
+ Tweet.eager_count(:favs).map(&:favs_count)
30
+ assert_equal(Tweet.has_reflection?(:favs_count), true)
31
+ end
32
+
33
+ def test_eager_count_has_many_with_count_loader_does_not_execute_n_1_queries
34
+ assert_queries(1 + tweets_count) { Tweet.all.map { |t| t.favorites.count } }
35
+ assert_queries(1 + tweets_count) { Tweet.all.map(&:favorites_count) }
36
+ assert_queries(1) { Tweet.eager_count(:favorites).map { |t| t.favorites.count } }
37
+ assert_queries(1) { Tweet.eager_count(:favorites).map(&:favorites_count) }
38
+ end
39
+
40
+ def test_eager_count_has_many_counts_properly
41
+ expected = Tweet.order(id: :asc).map { |t| t.favorites.count }
42
+ assert_equal(Tweet.order(id: :asc).map(&:favorites_count), expected)
43
+ assert_equal(Tweet.order(id: :asc).eager_count(:favorites).map { |t| t.favorites.count }, expected)
44
+ assert_equal(Tweet.order(id: :asc).eager_count(:favorites).map(&:favorites_count), expected)
45
+ end
46
+ end
@@ -4,17 +4,30 @@ require 'models/tweet'
4
4
 
5
5
  class EagerLoadTest < ActiveRecord::CountLoader::TestCase
6
6
  def setup
7
- tweet = Tweet.create
8
- Favorite.create(tweet: tweet)
7
+ tweets_count.times.map do |index|
8
+ tweet = Tweet.create
9
+ index.times { Favorite.create(tweet: tweet) }
10
+ end
9
11
  end
10
12
 
11
13
  def teardown
12
14
  [Tweet, Favorite].each(&:delete_all)
13
15
  end
14
16
 
15
- def test_eager_loaded_count_loader_raises_an_error
16
- assert_raises ActiveRecord::EagerLoadCountLoaderError do
17
- Tweet.eager_load(:favorites_count).to_a
18
- end
17
+ def tweets_count
18
+ 3
19
+ end
20
+
21
+ def test_eager_load_does_not_execute_n_1_queries
22
+ assert_queries(1 + tweets_count) { Tweet.all.map { |t| t.favorites.count } }
23
+ assert_queries(1 + tweets_count) { Tweet.all.map(&:favorites_count) }
24
+ assert_queries(1) { Tweet.eager_load(:favorites_count).map(&:favorites_count) }
25
+ end
26
+
27
+ def test_eager_loaded_count_loader_counts_properly
28
+ expected = Tweet.order(id: :asc).map { |t| t.favorites.count }
29
+ assert_equal(Tweet.order(id: :asc).map(&:favorites_count), expected)
30
+ assert_equal(Tweet.order(id: :asc).eager_load(:favorites_count).map { |t| t.favorites.count }, expected)
31
+ assert_equal(Tweet.order(id: :asc).eager_load(:favorites_count).map(&:favorites_count), expected)
19
32
  end
20
33
  end
@@ -6,6 +6,14 @@ class PrecountTest < ActiveRecord::CountLoader::TestCase
6
6
  tweet = Tweet.create
7
7
  index.times { Favorite.create(tweet: tweet) }
8
8
  end
9
+
10
+ if Tweet.has_reflection?(:favs_count)
11
+ if ActiveRecord::VERSION::MAJOR >= 4 && ActiveRecord::VERSION::MINOR >= 2
12
+ Tweet._reflections.delete('favs_count')
13
+ else
14
+ Tweet._reflections.delete(:favs_count)
15
+ end
16
+ end
9
17
  end
10
18
 
11
19
  def teardown
@@ -16,11 +24,10 @@ class PrecountTest < ActiveRecord::CountLoader::TestCase
16
24
  3
17
25
  end
18
26
 
19
- def test_precount_has_many_does_not_execute_n_1_queries
20
- assert_equal(Tweet.reflections['favs_count'].present?, false)
21
- assert_queries(1 + tweets_count) { Tweet.all.map { |t| t.favs.count } }
22
- assert_queries(2) { Tweet.precount(:favs).map { |t| t.favs.count } }
23
- assert_queries(2) { Tweet.precount(:favs).map(&:favs_count) }
27
+ def test_precount_defines_count_loader
28
+ assert_equal(Tweet.has_reflection?(:favs_count), false)
29
+ Tweet.precount(:favs).map(&:favs_count)
30
+ assert_equal(Tweet.has_reflection?(:favs_count), true)
24
31
  end
25
32
 
26
33
  def test_precount_has_many_with_count_loader_does_not_execute_n_1_queries
@@ -33,6 +40,7 @@ class PrecountTest < ActiveRecord::CountLoader::TestCase
33
40
  def test_precount_has_many_counts_properly
34
41
  expected = Tweet.all.map { |t| t.favorites.count }
35
42
  assert_equal(Tweet.all.map(&:favorites_count), expected)
43
+ assert_equal(Tweet.precount(:favorites).map { |t| t.favorites.count }, expected)
36
44
  assert_equal(Tweet.precount(:favorites).map(&:favorites_count), expected)
37
45
  end
38
46
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-precount
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.5.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: 2015-01-31 00:00:00.000000000 Z
11
+ date: 2015-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -251,6 +251,7 @@ files:
251
251
  - sample/public/robots.txt
252
252
  - sample/vendor/assets/javascripts/.keep
253
253
  - sample/vendor/assets/stylesheets/.keep
254
+ - test/cases/associations/eager_count_test.rb
254
255
  - test/cases/associations/eager_load_test.rb
255
256
  - test/cases/associations/includes_test.rb
256
257
  - test/cases/associations/precount_test.rb