eager_group 0.6.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +20 -0
- data/README.md +95 -39
- data/benchmark.rb +10 -9
- data/eager_group.gemspec +3 -2
- data/lib/eager_group.rb +11 -10
- data/lib/eager_group/definition.rb +16 -1
- data/lib/eager_group/preloader.rb +32 -13
- data/lib/eager_group/version.rb +1 -1
- metadata +22 -11
- data/lib/eager_group/active_record_base.rb +0 -8
- data/lib/eager_group/active_record_relation.rb +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 516b00c6397d1a6b397b165687091079118a48ed39fc0afce4542d3cf4f7f481
|
4
|
+
data.tar.gz: 9bf3083695c819003574f3971d2a592443320af92dc98c1ff36b302c87718889
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 389265b557184c2d3f3c0207340c8bd65086a38fb8e0b2b168a4c14ed37f82b5bcb0ee89ab7a48da528bfbcf2174c1c89dcc0fd917eade1de9c184cad3238e9b
|
7
|
+
data.tar.gz: 6e5e9bd946a9d333bda2087578ac47b98d57ab0cb8347adc9577f582124e1ca9a571fdddeaa28da48644aca0f9d0546f1ee323149742b2c0868d5d6c324354da
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
# Next Release
|
2
2
|
|
3
|
+
## 0.8.0 (10/21/2019)
|
4
|
+
|
5
|
+
* Support `has_and_belongs_to_many`
|
6
|
+
|
7
|
+
## 0.7.2 (10/10/2019)
|
8
|
+
|
9
|
+
* Simplify `association_klass` for `first_object` and `last_object`
|
10
|
+
|
11
|
+
## 0.7.1 (08/23/2019)
|
12
|
+
|
13
|
+
* Set `eager_group_definitions` by `mattr_accessor`
|
14
|
+
|
15
|
+
## 0.7.0 (08/22/2019)
|
16
|
+
|
17
|
+
* Add `first_object` and `last_object` aggregation
|
18
|
+
|
19
|
+
## 0.6.1 (03/05/2018)
|
20
|
+
|
21
|
+
* Skip preload when association is empty
|
22
|
+
|
3
23
|
## 0.6.0 (12/15/2018)
|
4
24
|
|
5
25
|
* Support hash as `eager_group` argument
|
data/README.md
CHANGED
@@ -1,36 +1,44 @@
|
|
1
1
|
# EagerGroup
|
2
2
|
|
3
|
-
[![Build Status](https://secure.travis-ci.org/
|
3
|
+
[![Build Status](https://secure.travis-ci.org/flyerhzm/eager_group.png)](http://travis-ci.org/flyerhzm/eager_group)
|
4
4
|
[![AwesomeCode Status for
|
5
|
-
|
5
|
+
flyerhzm/eager_group](https://awesomecode.io/projects/e5386790-9420-4003-831a-c9a8c8a48108/status)](https://awesomecode.io/repos/flyerhzm/eager_group)
|
6
6
|
|
7
|
-
[More explaination on our blog](http://blog.
|
7
|
+
[More explaination on our blog](http://blog.flyerhzm.com/2015/06/29/eager_group/)
|
8
8
|
|
9
9
|
Fix n+1 aggregate sql functions for rails, like
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
```
|
12
|
+
SELECT "posts".* FROM "posts";
|
13
|
+
SELECT COUNT(*) FROM "comments" WHERE "comments"."post_id" = 1 AND "comments"."status" = 'approved'
|
14
|
+
SELECT COUNT(*) FROM "comments" WHERE "comments"."post_id" = 2 AND "comments"."status" = 'approved'
|
15
|
+
SELECT COUNT(*) FROM "comments" WHERE "comments"."post_id" = 3 AND "comments"."status" = 'approved'
|
16
|
+
```
|
15
17
|
|
16
18
|
=>
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
+
```
|
21
|
+
SELECT "posts".* FROM "posts";
|
22
|
+
SELECT COUNT(*) AS count_all, post_id AS post_id FROM "comments" WHERE "comments"."post_id" IN (1, 2, 3) AND "comments"."status" = 'approved' GROUP BY post_id;
|
23
|
+
```
|
20
24
|
|
21
25
|
or
|
22
26
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
```
|
28
|
+
SELECT "posts".* FROM "posts";
|
29
|
+
SELECT AVG("comments"."rating") AS avg_id FROM "comments" WHERE "comments"."post_id" = 1;
|
30
|
+
SELECT AVG("comments"."rating") AS avg_id FROM "comments" WHERE "comments"."post_id" = 2;
|
31
|
+
SELECT AVG("comments"."rating") AS avg_id FROM "comments" WHERE "comments"."post_id" = 3;
|
32
|
+
```
|
27
33
|
|
28
34
|
=>
|
29
35
|
|
30
|
-
|
31
|
-
|
36
|
+
```
|
37
|
+
SELECT "posts".* FROM "posts";
|
38
|
+
SELECT AVG("comments"."rating") AS average_comments_rating, post_id AS post_id FROM "comments" WHERE "comments"."post_id" IN (1, 2, 3) GROUP BY post_id;
|
39
|
+
```
|
32
40
|
|
33
|
-
It supports Rails 4.x and Rails
|
41
|
+
It supports Rails 4.x, Rails 5.x and Rails 6.x
|
34
42
|
|
35
43
|
## Installation
|
36
44
|
|
@@ -42,29 +50,35 @@ gem 'eager_group'
|
|
42
50
|
|
43
51
|
And then execute:
|
44
52
|
|
45
|
-
|
53
|
+
```
|
54
|
+
$ bundle
|
55
|
+
```
|
46
56
|
|
47
57
|
Or install it yourself as:
|
48
58
|
|
49
|
-
|
59
|
+
```
|
60
|
+
$ gem install eager_group
|
61
|
+
```
|
50
62
|
|
51
63
|
## Usage
|
52
64
|
|
53
65
|
First you need to define what aggregate function you want to eager
|
54
66
|
load.
|
55
67
|
|
56
|
-
|
57
|
-
|
68
|
+
```ruby
|
69
|
+
class Post < ActiveRecord::Base
|
70
|
+
has_many :comments
|
58
71
|
|
59
|
-
|
60
|
-
|
61
|
-
|
72
|
+
define_eager_group :comments_average_rating, :comments, :average, :rating
|
73
|
+
define_eager_group :approved_comments_count, :comments, :count, :*, -> { approved }
|
74
|
+
end
|
62
75
|
|
63
|
-
|
64
|
-
|
76
|
+
class Comment < ActiveRecord::Base
|
77
|
+
belongs_to :post
|
65
78
|
|
66
|
-
|
67
|
-
|
79
|
+
scope :approved, -> { where(status: 'approved') }
|
80
|
+
end
|
81
|
+
```
|
68
82
|
|
69
83
|
The parameters for `define_eager_group` are as follows
|
70
84
|
|
@@ -73,18 +87,22 @@ method, it also generates a method with the same name to fetch the
|
|
73
87
|
result.
|
74
88
|
* `association`, association name you want to aggregate.
|
75
89
|
* `aggregate_function`, aggregate sql function, can be one of `average`,
|
76
|
-
`count`, `maximum`, `minimum`, `sum
|
90
|
+
`count`, `maximum`, `minimum`, `sum`, I define 2 additional aggregate
|
91
|
+
function `first_object` and `last_object` to eager load first and last
|
92
|
+
association objects.
|
77
93
|
* `column_name`, aggregate column name, it can be `:*` for `count`
|
78
94
|
* `scope`, scope is optional, it's used to filter data for aggregation.
|
79
95
|
|
80
96
|
Then you can use `eager_group` to fix n+1 aggregate sql functions
|
81
97
|
when querying
|
82
98
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
99
|
+
```ruby
|
100
|
+
posts = Post.all.eager_group(:comments_average_rating, :approved_comments_count)
|
101
|
+
posts.each do |post|
|
102
|
+
post.comments_average_rating
|
103
|
+
post.approved_comments_count
|
104
|
+
end
|
105
|
+
```
|
88
106
|
|
89
107
|
EagerGroup will execute `GROUP BY` sqls for you then set the value of
|
90
108
|
attributes.
|
@@ -93,13 +111,51 @@ attributes.
|
|
93
111
|
You can call the `definition_name` directly for convenience,
|
94
112
|
but it would not help you to fix n+1 aggregate sql issue.
|
95
113
|
|
96
|
-
|
97
|
-
|
98
|
-
|
114
|
+
```
|
115
|
+
post = Post.first
|
116
|
+
post.commets_average_rating
|
117
|
+
post.approved_comments_count
|
118
|
+
```
|
99
119
|
|
100
120
|
## Advanced
|
101
121
|
|
102
|
-
|
122
|
+
`eager_group` through association
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
User.limit(10).includes(:posts).eager_group(posts: [:comments_average_rating, :approved_comments_count])
|
126
|
+
```
|
127
|
+
|
128
|
+
pass parameter to scope
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
class Post < ActiveRecord::Base
|
132
|
+
has_many :comments
|
133
|
+
|
134
|
+
define_eager_group :comments_average_rating_by_author, :comments, :average, :rating, ->(author, ignore) { by_author(author, ignore) }
|
135
|
+
end
|
136
|
+
|
137
|
+
posts = Post.all.eager_group([:comments_average_rating_by_author, author, true])
|
138
|
+
posts.each { |post| post.comments_average_rating_by_author }
|
139
|
+
```
|
140
|
+
|
141
|
+
`first_object` and `last_object` aggregation to eager load first and
|
142
|
+
last association objects.
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
class Post < ActiveRecord::Base
|
146
|
+
has_many :comments
|
147
|
+
|
148
|
+
define_eager_group :first_comment, :comments, :first_object, :id
|
149
|
+
define_eager_group :last_comment, :comments, :last_object, :id
|
150
|
+
end
|
151
|
+
|
152
|
+
posts = Post.all.eager_group(:first_comment, :last_comment)
|
153
|
+
posts.each do |post|
|
154
|
+
post.first_comment
|
155
|
+
post.last_comment
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
103
159
|
|
104
160
|
## Benchmark
|
105
161
|
|
@@ -109,6 +165,6 @@ times faster, WOW!
|
|
109
165
|
|
110
166
|
## Contributing
|
111
167
|
|
112
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
168
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/flyerhzm/eager_group.
|
113
169
|
|
114
|
-
[1]: https://github.com/
|
170
|
+
[1]: https://github.com/flyerhzm/eager_group/blob/master/benchmark.rb
|
data/benchmark.rb
CHANGED
@@ -30,11 +30,11 @@ class Comment < ActiveRecord::Base
|
|
30
30
|
end
|
31
31
|
|
32
32
|
# create database eager_group_benchmark;
|
33
|
-
ActiveRecord::Base.establish_connection(
|
33
|
+
ActiveRecord::Base.establish_connection(
|
34
|
+
adapter: 'mysql2', database: 'eager_group_benchmark', server: '/tmp/mysql.socket', username: 'root'
|
35
|
+
)
|
34
36
|
|
35
|
-
ActiveRecord::Base.connection.tables.each
|
36
|
-
ActiveRecord::Base.connection.drop_table(table)
|
37
|
-
end
|
37
|
+
ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
|
38
38
|
|
39
39
|
ActiveRecord::Schema.define do
|
40
40
|
self.verbose = false
|
@@ -55,18 +55,19 @@ ActiveRecord::Schema.define do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
posts_size = 100
|
58
|
-
comments_size =
|
58
|
+
comments_size = 1_000
|
59
59
|
|
60
60
|
posts = []
|
61
|
-
posts_size.times
|
62
|
-
posts << Post.new(title: "Title #{i}", body: "Body #{i}")
|
63
|
-
end
|
61
|
+
posts_size.times { |i| posts << Post.new(title: "Title #{i}", body: "Body #{i}") }
|
64
62
|
Post.import posts
|
65
63
|
post_ids = Post.all.pluck(:id)
|
66
64
|
|
67
65
|
comments = []
|
68
66
|
comments_size.times do |i|
|
69
|
-
comments <<
|
67
|
+
comments <<
|
68
|
+
Comment.new(
|
69
|
+
body: "Comment #{i}", post_id: post_ids[i % 100], status: %w[approved deleted][i % 2], rating: i % 5 + 1
|
70
|
+
)
|
70
71
|
end
|
71
72
|
Comment.import comments
|
72
73
|
|
data/eager_group.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
|
13
13
|
spec.summary = 'Fix n+1 aggregate sql functions'
|
14
14
|
spec.description = 'Fix n+1 aggregate sql functions for rails'
|
15
|
-
spec.homepage = 'https://github.com/
|
15
|
+
spec.homepage = 'https://github.com/flyerhzm/eager_group'
|
16
16
|
|
17
17
|
spec.license = 'MIT'
|
18
18
|
|
@@ -23,9 +23,10 @@ Gem::Specification.new do |spec|
|
|
23
23
|
|
24
24
|
spec.add_development_dependency 'activerecord'
|
25
25
|
spec.add_development_dependency 'activerecord-import'
|
26
|
+
spec.add_development_dependency 'activesupport'
|
26
27
|
spec.add_development_dependency 'benchmark-ips'
|
27
28
|
spec.add_development_dependency 'bundler'
|
28
29
|
spec.add_development_dependency 'rake', '~> 10.0'
|
29
30
|
spec.add_development_dependency 'rspec', '~> 3.3'
|
30
|
-
spec.add_development_dependency 'sqlite3'
|
31
|
+
spec.add_development_dependency 'sqlite3'
|
31
32
|
end
|
data/lib/eager_group.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
3
4
|
require 'eager_group/version'
|
4
5
|
|
5
6
|
module EagerGroup
|
@@ -11,7 +12,7 @@ module EagerGroup
|
|
11
12
|
end
|
12
13
|
|
13
14
|
module ClassMethods
|
14
|
-
|
15
|
+
mattr_accessor :eager_group_definitions, default: {}
|
15
16
|
|
16
17
|
# class Post
|
17
18
|
# define_eager_group :comments_avergage_rating, :comments, :average, :rating
|
@@ -19,16 +20,16 @@ module EagerGroup
|
|
19
20
|
# end
|
20
21
|
def define_eager_group(attr, association, aggregate_function, column_name, scope = nil)
|
21
22
|
send :attr_accessor, attr
|
22
|
-
|
23
|
-
@eager_group_definitions[attr] = Definition.new association, aggregate_function, column_name, scope
|
23
|
+
eager_group_definitions[attr] = Definition.new(association, aggregate_function, column_name, scope)
|
24
24
|
|
25
|
-
define_method attr,
|
26
|
-
|
27
|
-
|
25
|
+
define_method attr,
|
26
|
+
lambda { |*args|
|
27
|
+
query_result_cache = instance_variable_get("@#{attr}")
|
28
|
+
return query_result_cache if args.blank? && query_result_cache.present?
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
preload_eager_group(attr, *args)
|
31
|
+
instance_variable_get("@#{attr}")
|
32
|
+
}
|
32
33
|
|
33
34
|
define_method "#{attr}=" do |val|
|
34
35
|
instance_variable_set("@#{attr}", val)
|
@@ -51,4 +52,4 @@ ActiveRecord::Base.class_eval do
|
|
51
52
|
end
|
52
53
|
end
|
53
54
|
require 'active_record/with_eager_group'
|
54
|
-
ActiveRecord::Relation.
|
55
|
+
ActiveRecord::Relation.prepend ActiveRecord::WithEagerGroup
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module EagerGroup
|
4
4
|
class Definition
|
5
|
-
attr_reader :association, :
|
5
|
+
attr_reader :association, :column_name, :scope
|
6
6
|
|
7
7
|
def initialize(association, aggregate_function, column_name, scope)
|
8
8
|
@association = association
|
@@ -10,5 +10,20 @@ module EagerGroup
|
|
10
10
|
@column_name = column_name
|
11
11
|
@scope = scope
|
12
12
|
end
|
13
|
+
|
14
|
+
def aggregation_function
|
15
|
+
return :maximum if @aggregate_function.to_sym == :last_object
|
16
|
+
return :minimum if @aggregate_function.to_sym == :first_object
|
17
|
+
|
18
|
+
@aggregate_function
|
19
|
+
end
|
20
|
+
|
21
|
+
def need_load_object
|
22
|
+
%i[first_object last_object].include?(@aggregate_function.to_sym)
|
23
|
+
end
|
24
|
+
|
25
|
+
def default_value
|
26
|
+
%i[first_object last_object].include?(@aggregate_function.to_sym) ? nil : 0
|
27
|
+
end
|
13
28
|
end
|
14
29
|
end
|
@@ -12,35 +12,54 @@ module EagerGroup
|
|
12
12
|
def run
|
13
13
|
primary_key = @klass.primary_key
|
14
14
|
@eager_group_values.each do |eager_group_value|
|
15
|
-
definition_key, arguments =
|
15
|
+
definition_key, arguments =
|
16
|
+
eager_group_value.is_a?(Array) ? [eager_group_value.shift, eager_group_value] : [eager_group_value, nil]
|
17
|
+
|
16
18
|
if definition_key.is_a?(Hash)
|
17
19
|
association_name, definition_key = *definition_key.first
|
18
20
|
@records = @records.flat_map { |record| record.send(association_name) }
|
21
|
+
next if @records.empty?
|
22
|
+
|
19
23
|
@klass = @records.first.class
|
20
24
|
end
|
21
25
|
record_ids = @records.map { |record| record.send(primary_key) }
|
22
|
-
|
26
|
+
unless definition = @klass.eager_group_definitions[definition_key]
|
27
|
+
next
|
28
|
+
end
|
23
29
|
|
24
30
|
reflection = @klass.reflect_on_association(definition.association)
|
25
31
|
association_class = reflection.klass
|
26
32
|
association_class = association_class.instance_exec(*arguments, &definition.scope) if definition.scope
|
27
33
|
|
28
|
-
if reflection.
|
34
|
+
if reflection.is_a?(ActiveRecord::Reflection::HasAndBelongsToManyReflection)
|
35
|
+
foreign_key = "#{reflection.join_table}.#{reflection.foreign_key}"
|
36
|
+
aggregate_hash =
|
37
|
+
@klass.joins(reflection.name).where(foreign_key => record_ids).where(
|
38
|
+
polymophic_as_condition(reflection)
|
39
|
+
)
|
40
|
+
.group(foreign_key)
|
41
|
+
.send(definition.aggregation_function, definition.column_name)
|
42
|
+
elsif reflection.through_reflection
|
29
43
|
foreign_key = "#{reflection.through_reflection.name}.#{reflection.through_reflection.foreign_key}"
|
30
|
-
aggregate_hash =
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
44
|
+
aggregate_hash =
|
45
|
+
association_class.joins(reflection.through_reflection.name).where(foreign_key => record_ids).where(
|
46
|
+
polymophic_as_condition(reflection.through_reflection)
|
47
|
+
)
|
48
|
+
.group(foreign_key)
|
49
|
+
.send(definition.aggregation_function, definition.column_name)
|
35
50
|
else
|
36
|
-
aggregate_hash =
|
37
|
-
|
38
|
-
|
39
|
-
|
51
|
+
aggregate_hash =
|
52
|
+
association_class.where(reflection.foreign_key => record_ids).where(polymophic_as_condition(reflection))
|
53
|
+
.group(reflection.foreign_key)
|
54
|
+
.send(definition.aggregation_function, definition.column_name)
|
55
|
+
end
|
56
|
+
if definition.need_load_object
|
57
|
+
aggregate_objects = reflection.klass.find(aggregate_hash.values).each_with_object({}) { |o, h| h[o.id] = o }
|
58
|
+
aggregate_hash.keys.each { |key| aggregate_hash[key] = aggregate_objects[aggregate_hash[key]] }
|
40
59
|
end
|
41
60
|
@records.each do |record|
|
42
61
|
id = record.send(primary_key)
|
43
|
-
record.send("#{definition_key}=", aggregate_hash[id] ||
|
62
|
+
record.send("#{definition_key}=", aggregate_hash[id] || definition.default_value)
|
44
63
|
end
|
45
64
|
end
|
46
65
|
end
|
data/lib/eager_group/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eager_group
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Huang
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activesupport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: benchmark-ips
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,16 +112,16 @@ dependencies:
|
|
98
112
|
name: sqlite3
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
|
-
- - "
|
115
|
+
- - ">="
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
117
|
+
version: '0'
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
|
-
- - "
|
122
|
+
- - ">="
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
124
|
+
version: '0'
|
111
125
|
description: Fix n+1 aggregate sql functions for rails
|
112
126
|
email:
|
113
127
|
- flyerhzm@gmail.com
|
@@ -128,12 +142,10 @@ files:
|
|
128
142
|
- eager_group.gemspec
|
129
143
|
- lib/active_record/with_eager_group.rb
|
130
144
|
- lib/eager_group.rb
|
131
|
-
- lib/eager_group/active_record_base.rb
|
132
|
-
- lib/eager_group/active_record_relation.rb
|
133
145
|
- lib/eager_group/definition.rb
|
134
146
|
- lib/eager_group/preloader.rb
|
135
147
|
- lib/eager_group/version.rb
|
136
|
-
homepage: https://github.com/
|
148
|
+
homepage: https://github.com/flyerhzm/eager_group
|
137
149
|
licenses:
|
138
150
|
- MIT
|
139
151
|
metadata: {}
|
@@ -152,8 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
164
|
- !ruby/object:Gem::Version
|
153
165
|
version: '0'
|
154
166
|
requirements: []
|
155
|
-
|
156
|
-
rubygems_version: 2.6.14
|
167
|
+
rubygems_version: 3.0.3
|
157
168
|
signing_key:
|
158
169
|
specification_version: 4
|
159
170
|
summary: Fix n+1 aggregate sql functions
|
@@ -1,32 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class ActiveRecord::Relation
|
4
|
-
# Post.all.eager_group(:approved_comments_count, :comments_average_rating)
|
5
|
-
|
6
|
-
def exec_queries_with_eager_group
|
7
|
-
records = exec_queries_without_eager_group
|
8
|
-
EagerGroup::Preloader.new(klass, records, eager_group_values).run if eager_group_values.present?
|
9
|
-
records
|
10
|
-
end
|
11
|
-
alias_method_chain :exec_queries, :eager_group
|
12
|
-
|
13
|
-
def eager_group(*args)
|
14
|
-
check_if_method_has_arguments!('eager_group', args)
|
15
|
-
spawn.eager_group!(*args)
|
16
|
-
end
|
17
|
-
|
18
|
-
def eager_group!(*args)
|
19
|
-
self.eager_group_values += args
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
|
-
def eager_group_values
|
24
|
-
@values[:eager_group] || []
|
25
|
-
end
|
26
|
-
|
27
|
-
def eager_group_values=(values)
|
28
|
-
raise ImmutableRelation if @loaded
|
29
|
-
|
30
|
-
@values[:eager_group] = values
|
31
|
-
end
|
32
|
-
end
|