jit_preloader 1.0.2 → 2.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b1347f4a6e1db52e169d10cb83f6c365867f04882c873c9d6fa11c72553c385
4
- data.tar.gz: 90fd4451da01e450c484ff23eec4ac08f9adbc955559adfa57972a639c37fefc
3
+ metadata.gz: '08fbd77fdcfc580733fbb24995cd80a1535bada8471f2dace6620ad000c25778'
4
+ data.tar.gz: bfb07a3212433bc5dd2a5a557ed05d0472f0ec227593a798a1b9442976815d57
5
5
  SHA512:
6
- metadata.gz: 5fbf30e83a2f31e93831930eb4d4c09d4dc42a75f753f43da8b62082867e8810845f41da09dca4e8e840c2fdae569e1b95d6af565239c55f30b8474c88505cf7
7
- data.tar.gz: caf85a19d5a50f325a828fca0c6c3f55adb56345c9fe76afea48abf366706baac3268ec6d6584946516af9f94a3cfc04346f5a886f920d73c8c1a7df6599839a
6
+ metadata.gz: c7fe821295fc841a48992f4fa93bbc372516509435a49455bf9e37543173fe089714198eaa9f0c355cf656d5c2696160c4c82bd657fad79edb9961d5e13e49c7
7
+ data.tar.gz: 33ae22de3c658a714be7b5c61705dcb82bdc1d762af3ee0d4ed084d29c6c9e8b6685fa3a353756f653c3287806d1eb946beb95df532983ce85536a82a8fab7fa
@@ -0,0 +1,3 @@
1
+ # Own any files in the .github/workflows directory and any of its
2
+ # subdirectories.
3
+ /.github/workflows/ @clio/application-security @clio/penguins
@@ -0,0 +1,30 @@
1
+ name: Ruby Gem
2
+
3
+ on:
4
+ release:
5
+ types: [ published ]
6
+
7
+ jobs:
8
+ build:
9
+ name: Build + Publish
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+
14
+ steps:
15
+ - uses: actions/checkout@v2
16
+ - name: Set up Ruby 2.7
17
+ uses: actions/setup-ruby@v1
18
+ with:
19
+ ruby-version: 2.7.x
20
+
21
+ - name: Publish to RubyGems
22
+ env:
23
+ GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
24
+ run: |
25
+ mkdir -p $HOME/.gem
26
+ touch $HOME/.gem/credentials
27
+ chmod 0600 $HOME/.gem/credentials
28
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
29
+ gem build *.gemspec
30
+ gem push *.gem
data/Gemfile.5.2 ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem "activerecord", "~>5.2"
4
+
5
+ # Specify your gem's dependencies in jit_preloader.gemspec
6
+ gemspec
data/Gemfile.5.2.lock ADDED
@@ -0,0 +1,72 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ jit_preloader (1.0.3)
5
+ activerecord (>= 5.2, < 7)
6
+ activesupport
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activemodel (5.2.6)
12
+ activesupport (= 5.2.6)
13
+ activerecord (5.2.6)
14
+ activemodel (= 5.2.6)
15
+ activesupport (= 5.2.6)
16
+ arel (>= 9.0)
17
+ activesupport (5.2.6)
18
+ concurrent-ruby (~> 1.0, >= 1.0.2)
19
+ i18n (>= 0.7, < 2)
20
+ minitest (~> 5.1)
21
+ tzinfo (~> 1.1)
22
+ arel (9.0.0)
23
+ byebug (11.1.3)
24
+ concurrent-ruby (1.1.9)
25
+ database_cleaner (2.0.1)
26
+ database_cleaner-active_record (~> 2.0.0)
27
+ database_cleaner-active_record (2.0.1)
28
+ activerecord (>= 5.a)
29
+ database_cleaner-core (~> 2.0.0)
30
+ database_cleaner-core (2.0.1)
31
+ db-query-matchers (0.10.0)
32
+ activesupport (>= 4.0, < 7)
33
+ rspec (~> 3.0)
34
+ diff-lcs (1.4.4)
35
+ i18n (1.8.10)
36
+ concurrent-ruby (~> 1.0)
37
+ minitest (5.14.4)
38
+ rake (13.0.6)
39
+ rspec (3.10.0)
40
+ rspec-core (~> 3.10.0)
41
+ rspec-expectations (~> 3.10.0)
42
+ rspec-mocks (~> 3.10.0)
43
+ rspec-core (3.10.1)
44
+ rspec-support (~> 3.10.0)
45
+ rspec-expectations (3.10.1)
46
+ diff-lcs (>= 1.2.0, < 2.0)
47
+ rspec-support (~> 3.10.0)
48
+ rspec-mocks (3.10.2)
49
+ diff-lcs (>= 1.2.0, < 2.0)
50
+ rspec-support (~> 3.10.0)
51
+ rspec-support (3.10.2)
52
+ sqlite3 (1.4.2)
53
+ thread_safe (0.3.6)
54
+ tzinfo (1.2.9)
55
+ thread_safe (~> 0.1)
56
+
57
+ PLATFORMS
58
+ x86_64-darwin-19
59
+
60
+ DEPENDENCIES
61
+ activerecord (~> 5.2)
62
+ bundler
63
+ byebug
64
+ database_cleaner
65
+ db-query-matchers
66
+ jit_preloader!
67
+ rake (~> 13.0)
68
+ rspec
69
+ sqlite3
70
+
71
+ BUNDLED WITH
72
+ 2.2.12
data/Gemfile.6.0 ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem "activerecord", "~>6.0.0"
4
+
5
+ # Specify your gem's dependencies in jit_preloader.gemspec
6
+ gemspec
data/Gemfile.6.0.lock ADDED
@@ -0,0 +1,72 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ jit_preloader (1.0.3)
5
+ activerecord (>= 5.2, < 7)
6
+ activesupport
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activemodel (6.0.4.1)
12
+ activesupport (= 6.0.4.1)
13
+ activerecord (6.0.4.1)
14
+ activemodel (= 6.0.4.1)
15
+ activesupport (= 6.0.4.1)
16
+ activesupport (6.0.4.1)
17
+ concurrent-ruby (~> 1.0, >= 1.0.2)
18
+ i18n (>= 0.7, < 2)
19
+ minitest (~> 5.1)
20
+ tzinfo (~> 1.1)
21
+ zeitwerk (~> 2.2, >= 2.2.2)
22
+ byebug (11.1.3)
23
+ concurrent-ruby (1.1.9)
24
+ database_cleaner (2.0.1)
25
+ database_cleaner-active_record (~> 2.0.0)
26
+ database_cleaner-active_record (2.0.1)
27
+ activerecord (>= 5.a)
28
+ database_cleaner-core (~> 2.0.0)
29
+ database_cleaner-core (2.0.1)
30
+ db-query-matchers (0.10.0)
31
+ activesupport (>= 4.0, < 7)
32
+ rspec (~> 3.0)
33
+ diff-lcs (1.4.4)
34
+ i18n (1.8.10)
35
+ concurrent-ruby (~> 1.0)
36
+ minitest (5.14.4)
37
+ rake (13.0.6)
38
+ rspec (3.10.0)
39
+ rspec-core (~> 3.10.0)
40
+ rspec-expectations (~> 3.10.0)
41
+ rspec-mocks (~> 3.10.0)
42
+ rspec-core (3.10.1)
43
+ rspec-support (~> 3.10.0)
44
+ rspec-expectations (3.10.1)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.10.0)
47
+ rspec-mocks (3.10.2)
48
+ diff-lcs (>= 1.2.0, < 2.0)
49
+ rspec-support (~> 3.10.0)
50
+ rspec-support (3.10.2)
51
+ sqlite3 (1.4.2)
52
+ thread_safe (0.3.6)
53
+ tzinfo (1.2.9)
54
+ thread_safe (~> 0.1)
55
+ zeitwerk (2.4.2)
56
+
57
+ PLATFORMS
58
+ x86_64-darwin-19
59
+
60
+ DEPENDENCIES
61
+ activerecord (~> 6.0.0)
62
+ bundler
63
+ byebug
64
+ database_cleaner
65
+ db-query-matchers
66
+ jit_preloader!
67
+ rake (~> 13.0)
68
+ rspec
69
+ sqlite3
70
+
71
+ BUNDLED WITH
72
+ 2.2.12
data/Gemfile.6.1 ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem "activerecord", "~>6.1"
4
+
5
+ # Specify your gem's dependencies in jit_preloader.gemspec
6
+ gemspec
data/Gemfile.6.1.lock ADDED
@@ -0,0 +1,72 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ jit_preloader (1.0.3)
5
+ activerecord (>= 5.2, < 7)
6
+ activesupport
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activemodel (6.1.4.1)
12
+ activesupport (= 6.1.4.1)
13
+ activerecord (6.1.4.1)
14
+ activemodel (= 6.1.4.1)
15
+ activesupport (= 6.1.4.1)
16
+ activesupport (6.1.4.1)
17
+ concurrent-ruby (~> 1.0, >= 1.0.2)
18
+ i18n (>= 1.6, < 2)
19
+ minitest (>= 5.1)
20
+ tzinfo (~> 2.0)
21
+ zeitwerk (~> 2.3)
22
+ byebug (11.1.3)
23
+ concurrent-ruby (1.1.9)
24
+ database_cleaner (2.0.1)
25
+ database_cleaner-active_record (~> 2.0.0)
26
+ database_cleaner-active_record (2.0.1)
27
+ activerecord (>= 5.a)
28
+ database_cleaner-core (~> 2.0.0)
29
+ database_cleaner-core (2.0.1)
30
+ db-query-matchers (0.10.0)
31
+ activesupport (>= 4.0, < 7)
32
+ rspec (~> 3.0)
33
+ diff-lcs (1.4.4)
34
+ i18n (1.8.10)
35
+ concurrent-ruby (~> 1.0)
36
+ minitest (5.14.4)
37
+ rake (13.0.6)
38
+ rspec (3.10.0)
39
+ rspec-core (~> 3.10.0)
40
+ rspec-expectations (~> 3.10.0)
41
+ rspec-mocks (~> 3.10.0)
42
+ rspec-core (3.10.1)
43
+ rspec-support (~> 3.10.0)
44
+ rspec-expectations (3.10.1)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.10.0)
47
+ rspec-mocks (3.10.2)
48
+ diff-lcs (>= 1.2.0, < 2.0)
49
+ rspec-support (~> 3.10.0)
50
+ rspec-support (3.10.2)
51
+ sqlite3 (1.4.2)
52
+ tzinfo (2.0.4)
53
+ concurrent-ruby (~> 1.0)
54
+ zeitwerk (2.4.2)
55
+
56
+ PLATFORMS
57
+ ruby
58
+ x86_64-darwin-19
59
+
60
+ DEPENDENCIES
61
+ activerecord (~> 6.1)
62
+ bundler
63
+ byebug
64
+ database_cleaner
65
+ db-query-matchers
66
+ jit_preloader!
67
+ rake (~> 13.0)
68
+ rspec
69
+ sqlite3
70
+
71
+ BUNDLED WITH
72
+ 2.2.12
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "activerecord", "> 5.0", "< 7"
21
+ spec.add_dependency "activerecord", ">= 7", "< 8"
22
22
  spec.add_dependency "activesupport"
