dase 3.2.1
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.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +98 -0
- data/Rakefile +11 -0
- data/dase.gemspec +25 -0
- data/lib/dase/mp_active_record_base.rb +38 -0
- data/lib/dase/mp_active_record_relation.rb +40 -0
- data/lib/dase/preloader.rb +35 -0
- data/lib/dase/preloader_methods.rb +15 -0
- data/lib/dase/version.rb +3 -0
- data/lib/dase.rb +10 -0
- data/test/fixtures/author.rb +9 -0
- data/test/fixtures/authors.yml +20 -0
- data/test/fixtures/book.rb +7 -0
- data/test/fixtures/books.yml +34 -0
- data/test/fixtures/quote.rb +4 -0
- data/test/fixtures/quotes.yml +16 -0
- data/test/fixtures/schema.rb +22 -0
- data/test/helper.rb +30 -0
- data/test/test_dase.rb +52 -0
- metadata +131 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Vladimir Yartsev
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# Dase
|
2
|
+
|
3
|
+
The gem is named by the german mathematician [Johann Dase](http://en.wikipedia.org/wiki/Zacharias_Dase),
|
4
|
+
who was a mental calculator - he could count and multiply numbers very quickly. Dase gem adds extra speed
|
5
|
+
to Active Record whenever you need to calculate the number of associated records.
|
6
|
+
|
7
|
+
Here's an example of the code that will cause N + 1 queries:
|
8
|
+
|
9
|
+
```
|
10
|
+
Author.find_each do |author|
|
11
|
+
cnt = author.books.where(year: 1992).count
|
12
|
+
puts "#{author.name} has published #{cnt} books in 1992"
|
13
|
+
end
|
14
|
+
```
|
15
|
+
|
16
|
+
Active Record has a built-in solution for efficient fetching of
|
17
|
+
associated records - see [Rails Guides](http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations)
|
18
|
+
```
|
19
|
+
authors = Author.includes(:books) # => will cause only 2 queries
|
20
|
+
authors.first
|
21
|
+
```
|
22
|
+
|
23
|
+
The Dase gem provides a similar solution for the efficient counting of associated records:
|
24
|
+
```
|
25
|
+
authors = Author.includes_count_of(:books) # => will cause only 2 queries
|
26
|
+
authors.first.books_count
|
27
|
+
```
|
28
|
+
|
29
|
+
|
30
|
+
## Installation
|
31
|
+
|
32
|
+
Add this line to your application's Gemfile:
|
33
|
+
|
34
|
+
gem 'dase', "~> 3.2.0"
|
35
|
+
|
36
|
+
And then execute:
|
37
|
+
|
38
|
+
$ bundle
|
39
|
+
|
40
|
+
Or install it yourself as:
|
41
|
+
|
42
|
+
$ gem install dase
|
43
|
+
|
44
|
+
### Note on version numbers
|
45
|
+
|
46
|
+
Dase version number correlates with the Active Record's versions number,
|
47
|
+
which it has been tested with.
|
48
|
+
E.g. the latest 3.2.* version of Dase will play nicely with the latest 3.2.* version of Active Record.
|
49
|
+
Since it's a sort of a "hack", make sure you specified the version number for "dase" gem in your Gemfile.
|
50
|
+
|
51
|
+
## Usage
|
52
|
+
|
53
|
+
### Basic usage:
|
54
|
+
|
55
|
+
```
|
56
|
+
Author.includes_count_of(:books).find_each do |author|
|
57
|
+
puts "#{author.name} has #{author.books_count} books published"
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
### Advanced usage:
|
62
|
+
|
63
|
+
You can specify a hash of options which will be passed to the underlying finder
|
64
|
+
which retrieves the association. Valid keys are: :conditions, :group, :having, :joins, :include
|
65
|
+
```
|
66
|
+
Author.includes_count_of(:books, :conditions => {:year => 1990})
|
67
|
+
```
|
68
|
+
|
69
|
+
### Known problems
|
70
|
+
|
71
|
+
1. Dase doesn't support :through option on associations
|
72
|
+
2. You can't put includes_count_of calls into a scope declaration, like this:
|
73
|
+
|
74
|
+
```
|
75
|
+
class Author
|
76
|
+
scope :with_counters, lambda {
|
77
|
+
includes_count_of(:books) # this will not work!!!
|
78
|
+
}
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
## How it works
|
83
|
+
|
84
|
+
The equivalent code would look something like this:
|
85
|
+
```
|
86
|
+
counters_hash = Book.count(:group => :author_id)
|
87
|
+
Author.find_each do |author|
|
88
|
+
puts "#{author.name} has #{counters_hash[author.id] || 0} books published"
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
## Contributing
|
93
|
+
|
94
|
+
1. Fork it
|
95
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
96
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
97
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
98
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/dase.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dase/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "dase"
|
8
|
+
gem.version = Dase::VERSION
|
9
|
+
gem.authors = ["Vladimir Yartsev"]
|
10
|
+
gem.email = ["vovayartsev@gmail.com"]
|
11
|
+
gem.description = %q{A solution for N+1 querying problem in Active Record associated records counting}
|
12
|
+
gem.summary = %q{Really fast associated records counting}
|
13
|
+
gem.homepage = "https://github.com/vovayartsev"
|
14
|
+
|
15
|
+
gem.add_runtime_dependency "activerecord", "~> 3.2.0"
|
16
|
+
gem.add_runtime_dependency "activesupport", "~> 3.2.0"
|
17
|
+
gem.add_development_dependency 'shoulda'
|
18
|
+
gem.add_development_dependency 'sqlite3', '~> 1.3.3'
|
19
|
+
gem.add_development_dependency 'debugger'
|
20
|
+
|
21
|
+
gem.files = `git ls-files`.split($/)
|
22
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
23
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
24
|
+
gem.require_paths = ["lib"]
|
25
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Monkey-patching ActiveRecord::Base to add xxx_count methods to it
|
2
|
+
|
3
|
+
module Dase
|
4
|
+
module ARBaseInstanceMethods
|
5
|
+
def set_dase_counter(name, value)
|
6
|
+
@dase_counters ||= {}
|
7
|
+
@dase_counters[name] = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def get_dase_counter(name)
|
11
|
+
@dase_counters[name]
|
12
|
+
end
|
13
|
+
|
14
|
+
def respond_to?(*args)
|
15
|
+
@dase_counters && @dase_counters.has_key?(args.first.to_sym) || super
|
16
|
+
end
|
17
|
+
|
18
|
+
def method_missing(name, *args)
|
19
|
+
if @dase_counters and @dase_counters.has_key?(name.to_sym)
|
20
|
+
get_dase_counter(name, *args)
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def self.included(klass)
|
29
|
+
class << klass
|
30
|
+
delegate :includes_count_of, :to => :scoped
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
ActiveRecord::Base.class_eval do
|
37
|
+
include Dase::ARBaseInstanceMethods
|
38
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Dase
|
2
|
+
module ARRelationInstanceMethods
|
3
|
+
attr_accessor :dase_values
|
4
|
+
|
5
|
+
def includes_count_of(*args)
|
6
|
+
args.reject! { |a| a.blank? }
|
7
|
+
options = args.extract_options!
|
8
|
+
options.assert_valid_keys(:conditions, :group, :having, :limit, :offset, :joins, :include, :from, :lock)
|
9
|
+
return self if args.empty?
|
10
|
+
relation = clone
|
11
|
+
relation.dase_values ||= {}
|
12
|
+
args.each { |a| relation.dase_values[a] = options}
|
13
|
+
relation
|
14
|
+
end
|
15
|
+
|
16
|
+
def attach_dase_counters_to_records
|
17
|
+
if dase_values.present? and !@has_dase_counters
|
18
|
+
dase_values.each do |associations, options|
|
19
|
+
Dase::Preloader.new(@records, associations, options).run
|
20
|
+
end
|
21
|
+
@has_dase_counters = true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
ActiveRecord::Relation.class_eval do
|
29
|
+
include Dase::ARRelationInstanceMethods
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
alias_method :exec_queries_before_dase, :exec_queries
|
34
|
+
|
35
|
+
def exec_queries
|
36
|
+
exec_queries_before_dase # original method from ActiveRecord
|
37
|
+
attach_dase_counters_to_records
|
38
|
+
@records
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Dase
|
2
|
+
class Preloader < ::ActiveRecord::Associations::Preloader
|
3
|
+
|
4
|
+
# custom preloaders for different association types
|
5
|
+
class HasMany < ::ActiveRecord::Associations::Preloader::HasMany
|
6
|
+
include Dase::PreloaderMethods
|
7
|
+
end
|
8
|
+
class HasAndBelongsToMany < ::ActiveRecord::Associations::Preloader::HasAndBelongsToMany
|
9
|
+
include Dase::PreloaderMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
# Not implemented yet
|
13
|
+
#class HasManyThrough < ::ActiveRecord::Associations::Preloader::HasManyThrough
|
14
|
+
# include Dase::PreloaderMethods
|
15
|
+
#end
|
16
|
+
|
17
|
+
# an overloaded version of ActiveRecord::Associations::Preloader's preloader_for
|
18
|
+
# which returns a class of a custom preloader for a given association
|
19
|
+
def preloader_for(reflection)
|
20
|
+
case reflection.macro
|
21
|
+
when :has_many
|
22
|
+
if reflection.options[:through]
|
23
|
+
raise NotImplementedError, "The support for HasManyThrough associations is not implemented yet"
|
24
|
+
else
|
25
|
+
HasMany
|
26
|
+
end
|
27
|
+
when :has_one, :belongs_to
|
28
|
+
raise ArgumentError, "You can't use includes_count_of with a #{reflection.macro} association"
|
29
|
+
when :has_and_belongs_to_many
|
30
|
+
HasAndBelongsToMany
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Dase
|
2
|
+
module PreloaderMethods
|
3
|
+
def preload
|
4
|
+
counter_name = "#{reflection.name}_count".to_sym
|
5
|
+
pk = model.primary_key.to_sym
|
6
|
+
ids = owners.map(&pk)
|
7
|
+
fk = "#{scoped.quoted_table_name}.#{reflection.foreign_key}"
|
8
|
+
counters_hash = records_for(ids).count(group: fk)
|
9
|
+
owners.each do |owner|
|
10
|
+
value = counters_hash[owner[pk]] || 0 # 0 is "default count", when no records found
|
11
|
+
owner.set_dase_counter(counter_name, value)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/dase/version.rb
ADDED
data/lib/dase.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require "dase/version"
|
2
|
+
require "dase/preloader_methods"
|
3
|
+
require "dase/preloader"
|
4
|
+
require "dase/mp_active_record_base"
|
5
|
+
require "dase/mp_active_record_relation"
|
6
|
+
|
7
|
+
module Dase
|
8
|
+
# take a look at mp_active_record_* files
|
9
|
+
# (there we monkey-patch Active Record)
|
10
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
joe:
|
2
|
+
name : Joe
|
3
|
+
id : 1
|
4
|
+
created_at: 1999-02-19 08:00
|
5
|
+
updated_at: 1999-02-19 08:00
|
6
|
+
# has 3 books: two old (year 1990) and one new (year 2012) book
|
7
|
+
|
8
|
+
bobby:
|
9
|
+
name : Bobby
|
10
|
+
id : 2
|
11
|
+
created_at: 1999-02-19 08:00
|
12
|
+
updated_at: 1999-02-19 08:00
|
13
|
+
# has 1 old book (year 1990)
|
14
|
+
|
15
|
+
teddy:
|
16
|
+
name : Teddy
|
17
|
+
id : 3
|
18
|
+
created_at: 1999-02-19 08:00
|
19
|
+
updated_at: 1999-02-19 08:00
|
20
|
+
# has no books at all
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Joe's books
|
2
|
+
first:
|
3
|
+
id : 1
|
4
|
+
year : 1990
|
5
|
+
title : First book
|
6
|
+
author_id : 1
|
7
|
+
created_at: 1999-02-19 08:00
|
8
|
+
updated_at: 1999-02-19 08:00
|
9
|
+
|
10
|
+
second:
|
11
|
+
id : 2
|
12
|
+
year : 1990
|
13
|
+
title : Second book
|
14
|
+
author_id : 1
|
15
|
+
created_at: 1999-02-19 08:00
|
16
|
+
updated_at: 1999-02-19 08:00
|
17
|
+
|
18
|
+
third:
|
19
|
+
id : 3
|
20
|
+
year : 2012
|
21
|
+
title : Third book
|
22
|
+
author_id : 1
|
23
|
+
created_at: 1999-02-19 08:00
|
24
|
+
updated_at: 1999-02-19 08:00
|
25
|
+
|
26
|
+
|
27
|
+
# Bobby's book
|
28
|
+
fourth:
|
29
|
+
id : 4
|
30
|
+
year : 1990
|
31
|
+
title : Fourth book
|
32
|
+
author_id : 2
|
33
|
+
created_at: 1999-02-19 08:00
|
34
|
+
updated_at: 1999-02-19 08:00
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Joe's quotation
|
2
|
+
first:
|
3
|
+
id: 1
|
4
|
+
book_id: 1
|
5
|
+
snippet: "To be or not to be, that is the question"
|
6
|
+
|
7
|
+
# Bobby's quotations
|
8
|
+
second:
|
9
|
+
id: 2
|
10
|
+
book_id: 4
|
11
|
+
snippet: "No matter how much cats fight, there always seem to be plenty of kittens"
|
12
|
+
|
13
|
+
third:
|
14
|
+
id: 3
|
15
|
+
book_id: 4
|
16
|
+
snippet: "I am fond of pigs. Dogs look up to us. Cats look down on us. Pigs treat us as equals."
|
@@ -0,0 +1,22 @@
|
|
1
|
+
ActiveRecord::Schema.define do
|
2
|
+
|
3
|
+
create_table "authors", :force => true do |t|
|
4
|
+
t.string "name"
|
5
|
+
t.datetime "created_at", :null => false
|
6
|
+
t.datetime "updated_at", :null => false
|
7
|
+
end
|
8
|
+
|
9
|
+
create_table "books", :force => true do |t|
|
10
|
+
t.integer "year"
|
11
|
+
t.string "title"
|
12
|
+
t.integer "author_id"
|
13
|
+
t.datetime "created_at", :null => false
|
14
|
+
t.datetime "updated_at", :null => false
|
15
|
+
end
|
16
|
+
|
17
|
+
create_table "quotes", :force => true do |t|
|
18
|
+
t.string "snippet"
|
19
|
+
t.integer "book_id"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# borrowed from https://github.com/ernie/meta_where/blob/master/test/helper.rb
|
2
|
+
# with slight modifications
|
3
|
+
require "rubygems"
|
4
|
+
require "bundler"
|
5
|
+
Bundler.setup
|
6
|
+
require 'test/unit'
|
7
|
+
require 'shoulda'
|
8
|
+
require 'active_record'
|
9
|
+
require 'active_record/fixtures'
|
10
|
+
require 'dase'
|
11
|
+
|
12
|
+
FIXTURES_PATH = File.join(File.dirname(__FILE__), 'fixtures')
|
13
|
+
|
14
|
+
ActiveRecord::Base.establish_connection(
|
15
|
+
:adapter => defined?(JRUBY_VERSION) ? 'jdbcsqlite3' : 'sqlite3',
|
16
|
+
:database => ':memory:'
|
17
|
+
)
|
18
|
+
|
19
|
+
dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies
|
20
|
+
dep.autoload_paths.unshift FIXTURES_PATH
|
21
|
+
|
22
|
+
ActiveRecord::Base.silence do
|
23
|
+
ActiveRecord::Migration.verbose = false
|
24
|
+
load File.join(FIXTURES_PATH, 'schema.rb')
|
25
|
+
end
|
26
|
+
|
27
|
+
ActiveRecord::Fixtures.create_fixtures(FIXTURES_PATH, ActiveRecord::Base.connection.tables)
|
28
|
+
|
29
|
+
class Test::Unit::TestCase
|
30
|
+
end
|
data/test/test_dase.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestBase < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def compare_counts(traditional, dase, true_counts)
|
6
|
+
assert_equal true_counts, traditional, "traditional counting failed - fixtures not loaded"
|
7
|
+
assert_equal true_counts, dase, "dase countings failed"
|
8
|
+
end
|
9
|
+
|
10
|
+
context "includes_count_of" do
|
11
|
+
setup do
|
12
|
+
@bobby, @joe, @teddy = Author.order(:name).all
|
13
|
+
end
|
14
|
+
|
15
|
+
should "count books" do
|
16
|
+
traditional_counts = Author.order(:name).map { |a| a.books.count }
|
17
|
+
dase_counts = Author.includes_count_of(:books).order(:name).map { |a| a.books_count }
|
18
|
+
# the order is: Bobby, Joe, Teddy - due to order(:name)
|
19
|
+
true_counts = [1, 3, 0] # see books.yml
|
20
|
+
compare_counts(traditional_counts, dase_counts, true_counts)
|
21
|
+
end
|
22
|
+
|
23
|
+
should "respond_to the counter method" do
|
24
|
+
assert_equal true, Author.includes_count_of(:books).first.respond_to?(:books_count), "doesn't respond'"
|
25
|
+
end
|
26
|
+
|
27
|
+
should "count old books" do
|
28
|
+
traditional_counts = Author.order(:name).map { |a| a.old_books.count }
|
29
|
+
dase_counts = Author.includes_count_of(:old_books).order(:name).map { |a| a.old_books_count }
|
30
|
+
# the order is: Bobby, Joe, Teddy - due to order(:name)
|
31
|
+
true_counts = [1, 2, 0] # see books.yml
|
32
|
+
compare_counts(traditional_counts, dase_counts, true_counts)
|
33
|
+
end
|
34
|
+
|
35
|
+
should "count books for year 1990" do
|
36
|
+
traditional_counts = Author.order(:name).map { |a| a.books.where(year: 1990).count }
|
37
|
+
dase_counts = Author.includes_count_of(:books, :conditions => {:year => 1990}).order(:name).map { |a| a.books_count }
|
38
|
+
# the order is: Bobby, Joe, Teddy - due to order(:name)
|
39
|
+
true_counts = [1, 2, 0] # see books.yml
|
40
|
+
compare_counts(traditional_counts, dase_counts, true_counts)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Not yet implemented
|
44
|
+
#should "count quotations" do
|
45
|
+
# traditional_counts = Author.order(:name).map { |a| a.quotes.count }
|
46
|
+
# dase_counts = Author.order(:name).includes_count_of(:quotes).map { |a| a.quotes_count }
|
47
|
+
# # the order is: Bobby, Joe, Teddy - due to order(:name)
|
48
|
+
# true_counts = [2, 1, 0] # see quotes.yml
|
49
|
+
# compare_counts(traditional_counts, dase_counts, true_counts)
|
50
|
+
#end
|
51
|
+
end
|
52
|
+
end
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dase
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 3.2.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Vladimir Yartsev
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: &70291652811140 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.2.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70291652811140
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
requirement: &70291652810620 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.2.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70291652810620
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: shoulda
|
38
|
+
requirement: &70291652810220 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70291652810220
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: sqlite3
|
49
|
+
requirement: &70291652808960 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.3.3
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70291652808960
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: debugger
|
60
|
+
requirement: &70291652808360 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70291652808360
|
69
|
+
description: A solution for N+1 querying problem in Active Record associated records
|
70
|
+
counting
|
71
|
+
email:
|
72
|
+
- vovayartsev@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.txt
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- dase.gemspec
|
83
|
+
- lib/dase.rb
|
84
|
+
- lib/dase/mp_active_record_base.rb
|
85
|
+
- lib/dase/mp_active_record_relation.rb
|
86
|
+
- lib/dase/preloader.rb
|
87
|
+
- lib/dase/preloader_methods.rb
|
88
|
+
- lib/dase/version.rb
|
89
|
+
- test/fixtures/author.rb
|
90
|
+
- test/fixtures/authors.yml
|
91
|
+
- test/fixtures/book.rb
|
92
|
+
- test/fixtures/books.yml
|
93
|
+
- test/fixtures/quote.rb
|
94
|
+
- test/fixtures/quotes.yml
|
95
|
+
- test/fixtures/schema.rb
|
96
|
+
- test/helper.rb
|
97
|
+
- test/test_dase.rb
|
98
|
+
homepage: https://github.com/vovayartsev
|
99
|
+
licenses: []
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
requirements: []
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 1.8.11
|
119
|
+
signing_key:
|
120
|
+
specification_version: 3
|
121
|
+
summary: Really fast associated records counting
|
122
|
+
test_files:
|
123
|
+
- test/fixtures/author.rb
|
124
|
+
- test/fixtures/authors.yml
|
125
|
+
- test/fixtures/book.rb
|
126
|
+
- test/fixtures/books.yml
|
127
|
+
- test/fixtures/quote.rb
|
128
|
+
- test/fixtures/quotes.yml
|
129
|
+
- test/fixtures/schema.rb
|
130
|
+
- test/helper.rb
|
131
|
+
- test/test_dase.rb
|