goldiloader 3.0.2 → 4.0.0

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
- SHA1:
3
- metadata.gz: cea2be18413e1cc1e5d2dc0a325a808f64165a52
4
- data.tar.gz: b9ea0538d9894df028174a7e081acd5b96b4455b
2
+ SHA256:
3
+ metadata.gz: 2b1702016efdeb47b12f583ff299bc46125714acc053b7c8594a9cf9a4fcba07
4
+ data.tar.gz: 6485555c4d71199683907813d9563fdecce3c8bada819d7ae1180f48ad5afadb
5
5
  SHA512:
6
- metadata.gz: 28df2ae2eed0bc12cd4d29458aebbc16cf5f667d2950d8b113bf92859447b75a2380d83abf59ef1b36ec0d707fe3954ef25d12b642b69502850d142aa590607e
7
- data.tar.gz: 1ebb5abe80281c1a76fc3b3dd8eed50367ccde1dce353493d90d7da468750e436c4d273e39e1d1388800d31ba2676e4729fbc37ee271e063267a83b6612c96c5
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/association_info'
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
- if Goldiloader::Compatibility.rails_4?
56
- raise ::ActiveRecord::Relation::ImmutableRelation if @loaded
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
- association_info = Goldiloader::AssociationInfo.new(self)
101
- association_info.auto_include? &&
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
- association_methods = [:size, :ids_reader, :empty?]
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
- if Goldiloader::Compatibility::ACTIVE_RECORD_VERSION >= ::Gem::Version.new('5.1')
152
- def find_from_target?
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
- ::ActiveRecord::Associations::Preloader.new.preload(models, [association_name])
19
- end
20
-
21
- def first_model_with_association(models, association_name)
22
- models.find { |model| has_association?(model, association_name) }
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
- if ::ActiveRecord::VERSION::MAJOR >= 5
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
@@ -4,6 +4,8 @@ module Goldiloader
4
4
  class AutoIncludeContext
5
5
  attr_reader :models
6
6
 
7
+ delegate :size, to: :models
8
+
7
9
  def initialize
8
10
  @models = []
9
11
  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.rails_4?
15
- ::ActiveRecord::VERSION::MAJOR == 4
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Goldiloader
4
- VERSION = '3.0.2'
4
+ VERSION = '4.0.0'
5
5
  end
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: 3.0.2
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: 2018-11-05 00:00:00.000000000 Z
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: '4.2'
19
+ version: '5.2'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '5.3'
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: '4.2'
29
+ version: '5.2'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '5.3'
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: '4.2'
39
+ version: '5.2'
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
- version: '5.3'
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: '4.2'
49
+ version: '5.2'
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
- version: '5.3'
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: coveralls
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.52.1.1
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.52.1.1
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: '0'
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: '0'
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.3'
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
- rubyforge_project:
219
- rubygems_version: 2.6.14
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