jit_preloader 1.0.4 → 2.1.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 +4 -4
- data/.github/workflows/ci.yml +32 -0
- data/.github/workflows/gem-push.yml +3 -4
- data/.gitignore +1 -0
- data/Gemfile +1 -0
- data/README.md +27 -0
- data/jit_preloader.gemspec +1 -1
- data/lib/jit_preloader/active_record/associations/preloader/ar7_association.rb +63 -0
- data/lib/jit_preloader/active_record/associations/preloader/ar7_branch.rb +22 -0
- data/lib/jit_preloader/active_record/base.rb +24 -15
- data/lib/jit_preloader/preloader.rb +36 -11
- data/lib/jit_preloader/version.rb +1 -1
- data/lib/jit_preloader.rb +14 -1
- data/spec/lib/jit_preloader/preloader_spec.rb +64 -0
- data/spec/support/models.rb +1 -0
- metadata +8 -11
- /data/.github/{workflows/CODEOWNERS → CODEOWNERS} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bca887aa87a283d55ee26b1fe606948733ecfecc7ce40d4cedc8b89d90efb834
|
4
|
+
data.tar.gz: 9a7c463ccacf8daeebc23d2eaa375d8c4f908b333c492baaa4c4c931bbc7d1b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 30920baa0426de8bc5188fc80ccfacf6e040f6bf1f7c934214bb75600080a090756ca957da9a59327a63b30550d7a4efdf5f4e66c873783e0c5aa627fe558e9f
|
7
|
+
data.tar.gz: 9adfa72af9bfcc684c3c22f6e82b353af9b36081224cae92e248e5c52db7f028a9c6f49dc3760d059f476980a48f4852b6f94c5e5faf82dbef28087e0b8dd3cd
|
@@ -0,0 +1,32 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [master]
|
6
|
+
pull_request:
|
7
|
+
branches: [master]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
fail-fast: false
|
14
|
+
matrix:
|
15
|
+
gemfile:
|
16
|
+
- Gemfile
|
17
|
+
- Gemfile.5.2
|
18
|
+
- Gemfile.6.0
|
19
|
+
- Gemfile.6.1
|
20
|
+
env:
|
21
|
+
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
22
|
+
steps:
|
23
|
+
- uses: actions/checkout@v4
|
24
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
25
|
+
uses: ruby/setup-ruby@v1
|
26
|
+
with:
|
27
|
+
ruby-version: 2.7
|
28
|
+
- name: Install dependencies
|
29
|
+
run: bundle install
|
30
|
+
- name: Run tests
|
31
|
+
run:
|
32
|
+
bundle exec rspec
|
@@ -1,7 +1,6 @@
|
|
1
1
|
name: Ruby Gem
|
2
2
|
|
3
3
|
on:
|
4
|
-
workflow_dispatch:
|
5
4
|
release:
|
6
5
|
types: [ published ]
|
7
6
|
|
@@ -13,11 +12,11 @@ jobs:
|
|
13
12
|
contents: read
|
14
13
|
|
15
14
|
steps:
|
16
|
-
- uses: actions/checkout@
|
15
|
+
- uses: actions/checkout@v4
|
17
16
|
- name: Set up Ruby 2.7
|
18
|
-
uses:
|
17
|
+
uses: ruby/setup-ruby@v1
|
19
18
|
with:
|
20
|
-
ruby-version: 2.7
|
19
|
+
ruby-version: 2.7
|
21
20
|
|
22
21
|
- name: Publish to RubyGems
|
23
22
|
env:
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -173,6 +173,20 @@ end
|
|
173
173
|
|
174
174
|
```
|
175
175
|
|
176
|
+
Furthermore, there is an argument `max_ids_per_query` setting max ids per query. This helps prevent running a single query with too large list of ids which may be less efficient than splitting into multiple queries.
|
177
|
+
```ruby
|
178
|
+
class Contact < ActiveRecord::Base
|
179
|
+
has_many :addresses
|
180
|
+
has_many_aggregate :addresses, :count_all, :count, "*", max_ids_per_query: 10
|
181
|
+
end
|
182
|
+
|
183
|
+
Contact.jit_preload.each do |contact|
|
184
|
+
contact.addresses_count_all
|
185
|
+
end
|
186
|
+
# SELECT contact_id, COUNT(*) FROM addresses WHERE contact_id IN (1, 2, 3, ... ,10) GROUP BY contact_id
|
187
|
+
# SELECT contact_id, COUNT(*) FROM addresses WHERE contact_id IN (11, 12, 13) GROUP BY contact_id
|
188
|
+
```
|
189
|
+
|
176
190
|
### Preloading a subset of an association
|
177
191
|
|
178
192
|
There are often times when you want to preload a subset of an association, or change how the SQL statement is generated. For example, if a `Contact` model has
|
@@ -213,6 +227,7 @@ end
|
|
213
227
|
### Jit preloading globally across your application
|
214
228
|
|
215
229
|
The JitPreloader can be globally enabled, in which case most N+1 queries in your app should just disappear. It is off by default.
|
230
|
+
The `max_ids_per_query` argument on loading aggregate methods can also apply on a global level.
|
216
231
|
|
217
232
|
```ruby
|
218
233
|
# Can be true or false
|
@@ -223,12 +238,24 @@ JitPreloader.globally_enabled = true
|
|
223
238
|
# so that you can turn it on or off dynamically.
|
224
239
|
JitPreloader.globally_enabled = ->{ $redis.get('always_jit_preload') == 'on' }
|
225
240
|
|
241
|
+
# Setting global max ids constraint on all aggregation methods.
|
242
|
+
JitPreloader.max_ids_per_query = 10
|
243
|
+
|
244
|
+
class Contact < ActiveRecord::Base
|
245
|
+
has_many :emails
|
246
|
+
has_many_aggregate :emails, :count_all, :count, "*"
|
247
|
+
end
|
248
|
+
|
226
249
|
# When enabled globally, this would not generate an N+1 query.
|
227
250
|
Contact.all.each do |contact|
|
228
251
|
contact.emails.each do |email|
|
229
252
|
# do something
|
230
253
|
end
|
254
|
+
# When max_ides_per_query is set globally, the aggregate method will split query base on the limit.
|
255
|
+
contact.emails_count_all
|
231
256
|
end
|
257
|
+
|
258
|
+
|
232
259
|
```
|
233
260
|
|
234
261
|
## What it doesn't solve
|
data/jit_preloader.gemspec
CHANGED
@@ -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", "
|
21
|
+
spec.add_dependency "activerecord", "< 8"
|
22
22
|
spec.add_dependency "activesupport"
|
23
23
|
|
24
24
|
spec.add_development_dependency "bundler"
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module JitPreloader
|
2
|
+
module PreloaderAssociation
|
3
|
+
|
4
|
+
# A monkey patch to ActiveRecord. The old method looked like the snippet
|
5
|
+
# below. Our changes here are that we remove records that are already
|
6
|
+
# part of the target, then attach all of the records to a new jit preloader.
|
7
|
+
#
|
8
|
+
# def run
|
9
|
+
# records = records_by_owner
|
10
|
+
|
11
|
+
# owners.each do |owner|
|
12
|
+
# associate_records_to_owner(owner, records[owner] || [])
|
13
|
+
# end if @associate
|
14
|
+
|
15
|
+
# self
|
16
|
+
# end
|
17
|
+
|
18
|
+
def run
|
19
|
+
return unless (reflection.scope.nil? || reflection.scope.arity == 0) && klass.ancestors.include?(ActiveRecord::Base)
|
20
|
+
|
21
|
+
super.tap do
|
22
|
+
if preloaded_records.any? && preloaded_records.none?(&:jit_preloader)
|
23
|
+
JitPreloader::Preloader.attach(preloaded_records) if owners.any?(&:jit_preloader) || JitPreloader.globally_enabled?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Original method:
|
29
|
+
# def associate_records_to_owner(owner, records)
|
30
|
+
# return if loaded?(owner)
|
31
|
+
#
|
32
|
+
# association = owner.association(reflection.name)
|
33
|
+
#
|
34
|
+
# if reflection.collection?
|
35
|
+
# association.target = records
|
36
|
+
# else
|
37
|
+
# association.target = records.first
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
def associate_records_to_owner(owner, records)
|
41
|
+
return if loaded?(owner)
|
42
|
+
|
43
|
+
association = owner.association(reflection.name)
|
44
|
+
|
45
|
+
if reflection.collection?
|
46
|
+
new_records = association.target.any? ? records - association.target : records
|
47
|
+
association.target.concat(new_records)
|
48
|
+
association.loaded!
|
49
|
+
else
|
50
|
+
association.target = records.first
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def build_scope
|
55
|
+
super.tap do |scope|
|
56
|
+
scope.jit_preload! if owners.any?(&:jit_preloader) || JitPreloader.globally_enabled?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
ActiveRecord::Associations::Preloader::Association.prepend(JitPreloader::PreloaderAssociation)
|
63
|
+
ActiveRecord::Associations::Preloader::ThroughAssociation.prepend(JitPreloader::PreloaderAssociation)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module JitPreloader
|
2
|
+
module PreloaderBranch
|
3
|
+
"""
|
4
|
+
ActiveRecord version >= 7.x.x introduced an improvement for preloading associations in batches:
|
5
|
+
https://github.com/rails/rails/blob/main/activerecord/lib/active_record/associations/preloader.rb#L121
|
6
|
+
|
7
|
+
Our existing monkey-patches will ignore associations whose classes are not descendants of
|
8
|
+
ActiveRecord::Base (example: https://github.com/clio/jit_preloader/blob/master/lib/jit_preloader/active_record/associations/preloader/ar6_association.rb#L19).
|
9
|
+
But this change breaks that behaviour because now Batch is calling `klass.base_class` (a method defined by ActiveRecord::Base)
|
10
|
+
before we have a chance to filter out the non-AR classes.
|
11
|
+
This patch for AR 7.x makes the Branch class ignore any association loaders that aren't for ActiveRecord::Base subclasses.
|
12
|
+
"""
|
13
|
+
|
14
|
+
def loaders
|
15
|
+
@loaders = super.find_all do |loader|
|
16
|
+
loader.klass < ::ActiveRecord::Base
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
ActiveRecord::Associations::Preloader::Branch.prepend(JitPreloader::PreloaderBranch)
|
@@ -18,7 +18,7 @@ module JitPreloadExtension
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new("
|
21
|
+
if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new("7.0.0")
|
22
22
|
def preload_scoped_relation(name:, base_association:, preload_scope: nil)
|
23
23
|
return jit_preload_scoped_relations[name] if jit_preload_scoped_relations&.key?(name)
|
24
24
|
|
@@ -33,11 +33,11 @@ module JitPreloadExtension
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
preloader_association = ActiveRecord::Associations::Preloader.new
|
37
|
-
records,
|
38
|
-
base_association,
|
39
|
-
preload_scope
|
40
|
-
).first
|
36
|
+
preloader_association = ActiveRecord::Associations::Preloader.new(
|
37
|
+
records: records,
|
38
|
+
associations: base_association,
|
39
|
+
scope: preload_scope
|
40
|
+
).call.first
|
41
41
|
|
42
42
|
records.each do |record|
|
43
43
|
record.jit_preload_scoped_relations ||= {}
|
@@ -90,7 +90,7 @@ module JitPreloadExtension
|
|
90
90
|
class << base
|
91
91
|
delegate :jit_preload, to: :all
|
92
92
|
|
93
|
-
def has_many_aggregate(assoc, name, aggregate, field, table_alias_name: nil, default: 0)
|
93
|
+
def has_many_aggregate(assoc, name, aggregate, field, table_alias_name: nil, default: 0, max_ids_per_query: nil)
|
94
94
|
method_name = "#{assoc}_#{name}"
|
95
95
|
|
96
96
|
define_method(method_name) do |conditions={}|
|
@@ -101,6 +101,13 @@ module JitPreloadExtension
|
|
101
101
|
if jit_preloader
|
102
102
|
reflection = association(assoc).reflection
|
103
103
|
primary_ids = jit_preloader.records.collect{|r| r[reflection.active_record_primary_key] }
|
104
|
+
max_ids_per_query = max_ids_per_query || JitPreloader.max_ids_per_query
|
105
|
+
if max_ids_per_query
|
106
|
+
slices = primary_ids.each_slice(max_ids_per_query)
|
107
|
+
else
|
108
|
+
slices = [primary_ids]
|
109
|
+
end
|
110
|
+
|
104
111
|
klass = reflection.klass
|
105
112
|
|
106
113
|
aggregate_association = reflection
|
@@ -115,15 +122,13 @@ module JitPreloadExtension
|
|
115
122
|
table_reference = table_alias_name
|
116
123
|
table_reference ||= association_scope.references_values.first || aggregate_association.table_name
|
117
124
|
|
118
|
-
conditions[table_reference] = { aggregate_association.foreign_key => primary_ids }
|
119
|
-
|
120
125
|
# If the association is a STI child model, specify its type in the condition so that it
|
121
126
|
# doesn't include results from other child models
|
122
127
|
parent_is_base_class = aggregate_association.klass.superclass.abstract_class? || aggregate_association.klass.superclass == ActiveRecord::Base
|
123
128
|
has_type_column = aggregate_association.klass.column_names.include?(aggregate_association.klass.inheritance_column)
|
124
129
|
is_child_sti_model = !parent_is_base_class && has_type_column
|
125
130
|
if is_child_sti_model
|
126
|
-
conditions[table_reference]
|
131
|
+
conditions[table_reference] = { aggregate_association.klass.inheritance_column => aggregate_association.klass.sti_name }
|
127
132
|
end
|
128
133
|
|
129
134
|
if reflection.type.present?
|
@@ -131,11 +136,15 @@ module JitPreloadExtension
|
|
131
136
|
end
|
132
137
|
group_by = "#{table_reference}.#{aggregate_association.foreign_key}"
|
133
138
|
|
134
|
-
preloaded_data =
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
+
preloaded_data = {}
|
140
|
+
slices.each do |slice|
|
141
|
+
data = Hash[association_scope
|
142
|
+
.where(conditions.deep_merge(table_reference => { aggregate_association.foreign_key => slice }))
|
143
|
+
.group(group_by)
|
144
|
+
.send(aggregate, field)
|
145
|
+
]
|
146
|
+
preloaded_data.merge!(data)
|
147
|
+
end
|
139
148
|
|
140
149
|
jit_preloader.records.each do |record|
|
141
150
|
record.jit_preload_aggregates ||= {}
|
@@ -3,22 +3,47 @@ module JitPreloader
|
|
3
3
|
|
4
4
|
attr_accessor :records
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new("7.0.0")
|
7
|
+
def self.attach(records)
|
8
|
+
new(records: records.dup, associations: nil).tap do |loader|
|
9
|
+
records.each do |record|
|
10
|
+
record.jit_preloader = loader
|
11
|
+
end
|
11
12
|
end
|
12
13
|
end
|
13
|
-
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
def jit_preload(associations)
|
16
|
+
# It is possible that the records array has multiple different classes (think single table inheritance).
|
17
|
+
# 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(associations).nil? }
|
19
|
+
|
20
|
+
# Some of the records may already have the association loaded and we should not load them again
|
21
|
+
records_requiring_loading = records_with_association.select{|r| !r.association(associations).loaded? }
|
22
|
+
|
23
|
+
self.class.new(records: records_requiring_loading, associations: associations).call
|
24
|
+
end
|
25
|
+
else
|
26
|
+
def self.attach(records)
|
27
|
+
new.tap do |loader|
|
28
|
+
loader.records = records.dup
|
29
|
+
records.each do |record|
|
30
|
+
record.jit_preloader = loader
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def jit_preload(associations)
|
36
|
+
# It is possible that the records array has multiple different classes (think single table inheritance).
|
37
|
+
# Thus, it is possible that some of the records don't have an association.
|
38
|
+
records_with_association = records.reject{ |record| record.class.reflect_on_association(associations).nil? }
|
39
|
+
|
40
|
+
# Some of the records may already have the association loaded and we should not load them again
|
41
|
+
records_requiring_loading = records_with_association.select{ |record| !record.association(associations).loaded? }
|
42
|
+
preload records_with_association, associations
|
43
|
+
end
|
20
44
|
end
|
21
45
|
|
46
|
+
|
22
47
|
# We do not want the jit_preloader to be dumpable
|
23
48
|
# If you dump a ActiveRecord::Base object that has a jit_preloader instance variable
|
24
49
|
# you will also end up dumping all of the records the preloader has reference to.
|
data/lib/jit_preloader.rb
CHANGED
@@ -8,7 +8,10 @@ require 'jit_preloader/active_record/base'
|
|
8
8
|
require 'jit_preloader/active_record/relation'
|
9
9
|
require 'jit_preloader/active_record/associations/collection_association'
|
10
10
|
require 'jit_preloader/active_record/associations/singular_association'
|
11
|
-
if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new("
|
11
|
+
if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new("7.0.0")
|
12
|
+
require 'jit_preloader/active_record/associations/preloader/ar7_association'
|
13
|
+
require 'jit_preloader/active_record/associations/preloader/ar7_branch'
|
14
|
+
elsif Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new("6.0.0")
|
12
15
|
require 'jit_preloader/active_record/associations/preloader/ar6_association'
|
13
16
|
elsif Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new("5.2.2")
|
14
17
|
require 'jit_preloader/active_record/associations/preloader/ar5_association'
|
@@ -23,6 +26,16 @@ module JitPreloader
|
|
23
26
|
@enabled = value
|
24
27
|
end
|
25
28
|
|
29
|
+
def self.max_ids_per_query=(max_ids)
|
30
|
+
if max_ids && max_ids >= 1
|
31
|
+
@max_ids_per_query = max_ids
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.max_ids_per_query
|
36
|
+
@max_ids_per_query
|
37
|
+
end
|
38
|
+
|
26
39
|
def self.globally_enabled?
|
27
40
|
if @enabled && @enabled.respond_to?(:call)
|
28
41
|
@enabled.call
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "spec_helper"
|
2
|
+
require "db-query-matchers"
|
2
3
|
|
3
4
|
RSpec.describe JitPreloader::Preloader do
|
4
5
|
let!(:contact1) do
|
@@ -479,6 +480,69 @@ RSpec.describe JitPreloader::Preloader do
|
|
479
480
|
end
|
480
481
|
end
|
481
482
|
end
|
483
|
+
|
484
|
+
context "with dive limit set" do
|
485
|
+
let!(:contact_book_1) { ContactBook.create(name: "The Yellow Pages") }
|
486
|
+
let!(:contact_book_2) { ContactBook.create(name: "The Yellow Pages") }
|
487
|
+
let!(:contact_book_3) { ContactBook.create(name: "The Yellow Pages") }
|
488
|
+
let!(:company1) { Company.create(name: "Company1", contact_book: contact_book_1) }
|
489
|
+
let!(:company2) { Company.create(name: "Company2", contact_book: contact_book_1) }
|
490
|
+
let!(:company3) { Company.create(name: "Company2", contact_book: contact_book_2) }
|
491
|
+
let!(:company4) { Company.create(name: "Company4", contact_book: contact_book_3) }
|
492
|
+
let!(:company5) { Company.create(name: "Company5", contact_book: contact_book_3) }
|
493
|
+
|
494
|
+
context "from the global value" do
|
495
|
+
before do
|
496
|
+
JitPreloader.max_ids_per_query = 2
|
497
|
+
end
|
498
|
+
|
499
|
+
after do
|
500
|
+
JitPreloader.max_ids_per_query = nil
|
501
|
+
end
|
502
|
+
|
503
|
+
it "can handle queries" do
|
504
|
+
contact_books = ContactBook.jit_preload.to_a
|
505
|
+
|
506
|
+
expect(contact_books.first.companies_count).to eq 2
|
507
|
+
expect(contact_books.second.companies_count).to eq 1
|
508
|
+
expect(contact_books.last.companies_count).to eq 2
|
509
|
+
end
|
510
|
+
|
511
|
+
it "makes the right number of queries based on dive limit" do
|
512
|
+
contact_books = ContactBook.jit_preload.to_a
|
513
|
+
expect do
|
514
|
+
contact_books.first.companies_count
|
515
|
+
end.to make_database_queries(count: 2)
|
516
|
+
|
517
|
+
expect do
|
518
|
+
contact_books.second.companies_count
|
519
|
+
contact_books.last.companies_count
|
520
|
+
end.to_not make_database_queries
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
context "from aggregate argument" do
|
525
|
+
it "can handle queries" do
|
526
|
+
contact_books = ContactBook.jit_preload.to_a
|
527
|
+
|
528
|
+
expect(contact_books.first.companies_count_with_max_ids_set).to eq 2
|
529
|
+
expect(contact_books.second.companies_count_with_max_ids_set).to eq 1
|
530
|
+
expect(contact_books.last.companies_count_with_max_ids_set).to eq 2
|
531
|
+
end
|
532
|
+
|
533
|
+
it "makes the right number of queries based on dive limit" do
|
534
|
+
contact_books = ContactBook.jit_preload.to_a
|
535
|
+
expect do
|
536
|
+
contact_books.first.companies_count_with_max_ids_set
|
537
|
+
end.to make_database_queries(count: 2)
|
538
|
+
|
539
|
+
expect do
|
540
|
+
contact_books.second.companies_count_with_max_ids_set
|
541
|
+
contact_books.last.companies_count_with_max_ids_set
|
542
|
+
end.to_not make_database_queries
|
543
|
+
end
|
544
|
+
end
|
545
|
+
end
|
482
546
|
end
|
483
547
|
|
484
548
|
end
|
data/spec/support/models.rb
CHANGED
@@ -10,6 +10,7 @@ class ContactBook < ActiveRecord::Base
|
|
10
10
|
has_many :children, through: :parents
|
11
11
|
|
12
12
|
has_many_aggregate :companies, :count, :count, "*"
|
13
|
+
has_many_aggregate :companies, :count_with_max_ids_set, :count, "*", max_ids_per_query: 2
|
13
14
|
has_many_aggregate :employees, :count, :count, "*"
|
14
15
|
has_many_aggregate :company_employees, :count, :count, "*"
|
15
16
|
has_many_aggregate :children, :count, :count, "*"
|
metadata
CHANGED
@@ -1,35 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jit_preloader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 2.1.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:
|
11
|
+
date: 2024-04-29 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
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '5.2'
|
20
17
|
- - "<"
|
21
18
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
19
|
+
version: '8'
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
|
-
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '5.2'
|
30
24
|
- - "<"
|
31
25
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
26
|
+
version: '8'
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
28
|
name: activesupport
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -151,7 +145,8 @@ executables: []
|
|
151
145
|
extensions: []
|
152
146
|
extra_rdoc_files: []
|
153
147
|
files:
|
154
|
-
- ".github/
|
148
|
+
- ".github/CODEOWNERS"
|
149
|
+
- ".github/workflows/ci.yml"
|
155
150
|
- ".github/workflows/gem-push.yml"
|
156
151
|
- ".gitignore"
|
157
152
|
- ".rspec"
|
@@ -170,6 +165,8 @@ files:
|
|
170
165
|
- lib/jit_preloader/active_record/associations/collection_association.rb
|
171
166
|
- lib/jit_preloader/active_record/associations/preloader/ar5_association.rb
|
172
167
|
- lib/jit_preloader/active_record/associations/preloader/ar6_association.rb
|
168
|
+
- lib/jit_preloader/active_record/associations/preloader/ar7_association.rb
|
169
|
+
- lib/jit_preloader/active_record/associations/preloader/ar7_branch.rb
|
173
170
|
- lib/jit_preloader/active_record/associations/preloader/collection_association.rb
|
174
171
|
- lib/jit_preloader/active_record/associations/preloader/singular_association.rb
|
175
172
|
- lib/jit_preloader/active_record/associations/singular_association.rb
|
File without changes
|