jit_preloader 0.2.2 → 0.2.3
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 +5 -5
- data/README.md +1 -1
- data/lib/jit_preloader/active_record/base.rb +16 -2
- data/lib/jit_preloader/version.rb +1 -1
- data/spec/lib/jit_preloader/preloader_spec.rb +60 -1
- data/spec/support/database.rb +3 -1
- data/spec/support/models.rb +40 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c2c802d6683cb058781abe0360bec58b0857c020
|
4
|
+
data.tar.gz: 3576db9546592974cc8383c26fa395b939971876
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4cf99a2440af7e4ef861cf2a2ea679f6ff3fac90494aab0fddb5722a1712b9611357d03c15d6cf1a1ced43f698231228c276c517b362fb05937f8e3510a7a8e4
|
7
|
+
data.tar.gz: ba29dd13180a27824ce4e1ad1ec88124c1200e6025a5341a88aff891b706cb1f899a6ba6d59c208c2ae042cc8112df0ea9c4fed90b3e2a7b6d428145b39b5f1b
|
data/README.md
CHANGED
@@ -215,7 +215,7 @@ end
|
|
215
215
|
|
216
216
|
## Contributing
|
217
217
|
|
218
|
-
1. Fork it ( https://github.com/
|
218
|
+
1. Fork it ( https://github.com/clio/jit_preloader/fork )
|
219
219
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
220
220
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
221
221
|
4. Push to the branch (`git push origin my-new-feature`)
|
@@ -41,11 +41,25 @@ module JitPreloadExtension
|
|
41
41
|
association_scope = klass.all.merge(association(assoc).scope).unscope(where: aggregate_association.foreign_key)
|
42
42
|
association_scope = association_scope.instance_exec(&reflection.scope).reorder(nil) if reflection.scope
|
43
43
|
|
44
|
-
|
44
|
+
# If the query uses an alias for the association, use that instead of the table name
|
45
|
+
table_alias_name = association_scope.references_values.first
|
46
|
+
table_reference = table_alias_name || aggregate_association.table_name
|
47
|
+
|
48
|
+
conditions[table_reference] = { aggregate_association.foreign_key => primary_ids }
|
49
|
+
|
50
|
+
# If the association is a STI child model, specify its type in the condition so that it
|
51
|
+
# doesn't include results from other child models
|
52
|
+
parent_is_base_class = aggregate_association.klass.superclass.abstract_class? || aggregate_association.klass.superclass == ActiveRecord::Base
|
53
|
+
has_type_column = aggregate_association.klass.column_names.include?(aggregate_association.klass.inheritance_column)
|
54
|
+
is_child_sti_model = !parent_is_base_class && has_type_column
|
55
|
+
if is_child_sti_model
|
56
|
+
conditions[table_reference].merge!({ aggregate_association.klass.inheritance_column => aggregate_association.klass.sti_name })
|
57
|
+
end
|
58
|
+
|
45
59
|
if reflection.type.present?
|
46
60
|
conditions[reflection.type] = self.class.name
|
47
61
|
end
|
48
|
-
group_by = "#{
|
62
|
+
group_by = "#{table_reference}.#{aggregate_association.foreign_key}"
|
49
63
|
|
50
64
|
preloaded_data = Hash[association_scope
|
51
65
|
.where(conditions)
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe JitPreloader::Preloader do
|
4
|
-
|
5
4
|
let!(:contact1) do
|
6
5
|
addresses = [
|
7
6
|
Address.new(street: "123 Fake st", country: canada),
|
@@ -49,6 +48,66 @@ RSpec.describe JitPreloader::Preloader do
|
|
49
48
|
->(event, data){ source_map[data[:source]] << data[:association] }
|
50
49
|
end
|
51
50
|
|
51
|
+
context "for single table inheritance" do
|
52
|
+
context "when preloading an aggregate for a child model" do
|
53
|
+
let!(:contact_book) { ContactBook.create(name: "The Yellow Pages") }
|
54
|
+
let!(:company1) { Company.create(name: "Company1", contact_book: contact_book) }
|
55
|
+
let!(:company2) { Company.create(name: "Company2", contact_book: contact_book) }
|
56
|
+
|
57
|
+
it "can handle queries" do
|
58
|
+
contact_books = ContactBook.jit_preload.to_a
|
59
|
+
expect(contact_books.first.companies_count).to eq 2
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when preloading an aggregate of a child model through its base model" do
|
64
|
+
let!(:contact_book) { ContactBook.create(name: "The Yellow Pages") }
|
65
|
+
let!(:contact) { Contact.create(name: "Contact", contact_book: contact_book) }
|
66
|
+
let!(:company1) { Company.create(name: "Company1", contact_book: contact_book) }
|
67
|
+
let!(:company2) { Company.create(name: "Company2", contact_book: contact_book) }
|
68
|
+
let!(:contact_employee1) { Employee.create(name: "Contact Employee1", contact: contact) }
|
69
|
+
let!(:contact_employee2) { Employee.create(name: "Contact Employee2", contact: contact) }
|
70
|
+
let!(:company_employee1) { Employee.create(name: "Company Employee1", contact: company1) }
|
71
|
+
let!(:company_employee2) { Employee.create(name: "Company Employee2", contact: company2) }
|
72
|
+
|
73
|
+
it "can handle queries" do
|
74
|
+
contact_books = ContactBook.jit_preload.to_a
|
75
|
+
expect(contact_books.first.employees_count).to eq 4
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "when preloading an aggregate of a nested child model through another child model" do
|
80
|
+
let!(:contact_book) { ContactBook.create(name: "The Yellow Pages") }
|
81
|
+
let!(:contact) { Contact.create(name: "Contact", contact_book: contact_book) }
|
82
|
+
let!(:company1) { Company.create(name: "Company1", contact_book: contact_book) }
|
83
|
+
let!(:company2) { Company.create(name: "Company2", contact_book: contact_book) }
|
84
|
+
let!(:contact_employee1) { Employee.create(name: "Contact Employee1", contact: contact) }
|
85
|
+
let!(:contact_employee2) { Employee.create(name: "Contact Employee2", contact: contact) }
|
86
|
+
let!(:company_employee1) { Employee.create(name: "Company Employee1", contact: company1) }
|
87
|
+
let!(:company_employee2) { Employee.create(name: "Company Employee2", contact: company2) }
|
88
|
+
|
89
|
+
it "can handle queries" do
|
90
|
+
contact_books = ContactBook.jit_preload.to_a
|
91
|
+
expect(contact_books.first.company_employees_count).to eq 2
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "when preloading an aggregate of a nested child model through a many-to-many relationship with another child model" do
|
96
|
+
let!(:contact_book) { ContactBook.create(name: "The Yellow Pages") }
|
97
|
+
let!(:child1) { Child.create(name: "Child1") }
|
98
|
+
let!(:child2) { Child.create(name: "Child2") }
|
99
|
+
let!(:child3) { Child.create(name: "Child3") }
|
100
|
+
let!(:parent1) { Parent.create(name: "Parent1", contact_book: contact_book, children: [child1, child2]) }
|
101
|
+
let!(:parent2) { Parent.create(name: "Parent2", contact_book: contact_book, children: [child2, child3]) }
|
102
|
+
|
103
|
+
it "can handle queries" do
|
104
|
+
contact_books = ContactBook.jit_preload.to_a
|
105
|
+
expect(contact_books.first.children_count).to eq 4
|
106
|
+
expect(contact_books.first.children).to include(child1, child2, child3)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
52
111
|
context "when preloading an aggregate as polymorphic" do
|
53
112
|
let(:contact_owner_counts) { [2] }
|
54
113
|
|
data/spec/support/database.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
class Database
|
2
2
|
def self.tables
|
3
3
|
[
|
4
|
-
"CREATE TABLE
|
4
|
+
"CREATE TABLE contact_books (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(255))",
|
5
|
+
"CREATE TABLE contacts (id INTEGER NOT NULL PRIMARY KEY, type VARCHAR(255), contact_book_id INTEGER, contact_id INTEGER, name VARCHAR(255), contact_owner_id INTEGER, contact_owner_type VARCHAR(255))",
|
5
6
|
"CREATE TABLE contact_owners (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(255))",
|
6
7
|
"CREATE TABLE addresses (id INTEGER NOT NULL PRIMARY KEY, contact_id INTEGER NOT NULL, country_id INTEGER NOT NULL, street VARCHAR(255))",
|
7
8
|
"CREATE TABLE email_addresses (id INTEGER NOT NULL PRIMARY KEY, contact_id INTEGER NOT NULL, address VARCHAR(255))",
|
8
9
|
"CREATE TABLE phone_numbers (id INTEGER NOT NULL PRIMARY KEY, contact_id INTEGER NOT NULL, phone VARCHAR(10))",
|
9
10
|
"CREATE TABLE countries (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(255))",
|
11
|
+
"CREATE TABLE parents_children (id INTEGER NOT NULL PRIMARY KEY, parent_id INTEGER, child_id INTEGER)",
|
10
12
|
]
|
11
13
|
end
|
12
14
|
|
data/spec/support/models.rb
CHANGED
@@ -1,15 +1,55 @@
|
|
1
|
+
class ContactBook < ActiveRecord::Base
|
2
|
+
has_many :contacts
|
3
|
+
has_many :employees, through: :contacts
|
4
|
+
|
5
|
+
has_many :companies
|
6
|
+
has_many :company_employees, through: :companies, source: :employees
|
7
|
+
|
8
|
+
has_many :parents
|
9
|
+
has_many :children, through: :parents
|
10
|
+
|
11
|
+
has_many_aggregate :companies, :count, :count, "*"
|
12
|
+
has_many_aggregate :employees, :count, :count, "*"
|
13
|
+
has_many_aggregate :company_employees, :count, :count, "*"
|
14
|
+
has_many_aggregate :children, :count, :count, "*"
|
15
|
+
end
|
16
|
+
|
1
17
|
class Contact < ActiveRecord::Base
|
18
|
+
belongs_to :contact_book
|
2
19
|
belongs_to :contact_owner, polymorphic: true
|
3
20
|
|
4
21
|
has_many :addresses
|
5
22
|
has_many :phone_numbers
|
6
23
|
has_one :email_address
|
24
|
+
has_many :employees
|
7
25
|
|
8
26
|
has_many_aggregate :addresses, :max_street_length, :maximum, "LENGTH(street)"
|
9
27
|
has_many_aggregate :phone_numbers, :count, :count, "id"
|
10
28
|
has_many_aggregate :addresses, :count, :count, "*"
|
11
29
|
end
|
12
30
|
|
31
|
+
class Company < Contact
|
32
|
+
end
|
33
|
+
|
34
|
+
class Employee < Contact
|
35
|
+
belongs_to :contact
|
36
|
+
end
|
37
|
+
|
38
|
+
class ParentsChild < ActiveRecord::Base
|
39
|
+
belongs_to :parent
|
40
|
+
belongs_to :child
|
41
|
+
end
|
42
|
+
|
43
|
+
class Parent < Contact
|
44
|
+
has_many :parents_child
|
45
|
+
has_many :children, through: :parents_child
|
46
|
+
end
|
47
|
+
|
48
|
+
class Child < Contact
|
49
|
+
has_many :parents_child
|
50
|
+
has_many :parents, through: :parents_child
|
51
|
+
end
|
52
|
+
|
13
53
|
class Address < ActiveRecord::Base
|
14
54
|
belongs_to :contact
|
15
55
|
belongs_to :country
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jit_preloader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kyle d'Oliveira
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -178,7 +178,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
178
178
|
- !ruby/object:Gem::Version
|
179
179
|
version: '0'
|
180
180
|
requirements: []
|
181
|
-
|
181
|
+
rubyforge_project:
|
182
|
+
rubygems_version: 2.5.2.1
|
182
183
|
signing_key:
|
183
184
|
specification_version: 4
|
184
185
|
summary: Tool to understand N+1 queries and to remove them
|