23
23
 
24
24
  spec.add_development_dependency "bundler"
@@ -49,7 +49,7 @@ module JitPreloader
49
49
  association.target.concat(new_records)
50
50
  association.loaded!
51
51
  else
52
- association.target ||= records.first unless records.empty?
52
+ association.target = records.first unless records.empty?
53
53
  end
54
54
  end
55
55
 
@@ -23,17 +23,30 @@ module JitPreloadExtension
23
23
  return jit_preload_scoped_relations[name] if jit_preload_scoped_relations&.key?(name)
24
24
 
25
25
  records = jit_preloader&.records || [self]
26
+ previous_association_values = {}
26
27
 
27
- preloader_association = ActiveRecord::Associations::Preloader.new.preload(
28
- records,
29
- base_association,
30
- preload_scope
31
- ).first
28
+ records.each do |record|
29
+ association = record.association(base_association)
30
+ if association.loaded?
31
+ previous_association_values[record] = association.target
32
+ association.reset
33
+ end
34
+ end
35
+
36
+ preloader_association = ActiveRecord::Associations::Preloader.new(
37
+ records: records,
38
+ associations: base_association,
39
+ scope: preload_scope
40
+ ).call.first
32
41
 
33
42
  records.each do |record|
34
43
  record.jit_preload_scoped_relations ||= {}
