activerecord-precount 0.4.3 → 0.5.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: 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