sunstone 5.1.0.4 → 5.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +5 -13
  3. data/ext/active_record/associations.rb +2 -7
  4. data/ext/active_record/associations/collection_association.rb +25 -18
  5. data/ext/active_record/attribute_methods.rb +19 -35
  6. data/ext/active_record/finder_methods.rb +138 -90
  7. data/ext/active_record/persistence.rb +16 -11
  8. data/ext/active_record/relation.rb +7 -47
  9. data/ext/active_record/relation/calculations.rb +5 -3
  10. data/ext/active_record/relation/query_methods.rb +9 -0
  11. data/ext/active_record/statement_cache.rb +4 -6
  12. data/ext/active_record/transactions.rb +9 -19
  13. data/ext/arel/nodes/select_statement.rb +26 -12
  14. data/lib/active_record/connection_adapters/sunstone/database_statements.rb +76 -25
  15. data/lib/active_record/connection_adapters/sunstone/type/json.rb +1 -1
  16. data/lib/active_record/connection_adapters/sunstone_adapter.rb +2 -3
  17. data/lib/arel/collectors/sunstone.rb +21 -19
  18. data/lib/arel/visitors/sunstone.rb +4 -8
  19. data/lib/sunstone.rb +2 -3
  20. data/lib/sunstone/connection.rb +2 -2
  21. data/lib/sunstone/exception.rb +8 -1
  22. data/lib/sunstone/version.rb +1 -1
  23. data/sunstone.gemspec +3 -3
  24. data/test/active_record/associations/has_many_test.rb +30 -2
  25. data/test/active_record/eager_loading_test.rb +10 -0
  26. data/test/active_record/persistance_test.rb +7 -7
  27. data/test/active_record/query/count_test.rb +13 -0
  28. data/test/active_record/query_test.rb +6 -6
  29. data/test/sunstone/connection/send_request_test.rb +1 -1
  30. data/test/test_helper.rb +1 -1
  31. metadata +9 -10
  32. data/ext/active_record/associations/association.rb +0 -16
  33. data/ext/active_record/batches.rb +0 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d53af8c7411662e7621971b1c2a3f39f130ea8c3
4
- data.tar.gz: 8a61637315c7faf35265b47b8334901340b41798
2
+ SHA256:
3
+ metadata.gz: f235687b97d48caa7ecf7a231928452bbaf807b8d2e6e6508a7f9159372dc600
4
+ data.tar.gz: 94eec63ac1c23762404058fe37b1558a62ec7ad564e262977e1534721949c149
5
5
  SHA512:
6
- metadata.gz: 690936bd2ba33aab551c98da50ea1871e29fdfa9207dd71c7bcd78050bfa56f219ad859c068ac33346833ffb44feb058bc2f41a46ab7c2e4f70b11c0f1449a62
7
- data.tar.gz: 6e9f804cc2b2e75584e184b9791dc3f5b2d0d682c71cd5ef1c60cb4ffdf1af23b6607bf3f650be218acb87f0173dad53b2621fffa3aa9dac40f72fc51efc4663
6
+ metadata.gz: c16d5374f32074dcd7a9e96ecf7f01dc6c77848df299454a5209913f25cdb23b333f4cc6b9a93e6f58d25b6681a11f54b8124f8352427702b22301e81a98a6a7
7
+ data.tar.gz: fb6512b92823f37cac2477010df776a703f12a3f13f455a6d7388c8edffe4a59192fa3aa2114b4f62e244aa4b9a771f32e01718e5c5f2a0ddf2ed382fe49390a
@@ -7,22 +7,14 @@ cache:
7
7
  - /home/travis/.rvm/gems
8
8
 
9
9
  rvm:
10
- - 2.4.1
10
+ - 2.4.4
11
+ - 2.5.1
11
12
 
12
13
  env:
13
14
  matrix:
