activerecord 6.0.6 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +783 -910
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +43 -26
- data/lib/active_record/associations/association_scope.rb +11 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +19 -13
- data/lib/active_record/associations/collection_proxy.rb +12 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +29 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +63 -49
- data/lib/active_record/associations/preloader/association.rb +13 -5
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations.rb +114 -11
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +11 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +32 -7
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +152 -22
- data/lib/active_record/coders/yaml_column.rb +2 -24
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +110 -30
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
- data/lib/active_record/connection_adapters/abstract_adapter.rb +49 -72
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -53
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -5
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +223 -66
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -40
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +27 -10
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -2
- data/lib/active_record/fixtures.rb +54 -8
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +34 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +13 -16
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +26 -8
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +67 -17
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/model_schema.rb +88 -13
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/databases.rake +266 -95
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/calculations.rb +100 -43
- data/lib/active_record/relation/finder_methods.rb +44 -14
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +20 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +57 -33
- data/lib/active_record/relation/query_methods.rb +318 -195
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +104 -57
- data/lib/active_record/relation.rb +90 -64
- data/lib/active_record/result.rb +41 -33
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/named.rb +1 -17
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -51
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +36 -33
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +15 -64
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -14
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -13
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
- data/lib/rails/generators/active_record/migration.rb +6 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +28 -30
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
@@ -162,13 +162,7 @@ module ActiveRecord
|
|
162
162
|
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
|
163
163
|
# <tt>has_many :clients</tt> returns <tt>'Client'</tt>
|
164
164
|
def class_name
|
165
|
-
@class_name ||= (options[:class_name] || derive_class_name)
|
166
|
-
end
|
167
|
-
|
168
|
-
JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
|
169
|
-
|
170
|
-
def join_keys
|
171
|
-
@join_keys ||= get_join_keys(klass)
|
165
|
+
@class_name ||= -(options[:class_name]&.to_s || derive_class_name)
|
172
166
|
end
|
173
167
|
|
174
168
|
# Returns a list of scopes that should be applied for this Reflection
|
@@ -188,10 +182,10 @@ module ActiveRecord
|
|
188
182
|
|
189
183
|
scope_chain_items.inject(klass_scope, &:merge!)
|
190
184
|
|
191
|
-
|
192
|
-
foreign_key =
|
185
|
+
primary_key = join_primary_key
|
186
|
+
foreign_key = join_foreign_key
|
193
187
|
|
194
|
-
klass_scope.where!(table[
|
188
|
+
klass_scope.where!(table[primary_key].eq(foreign_table[foreign_key]))
|
195
189
|
|
196
190
|
if klass.finder_needs_type_condition?
|
197
191
|
klass_scope.where!(klass.send(:type_condition, table))
|
@@ -218,14 +212,14 @@ module ActiveRecord
|
|
218
212
|
end
|
219
213
|
|
220
214
|
def counter_cache_column
|
221
|
-
if belongs_to?
|
215
|
+
@counter_cache_column ||= if belongs_to?
|
222
216
|
if options[:counter_cache] == true
|
223
|
-
"#{active_record.name.demodulize.underscore.pluralize}_count"
|
217
|
+
-"#{active_record.name.demodulize.underscore.pluralize}_count"
|
224
218
|
elsif options[:counter_cache]
|
225
|
-
options[:counter_cache].to_s
|
219
|
+
-options[:counter_cache].to_s
|
226
220
|
end
|
227
221
|
else
|
228
|
-
options[:counter_cache]
|
222
|
+
-(options[:counter_cache]&.to_s || "#{name}_count")
|
229
223
|
end
|
230
224
|
end
|
231
225
|
|
@@ -272,7 +266,7 @@ module ActiveRecord
|
|
272
266
|
def has_cached_counter?
|
273
267
|
options[:counter_cache] ||
|
274
268
|
inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
|
275
|
-
|
269
|
+
active_record.has_attribute?(counter_cache_column)
|
276
270
|
end
|
277
271
|
|
278
272
|
def counter_must_be_updated_by_has_many?
|
@@ -287,10 +281,6 @@ module ActiveRecord
|
|
287
281
|
collect_join_chain
|
288
282
|
end
|
289
283
|
|
290
|
-
def get_join_keys(association_klass)
|
291
|
-
JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
|
292
|
-
end
|
293
|
-
|
294
284
|
def build_scope(table, predicate_builder = predicate_builder(table), klass = self.klass)
|
295
285
|
Relation.create(
|
296
286
|
klass,
|
@@ -299,12 +289,8 @@ module ActiveRecord
|
|
299
289
|
)
|
300
290
|
end
|
301
291
|
|
302
|
-
def
|
303
|
-
|
304
|
-
end
|
305
|
-
|
306
|
-
def join_foreign_key
|
307
|
-
active_record_primary_key
|
292
|
+
def strict_loading?
|
293
|
+
options[:strict_loading]
|
308
294
|
end
|
309
295
|
|
310
296
|
protected
|
@@ -428,8 +414,8 @@ module ActiveRecord
|
|
428
414
|
|
429
415
|
def initialize(name, scope, options, active_record)
|
430
416
|
super
|
431
|
-
@type
|
432
|
-
@foreign_type =
|
417
|
+
@type = -(options[:foreign_type]&.to_s || "#{options[:as]}_type") if options[:as]
|
418
|
+
@foreign_type = -(options[:foreign_type]&.to_s || "#{name}_type") if options[:polymorphic]
|
433
419
|
@constructable = calculate_constructable(macro, options)
|
434
420
|
|
435
421
|
if options[:class_name] && options[:class_name].class == Class
|
@@ -450,24 +436,31 @@ module ActiveRecord
|
|
450
436
|
end
|
451
437
|
|
452
438
|
def join_table
|
453
|
-
@join_table ||= options[:join_table] || derive_join_table
|
439
|
+
@join_table ||= -(options[:join_table]&.to_s || derive_join_table)
|
454
440
|
end
|
455
441
|
|
456
442
|
def foreign_key
|
457
|
-
@foreign_key ||= options[:foreign_key] || derive_foreign_key
|
443
|
+
@foreign_key ||= -(options[:foreign_key]&.to_s || derive_foreign_key)
|
458
444
|
end
|
459
445
|
|
460
446
|
def association_foreign_key
|
461
|
-
@association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
|
447
|
+
@association_foreign_key ||= -(options[:association_foreign_key]&.to_s || class_name.foreign_key)
|
462
448
|
end
|
463
449
|
|
464
|
-
# klass option is necessary to support loading polymorphic associations
|
465
450
|
def association_primary_key(klass = nil)
|
466
|
-
|
451
|
+
primary_key(klass || self.klass)
|
467
452
|
end
|
468
453
|
|
469
454
|
def active_record_primary_key
|
470
|
-
@active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
|
455
|
+
@active_record_primary_key ||= -(options[:primary_key]&.to_s || primary_key(active_record))
|
456
|
+
end
|
457
|
+
|
458
|
+
def join_primary_key(klass = nil)
|
459
|
+
foreign_key
|
460
|
+
end
|
461
|
+
|
462
|
+
def join_foreign_key
|
463
|
+
active_record_primary_key
|
471
464
|
end
|
472
465
|
|
473
466
|
def check_validity!
|
@@ -630,6 +623,7 @@ module ActiveRecord
|
|
630
623
|
# with the current reflection's klass name.
|
631
624
|
def valid_inverse_reflection?(reflection)
|
632
625
|
reflection &&
|
626
|
+
foreign_key == reflection.foreign_key &&
|
633
627
|
klass <= reflection.active_record &&
|
634
628
|
can_find_inverse_of_automatically?(reflection)
|
635
629
|
end
|
@@ -683,10 +677,6 @@ module ActiveRecord
|
|
683
677
|
Associations::HasManyAssociation
|
684
678
|
end
|
685
679
|
end
|
686
|
-
|
687
|
-
def association_primary_key(klass = nil)
|
688
|
-
primary_key(klass || self.klass)
|
689
|
-
end
|
690
680
|
end
|
691
681
|
|
692
682
|
class HasOneReflection < AssociationReflection # :nodoc:
|
@@ -721,6 +711,15 @@ module ActiveRecord
|
|
721
711
|
end
|
722
712
|
end
|
723
713
|
|
714
|
+
# klass option is necessary to support loading polymorphic associations
|
715
|
+
def association_primary_key(klass = nil)
|
716
|
+
if primary_key = options[:primary_key]
|
717
|
+
@association_primary_key ||= -primary_key.to_s
|
718
|
+
else
|
719
|
+
primary_key(klass || self.klass)
|
720
|
+
end
|
721
|
+
end
|
722
|
+
|
724
723
|
def join_primary_key(klass = nil)
|
725
724
|
polymorphic? ? association_primary_key(klass) : association_primary_key
|
726
725
|
end
|
@@ -729,6 +728,10 @@ module ActiveRecord
|
|
729
728
|
foreign_key
|
730
729
|
end
|
731
730
|
|
731
|
+
def join_foreign_type
|
732
|
+
foreign_type
|
733
|
+
end
|
734
|
+
|
732
735
|
private
|
733
736
|
def can_find_inverse_of_automatically?(_)
|
734
737
|
!polymorphic? && super
|
@@ -750,8 +753,8 @@ module ActiveRecord
|
|
750
753
|
# Holds all the metadata about a :through association as it was specified
|
751
754
|
# in the Active Record class.
|
752
755
|
class ThroughReflection < AbstractReflection #:nodoc:
|
753
|
-
delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for,
|
754
|
-
:active_record_primary_key, :
|
756
|
+
delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for, :type,
|
757
|
+
:active_record_primary_key, :join_foreign_key, to: :source_reflection
|
755
758
|
|
756
759
|
def initialize(delegate_reflection)
|
757
760
|
@delegate_reflection = delegate_reflection
|
@@ -858,7 +861,15 @@ module ActiveRecord
|
|
858
861
|
def association_primary_key(klass = nil)
|
859
862
|
# Get the "actual" source reflection if the immediate source reflection has a
|
860
863
|
# source reflection itself
|
861
|
-
actual_source_reflection.options[:primary_key]
|
864
|
+
if primary_key = actual_source_reflection.options[:primary_key]
|
865
|
+
@association_primary_key ||= -primary_key.to_s
|
866
|
+
else
|
867
|
+
primary_key(klass || self.klass)
|
868
|
+
end
|
869
|
+
end
|
870
|
+
|
871
|
+
def join_primary_key(klass = self.klass)
|
872
|
+
source_reflection.join_primary_key(klass)
|
862
873
|
end
|
863
874
|
|
864
875
|
# Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
|
@@ -907,7 +918,7 @@ module ActiveRecord
|
|
907
918
|
|
908
919
|
def check_validity!
|
909
920
|
if through_reflection.nil?
|
910
|
-
raise HasManyThroughAssociationNotFoundError.new(active_record
|
921
|
+
raise HasManyThroughAssociationNotFoundError.new(active_record, self)
|
911
922
|
end
|
912
923
|
|
913
924
|
if through_reflection.polymorphic?
|
@@ -994,7 +1005,8 @@ module ActiveRecord
|
|
994
1005
|
end
|
995
1006
|
|
996
1007
|
class PolymorphicReflection < AbstractReflection # :nodoc:
|
997
|
-
delegate :klass, :scope, :plural_name, :type, :
|
1008
|
+
delegate :klass, :scope, :plural_name, :type, :join_primary_key, :join_foreign_key,
|
1009
|
+
:name, :scope_for, to: :@reflection
|
998
1010
|
|
999
1011
|
def initialize(reflection, previous_reflection)
|
1000
1012
|
@reflection = reflection
|
@@ -1019,7 +1031,7 @@ module ActiveRecord
|
|
1019
1031
|
end
|
1020
1032
|
|
1021
1033
|
class RuntimeReflection < AbstractReflection # :nodoc:
|
1022
|
-
delegate :scope, :type, :constraints, :
|
1034
|
+
delegate :scope, :type, :constraints, :join_foreign_key, to: :@reflection
|
1023
1035
|
|
1024
1036
|
def initialize(reflection, association)
|
1025
1037
|
@reflection = reflection
|
@@ -1031,7 +1043,11 @@ module ActiveRecord
|
|
1031
1043
|
end
|
1032
1044
|
|
1033
1045
|
def aliased_table
|
1034
|
-
|
1046
|
+
klass.arel_table
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
def join_primary_key(klass = self.klass)
|
1050
|
+
@reflection.join_primary_key(klass)
|
1035
1051
|
end
|
1036
1052
|
|
1037
1053
|
def all_includes; yield; end
|
@@ -41,19 +41,35 @@ module ActiveRecord
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
#
|
44
|
+
# Deletes records in batches. Returns the total number of rows affected.
|
45
45
|
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
46
|
+
# Person.in_batches.delete_all
|
47
|
+
#
|
48
|
+
# See Relation#delete_all for details of how each batch is deleted.
|
49
|
+
def delete_all
|
50
|
+
sum(&:delete_all)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Updates records in batches. Returns the total number of rows affected.
|
54
|
+
#
|
55
|
+
# Person.in_batches.update_all("age = age + 1")
|
56
|
+
#
|
57
|
+
# See Relation#update_all for details of how each batch is updated.
|
58
|
+
def update_all(updates)
|
59
|
+
sum do |relation|
|
60
|
+
relation.update_all(updates)
|
54
61
|
end
|
55
62
|
end
|
56
63
|
|
64
|
+
# Destroys records in batches.
|
65
|
+
#
|
66
|
+
# Person.where("age < 10").in_batches.destroy_all
|
67
|
+
#
|
68
|
+
# See Relation#destroy_all for details of how each batch is destroyed.
|
69
|
+
def destroy_all
|
70
|
+
each(&:destroy_all)
|
71
|
+
end
|
72
|
+
|
57
73
|
# Yields an ActiveRecord::Relation object for each batch of records.
|
58
74
|
#
|
59
75
|
# Person.in_batches.each do |relation|
|
@@ -37,6 +37,7 @@ module ActiveRecord
|
|
37
37
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
38
38
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
39
39
|
# an order is present in the relation.
|
40
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be :asc or :desc). Defaults to :asc.
|
40
41
|
#
|
41
42
|
# Limits are honored, and if present there is no requirement for the batch
|
42
43
|
# size: it can be less than, equal to, or greater than the limit.
|
@@ -57,22 +58,22 @@ module ActiveRecord
|
|
57
58
|
# person.party_all_night!
|
58
59
|
# end
|
59
60
|
#
|
60
|
-
# NOTE:
|
61
|
-
# ascending on the primary key ("id ASC")
|
62
|
-
#
|
61
|
+
# NOTE: Order can be ascending (:asc) or descending (:desc). It is automatically set to
|
62
|
+
# ascending on the primary key ("id ASC").
|
63
|
+
# This also means that this method only works when the primary key is
|
63
64
|
# orderable (e.g. an integer or string).
|
64
65
|
#
|
65
66
|
# NOTE: By its nature, batch processing is subject to race conditions if
|
66
67
|
# other processes are modifying the database.
|
67
|
-
def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil)
|
68
|
+
def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc)
|
68
69
|
if block_given?
|
69
|
-
find_in_batches(start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore) do |records|
|
70
|
+
find_in_batches(start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do |records|
|
70
71
|
records.each { |record| yield record }
|
71
72
|
end
|
72
73
|
else
|
73
|
-
enum_for(:find_each, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore) do
|
74
|
+
enum_for(:find_each, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do
|
74
75
|
relation = self
|
75
|
-
apply_limits(relation, start, finish).size
|
76
|
+
apply_limits(relation, start, finish, order).size
|
76
77
|
end
|
77
78
|
end
|
78
79
|
end
|
@@ -101,6 +102,7 @@ module ActiveRecord
|
|
101
102
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
102
103
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
103
104
|
# an order is present in the relation.
|
105
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be :asc or :desc). Defaults to :asc.
|
104
106
|
#
|
105
107
|
# Limits are honored, and if present there is no requirement for the batch
|
106
108
|
# size: it can be less than, equal to, or greater than the limit.
|
@@ -116,23 +118,23 @@ module ActiveRecord
|
|
116
118
|
# group.each { |person| person.party_all_night! }
|
117
119
|
# end
|
118
120
|
#
|
119
|
-
# NOTE:
|
120
|
-
# ascending on the primary key ("id ASC")
|
121
|
-
#
|
121
|
+
# NOTE: Order can be ascending (:asc) or descending (:desc). It is automatically set to
|
122
|
+
# ascending on the primary key ("id ASC").
|
123
|
+
# This also means that this method only works when the primary key is
|
122
124
|
# orderable (e.g. an integer or string).
|
123
125
|
#
|
124
126
|
# NOTE: By its nature, batch processing is subject to race conditions if
|
125
127
|
# other processes are modifying the database.
|
126
|
-
def find_in_batches(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil)
|
128
|
+
def find_in_batches(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc)
|
127
129
|
relation = self
|
128
130
|
unless block_given?
|
129
|
-
return to_enum(:find_in_batches, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore) do
|
130
|
-
total = apply_limits(relation, start, finish).size
|
131
|
+
return to_enum(:find_in_batches, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do
|
132
|
+
total = apply_limits(relation, start, finish, order).size
|
131
133
|
(total - 1).div(batch_size) + 1
|
132
134
|
end
|
133
135
|
end
|
134
136
|
|
135
|
-
in_batches(of: batch_size, start: start, finish: finish, load: true, error_on_ignore: error_on_ignore) do |batch|
|
137
|
+
in_batches(of: batch_size, start: start, finish: finish, load: true, error_on_ignore: error_on_ignore, order: order) do |batch|
|
136
138
|
yield batch.to_a
|
137
139
|
end
|
138
140
|
end
|
@@ -165,6 +167,7 @@ module ActiveRecord
|
|
165
167
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
166
168
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
167
169
|
# an order is present in the relation.
|
170
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be :asc or :desc). Defaults to :asc.
|
168
171
|
#
|
169
172
|
# Limits are honored, and if present there is no requirement for the batch
|
170
173
|
# size, it can be less than, equal, or greater than the limit.
|
@@ -191,19 +194,23 @@ module ActiveRecord
|
|
191
194
|
#
|
192
195
|
# Person.in_batches.each_record(&:party_all_night!)
|
193
196
|
#
|
194
|
-
# NOTE:
|
195
|
-
# ascending on the primary key ("id ASC")
|
196
|
-
#
|
197
|
-
# or
|
197
|
+
# NOTE: Order can be ascending (:asc) or descending (:desc). It is automatically set to
|
198
|
+
# ascending on the primary key ("id ASC").
|
199
|
+
# This also means that this method only works when the primary key is
|
200
|
+
# orderable (e.g. an integer or string).
|
198
201
|
#
|
199
202
|
# NOTE: By its nature, batch processing is subject to race conditions if
|
200
203
|
# other processes are modifying the database.
|
201
|
-
def in_batches(of: 1000, start: nil, finish: nil, load: false, error_on_ignore: nil)
|
204
|
+
def in_batches(of: 1000, start: nil, finish: nil, load: false, error_on_ignore: nil, order: :asc)
|
202
205
|
relation = self
|
203
206
|
unless block_given?
|
204
207
|
return BatchEnumerator.new(of: of, start: start, finish: finish, relation: self)
|
205
208
|
end
|
206
209
|
|
210
|
+
unless [:asc, :desc].include?(order)
|
211
|
+
raise ArgumentError, ":order must be :asc or :desc, got #{order.inspect}"
|
212
|
+
end
|
213
|
+
|
207
214
|
if arel.orders.present?
|
208
215
|
act_on_ignored_order(error_on_ignore)
|
209
216
|
end
|
@@ -214,8 +221,8 @@ module ActiveRecord
|
|
214
221
|
batch_limit = remaining if remaining < batch_limit
|
215
222
|
end
|
216
223
|
|
217
|
-
relation = relation.reorder(batch_order).limit(batch_limit)
|
218
|
-
relation = apply_limits(relation, start, finish)
|
224
|
+
relation = relation.reorder(batch_order(order)).limit(batch_limit)
|
225
|
+
relation = apply_limits(relation, start, finish, order)
|
219
226
|
relation.skip_query_cache! # Retaining the results in the query cache would undermine the point of batching
|
220
227
|
batch_relation = relation
|
221
228
|
|
@@ -252,28 +259,28 @@ module ActiveRecord
|
|
252
259
|
end
|
253
260
|
|
254
261
|
batch_relation = relation.where(
|
255
|
-
|
262
|
+
predicate_builder[primary_key, primary_key_offset, order == :desc ? :lt : :gt]
|
256
263
|
)
|
257
264
|
end
|
258
265
|
end
|
259
266
|
|
260
267
|
private
|
261
|
-
def apply_limits(relation, start, finish)
|
262
|
-
relation = apply_start_limit(relation, start) if start
|
263
|
-
relation = apply_finish_limit(relation, finish) if finish
|
268
|
+
def apply_limits(relation, start, finish, order)
|
269
|
+
relation = apply_start_limit(relation, start, order) if start
|
270
|
+
relation = apply_finish_limit(relation, finish, order) if finish
|
264
271
|
relation
|
265
272
|
end
|
266
273
|
|
267
|
-
def apply_start_limit(relation, start)
|
268
|
-
relation.where(
|
274
|
+
def apply_start_limit(relation, start, order)
|
275
|
+
relation.where(predicate_builder[primary_key, start, order == :desc ? :lteq : :gteq])
|
269
276
|
end
|
270
277
|
|
271
|
-
def apply_finish_limit(relation, finish)
|
272
|
-
relation.where(
|
278
|
+
def apply_finish_limit(relation, finish, order)
|
279
|
+
relation.where(predicate_builder[primary_key, finish, order == :desc ? :gteq : :lteq])
|
273
280
|
end
|
274
281
|
|
275
|
-
def batch_order
|
276
|
-
|
282
|
+
def batch_order(order)
|
283
|
+
table[primary_key].public_send(order)
|
277
284
|
end
|
278
285
|
|
279
286
|
def act_on_ignored_order(error_on_ignore)
|