goldiloader 3.0.2 → 4.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 +5 -5
- data/lib/goldiloader.rb +1 -1
- data/lib/goldiloader/active_record_patches.rb +41 -33
- data/lib/goldiloader/association_loader.rb +5 -11
- data/lib/goldiloader/association_options.rb +1 -5
- data/lib/goldiloader/auto_include_context.rb +2 -0
- data/lib/goldiloader/compatibility.rb +4 -21
- data/lib/goldiloader/scope_info.rb +35 -0
- data/lib/goldiloader/version.rb +1 -1
- metadata +53 -26
- data/lib/goldiloader/association_info.rb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2b1702016efdeb47b12f583ff299bc46125714acc053b7c8594a9cf9a4fcba07
|
4
|
+
data.tar.gz: 6485555c4d71199683907813d9563fdecce3c8bada819d7ae1180f48ad5afadb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 949fc36b600662dde9597b87c26430949bbdc12dff2d2eb9845405dcb273c2c9621edbb8d850f95dd602c892687dffc95849243bbd94c4e3473c31932f48464a
|
7
|
+
data.tar.gz: 5d645a33f703ad458096af205535efcd5cebb2ab802ae0af8203cc6236f388a73d79ec0c08681c447dbbe4b057a29a0bd373c001ce277dd34285447614f138a8
|
data/lib/goldiloader.rb
CHANGED
@@ -4,7 +4,7 @@ require 'active_support/all'
|
|
4
4
|
require 'active_record'
|
5
5
|
require 'goldiloader/compatibility'
|
6
6
|
require 'goldiloader/auto_include_context'
|
7
|
-
require 'goldiloader/
|
7
|
+
require 'goldiloader/scope_info'
|
8
8
|
require 'goldiloader/association_options'
|
9
9
|
require 'goldiloader/association_loader'
|
10
10
|
require 'goldiloader/active_record_patches'
|
@@ -47,21 +47,12 @@ module Goldiloader
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def auto_include_value
|
50
|
-
# Note: Don't use get_value because that doesn't work properly with defaulting boolean values
|
51
50
|
@values.fetch(:auto_include, true)
|
52
51
|
end
|
53
52
|
|
54
53
|
def auto_include_value=(value)
|
55
|
-
|
56
|
-
|
57
|
-
check_cached_relation
|
58
|
-
@values[:auto_include] = value
|
59
|
-
elsif Goldiloader::Compatibility.rails_5_0?
|
60
|
-
assert_mutability!
|
61
|
-
@values[:auto_include] = value
|
62
|
-
else
|
63
|
-
set_value(:auto_include, value)
|
64
|
-
end
|
54
|
+
assert_mutability!
|
55
|
+
@values[:auto_include] = value
|
65
56
|
end
|
66
57
|
end
|
67
58
|
::ActiveRecord::Relation.prepend(::Goldiloader::RelationPatch)
|
@@ -76,6 +67,29 @@ module Goldiloader
|
|
76
67
|
end
|
77
68
|
ActiveRecord::Relation::Merger.prepend(::Goldiloader::MergerPatch)
|
78
69
|
|
70
|
+
module AssociationReflectionPatch
|
71
|
+
def eager_loadable?
|
72
|
+
return @eager_loadable if instance_variable_defined?(:@eager_loadable)
|
73
|
+
|
74
|
+
@eager_loadable = if scope.nil?
|
75
|
+
# Associations without any scoping options are eager loadable
|
76
|
+
true
|
77
|
+
elsif scope.arity > 0
|
78
|
+
# The scope will be evaluated for every model instance so it can't
|
79
|
+
# be eager loaded
|
80
|
+
false
|
81
|
+
else
|
82
|
+
scope_info = Goldiloader::ScopeInfo.new(scope_for(klass.unscoped))
|
83
|
+
scope_info.auto_include? &&
|
84
|
+
!scope_info.limit? &&
|
85
|
+
!scope_info.offset? &&
|
86
|
+
(!has_one? || !scope_info.order?)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
ActiveRecord::Reflection::AssociationReflection.include(::Goldiloader::AssociationReflectionPatch)
|
91
|
+
ActiveRecord::Reflection::ThroughReflection.include(::Goldiloader::AssociationReflectionPatch)
|
92
|
+
|
79
93
|
module AssociationPatch
|
80
94
|
extend ActiveSupport::Concern
|
81
95
|
|
@@ -97,25 +111,26 @@ module Goldiloader
|
|
97
111
|
private
|
98
112
|
|
99
113
|
def eager_loadable?
|
100
|
-
|
101
|
-
|
102
|
-
!association_info.limit? &&
|
103
|
-
!association_info.offset? &&
|
104
|
-
(!association_info.has_one? || !association_info.order?) &&
|
105
|
-
(::Goldiloader::Compatibility.group_eager_loadable? || !association_info.group?) &&
|
106
|
-
(::Goldiloader::Compatibility.from_eager_loadable? || !association_info.from?) &&
|
107
|
-
(::Goldiloader::Compatibility.destroyed_model_associations_eager_loadable? || !owner.destroyed?) &&
|
108
|
-
!association_info.instance_dependent?
|
114
|
+
reflection.eager_loadable? &&
|
115
|
+
(::Goldiloader::Compatibility.destroyed_model_associations_eager_loadable? || !owner.destroyed?)
|
109
116
|
end
|
110
117
|
|
111
118
|
def load_with_auto_include
|
112
119
|
if loaded? && !stale_target?
|
113
120
|
target
|
114
|
-
elsif auto_include?
|
121
|
+
elsif !auto_include?
|
122
|
+
yield
|
123
|
+
elsif owner.auto_include_context.size == 1
|
124
|
+
# Bypassing the preloader for a single model reduces object allocations by ~5% in benchmarks
|
125
|
+
result = yield
|
126
|
+
# As of https://github.com/rails/rails/commit/bd3b28f7f181dce53e872daa23dda101498b8fb4
|
127
|
+
# ActiveRecord does not use ActiveRecord::Relation#exec_queries to resolve association
|
128
|
+
# queries
|
129
|
+
Goldiloader::AutoIncludeContext.register_models(result)
|
130
|
+
result
|
131
|
+
else
|
115
132
|
Goldiloader::AssociationLoader.load(owner, reflection.name)
|
116
133
|
target
|
117
|
-
else
|
118
|
-
yield
|
119
134
|
end
|
120
135
|
end
|
121
136
|
end
|
@@ -132,12 +147,7 @@ module Goldiloader
|
|
132
147
|
|
133
148
|
module CollectionAssociationPatch
|
134
149
|
# Force these methods to load the entire association for fully_load associations
|
135
|
-
|
136
|
-
if Goldiloader::Compatibility::ACTIVE_RECORD_VERSION < ::Gem::Version.new('5.1')
|
137
|
-
association_methods.concat([:first, :second, :third, :fourth, :fifth, :last])
|
138
|
-
end
|
139
|
-
|
140
|
-
association_methods.each do |method|
|
150
|
+
[:size, :ids_reader, :empty?].each do |method|
|
141
151
|
define_method(method) do |*args, &block|
|
142
152
|
load_target if fully_load?
|
143
153
|
super(*args, &block)
|
@@ -148,10 +158,8 @@ module Goldiloader
|
|
148
158
|
load_with_auto_include { super }
|
149
159
|
end
|
150
160
|
|
151
|
-
|
152
|
-
|
153
|
-
fully_load? || super
|
154
|
-
end
|
161
|
+
def find_from_target?
|
162
|
+
fully_load? || super
|
155
163
|
end
|
156
164
|
end
|
157
165
|
::ActiveRecord::Associations::CollectionAssociation.prepend(::Goldiloader::CollectionAssociationPatch)
|
@@ -15,17 +15,11 @@ module Goldiloader
|
|
15
15
|
private
|
16
16
|
|
17
17
|
def eager_load(models, association_name)
|
18
|
-
::
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
def associated_models(models, association_name)
|
26
|
-
# We can't just do model.send(association_name) because the association method may have been
|
27
|
-
# overridden
|
28
|
-
models.map { |model| model.association(association_name).target }.flatten.compact.uniq
|
18
|
+
if Goldiloader::Compatibility.pre_rails_6_2?
|
19
|
+
::ActiveRecord::Associations::Preloader.new.preload(models, [association_name])
|
20
|
+
else
|
21
|
+
::ActiveRecord::Associations::Preloader.new(records: models, associations: [association_name]).call
|
22
|
+
end
|
29
23
|
end
|
30
24
|
|
31
25
|
def load?(model, association_name)
|
@@ -18,11 +18,7 @@ module Goldiloader
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def register
|
21
|
-
|
22
|
-
ActiveRecord::Associations::Builder::Association.extensions << AssociationBuilderExtension
|
23
|
-
else
|
24
|
-
ActiveRecord::Associations::Builder::Association.valid_options.concat(OPTIONS)
|
25
|
-
end
|
21
|
+
ActiveRecord::Associations::Builder::Association.extensions << AssociationBuilderExtension
|
26
22
|
end
|
27
23
|
end
|
28
24
|
end
|
@@ -2,34 +2,17 @@
|
|
2
2
|
|
3
3
|
module Goldiloader
|
4
4
|
module Compatibility
|
5
|
-
ACTIVE_RECORD_VERSION = ::Gem::Version.new(::ActiveRecord::VERSION::STRING)
|
5
|
+
ACTIVE_RECORD_VERSION = ::Gem::Version.new(::ActiveRecord::VERSION::STRING).release
|
6
|
+
PRE_RAILS_6_2 = ACTIVE_RECORD_VERSION < ::Gem::Version.new('6.2.0')
|
6
7
|
RAILS_5_2_0 = ACTIVE_RECORD_VERSION == ::Gem::Version.new('5.2.0')
|
7
|
-
PRE_RAILS_5_2 = ACTIVE_RECORD_VERSION < ::Gem::Version.new('5.2.0')
|
8
|
-
POST_RAILS_5_1_4 = ACTIVE_RECORD_VERSION > ::Gem::Version.new('5.1.5')
|
9
|
-
PRE_RAILS_5_1_5 = ACTIVE_RECORD_VERSION < ::Gem::Version.new('5.1.5')
|
10
|
-
FROM_EAGER_LOADABLE = ACTIVE_RECORD_VERSION >= ::Gem::Version.new('5.1.5') ||
|
11
|
-
(ACTIVE_RECORD_VERSION >= ::Gem::Version.new('5.0.7') && ACTIVE_RECORD_VERSION < ::Gem::Version.new('5.1.0'))
|
12
|
-
GROUP_EAGER_LOADABLE = FROM_EAGER_LOADABLE
|
13
8
|
|
14
|
-
def self.
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.rails_5_0?
|
19
|
-
::ActiveRecord::VERSION::MAJOR == 5 && ::ActiveRecord::VERSION::MINOR == 0
|
9
|
+
def self.pre_rails_6_2?
|
10
|
+
PRE_RAILS_6_2
|
20
11
|
end
|
21
12
|
|
22
13
|
# See https://github.com/rails/rails/pull/32375
|
23
14
|
def self.destroyed_model_associations_eager_loadable?
|
24
15
|
!RAILS_5_2_0
|
25
16
|
end
|
26
|
-
|
27
|
-
def self.from_eager_loadable?
|
28
|
-
FROM_EAGER_LOADABLE
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.group_eager_loadable?
|
32
|
-
GROUP_EAGER_LOADABLE
|
33
|
-
end
|
34
17
|
end
|
35
18
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Goldiloader
|
4
|
+
class ScopeInfo
|
5
|
+
attr_reader :scope
|
6
|
+
|
7
|
+
def initialize(scope)
|
8
|
+
@scope = scope
|
9
|
+
end
|
10
|
+
|
11
|
+
def offset?
|
12
|
+
scope.offset_value.present?
|
13
|
+
end
|
14
|
+
|
15
|
+
def limit?
|
16
|
+
scope.limit_value.present?
|
17
|
+
end
|
18
|
+
|
19
|
+
def auto_include?
|
20
|
+
scope.auto_include_value
|
21
|
+
end
|
22
|
+
|
23
|
+
def from?
|
24
|
+
scope.from_clause.present?
|
25
|
+
end
|
26
|
+
|
27
|
+
def group?
|
28
|
+
scope.group_values.present?
|
29
|
+
end
|
30
|
+
|
31
|
+
def order?
|
32
|
+
scope.order_values.present?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/goldiloader/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: goldiloader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Turkel
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,40 +16,40 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '5.2'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '7.1'
|
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: '
|
29
|
+
version: '5.2'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '7.1'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: activesupport
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '
|
39
|
+
version: '5.2'
|
40
40
|
- - "<"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: '
|
42
|
+
version: '7.1'
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
47
|
- - ">="
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version: '
|
49
|
+
version: '5.2'
|
50
50
|
- - "<"
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: '
|
52
|
+
version: '7.1'
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: appraisal
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -65,7 +65,7 @@ dependencies:
|
|
65
65
|
- !ruby/object:Gem::Version
|
66
66
|
version: '0'
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
|
-
name:
|
68
|
+
name: benchmark-ips
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
70
70
|
requirements:
|
71
71
|
- - ">="
|
@@ -78,6 +78,20 @@ dependencies:
|
|
78
78
|
- - ">="
|
79
79
|
- !ruby/object:Gem::Version
|
80
80
|
version: '0'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: coveralls_reborn
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 0.18.0
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 0.18.0
|
81
95
|
- !ruby/object:Gem::Dependency
|
82
96
|
name: database_cleaner
|
83
97
|
requirement: !ruby/object:Gem::Requirement
|
@@ -134,20 +148,34 @@ dependencies:
|
|
134
148
|
- - "~>"
|
135
149
|
- !ruby/object:Gem::Version
|
136
150
|
version: '3'
|
151
|
+
- !ruby/object:Gem::Dependency
|
152
|
+
name: rspec_junit_formatter
|
153
|
+
requirement: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
type: :development
|
159
|
+
prerelease: false
|
160
|
+
version_requirements: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0'
|
137
165
|
- !ruby/object:Gem::Dependency
|
138
166
|
name: salsify_rubocop
|
139
167
|
requirement: !ruby/object:Gem::Requirement
|
140
168
|
requirements:
|
141
|
-
- -
|
169
|
+
- - "~>"
|
142
170
|
- !ruby/object:Gem::Version
|
143
|
-
version: 0.
|
171
|
+
version: 1.0.1
|
144
172
|
type: :development
|
145
173
|
prerelease: false
|
146
174
|
version_requirements: !ruby/object:Gem::Requirement
|
147
175
|
requirements:
|
148
|
-
- -
|
176
|
+
- - "~>"
|
149
177
|
- !ruby/object:Gem::Version
|
150
|
-
version: 0.
|
178
|
+
version: 1.0.1
|
151
179
|
- !ruby/object:Gem::Dependency
|
152
180
|
name: simplecov
|
153
181
|
requirement: !ruby/object:Gem::Requirement
|
@@ -166,16 +194,16 @@ dependencies:
|
|
166
194
|
name: sqlite3
|
167
195
|
requirement: !ruby/object:Gem::Requirement
|
168
196
|
requirements:
|
169
|
-
- - "
|
197
|
+
- - "~>"
|
170
198
|
- !ruby/object:Gem::Version
|
171
|
-
version: '
|
199
|
+
version: '1.3'
|
172
200
|
type: :development
|
173
201
|
prerelease: false
|
174
202
|
version_requirements: !ruby/object:Gem::Requirement
|
175
203
|
requirements:
|
176
|
-
- - "
|
204
|
+
- - "~>"
|
177
205
|
- !ruby/object:Gem::Version
|
178
|
-
version: '
|
206
|
+
version: '1.3'
|
179
207
|
description: Automatically eager loads Rails associations as associations are traversed
|
180
208
|
email:
|
181
209
|
- jturkel@salsify.com
|
@@ -186,11 +214,11 @@ files:
|
|
186
214
|
- LICENSE.txt
|
187
215
|
- lib/goldiloader.rb
|
188
216
|
- lib/goldiloader/active_record_patches.rb
|
189
|
-
- lib/goldiloader/association_info.rb
|
190
217
|
- lib/goldiloader/association_loader.rb
|
191
218
|
- lib/goldiloader/association_options.rb
|
192
219
|
- lib/goldiloader/auto_include_context.rb
|
193
220
|
- lib/goldiloader/compatibility.rb
|
221
|
+
- lib/goldiloader/scope_info.rb
|
194
222
|
- lib/goldiloader/version.rb
|
195
223
|
homepage: https://github.com/salsify/goldiloader
|
196
224
|
licenses:
|
@@ -200,7 +228,7 @@ metadata:
|
|
200
228
|
changelog_uri: https://github.com/salsify/goldiloader/blob/master/CHANGELOG.md
|
201
229
|
source_code_uri: https://github.com/salsify/goldiloader/
|
202
230
|
bug_tracker_uri: https://github.com/salsify/goldiloader/issues
|
203
|
-
post_install_message:
|
231
|
+
post_install_message:
|
204
232
|
rdoc_options: []
|
205
233
|
require_paths:
|
206
234
|
- lib
|
@@ -208,16 +236,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
208
236
|
requirements:
|
209
237
|
- - ">="
|
210
238
|
- !ruby/object:Gem::Version
|
211
|
-
version: '2.
|
239
|
+
version: '2.6'
|
212
240
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
213
241
|
requirements:
|
214
242
|
- - ">="
|
215
243
|
- !ruby/object:Gem::Version
|
216
244
|
version: '0'
|
217
245
|
requirements: []
|
218
|
-
|
219
|
-
|
220
|
-
signing_key:
|
246
|
+
rubygems_version: 3.1.4
|
247
|
+
signing_key:
|
221
248
|
specification_version: 4
|
222
249
|
summary: Automatic Rails association eager loading
|
223
250
|
test_files: []
|
@@ -1,48 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Goldiloader
|
4
|
-
class AssociationInfo
|
5
|
-
|
6
|
-
def initialize(association)
|
7
|
-
@association = association
|
8
|
-
end
|
9
|
-
|
10
|
-
delegate :association_scope, :reflection, to: :@association
|
11
|
-
|
12
|
-
def has_one? # rubocop:disable Naming/PredicateName
|
13
|
-
reflection.has_one?
|
14
|
-
end
|
15
|
-
|
16
|
-
def offset?
|
17
|
-
association_scope && association_scope.offset_value.present?
|
18
|
-
end
|
19
|
-
|
20
|
-
def limit?
|
21
|
-
association_scope && association_scope.limit_value.present?
|
22
|
-
end
|
23
|
-
|
24
|
-
def auto_include?
|
25
|
-
association_scope.nil? || association_scope.auto_include_value
|
26
|
-
end
|
27
|
-
|
28
|
-
def from?
|
29
|
-
if ActiveRecord::VERSION::MAJOR >= 5
|
30
|
-
association_scope && association_scope.from_clause.present?
|
31
|
-
else
|
32
|
-
association_scope && association_scope.from_value.present?
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def group?
|
37
|
-
association_scope && association_scope.group_values.present?
|
38
|
-
end
|
39
|
-
|
40
|
-
def order?
|
41
|
-
association_scope && association_scope.order_values.present?
|
42
|
-
end
|
43
|
-
|
44
|
-
def instance_dependent?
|
45
|
-
reflection.scope.present? && reflection.scope.arity > 0
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|