jit_preloader 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: a2439886049ccbcd7845882f8fa47524e500ffc96d8b9620711288853c47c131
4
- data.tar.gz: 189adc93418cf777c6eb33617934d92426cfbdc105a05a10c639f9dd387736f8
2
+ SHA1:
3
+ metadata.gz: c2c802d6683cb058781abe0360bec58b0857c020
4
+ data.tar.gz: 3576db9546592974cc8383c26fa395b939971876
5
5
  SHA512:
6
- metadata.gz: 932327300aea76f21906abf912ba85d655fbeb04b6cf940c1c650e21d39a72682d4fb55d529c389897ed7d5b45d9a41cec411a5c7eb932f2216df03b91fef47e
7
- data.tar.gz: 591bc82f9d763b963a78d6869da2f6346c7c3d49b044e48d0a12529fd61c94b104c3e0cc8e7e08a8a8fd9f4feee4ce73e66fbc72cf36ef11477852949d012802
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/[my-github-username]/jit_preloader/fork )
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
- conditions[aggregate_association.table_name] = { aggregate_association.foreign_key => primary_ids }
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 = "#{aggregate_association.table_name}.#{aggregate_association.foreign_key}"
62
+ group_by = "#{table_reference}.#{aggregate_association.foreign_key}"
49
63
 
50
64
  preloaded_data = Hash[association_scope
51
65
  .where(conditions)
@@ -1,3 +1,3 @@
1
1
  module JitPreloader
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
@@ -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
 
@@ -1,12 +1,14 @@
1
1
  class Database
2
2
  def self.tables
3
3
  [
4
- "CREATE TABLE contacts (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(255), contact_owner_id INTEGER, contact_owner_type VARCHAR(255))",
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
 
@@ -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.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-10-16 00:00:00.000000000 Z
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
- rubygems_version: 3.0.3
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