activerecord-has_count 0.0.1 → 0.0.2
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 +4 -4
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/.travis.yml +7 -0
- data/README.md +3 -3
- data/activerecord-has_count.gemspec +2 -2
- data/benchmarks/Gemfile +9 -0
- data/benchmarks/README.md +16 -0
- data/benchmarks/benchmark.rb +60 -0
- data/lib/active_record/associations/has_count.rb +1 -14
- data/lib/activerecord-has_count/model.rb +23 -0
- data/lib/{active_record/has_count → activerecord-has_count}/version.rb +1 -1
- data/lib/activerecord-has_count.rb +6 -6
- data/spec/database.yml +13 -0
- data/spec/eager_load_spec.rb +28 -0
- data/spec/includes_spec.rb +57 -0
- data/spec/models/reply.rb +3 -0
- data/spec/models/tweet.rb +4 -0
- data/spec/preload_spec.rb +57 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/assert_queries.rb +54 -0
- data/spec/support/factories.rb +4 -0
- metadata +31 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69e774d016a1d4b507eb55f8f0f9504cbf198a3b
|
4
|
+
data.tar.gz: abbd2d57baa8ebdf82d65ce8f6080febafaaaf57
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ef3dacda31025b0d12def2faa3b14a75b43ab114a0389489a7962bc0e1c53542402991e0809198192ba8c28cc77c0bfd56c7533f79ca05a5cc6fe0406c65b94
|
7
|
+
data.tar.gz: 30460a520bfd15c0f131ec19091415976834fb0b876bc4c362148bc604f34a71827b39e76e33f00d1f07d03f8e4148e1e480191829e007ad4daad26dad74a73c
|
data/.gitignore
CHANGED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-c
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# ActiveRecord::HasCount
|
1
|
+
# ActiveRecord::HasCount [](https://travis-ci.org/k0kubun/activerecord-has_count)
|
2
2
|
|
3
3
|
N+1 count query killer for ActiveRecord
|
4
4
|
ActiveRecord::HasCount allows you to cache count of associated records by eager loading
|
@@ -20,7 +20,7 @@ gem 'activerecord-has_count'
|
|
20
20
|
|
21
21
|
## Usage
|
22
22
|
|
23
|
-
### Add
|
23
|
+
### Add has\_count scope
|
24
24
|
First, call `has_count` with an association whose count you want to preload
|
25
25
|
|
26
26
|
```rb
|
@@ -63,7 +63,7 @@ end
|
|
63
63
|
|
64
64
|
## Contributing
|
65
65
|
|
66
|
-
1. Fork it ( https://github.com/k0kubun/has_count/fork )
|
66
|
+
1. Fork it ( https://github.com/k0kubun/activerecord-has_count/fork )
|
67
67
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
68
68
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
69
69
|
4. Push to the branch (`git push origin my-new-feature`)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
lib = File.expand_path('../lib', __FILE__)
|
2
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
-
require '
|
3
|
+
require 'activerecord-has_count/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "activerecord-has_count"
|
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.require_paths = ["lib"]
|
18
18
|
|
19
19
|
spec.required_ruby_version = ">= 1.9.2"
|
20
|
-
spec.add_runtime_dependency "activerecord", ">= 3.0"
|
20
|
+
spec.add_runtime_dependency "activerecord", ">= 3.2.0"
|
21
21
|
spec.add_development_dependency "rspec", "~> 3.0.0"
|
22
22
|
spec.add_development_dependency "factory_girl", "~> 4.2.0"
|
23
23
|
spec.add_development_dependency "sqlite3"
|
data/benchmarks/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# N+1 COUNT query benchmarks
|
2
|
+
|
3
|
+
## Preparation
|
4
|
+
|
5
|
+
```bash
|
6
|
+
$ git clone git@github.com:k0kubun/activerecord-has_count
|
7
|
+
$ cd activerecord-has_count
|
8
|
+
$ mysql -uroot -e"create database bench"
|
9
|
+
$ bundle install
|
10
|
+
```
|
11
|
+
|
12
|
+
## Run
|
13
|
+
|
14
|
+
```bash
|
15
|
+
$ bundle exec ruby benchmark.rb
|
16
|
+
```
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "benchmark"
|
2
|
+
require "active_record"
|
3
|
+
require "activerecord-import"
|
4
|
+
require "activerecord-has_count"
|
5
|
+
|
6
|
+
spec_dir = File.expand_path("../../spec", __FILE__)
|
7
|
+
Dir[File.join(spec_dir, "models/*.rb")].each { |f| require f }
|
8
|
+
|
9
|
+
database_yml = File.join(spec_dir, "database.yml")
|
10
|
+
ActiveRecord::Base.configurations["bench"] = YAML.load_file(database_yml)["bench"]
|
11
|
+
ActiveRecord::Base.establish_connection :bench
|
12
|
+
|
13
|
+
ActiveRecord::Schema.define do
|
14
|
+
create_table :tweets, force: true do |t|
|
15
|
+
t.column :created_at, :datetime
|
16
|
+
t.column :updated_at, :datetime
|
17
|
+
end
|
18
|
+
|
19
|
+
create_table :replies, force: true do |t|
|
20
|
+
t.column :tweet_id, :integer
|
21
|
+
t.column :created_at, :datetime
|
22
|
+
t.column :updated_at, :datetime
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
[Tweet, Reply].each(&:delete_all)
|
27
|
+
|
28
|
+
TWEET_COUNT = 5
|
29
|
+
REPLY_COUNT = 10000
|
30
|
+
|
31
|
+
TWEET_COUNT.times do
|
32
|
+
tweet = Tweet.create
|
33
|
+
|
34
|
+
replies = REPLY_COUNT.times.map do
|
35
|
+
Reply.new(tweet: tweet)
|
36
|
+
end
|
37
|
+
Reply.import(replies, validate: false)
|
38
|
+
end
|
39
|
+
|
40
|
+
Benchmark.bmbm do |bench|
|
41
|
+
bench.report("COUNT association") do
|
42
|
+
tweets = Tweet.first(TWEET_COUNT)
|
43
|
+
|
44
|
+
tweets.each { |t| t.replies.count }
|
45
|
+
end
|
46
|
+
|
47
|
+
bench.report("LEFT JOIN") do
|
48
|
+
tweets = Tweet.joins('LEFT JOIN replies ON tweets.id = replies.tweet_id').
|
49
|
+
select('tweets.*, COUNT(replies.id) AS replies_count').
|
50
|
+
group('tweets.id').first(TWEET_COUNT)
|
51
|
+
|
52
|
+
tweets.each { |t| t.replies_count }
|
53
|
+
end
|
54
|
+
|
55
|
+
bench.report("size of preloaded association") do
|
56
|
+
tweets = Tweet.preload(:replies).first(TWEET_COUNT)
|
57
|
+
|
58
|
+
tweets.each { |t| t.replies.size }
|
59
|
+
end
|
60
|
+
end
|
@@ -1,20 +1,7 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module Associations
|
3
|
-
module ClassMethods
|
4
|
-
module HasCount
|
5
|
-
private
|
6
|
-
|
7
|
-
def has_count(name, scope = nil, options = {}, &extension)
|
8
|
-
name_with_count = :"#{name}_count"
|
9
|
-
|
10
|
-
reflection = Builder::HasCount.build(self, name_with_count, scope, options, &extension)
|
11
|
-
Reflection.add_reflection(self, name_with_count, reflection)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
3
|
class HasCount < SingularAssociation
|
17
|
-
# Not preloaded behaviour of
|
4
|
+
# Not preloaded behaviour of has_count association
|
18
5
|
# When this method is called, it will be N+1 query
|
19
6
|
def load_target
|
20
7
|
count_target = name_without_count.to_sym
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module HasCount
|
3
|
+
module Model
|
4
|
+
def self.included(model)
|
5
|
+
model.singleton_class.class_eval do
|
6
|
+
include ClassMethods
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
private
|
12
|
+
|
13
|
+
def has_count(name, scope = nil, options = {}, &extension)
|
14
|
+
name_with_count = :"#{name}_count"
|
15
|
+
|
16
|
+
reflection = ActiveRecord::Associations::Builder::HasCount.
|
17
|
+
build(self, name_with_count, scope, options, &extension)
|
18
|
+
ActiveRecord::Reflection.add_reflection(self, name_with_count, reflection)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
|
+
require "active_record"
|
2
|
+
require "active_support/lazy_load_hooks"
|
3
|
+
|
1
4
|
require "active_record/associations/has_count"
|
2
5
|
require "active_record/associations/builder/has_count"
|
3
6
|
require "active_record/associations/preloader/has_count"
|
4
7
|
require "active_record/associations/join_dependency/has_count"
|
5
8
|
require "active_record/reflection/has_count"
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
include HasCount
|
11
|
-
end
|
12
|
-
end
|
10
|
+
ActiveSupport.on_load(:active_record) do
|
11
|
+
require "activerecord-has_count/model"
|
12
|
+
ActiveRecord::Base.send(:include, ActiveRecord::HasCount::Model)
|
13
13
|
end
|
14
14
|
|
15
15
|
module ActiveRecord
|
data/spec/database.yml
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "#eager_load" do
|
4
|
+
describe "has_count association" do
|
5
|
+
let(:tweets_count) { 3 }
|
6
|
+
let(:tweets) do
|
7
|
+
tweets_count.times.map do
|
8
|
+
FactoryGirl.create(:tweet)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
before do
|
13
|
+
tweets.each_with_index do |tweet, index|
|
14
|
+
index.times do
|
15
|
+
FactoryGirl.create(:reply, tweet: tweet)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "raises ActiveRecord::EagerLoadHasCountError" do
|
21
|
+
# Currently this is not supported because I can't come up with how to implement.
|
22
|
+
# I'm waiting for your contribution.
|
23
|
+
expect {
|
24
|
+
Tweet.all.eager_load(:replies_count).map(&:replies_count)
|
25
|
+
}.to raise_error(ActiveRecord::EagerLoadHasCountError)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "#includes" do
|
4
|
+
describe "builtin associations" do
|
5
|
+
let(:replies_count) { 3 }
|
6
|
+
let!(:tweet) { FactoryGirl.create(:tweet) }
|
7
|
+
before do
|
8
|
+
replies_count.times do
|
9
|
+
FactoryGirl.create(:reply, tweet: tweet)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "given has_many association" do
|
14
|
+
it "works as usual" do
|
15
|
+
tweet = Tweet.includes(:replies).first
|
16
|
+
expect(tweet.replies.count).to eq(replies_count)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "given belongs_to association" do
|
21
|
+
let!(:reply) { FactoryGirl.create(:reply, tweet: tweet) }
|
22
|
+
|
23
|
+
it "works as usual" do
|
24
|
+
included_reply = Reply.includes(:tweet).find(reply.id)
|
25
|
+
expect(included_reply.tweet).to eq(tweet)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "has_count association" do
|
31
|
+
let(:tweets_count) { 3 }
|
32
|
+
let(:tweets) do
|
33
|
+
tweets_count.times.map do
|
34
|
+
FactoryGirl.create(:tweet)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
before do
|
39
|
+
tweets.each_with_index do |tweet, index|
|
40
|
+
index.times do
|
41
|
+
FactoryGirl.create(:reply, tweet: tweet)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it "does not execute N+1 queries by preload" do
|
47
|
+
expect_query_counts(1 + tweets_count) { Tweet.all.map(&:replies_count) }
|
48
|
+
expect_query_counts(2) { Tweet.all.includes(:replies_count).map(&:replies_count) }
|
49
|
+
end
|
50
|
+
|
51
|
+
it "counts properly" do
|
52
|
+
expected = Tweet.all.map { |t| t.replies.count }
|
53
|
+
expect(Tweet.all.map(&:replies_count)).to eq(expected)
|
54
|
+
expect(Tweet.all.includes(:replies_count).map(&:replies_count)).to eq(expected)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "#preload" do
|
4
|
+
describe "builtin associations" do
|
5
|
+
let(:replies_count) { 3 }
|
6
|
+
let!(:tweet) { FactoryGirl.create(:tweet) }
|
7
|
+
before do
|
8
|
+
replies_count.times do
|
9
|
+
FactoryGirl.create(:reply, tweet: tweet)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "given has_many association" do
|
14
|
+
it "works as usual" do
|
15
|
+
tweet = Tweet.preload(:replies).first
|
16
|
+
expect(tweet.replies.count).to eq(replies_count)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "given belongs_to association" do
|
21
|
+
let!(:reply) { FactoryGirl.create(:reply, tweet: tweet) }
|
22
|
+
|
23
|
+
it "works as usual" do
|
24
|
+
preloaded_reply = Reply.preload(:tweet).find(reply.id)
|
25
|
+
expect(preloaded_reply.tweet).to eq(tweet)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "has_count association" do
|
31
|
+
let(:tweets_count) { 3 }
|
32
|
+
let(:tweets) do
|
33
|
+
tweets_count.times.map do
|
34
|
+
FactoryGirl.create(:tweet)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
before do
|
39
|
+
tweets.each_with_index do |tweet, index|
|
40
|
+
index.times do
|
41
|
+
FactoryGirl.create(:reply, tweet: tweet)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it "does not execute N+1 queries by preload" do
|
47
|
+
expect_query_counts(1 + tweets_count) { Tweet.all.map(&:replies_count) }
|
48
|
+
expect_query_counts(2) { Tweet.all.preload(:replies_count).map(&:replies_count) }
|
49
|
+
end
|
50
|
+
|
51
|
+
it "counts properly" do
|
52
|
+
expected = Tweet.all.map { |t| t.replies.count }
|
53
|
+
expect(Tweet.all.map(&:replies_count)).to eq(expected)
|
54
|
+
expect(Tweet.all.preload(:replies_count).map(&:replies_count)).to eq(expected)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "pry"
|
3
|
+
require "active_record"
|
4
|
+
require "activerecord-has_count"
|
5
|
+
|
6
|
+
spec_dir = Pathname.new(File.dirname(__FILE__))
|
7
|
+
Dir[File.join(spec_dir, "models/*.rb")].each { |f| require f }
|
8
|
+
|
9
|
+
require "factory_girl"
|
10
|
+
Dir[File.join(spec_dir, "support/*.rb")].each { |f| require f }
|
11
|
+
|
12
|
+
database_yml = File.join(spec_dir, "database.yml")
|
13
|
+
ActiveRecord::Base.configurations["test"] = YAML.load_file(database_yml)["test"]
|
14
|
+
ActiveRecord::Base.establish_connection :test
|
15
|
+
|
16
|
+
ActiveRecord::Schema.define do
|
17
|
+
create_table :tweets, force: true do |t|
|
18
|
+
t.column :user_id, :integer
|
19
|
+
t.column :created_at, :datetime
|
20
|
+
t.column :updated_at, :datetime
|
21
|
+
end
|
22
|
+
|
23
|
+
create_table :replies, force: true do |t|
|
24
|
+
t.column :tweet_id, :integer
|
25
|
+
t.column :created_at, :datetime
|
26
|
+
t.column :updated_at, :datetime
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
RSpec.configure do |config|
|
31
|
+
ALL_MODELS = [
|
32
|
+
Tweet,
|
33
|
+
Reply,
|
34
|
+
].freeze
|
35
|
+
|
36
|
+
config.after do
|
37
|
+
ALL_MODELS.each(&:delete_all)
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Copied from:
|
2
|
+
# https://github.com/rails/rails/blob/9bb76261d39b59e7e229c80d052ca91a65ff17be/activerecord/test/cases/test_case.rb#L40-L52
|
3
|
+
def expect_query_counts(num = 1, options = {})
|
4
|
+
ignore_none = options.fetch(:ignore_none) { num == :any }
|
5
|
+
SQLCounter.clear_log
|
6
|
+
x = yield
|
7
|
+
|
8
|
+
the_log = ignore_none ? SQLCounter.log_all : SQLCounter.log
|
9
|
+
expect(the_log.size).to eq(num)
|
10
|
+
|
11
|
+
x
|
12
|
+
end
|
13
|
+
|
14
|
+
class SQLCounter
|
15
|
+
class << self
|
16
|
+
attr_accessor :ignored_sql, :log, :log_all
|
17
|
+
def clear_log; self.log = []; self.log_all = []; end
|
18
|
+
end
|
19
|
+
|
20
|
+
self.clear_log
|
21
|
+
|
22
|
+
self.ignored_sql = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^SHOW max_identifier_length/, /^BEGIN/, /^COMMIT/]
|
23
|
+
|
24
|
+
# FIXME: this needs to be refactored so specific database can add their own
|
25
|
+
# ignored SQL, or better yet, use a different notification for the queries
|
26
|
+
# instead examining the SQL content.
|
27
|
+
oracle_ignored = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from all_triggers/im, /^\s*select .* from all_constraints/im, /^\s*select .* from all_tab_cols/im]
|
28
|
+
mysql_ignored = [/^SHOW TABLES/i, /^SHOW FULL FIELDS/, /^SHOW CREATE TABLE /i]
|
29
|
+
postgresql_ignored = [/^\s*select\b.*\bfrom\b.*pg_namespace\b/im, /^\s*select\b.*\battname\b.*\bfrom\b.*\bpg_attribute\b/im, /^SHOW search_path/i]
|
30
|
+
sqlite3_ignored = [/^\s*SELECT name\b.*\bFROM sqlite_master/im]
|
31
|
+
|
32
|
+
[oracle_ignored, mysql_ignored, postgresql_ignored, sqlite3_ignored].each do |db_ignored_sql|
|
33
|
+
ignored_sql.concat db_ignored_sql
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :ignore
|
37
|
+
|
38
|
+
def initialize(ignore = Regexp.union(self.class.ignored_sql))
|
39
|
+
@ignore = ignore
|
40
|
+
end
|
41
|
+
|
42
|
+
def call(name, start, finish, message_id, values)
|
43
|
+
sql = values[:sql]
|
44
|
+
|
45
|
+
# FIXME: this seems bad. we should probably have a better way to indicate
|
46
|
+
# the query was cached
|
47
|
+
return if 'CACHE' == values[:name]
|
48
|
+
|
49
|
+
self.class.log_all << sql
|
50
|
+
self.class.log << sql unless ignore =~ sql
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
ActiveSupport::Notifications.subscribe('sql.active_record', SQLCounter.new)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-has_count
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
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-09-
|
11
|
+
date: 2014-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 3.2.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 3.2.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -116,18 +116,33 @@ extensions: []
|
|
116
116
|
extra_rdoc_files: []
|
117
117
|
files:
|
118
118
|
- .gitignore
|
119
|
+
- .rspec
|
120
|
+
- .travis.yml
|
119
121
|
- Gemfile
|
120
122
|
- LICENSE.txt
|
121
123
|
- README.md
|
122
124
|
- Rakefile
|
123
125
|
- activerecord-has_count.gemspec
|
126
|
+
- benchmarks/Gemfile
|
127
|
+
- benchmarks/README.md
|
128
|
+
- benchmarks/benchmark.rb
|
124
129
|
- lib/active_record/associations/builder/has_count.rb
|
125
130
|
- lib/active_record/associations/has_count.rb
|
126
131
|
- lib/active_record/associations/join_dependency/has_count.rb
|
127
132
|
- lib/active_record/associations/preloader/has_count.rb
|
128
|
-
- lib/active_record/has_count/version.rb
|
129
133
|
- lib/active_record/reflection/has_count.rb
|
130
134
|
- lib/activerecord-has_count.rb
|
135
|
+
- lib/activerecord-has_count/model.rb
|
136
|
+
- lib/activerecord-has_count/version.rb
|
137
|
+
- spec/database.yml
|
138
|
+
- spec/eager_load_spec.rb
|
139
|
+
- spec/includes_spec.rb
|
140
|
+
- spec/models/reply.rb
|
141
|
+
- spec/models/tweet.rb
|
142
|
+
- spec/preload_spec.rb
|
143
|
+
- spec/spec_helper.rb
|
144
|
+
- spec/support/assert_queries.rb
|
145
|
+
- spec/support/factories.rb
|
131
146
|
homepage: https://github.com/k0kubun/activerecord-has_count
|
132
147
|
licenses:
|
133
148
|
- MIT
|
@@ -148,9 +163,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
148
163
|
version: '0'
|
149
164
|
requirements: []
|
150
165
|
rubyforge_project:
|
151
|
-
rubygems_version: 2.0.
|
166
|
+
rubygems_version: 2.0.14
|
152
167
|
signing_key:
|
153
168
|
specification_version: 4
|
154
169
|
summary: N+1 count query killer for ActiveRecord
|
155
|
-
test_files:
|
170
|
+
test_files:
|
171
|
+
- spec/database.yml
|
172
|
+
- spec/eager_load_spec.rb
|
173
|
+
- spec/includes_spec.rb
|
174
|
+
- spec/models/reply.rb
|
175
|
+
- spec/models/tweet.rb
|
176
|
+
- spec/preload_spec.rb
|
177
|
+
- spec/spec_helper.rb
|
178
|
+
- spec/support/assert_queries.rb
|
179
|
+
- spec/support/factories.rb
|
156
180
|
has_rdoc:
|