14
- - RAILS_VERSION=v5.1.0 GEM=ar:mysql2
15
- - RAILS_VERSION=v5.1.0 GEM=ar:sqlite3
16
- - RAILS_VERSION=v5.1.0 GEM=ar:postgresql
17
- - RAILS_VERSION=v5.1.1 GEM=ar:mysql2
18
- - RAILS_VERSION=v5.1.1 GEM=ar:sqlite3
19
- - RAILS_VERSION=v5.1.1 GEM=ar:postgresql
20
- - RAILS_VERSION=v5.1.2 GEM=ar:mysql2
21
- - RAILS_VERSION=v5.1.2 GEM=ar:sqlite3
22
- - RAILS_VERSION=v5.1.2 GEM=ar:postgresql
23
- - RAILS_VERSION=v5.1.3 GEM=ar:mysql2
24
- - RAILS_VERSION=v5.1.3 GEM=ar:sqlite3
25
- - RAILS_VERSION=v5.1.3 GEM=ar:postgresql
15
+ - RAILS_VERSION=v5.2.0 GEM=ar:mysql2
16
+ - RAILS_VERSION=v5.2.0 GEM=ar:sqlite3
17
+ - RAILS_VERSION=v5.2.0 GEM=ar:postgresql
26
18
 
27
19
  addons:
28
20
  postgresql: "9.4"
@@ -3,12 +3,7 @@ require 'active_record/associations'
3
3
  module ActiveRecord
4
4
  module Associations
5
5
  module ClassMethods
6
- def has_and_belongs_to_many(name, scope = nil, options = {}, &extension)
7
- if scope.is_a?(Hash)
8
- options = scope
9
- scope = nil
10
- end
11
-
6
+ def has_and_belongs_to_many(name, scope = nil, **options, &extension)
12
7
  habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
13
8
 
14
9
  builder = Builder::HasAndBelongsToMany.new name, self, options
@@ -45,7 +40,7 @@ module ActiveRecord
45
40
  end
46
41
 
47
42
  has_many name, scope, hm_options, &extension
48
- self._reflections[name.to_s].parent_reflection = habtm_reflection
43
+ _reflections[name.to_s].parent_reflection = habtm_reflection
49
44
  end
50
45
  end
51
46
  end
@@ -9,17 +9,24 @@ module ActiveRecord
9
9
  if owner.new_record?
10
10
  replace_records(other_array, original_target)
11
11
  elsif owner.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && owner.instance_variable_defined?(:@updating) && owner.instance_variable_get(:@updating)
12
- self.instance_variable_set(:@sunstone_changed, true)
13
12
  replace_common_records_in_memory(other_array, original_target)
14
13
 
15
14
  # Remove from target
16
- (original_target - other_array).each { |record| callback(:before_remove, record) }
17
- (original_target - other_array).each { |record| target.delete(record) }
18
- (original_target - other_array).each { |record| callback(:after_remove, record) }
15
+ records_for_removal = (original_target - other_array)
16
+ if !records_for_removal.empty?
17
+ self.instance_variable_set(:@sunstone_changed, true)
18
+ records_for_removal.each { |record| callback(:before_remove, record) }
19
+ records_for_removal.each { |record| target.delete(record) }
20
+ records_for_removal.each { |record| callback(:after_remove, record) }
21
+ end
19
22
 
20
23
  # Add to target
21
- (other_array - original_target).each do |record|
22
- add_to_target(record)
24
+ records_for_addition = (other_array - original_target)
25
+ if !records_for_addition.empty?
26
+ self.instance_variable_set(:@sunstone_changed, true)
27
+ (other_array - original_target).each do |record|
28
+ add_to_target(record)
29
+ end
23
30
  end
24
31
 
25
32
  other_array
@@ -33,28 +40,28 @@ module ActiveRecord
33
40
  end
34
41
  end
35
42
 
36
-
37
- end
38
-
39
- class HasManyAssociation
40
-
41
- def insert_record(record, validate = true, raise = false)
42
- set_owner_attributes(record)
43
- set_inverse_instance(record)
44
-
43
+ def insert_record(record, validate = true, raise = false, &block)
45
44
  if record.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && (!owner.instance_variable_defined?(:@updating) && owner.instance_variable_get(:@updating))
46
45
  true
47
46
  elsif raise
48
- record.save!(:validate => validate)
47
+ record.save!(validate: validate, &block)
49
48
  else
50
- record.save(:validate => validate)
49
+ record.save(validate: validate, &block)
51
50
  end
52
51
  end
53
52
 
53
+
54
+ end
55
+
56
+ class HasManyThroughAssociation
57
+
54
58
  private
55
59
  def save_through_record(record)
56
60
  return if record.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