35
44
  association = record.association(base_association)
36
- record.jit_preload_scoped_relations[name] = preloader_association.records_by_owner[record]
45
+ record.jit_preload_scoped_relations[name] = preloader_association.records_by_owner[record] || []
46
+ association.reset
47
+ if previous_association_values.key?(record)
48
+ association.target = previous_association_values[record]
49
+ end
37
50
  end
38
51
 
39
52
  jit_preload_scoped_relations[name]
@@ -4,19 +4,18 @@ module JitPreloader
4
4
  attr_accessor :records
5
5
 
6
6
  def self.attach(records)
7
- new.tap do |loader|
8
- loader.records = records.dup
7
+ new(records: records.dup, associations: nil).tap do |loader|
9
8
  records.each do |record|
10
9
  record.jit_preloader = loader
11
10
  end
12
11
  end
13
12
  end
14
13
 
15
- def jit_preload(association)
14
+ def jit_preload(associations)
16
15
  # It is possible that the records array has multiple different classes (think single table inheritance).
17
16
  # Thus, it is possible that some of the records don't have an association.
18
- records_with_association = records.reject{|r| r.class.reflect_on_association(association).nil? }
19
- preload records_with_association, association
17
+ records_with_association = records.reject{|r| r.class.reflect_on_association(associations).nil? }
18
+ self.class.new(records: records_with_association, associations: associations).call
20
19
  end
