includes-count 0.1 → 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 +7 -0
- data/README.md +137 -3
- data/lib/includes-count.rb +7 -2
- data/lib/includes-count/version.rb +1 -1
- metadata +14 -13
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 01664881d5b615683b68c72b023bf901e492fb35
|
4
|
+
data.tar.gz: 15a6cba04f0c7a280de2eb6825532665cee4e15c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1b60c9999656159d056e45ca3a457e597079d3891bc734aa4f7be65caa9515aec046156c79de7c01f5356a4547e9f02bfb2524172fc9d186fb09e6e677dc71a5
|
7
|
+
data.tar.gz: 8312170635c24bad30c4ae06c5f5bd290bbb8be175ec112c27ac51e7b8848d76f39071aae08dea7c2940418df8ee8150c2efe8d40470c62c66ca36baa7931d4a
|
data/README.md
CHANGED
@@ -1,4 +1,138 @@
|
|
1
|
-
Includes Count
|
2
|
-
|
1
|
+
Includes Count
|
2
|
+
==============
|
3
3
|
|
4
|
-
|
4
|
+
This gem adds an `includes_count` method to active record queries, which adds the count of an association to a relation using a simple `SELECT` SQL query in a similar way as the `includes` method does, only that retrieving counts instead of the full records collection.
|
5
|
+
|
6
|
+
This gem has been tested with ActiveRecord version 3.1.3.
|
7
|
+
|
8
|
+
Usage
|
9
|
+
=====
|
10
|
+
|
11
|
+
For example, in the following model:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
class Blog
|
15
|
+
has_many :posts
|
16
|
+
has_many :comments, :through => :posts
|
17
|
+
end
|
18
|
+
|
19
|
+
class Post
|
20
|
+
belongs_to :blog
|
21
|
+
has_many :comments
|
22
|
+
end
|
23
|
+
|
24
|
+
class Comment
|
25
|
+
belongs_to :post
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
It is possible to retrieve the number of posts in every blog with the command:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
blogs_with_posts_count = Blog.scoped.includes_count(:posts)
|
33
|
+
```
|
34
|
+
|
35
|
+
This will issue a simple `SELECT` query retrieving all counts and assigning them in memory, thus not requiring an `INNER JOIN` that could be expensive to handle in the database:
|
36
|
+
|
37
|
+
```sql
|
38
|
+
SELECT SQL_NO_CACHE posts.blog_id, COUNT(id) AS posts_count
|
39
|
+
FROM `posts`
|
40
|
+
WHERE `posts`.`blog_id` IN (1, 2, 3, 4, 5, 6, 7, 8)
|
41
|
+
GROUP BY `posts`.`blog_id`
|
42
|
+
```
|
43
|
+
|
44
|
+
The count is projected to a field named by default `association_name_count`:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
blogs_with_posts_count.map(&:posts_count)
|
48
|
+
```
|
49
|
+
|
50
|
+
The name of the method can be changed by supplying the `count_name` option:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
blogs_with_posts_count = Blog.scoped.includes_count(:posts, :count_name => 'number_of_posts')
|
54
|
+
blogs_with_posts_count.map(&:posts_count)
|
55
|
+
```
|
56
|
+
|
57
|
+
The execution of the count is delayed until execution of the query, as happens with the `includes` clause, so further clauses, such as `where`, can be set to the relation:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
latest_blogs_with_posts_count = Blog.scoped.includes_count(:posts).where('updated_at > ?', 1.week.ago)
|
61
|
+
```
|
62
|
+
|
63
|
+
This will retrieve only the blogs that have been updated since 1 week ago, along with their counts. Supposing there are only two blogs that match that condition (ids 3 and 5), the `SELECT` query issued will be the following:
|
64
|
+
|
65
|
+
```sql
|
66
|
+
SELECT SQL_NO_CACHE posts.blog_id, COUNT(id) AS posts_count
|
67
|
+
FROM `posts`
|
68
|
+
WHERE `posts`.`blog_id` IN (3, 5)
|
69
|
+
GROUP BY `posts`.`blog_id`
|
70
|
+
```
|
71
|
+
|
72
|
+
Conditions can be specified on the included association (using a string, a hash or a proc), in order to filter which records are to be counted:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
blogs_with_rails_posts_count = Blog.scoped.includes_count(:posts, :count_name => 'rails_posts_count', :conditions => "category = 'rails'")
|
76
|
+
```
|
77
|
+
|
78
|
+
```sql
|
79
|
+
SELECT SQL_NO_CACHE posts.blog_id, COUNT(id) AS posts_count
|
80
|
+
FROM `posts`
|
81
|
+
WHERE `posts`.`blog_id` IN (3, 5)
|
82
|
+
AND `posts`.`category` = 'rails'
|
83
|
+
GROUP BY `posts`.`blog_id`
|
84
|
+
```
|
85
|
+
|
86
|
+
Through Associations
|
87
|
+
--------------------
|
88
|
+
|
89
|
+
The `includes_count` method also supports through associations, and issues as many `SELECT` queries as needed to navigate the hierarchy and obtain the specified counts.
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
blogs_with_comments_count = Blog.scoped.includes_count(:comments)
|
93
|
+
```
|
94
|
+
|
95
|
+
```sql
|
96
|
+
SELECT SQL_NO_CACHE `posts`.*
|
97
|
+
FROM `posts`
|
98
|
+
WHERE `posts`.`blog_id` IN (1, 2, 3, 4, 5, 6, 7, 8)
|
99
|
+
```
|
100
|
+
|
101
|
+
```sql
|
102
|
+
SELECT SQL_NO_CACHE `comments`.post_id, COUNT(id) AS comments_count
|
103
|
+
FROM `comments`
|
104
|
+
WHERE `comments`.`post_id` IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
|
105
|
+
GROUP BY `comments`.`post_id`
|
106
|
+
```
|
107
|
+
|
108
|
+
As usual, the value can be accessed via the method named after the association, and overridden via `count_name`:
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
blogs_with_posts_count.map(&:comments_count)
|
112
|
+
```
|
113
|
+
|
114
|
+
It is also possible to specify conditions at any of the intermediate associations in the `through` association:
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
blogs_with_comments_count_from_rails_posts = Blog.scoped.includes_count(:comments, :through_options => { :posts => { :conditions => "category = 'rails'"} })
|
118
|
+
```
|
119
|
+
|
120
|
+
```sql
|
121
|
+
SELECT SQL_NO_CACHE `posts`.*
|
122
|
+
FROM `posts`
|
123
|
+
WHERE `posts`.`blog_id` IN (1, 2, 3, 4, 5, 6, 7, 8)
|
124
|
+
AND `posts`.`category` = 'rails'
|
125
|
+
```
|
126
|
+
|
127
|
+
```sql
|
128
|
+
SELECT SQL_NO_CACHE `comments`.post_id, COUNT(id) AS comments_count
|
129
|
+
FROM `comments`
|
130
|
+
WHERE `comments`.`post_id` IN (5, 6, 10, 11, 12)
|
131
|
+
GROUP BY `comments`.`post_id`
|
132
|
+
```
|
133
|
+
|
134
|
+
|
135
|
+
Known Issues
|
136
|
+
------------
|
137
|
+
|
138
|
+
* The `includes_count` method is included only in `ActiveRecord::Relation` objects, which means you cannot execute it straight on a model. As a workaround, supply the method `scoped` before executing `includes_count`: `Blog.scoped.includes_count(:posts)`
|
data/lib/includes-count.rb
CHANGED
@@ -19,8 +19,13 @@ module ActiveRecord
|
|
19
19
|
|
20
20
|
def preload
|
21
21
|
associated_records_by_owner.each do |owner, associated_records|
|
22
|
-
|
23
|
-
owner
|
22
|
+
sum = associated_records.map{|r| r[count_name] || 0}.sum
|
23
|
+
owner.instance_eval "
|
24
|
+
def #{count_name}
|
25
|
+
@#{count_name} ||= 0
|
26
|
+
@#{count_name} += #{sum}
|
27
|
+
end
|
28
|
+
"
|
24
29
|
end
|
25
30
|
end
|
26
31
|
|
metadata
CHANGED
@@ -1,27 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: includes-count
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
5
|
-
prerelease:
|
4
|
+
version: '0.2'
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Santiago Palladino
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-08-08 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: activerecord
|
16
|
-
requirement:
|
17
|
-
none: false
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
|
-
version_requirements:
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
25
27
|
description: The includes_count method executes a SQL count on an association to retrieve
|
26
28
|
its number of records, optionally filtered by a set of conditions.
|
27
29
|
email:
|
@@ -39,26 +41,25 @@ files:
|
|
39
41
|
- lib/includes-count/version.rb
|
40
42
|
homepage: ''
|
41
43
|
licenses: []
|
44
|
+
metadata: {}
|
42
45
|
post_install_message:
|
43
46
|
rdoc_options: []
|
44
47
|
require_paths:
|
45
48
|
- lib
|
46
49
|
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
-
none: false
|
48
50
|
requirements:
|
49
|
-
- -
|
51
|
+
- - '>='
|
50
52
|
- !ruby/object:Gem::Version
|
51
53
|
version: '0'
|
52
54
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
-
none: false
|
54
55
|
requirements:
|
55
|
-
- -
|
56
|
+
- - '>='
|
56
57
|
- !ruby/object:Gem::Version
|
57
58
|
version: '0'
|
58
59
|
requirements: []
|
59
60
|
rubyforge_project: includes-count
|
60
|
-
rubygems_version:
|
61
|
+
rubygems_version: 2.0.14
|
61
62
|
signing_key:
|
62
|
-
specification_version:
|
63
|
+
specification_version: 4
|
63
64
|
summary: Adds includes_count method to active record queries
|
64
65
|
test_files: []
|