57
- build_through_record(record).save!
61
+ association = build_through_record(record)
62
+ if association.changed?
63
+ association.save!
64
+ end
58
65
  ensure
59
66
  @through_records.delete(record.object_id)
60
67
  end
@@ -5,26 +5,23 @@ module ActiveRecord
5
5
 
6
6
  # Returns a Hash of the Arel::Attributes and attribute values that have been
7
7
  # typecasted for use in an Arel insert/update method.
8
- def arel_attributes_with_values(attribute_names)
9
- attrs = {}
10
- arel_table = self.class.arel_table
11
-
12
- attribute_names.each do |name|
13
- attrs[arel_table[name]] = typecasted_attribute_value(name)
8
+ def attributes_with_values(attribute_names)
9
+ attrs = attribute_names.each_with_object({}) do |name, attrs|
10
+ attrs[name] = _read_attribute(name)
14
11
  end
15
12
 
16
13
  if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
17
14
  self.class.reflect_on_all_associations.each do |reflection|
18
15
  if reflection.belongs_to?
19
16
  if association(reflection.name).loaded? && association(reflection.name).target == Thread.current[:sunstone_updating_model]
20
- attrs.delete(arel_table[reflection.foreign_key])
17
+ attrs.delete(reflection.foreign_key)
21
18
  else
22
19
  add_attributes_for_belongs_to_association(reflection, attrs)
23
20
  end
24
21
  elsif reflection.has_one?
25
22
  add_attributes_for_has_one_association(reflection, attrs)
26
23
  elsif reflection.collection?
27
- add_attributes_for_collection_association(reflection, attrs, arel_table)
24
+ add_attributes_for_collection_association(reflection, attrs, self.class.arel_table)
28
25
  end
29
26
  end
30
27
  end
@@ -50,13 +47,9 @@ module ActiveRecord
50
47
  elsif autosave != false
51
48
  if record.new_record? || (autosave && record.changed_for_autosave?)
52
49
  if record.new_record?
53
- record.send(:arel_attributes_with_values_for_create, record.attribute_names).each do |k, v|
54
- attrs[Arel::Attributes::Relation.new(k, reflection.name, false, true)] = v
55
- end
50
+ attrs["#{reflection.name}_attributes"] = record.send(:attributes_with_values_for_create, record.attribute_names)
56
51
  else
57
- record.send(:arel_attributes_with_values_for_update, record.attribute_names).each do |k, v|
58
- attrs[Arel::Attributes::Relation.new(k, reflection.name, false, true)] = v
59
- end
52
+ attrs["#{reflection.name}_attributes"] = record.send(:attributes_with_values_for_update, record.attribute_names)
60
53
  end
61
54
  end
62
55
  end
@@ -87,13 +80,9 @@ module ActiveRecord
87
80
  end
88
81
 
89
82
  if record.new_record?
90
- record.send(:arel_attributes_with_values_for_create, record.attribute_names).each do |k, v|
91
- attrs[Arel::Attributes::Relation.new(k, reflection.name, false, true)] = v
92
- end
83
+ attrs["#{reflection.name}_attributes"] = record.send(:attributes_with_values_for_create, record.attribute_names)
93
84
  else
94
- record.send(:arel_attributes_with_values_for_update, record.attribute_names).each do |k, v|
95
- attrs[Arel::Attributes::Relation.new(k, reflection.name, false, true)] = v
96
- end
85
+ attrs["#{reflection.name}_attributes"] = record.send(:attributes_with_values_for_update, record.attribute_names)
97
86
  end
98
87
  end
99
88
  end
@@ -111,22 +100,19 @@ module ActiveRecord
111
100
  end
112
101
 
113
102
  if association = association_instance_get(reflection.name)