21
20
 
22
21
  # We do not want the jit_preloader to be dumpable
@@ -1,3 +1,3 @@
1
1
  module JitPreloader
2
- VERSION = "1.0.2"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -74,6 +74,9 @@ RSpec.describe "ActiveRecord::Base Extensions" do
74
74
 
75
75
  it "doesn't load the value into the association" do
76
76
  contacts = Contact.jit_preload.limit(2).to_a
77
+ expect(contacts.first.association(:addresses)).to_not be_loaded
78
+ expect(contacts.last.association(:addresses)).to_not be_loaded
79
+
77
80
  call(contacts.first)
78
81
 
79
82
  expect(contacts.first.association(:addresses)).to_not be_loaded
@@ -90,5 +93,18 @@ RSpec.describe "ActiveRecord::Base Extensions" do
90
93
  expect(contacts.last.association(:addresses)).to be_loaded
91
94
  end
92
95
  end
96
+
97
+ context "when no records exist for the association" do
98
+ let!(:record) { Parent.create }
99
+
100
+ it "returns an empty array" do
101
+ value = record.preload_scoped_relation(
102
+ name: "Parent Children",
103
+ base_association: :parents_child
104
+ )
105
+
106
+ expect(value).to eq([])
107
+ end
108
+ end
93
109
  end
94
110
  end
@@ -288,6 +288,22 @@ RSpec.describe JitPreloader::Preloader do
288
288
  end
289
289
  end
290
290
 
291
+ context "when a singular association id changes after preload" do
292
+ let!(:contact_book1) { ContactBook.create(name: "The Yellow Pages") }
293
+ let!(:contact_book2) { ContactBook.create(name: "The White Pages") }
294
+ let!(:company1) { Company.create(name: "Company1", contact_book: contact_book1) }
295
+ let!(:company2) { Company.create(name: "Company2", contact_book: contact_book1) }
296
+
297
+ it "allows the association to be reloaded" do
298
+ companies = Company.where(id: [company1.id, company2.id]).jit_preload.all.to_a
299
+ expect(companies.map(&:contact_book)).to match_array [contact_book1, contact_book1]
300
+
301
+ company = companies.each {|c| c.contact_book_id = contact_book2.id }
302
+
303
+ expect(companies.map(&:contact_book)).to match_array [contact_book2, contact_book2]
304
+ end
305
+ end
306
+
291
307
  context "when preloading an aggregate" do
292
308
  let(:addresses_counts) { [3, 0, 2] }
293
309
  let(:phone_number_counts) { [2, 0, 1] }
metadata CHANGED
@@ -1,35 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jit_preloader
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 2.0.0
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: 2021-03-03 00:00:00.000000000 Z
11
+ date: 2022-05-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5.0'
19
+ version: '7'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '7'
22
+ version: '8'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
- - - ">"
27
+ - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '5.0'
29
+ version: '7'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '7'
32
+ version: '8'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: activesupport
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -151,9 +151,17 @@ executables: []
151
151
  extensions: []
152
152
  extra_rdoc_files: []
153
153
  files:
154
+ - ".github/CODEOWNERS"
155
+ - ".github/workflows/gem-push.yml"
154
156
  - ".gitignore"
155
157
  - ".rspec"
156
158
  - Gemfile
159
+ - Gemfile.5.2
160
+ - Gemfile.5.2.lock
161
+ - Gemfile.6.0
162
+ - Gemfile.6.0.lock
163
+ - Gemfile.6.1
164
+ - Gemfile.6.1.lock
157
165
  - LICENSE
158
166
  - README.md
159
167
  - Rakefile
@@ -193,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
193
201
  - !ruby/object:Gem::Version
194
202
  version: '0'
195
203
  requirements: []
196
- rubygems_version: 3.0.3
204
+ rubygems_version: 3.1.6
197
205
  signing_key:
198
206
  specification_version: 4
199
207
  summary: Tool to understand N+1 queries and to remove them