114
- if new_record? || (association.instance_variable_defined?(:@sunstone_changed) && association.instance_variable_get(:@sunstone_changed)) || reflection.options[:autosave] || association.target.any?(&:changed_for_autosave?) || association.target.any?(&:new_record?)
115
- attrs[Arel::Attributes::EmptyRelation.new(arel_table, reflection.name, true, true)] = [] if association.target.empty?
116
-
117
- association.target.each_with_index do |record, idx|
118
- next if record.destroyed?
119
-
120
- if record.new_record?
121
- record.send(:arel_attributes_with_values_for_create, record.send(:keys_for_partial_write) + [record.class.primary_key]).each do |k, v|
122
- attrs[Arel::Attributes::Relation.new(k, reflection.name, idx, true)] = v
123
- end
124
- else
125
- record.send(:arel_attributes_with_values_for_update, record.send(:keys_for_partial_write) + [record.class.primary_key]).each do |k, v|
126
- attrs[Arel::Attributes::Relation.new(k, reflection.name, idx, true)] = v
103
+ if new_record? || (association.instance_variable_defined?(:@sunstone_changed) && association.instance_variable_get(:@sunstone_changed)) || association.target.any?(&:changed_for_autosave?) || association.target.any?(&:new_record?)
104
+ attrs["#{reflection.name}_attributes"] = if association.target.empty?
105
+ []
106
+ else
107
+ association.target.select { |r| !r.destroyed? }.map do |record|
108
+ if record.new_record?
109
+ record.send(:attributes_with_values_for_create, record.send(:keys_for_partial_write) + [record.class.primary_key])
110
+ else
111
+ record.send(:attributes_with_values_for_update, record.send(:keys_for_partial_write) + [record.class.primary_key])
127
112
  end
128
113
  end
129
114
  end
115
+
130
116
  association.instance_variable_set(:@sunstone_changed, false)
131
117
  end
132
118
 
@@ -134,8 +120,6 @@ module ActiveRecord
134
120
  association.reset_scope if association.respond_to?(:reset_scope)
135
121
  end
136
122
  end
137
-
138
-
139
123
 
140
124
  end
141
125
  end
@@ -17,7 +17,7 @@ module ActiveRecord
17
17
  return ["1=0"] if attributes.empty?
18
18
 
19
19
  attributes.flat_map do |key, value|
20
- if value.is_a?(Hash)
20
+ if value.is_a?(Hash) && !table.has_column?(key)
21
21
  ka = associated_predicate_builder(key).expand_from_hash(value)
22
22
  if self.table.instance_variable_get(:@klass).connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
23
23
  ka.each { |k|
@@ -27,6 +27,38 @@ module ActiveRecord
27
27
  }
28
28
  end
29
29
  ka
30
+ elsif table.associated_with?(key)
31
+ # Find the foreign key when using queries such as:
32
+ # Post.where(author: author)
33
+ #
34
+ # For polymorphic relationships, find the foreign key and type:
35
+ # PriceEstimate.where(estimate_of: treasure)
36
+ associated_table = table.associated_table(key)
37
+ if associated_table.polymorphic_association?
38
+ case value.is_a?(Array) ? value.first : value
39
+ when Base, Relation
40
+ value = [value] unless value.is_a?(Array)
41
+ klass = PolymorphicArrayValue
42
+ end
43
+ end
44
+
45
+ klass ||= AssociationQueryValue
46
+ queries = klass.new(associated_table, value).queries.map do |query|
47
+ expand_from_hash(query).reduce(&:and)
48
+ end
49
+ queries.reduce(&:or)
50
+ elsif table.aggregated_with?(key)
51
+ mapping = table.reflect_on_aggregation(key).mapping
52
+ queries = Array.wrap(value).map do |object|
53
+ mapping.map do |field_attr, aggregate_attr|
54
+ if mapping.size == 1 && !object.respond_to?(aggregate_attr)
55
+ build(table.arel_attribute(field_attr), object)
56
+ else
57
+ build(table.arel_attribute(field_attr), object.send(aggregate_attr))
58
+ end
59
+ end.reduce(&:and)
60
+ end
61
+ queries.reduce(&:or)
30
62
  else
31
63
  build(table.arel_attribute(key), value)
32
64
  end
@@ -39,98 +71,113 @@ end
39
71
  module ActiveRecord
40
72
  module FinderMethods
41
73
 
42
- def find_with_associations
43
- join_dependency = nil
44
- aliases = nil
45
- relation = if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
46
- arel.eager_load = Arel::Nodes::EagerLoad.new(eager_load_values)
47
- self
48
- else
49
- join_dependency = construct_join_dependency(joins_values)
50
- aliases = join_dependency.aliases
51
- apply_join_dependency(select(aliases.columns), join_dependency)
74
+ class SunstoneJoinDependency
75
+ def initialize(klass)
76
+ @klass = klass
52
77
  end
53
78
 
54
- if block_given?
55
- yield relation
56
- else
57
- if ActiveRecord::NullRelation === relation
58
- []
59
- else
60
- arel = relation.arel
61
- rows = if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
62
- connection.select_all(arel, 'SQL', arel.bind_values + relation.bound_attributes)
63
- else
64
- connection.select_all(arel, 'SQL', relation.bound_attributes)
65
- end
66
- if join_dependency
67
- join_dependency.instantiate(rows, aliases)
68
- else
69
- instantiate_with_associations(rows, relation)
70
- end
71
- end
79
+ def reflections
80
+ []
72
81
  end
73
- end
82
+
83
+ def apply_column_aliases(relation)
84
+ relation
85
+ end
86
+
87
+ def instantiate(result_set, &block)
88
+ seen = Hash.new { |i, object_id|
89
+ i[object_id] = Hash.new { |j, child_class|
90
+ j[child_class] = {}
91
+ }
92
+ }
93
+
94
+ model_cache = Hash.new { |h, klass| h[klass] = {} }
95
+ parents = model_cache[@klass]
96
+
97
+ message_bus = ActiveSupport::Notifications.instrumenter
74
98
 
75
- def instantiate_with_associations(result_set, klass)
76
- seen = Hash.new { |h, parent_klass|
77
- h[parent_klass] = Hash.new { |i, parent_id|
78
- i[parent_id] = Hash.new { |j, child_klass| j[child_klass] = {} }
99
+ payload = {
100
+ record_count: result_set.length,
101
+ class_name: @klass.name
79
102
  }
80
- }
81
103
 
82
- model_cache = Hash.new { |h,kklass| h[kklass] = {} }
83
- parents = model_cache[self.base_class]
104
+ message_bus.instrument("instantiation.active_record", payload) do
105
+ result_set.each { |row_hash|
106
+ parent_key = @klass.primary_key ? row_hash[@klass.primary_key] : row_hash
107
+ parent = parents[parent_key] ||= @klass.instantiate(row_hash.select{|k,v| @klass.column_names.include?(k.to_s) }, &block)
108
+ construct(parent, row_hash.select{|k,v| !@klass.column_names.include?(k.to_s) }, seen, model_cache)
109
+ }
110
+ end
84
111
 
85
- result_set.each { |row_hash|
86
- parent = parents[row_hash[primary_key]] ||= instantiate(row_hash.select{|k,v| column_names.include?(k.to_s) })
87
- construct(parent, row_hash.select{|k,v| !column_names.include?(k.to_s) }, seen, model_cache)
88
- }
112
+ parents.values
113
+ end
89
114
 
90
- parents.values
91
- end
115
+ def construct(parent, relations, seen, model_cache)
116
+ relations.each do |key, attributes|
117
+ reflection = parent.class.reflect_on_association(key)
118
+ next unless reflection
92
119
 
93
- def construct(parent, relations, seen, model_cache)
94
- relations.each do |key, attributes|
95
- reflection = parent.class.reflect_on_association(key)
96
- next unless reflection
120
+ if reflection.collection?
121
+ other = parent.association(reflection.name)
122
+ other.loaded!
123
+ else
124
+ if parent.association_cached?(reflection.name)
125
+ model = parent.association(reflection.name).target
126
+ construct(model, attributes.select{|k,v| !model.class.column_names.include?(k.to_s) }, seen, model_cache)
127
+ end
128
+ end
97
129
 
98
- if reflection.collection?
99
- other = parent.association(reflection.name)
100
- other.loaded!
101
- else
102
- if parent.association_cached?(reflection.name)
103
- model = parent.association(reflection.name).target
104
- construct(model, attributes.select{|k,v| !model.class.column_names.include?(k.to_s) }, seen, model_cache)
130
+ if !reflection.collection?
131
+ construct_association(parent, reflection, attributes, seen, model_cache)
132
+ else
133
+ attributes.each do |row|
134
+ construct_association(parent, reflection, row, seen, model_cache)
135
+ end
105
136
  end
137
+
106
138
  end
139
+ end
140
+
141
+ def construct_association(parent, reflection, attributes, seen, model_cache)
142
+ return if attributes.nil?
107
143
 
108
- if !reflection.collection?
109
- construct_association(parent, reflection, attributes, seen, model_cache)
144
+ klass = if reflection.polymorphic?
145
+ parent.send(reflection.foreign_type).constantize.base_class
110
146
  else
111
- attributes.each do |row|
112
- construct_association(parent, reflection, row, seen, model_cache)
113
- end
147
+ reflection.klass
114
148
  end
149
+ id = attributes[klass.primary_key]
150
+ model = seen[parent.object_id][klass][id]
115
151
 
116
- end
117
- end
152
+ if model
153
+ construct(model, attributes.select{|k,v| !klass.column_names.include?(k.to_s) }, seen, model_cache)
118
154
 
119
- def construct_association(parent, reflection, attributes, seen, model_cache)
120
- return if attributes.nil?
155
+ other = parent.association(reflection.name)
121
156
 
122
- klass = if reflection.polymorphic?
123
- parent.send(reflection.foreign_type).constantize.base_class
124
- else
125
- reflection.klass
157
+ if reflection.collection?
158
+ other.target.push(model)
159
+ else
160
+ other.target = model
161
+ end
162
+
163
+ other.set_inverse_instance(model)
164
+ else
165
+ model = construct_model(parent, reflection, id, attributes.select{|k,v| klass.column_names.include?(k.to_s) }, seen, model_cache)
166
+ seen[parent.object_id][model.class.base_class][id] = model
167
+ construct(model, attributes.select{|k,v| !klass.column_names.include?(k.to_s) }, seen, model_cache)
168
+ end
126
169
  end
127
- id = attributes[klass.primary_key]
128
- model = seen[parent.class.base_class][parent.id][klass][id]
129
170
 
130
- if model
131
- construct(model, attributes.select{|k,v| !klass.column_names.include?(k.to_s) }, seen, model_cache)
132
171
 
133
- other = parent.association(reflection.name)
172
+ def construct_model(record, reflection, id, attributes, seen, model_cache)
173
+ klass = if reflection.polymorphic?
174
+ record.send(reflection.foreign_type).constantize
175
+ else
176
+ reflection.klass
177
+ end
178
+
179
+ model = model_cache[klass][id] ||= klass.instantiate(attributes)
180
+ other = record.association(reflection.name)
134
181
 
135
182
  if reflection.collection?
136
183
  other.target.push(model)
@@ -139,34 +186,35 @@ module ActiveRecord
139
186
  end
140
187
 
141
188
  other.set_inverse_instance(model)
142
- else
143
- model = construct_model(parent, reflection, id, attributes.select{|k,v| klass.column_names.include?(k.to_s) }, seen, model_cache)
144
- seen[parent.class.base_class][parent.id][model.class.base_class][id] = model
145
- construct(model, attributes.select{|k,v| !klass.column_names.include?(k.to_s) }, seen, model_cache)
189
+ model
146
190
  end
191
+
147
192
  end
148
193
 
149
-
150
- def construct_model(record, reflection, id, attributes, seen, model_cache)
151
- klass = if reflection.polymorphic?
152
- record.send(reflection.foreign_type).constantize
194
+ def apply_join_dependency(eager_loading: group_values.empty?)
195
+ if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
196
+ join_dependency = SunstoneJoinDependency.new(base_class)
197
+ relation = except(:includes, :eager_load, :preload)
198
+ relation.arel.eager_load = Arel::Nodes::EagerLoad.new(eager_load_values)
153
199
  else
154
- reflection.klass
200
+ join_dependency = construct_join_dependency
201
+ relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
155
202
  end
156
203
 
157
- model = model_cache[klass][id] ||= klass.instantiate(attributes)
158
- other = record.association(reflection.name)
204
+ if eager_loading && !using_limitable_reflections?(join_dependency.reflections)
205
+ if has_limit_or_offset?
206
+ limited_ids = limited_ids_for(relation)
207
+ limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
208
+ end
209
+ relation.limit_value = relation.offset_value = nil
210
+ end
159
211
 
160
- if reflection.collection?
161
- other.target.push(model)
212
+ if block_given?
213
+ yield relation, join_dependency
162
214
  else
163
- other.target = model
215
+ relation
164
216
  end
165
-
166
- other.set_inverse_instance(model)
167
- model
168
217
  end
169
-
170
218
  end
171
219
 
172
220
  end