activerecord 5.2.3 → 6.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.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +898 -532
- data/MIT-LICENSE +3 -1
- data/README.rdoc +7 -5
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +5 -4
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +95 -42
- data/lib/active_record/associations/association_scope.rb +21 -21
- data/lib/active_record/associations/belongs_to_association.rb +50 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -5
- data/lib/active_record/associations/builder/association.rb +23 -21
- data/lib/active_record/associations/builder/belongs_to.rb +29 -59
- data/lib/active_record/associations/builder/collection_association.rb +10 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -2
- data/lib/active_record/associations/builder/has_one.rb +33 -2
- data/lib/active_record/associations/builder/singular_association.rb +3 -1
- data/lib/active_record/associations/collection_association.rb +31 -29
- data/lib/active_record/associations/collection_proxy.rb +25 -21
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +26 -13
- data/lib/active_record/associations/has_many_through_association.rb +27 -28
- data/lib/active_record/associations/has_one_association.rb +43 -31
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +54 -12
- data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +91 -60
- data/lib/active_record/associations/preloader/association.rb +71 -43
- data/lib/active_record/associations/preloader/through_association.rb +49 -40
- data/lib/active_record/associations/preloader.rb +48 -35
- data/lib/active_record/associations/singular_association.rb +3 -17
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +133 -25
- data/lib/active_record/attribute_assignment.rb +17 -19
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -40
- data/lib/active_record/attribute_methods/primary_key.rb +20 -25
- data/lib/active_record/attribute_methods/query.rb +4 -8
- data/lib/active_record/attribute_methods/read.rb +14 -56
- data/lib/active_record/attribute_methods/serialization.rb +12 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +18 -34
- data/lib/active_record/attribute_methods.rb +81 -143
- data/lib/active_record/attributes.rb +45 -8
- data/lib/active_record/autosave_association.rb +76 -47
- data/lib/active_record/base.rb +4 -17
- data/lib/active_record/callbacks.rb +158 -43
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +293 -132
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +21 -17
- data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +203 -90
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +381 -146
- data/lib/active_record/connection_adapters/abstract/transaction.rb +155 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -98
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
- data/lib/active_record/connection_adapters/column.rb +30 -12
- 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/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +86 -32
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
- 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 +37 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +38 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- 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 +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
- 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/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +222 -112
- data/lib/active_record/connection_adapters/schema_cache.rb +127 -21
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +19 -6
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +175 -187
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +285 -33
- data/lib/active_record/core.rb +308 -100
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/database_configurations.rb +272 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +71 -17
- data/lib/active_record/errors.rb +62 -19
- data/lib/active_record/explain.rb +10 -6
- 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 +32 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +197 -481
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +53 -24
- data/lib/active_record/insert_all.rb +208 -0
- data/lib/active_record/integration.rb +67 -17
- data/lib/active_record/internal_metadata.rb +26 -9
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +26 -22
- data/lib/active_record/locking/pessimistic.rb +9 -5
- data/lib/active_record/log_subscriber.rb +34 -35
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/migration/command_recorder.rb +96 -44
- data/lib/active_record/migration/compatibility.rb +141 -64
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +205 -156
- data/lib/active_record/model_schema.rb +148 -22
- data/lib/active_record/nested_attributes.rb +4 -7
- data/lib/active_record/no_touching.rb +8 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +267 -59
- data/lib/active_record/query_cache.rb +21 -4
- data/lib/active_record/querying.rb +40 -23
- data/lib/active_record/railtie.rb +115 -58
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +402 -78
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +113 -101
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +44 -35
- data/lib/active_record/relation/calculations.rb +157 -93
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +65 -40
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +32 -40
- data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -7
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +58 -40
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +487 -199
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +9 -9
- data/lib/active_record/relation/where_clause.rb +108 -58
- data/lib/active_record/relation.rb +375 -104
- data/lib/active_record/result.rb +64 -38
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +22 -41
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +54 -9
- data/lib/active_record/schema_migration.rb +7 -9
- data/lib/active_record/scoping/default.rb +6 -8
- data/lib/active_record/scoping/named.rb +17 -24
- data/lib/active_record/scoping.rb +8 -9
- 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 +51 -8
- data/lib/active_record/store.rb +88 -9
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -43
- data/lib/active_record/tasks/database_tasks.rb +276 -81
- data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
- data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +246 -0
- data/lib/active_record/timestamp.rb +43 -32
- data/lib/active_record/touch_later.rb +23 -22
- data/lib/active_record/transactions.rb +59 -117
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +10 -5
- data/lib/active_record/type_caster/connection.rb +15 -15
- data/lib/active_record/type_caster/map.rb +8 -8
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +38 -30
- data/lib/active_record/validations.rb +4 -3
- data/lib/active_record.rb +13 -12
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +15 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +70 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +54 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
- data/lib/rails/generators/active_record/migration.rb +19 -2
- 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
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +117 -32
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
- data/lib/active_record/relation/where_clause_factory.rb +0 -34
| @@ -1,7 +1,6 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            require "active_support/core_ext/string/filters"
         | 
| 4 | 
            -
            require "concurrent/map"
         | 
| 5 4 |  | 
| 6 5 | 
             
            module ActiveRecord
         | 
| 7 6 | 
             
              # = Active Record Reflection
         | 
| @@ -13,33 +12,37 @@ module ActiveRecord | |
| 13 12 | 
             
                  class_attribute :aggregate_reflections, instance_writer: false, default: {}
         | 
| 14 13 | 
             
                end
         | 
| 15 14 |  | 
| 16 | 
            -
                 | 
| 17 | 
            -
                   | 
| 18 | 
            -
                     | 
| 19 | 
            -
                     | 
| 20 | 
            -
             | 
| 21 | 
            -
                    when :has_many
         | 
| 22 | 
            -
                      HasManyReflection
         | 
| 23 | 
            -
                    when :has_one
         | 
| 24 | 
            -
                      HasOneReflection
         | 
| 25 | 
            -
                    when :belongs_to
         | 
| 26 | 
            -
                      BelongsToReflection
         | 
| 27 | 
            -
                    else
         | 
| 28 | 
            -
                      raise "Unsupported Macro: #{macro}"
         | 
| 29 | 
            -
                    end
         | 
| 15 | 
            +
                class << self
         | 
| 16 | 
            +
                  def create(macro, name, scope, options, ar)
         | 
| 17 | 
            +
                    reflection = reflection_class_for(macro).new(name, scope, options, ar)
         | 
| 18 | 
            +
                    options[:through] ? ThroughReflection.new(reflection) : reflection
         | 
| 19 | 
            +
                  end
         | 
| 30 20 |  | 
| 31 | 
            -
                   | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 21 | 
            +
                  def add_reflection(ar, name, reflection)
         | 
| 22 | 
            +
                    ar.clear_reflections_cache
         | 
| 23 | 
            +
                    name = -name.to_s
         | 
| 24 | 
            +
                    ar._reflections = ar._reflections.except(name).merge!(name => reflection)
         | 
| 25 | 
            +
                  end
         | 
| 34 26 |  | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
                   | 
| 38 | 
            -
                  ar._reflections = ar._reflections.except(name).merge!(name => reflection)
         | 
| 39 | 
            -
                end
         | 
| 27 | 
            +
                  def add_aggregate_reflection(ar, name, reflection)
         | 
| 28 | 
            +
                    ar.aggregate_reflections = ar.aggregate_reflections.merge(-name.to_s => reflection)
         | 
| 29 | 
            +
                  end
         | 
| 40 30 |  | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 31 | 
            +
                  private
         | 
| 32 | 
            +
                    def reflection_class_for(macro)
         | 
| 33 | 
            +
                      case macro
         | 
| 34 | 
            +
                      when :composed_of
         | 
| 35 | 
            +
                        AggregateReflection
         | 
| 36 | 
            +
                      when :has_many
         | 
| 37 | 
            +
                        HasManyReflection
         | 
| 38 | 
            +
                      when :has_one
         | 
| 39 | 
            +
                        HasOneReflection
         | 
| 40 | 
            +
                      when :belongs_to
         | 
| 41 | 
            +
                        BelongsToReflection
         | 
| 42 | 
            +
                      else
         | 
| 43 | 
            +
                        raise "Unsupported Macro: #{macro}"
         | 
| 44 | 
            +
                      end
         | 
| 45 | 
            +
                    end
         | 
| 43 46 | 
             
                end
         | 
| 44 47 |  | 
| 45 48 | 
             
                # \Reflection enables the ability to examine the associations and aggregations of
         | 
| @@ -159,13 +162,7 @@ module ActiveRecord | |
| 159 162 | 
             
                  # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
         | 
| 160 163 | 
             
                  # <tt>has_many :clients</tt> returns <tt>'Client'</tt>
         | 
| 161 164 | 
             
                  def class_name
         | 
| 162 | 
            -
                    @class_name ||= (options[:class_name] || derive_class_name) | 
| 163 | 
            -
                  end
         | 
| 164 | 
            -
             | 
| 165 | 
            -
                  JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
         | 
| 166 | 
            -
             | 
| 167 | 
            -
                  def join_keys
         | 
| 168 | 
            -
                    @join_keys ||= get_join_keys(klass)
         | 
| 165 | 
            +
                    @class_name ||= -(options[:class_name]&.to_s || derive_class_name)
         | 
| 169 166 | 
             
                  end
         | 
| 170 167 |  | 
| 171 168 | 
             
                  # Returns a list of scopes that should be applied for this Reflection
         | 
| @@ -174,20 +171,7 @@ module ActiveRecord | |
| 174 171 | 
             
                    scope ? [scope] : []
         | 
| 175 172 | 
             
                  end
         | 
| 176 173 |  | 
| 177 | 
            -
                  def  | 
| 178 | 
            -
                    key         = join_keys.key
         | 
| 179 | 
            -
                    foreign_key = join_keys.foreign_key
         | 
| 180 | 
            -
             | 
| 181 | 
            -
                    constraint = table[key].eq(foreign_table[foreign_key])
         | 
| 182 | 
            -
             | 
| 183 | 
            -
                    if klass.finder_needs_type_condition?
         | 
| 184 | 
            -
                      table.create_and([constraint, klass.send(:type_condition, table)])
         | 
| 185 | 
            -
                    else
         | 
| 186 | 
            -
                      constraint
         | 
| 187 | 
            -
                    end
         | 
| 188 | 
            -
                  end
         | 
| 189 | 
            -
             | 
| 190 | 
            -
                  def join_scope(table, foreign_klass)
         | 
| 174 | 
            +
                  def join_scope(table, foreign_table, foreign_klass)
         | 
| 191 175 | 
             
                    predicate_builder = predicate_builder(table)
         | 
| 192 176 | 
             
                    scope_chain_items = join_scopes(table, predicate_builder)
         | 
| 193 177 | 
             
                    klass_scope       = klass_join_scope(table, predicate_builder)
         | 
| @@ -197,11 +181,22 @@ module ActiveRecord | |
| 197 181 | 
             
                    end
         | 
| 198 182 |  | 
| 199 183 | 
             
                    scope_chain_items.inject(klass_scope, &:merge!)
         | 
| 184 | 
            +
             | 
| 185 | 
            +
                    primary_key = join_primary_key
         | 
| 186 | 
            +
                    foreign_key = join_foreign_key
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                    klass_scope.where!(table[primary_key].eq(foreign_table[foreign_key]))
         | 
| 189 | 
            +
             | 
| 190 | 
            +
                    if klass.finder_needs_type_condition?
         | 
| 191 | 
            +
                      klass_scope.where!(klass.send(:type_condition, table))
         | 
| 192 | 
            +
                    end
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                    klass_scope
         | 
| 200 195 | 
             
                  end
         | 
| 201 196 |  | 
| 202 | 
            -
                  def join_scopes(table, predicate_builder) # :nodoc:
         | 
| 197 | 
            +
                  def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
         | 
| 203 198 | 
             
                    if scope
         | 
| 204 | 
            -
                      [scope_for(build_scope(table, predicate_builder))]
         | 
| 199 | 
            +
                      [scope_for(build_scope(table, predicate_builder, klass))]
         | 
| 205 200 | 
             
                    else
         | 
| 206 201 | 
             
                      []
         | 
| 207 202 | 
             
                    end
         | 
| @@ -217,14 +212,14 @@ module ActiveRecord | |
| 217 212 | 
             
                  end
         | 
| 218 213 |  | 
| 219 214 | 
             
                  def counter_cache_column
         | 
| 220 | 
            -
                    if belongs_to?
         | 
| 215 | 
            +
                    @counter_cache_column ||= if belongs_to?
         | 
| 221 216 | 
             
                      if options[:counter_cache] == true
         | 
| 222 | 
            -
                        "#{active_record.name.demodulize.underscore.pluralize}_count"
         | 
| 217 | 
            +
                        -"#{active_record.name.demodulize.underscore.pluralize}_count"
         | 
| 223 218 | 
             
                      elsif options[:counter_cache]
         | 
| 224 | 
            -
                        options[:counter_cache].to_s
         | 
| 219 | 
            +
                        -options[:counter_cache].to_s
         | 
| 225 220 | 
             
                      end
         | 
| 226 221 | 
             
                    else
         | 
| 227 | 
            -
                      options[:counter_cache] | 
| 222 | 
            +
                      -(options[:counter_cache]&.to_s || "#{name}_count")
         | 
| 228 223 | 
             
                    end
         | 
| 229 224 | 
             
                  end
         | 
| 230 225 |  | 
| @@ -271,7 +266,7 @@ module ActiveRecord | |
| 271 266 | 
             
                  def has_cached_counter?
         | 
| 272 267 | 
             
                    options[:counter_cache] ||
         | 
| 273 268 | 
             
                      inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
         | 
| 274 | 
            -
                       | 
| 269 | 
            +
                      active_record.has_attribute?(counter_cache_column)
         | 
| 275 270 | 
             
                  end
         | 
| 276 271 |  | 
| 277 272 | 
             
                  def counter_must_be_updated_by_has_many?
         | 
| @@ -286,11 +281,7 @@ module ActiveRecord | |
| 286 281 | 
             
                    collect_join_chain
         | 
| 287 282 | 
             
                  end
         | 
| 288 283 |  | 
| 289 | 
            -
                  def  | 
| 290 | 
            -
                    JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
         | 
| 291 | 
            -
                  end
         | 
| 292 | 
            -
             | 
| 293 | 
            -
                  def build_scope(table, predicate_builder = predicate_builder(table))
         | 
| 284 | 
            +
                  def build_scope(table, predicate_builder = predicate_builder(table), klass = self.klass)
         | 
| 294 285 | 
             
                    Relation.create(
         | 
| 295 286 | 
             
                      klass,
         | 
| 296 287 | 
             
                      table: table,
         | 
| @@ -298,12 +289,8 @@ module ActiveRecord | |
| 298 289 | 
             
                    )
         | 
| 299 290 | 
             
                  end
         | 
| 300 291 |  | 
| 301 | 
            -
                  def  | 
| 302 | 
            -
                     | 
| 303 | 
            -
                  end
         | 
| 304 | 
            -
             | 
| 305 | 
            -
                  def join_foreign_key
         | 
| 306 | 
            -
                    active_record_primary_key
         | 
| 292 | 
            +
                  def strict_loading?
         | 
| 293 | 
            +
                    options[:strict_loading]
         | 
| 307 294 | 
             
                  end
         | 
| 308 295 |  | 
| 309 296 | 
             
                  protected
         | 
| @@ -417,7 +404,7 @@ module ActiveRecord | |
| 417 404 | 
             
                class AssociationReflection < MacroReflection #:nodoc:
         | 
| 418 405 | 
             
                  def compute_class(name)
         | 
| 419 406 | 
             
                    if polymorphic?
         | 
| 420 | 
            -
                      raise ArgumentError, "Polymorphic  | 
| 407 | 
            +
                      raise ArgumentError, "Polymorphic associations do not support computing the class."
         | 
| 421 408 | 
             
                    end
         | 
| 422 409 | 
             
                    active_record.send(:compute_type, name)
         | 
| 423 410 | 
             
                  end
         | 
| @@ -427,22 +414,21 @@ module ActiveRecord | |
| 427 414 |  | 
| 428 415 | 
             
                  def initialize(name, scope, options, active_record)
         | 
| 429 416 | 
             
                    super
         | 
| 430 | 
            -
                    @type | 
| 431 | 
            -
                    @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]
         | 
| 432 419 | 
             
                    @constructable = calculate_constructable(macro, options)
         | 
| 433 | 
            -
                    @association_scope_cache = Concurrent::Map.new
         | 
| 434 420 |  | 
| 435 421 | 
             
                    if options[:class_name] && options[:class_name].class == Class
         | 
| 436 422 | 
             
                      raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
         | 
| 437 423 | 
             
                    end
         | 
| 438 424 | 
             
                  end
         | 
| 439 425 |  | 
| 440 | 
            -
                  def association_scope_cache( | 
| 441 | 
            -
                    key =  | 
| 426 | 
            +
                  def association_scope_cache(klass, owner, &block)
         | 
| 427 | 
            +
                    key = self
         | 
| 442 428 | 
             
                    if polymorphic?
         | 
| 443 429 | 
             
                      key = [key, owner._read_attribute(@foreign_type)]
         | 
| 444 430 | 
             
                    end
         | 
| 445 | 
            -
                     | 
| 431 | 
            +
                    klass.cached_find_by_statement(key, &block)
         | 
| 446 432 | 
             
                  end
         | 
| 447 433 |  | 
| 448 434 | 
             
                  def constructable? # :nodoc:
         | 
| @@ -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!
         | 
| @@ -477,7 +470,7 @@ module ActiveRecord | |
| 477 470 | 
             
                  def check_preloadable!
         | 
| 478 471 | 
             
                    return unless scope
         | 
| 479 472 |  | 
| 480 | 
            -
                     | 
| 473 | 
            +
                    unless scope.arity == 0
         | 
| 481 474 | 
             
                      raise ArgumentError, <<-MSG.squish
         | 
| 482 475 | 
             
                        The association scope '#{name}' is instance dependent (the scope
         | 
| 483 476 | 
             
                        block takes an argument). Preloading instance dependent scopes is
         | 
| @@ -508,7 +501,7 @@ module ActiveRecord | |
| 508 501 | 
             
                  # This is for clearing cache on the reflection. Useful for tests that need to compare
         | 
| 509 502 | 
             
                  # SQL queries on associations.
         | 
| 510 503 | 
             
                  def clear_association_scope_cache # :nodoc:
         | 
| 511 | 
            -
                     | 
| 504 | 
            +
                    klass.initialize_find_by_cache
         | 
| 512 505 | 
             
                  end
         | 
| 513 506 |  | 
| 514 507 | 
             
                  def nested?
         | 
| @@ -590,7 +583,6 @@ module ActiveRecord | |
| 590 583 | 
             
                  end
         | 
| 591 584 |  | 
| 592 585 | 
             
                  private
         | 
| 593 | 
            -
             | 
| 594 586 | 
             
                    def calculate_constructable(macro, options)
         | 
| 595 587 | 
             
                      true
         | 
| 596 588 | 
             
                    end
         | 
| @@ -620,7 +612,7 @@ module ActiveRecord | |
| 620 612 | 
             
                        end
         | 
| 621 613 |  | 
| 622 614 | 
             
                        if valid_inverse_reflection?(reflection)
         | 
| 623 | 
            -
                           | 
| 615 | 
            +
                          inverse_name
         | 
| 624 616 | 
             
                        end
         | 
| 625 617 | 
             
                      end
         | 
| 626 618 | 
             
                    end
         | 
| @@ -631,6 +623,7 @@ module ActiveRecord | |
| 631 623 | 
             
                    # with the current reflection's klass name.
         | 
| 632 624 | 
             
                    def valid_inverse_reflection?(reflection)
         | 
| 633 625 | 
             
                      reflection &&
         | 
| 626 | 
            +
                        foreign_key == reflection.foreign_key &&
         | 
| 634 627 | 
             
                        klass <= reflection.active_record &&
         | 
| 635 628 | 
             
                        can_find_inverse_of_automatically?(reflection)
         | 
| 636 629 | 
             
                    end
         | 
| @@ -684,10 +677,6 @@ module ActiveRecord | |
| 684 677 | 
             
                      Associations::HasManyAssociation
         | 
| 685 678 | 
             
                    end
         | 
| 686 679 | 
             
                  end
         | 
| 687 | 
            -
             | 
| 688 | 
            -
                  def association_primary_key(klass = nil)
         | 
| 689 | 
            -
                    primary_key(klass || self.klass)
         | 
| 690 | 
            -
                  end
         | 
| 691 680 | 
             
                end
         | 
| 692 681 |  | 
| 693 682 | 
             
                class HasOneReflection < AssociationReflection # :nodoc:
         | 
| @@ -704,7 +693,6 @@ module ActiveRecord | |
| 704 693 | 
             
                  end
         | 
| 705 694 |  | 
| 706 695 | 
             
                  private
         | 
| 707 | 
            -
             | 
| 708 696 | 
             
                    def calculate_constructable(macro, options)
         | 
| 709 697 | 
             
                      !options[:through]
         | 
| 710 698 | 
             
                    end
         | 
| @@ -723,6 +711,15 @@ module ActiveRecord | |
| 723 711 | 
             
                    end
         | 
| 724 712 | 
             
                  end
         | 
| 725 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 | 
            +
             | 
| 726 723 | 
             
                  def join_primary_key(klass = nil)
         | 
| 727 724 | 
             
                    polymorphic? ? association_primary_key(klass) : association_primary_key
         | 
| 728 725 | 
             
                  end
         | 
| @@ -731,6 +728,10 @@ module ActiveRecord | |
| 731 728 | 
             
                    foreign_key
         | 
| 732 729 | 
             
                  end
         | 
| 733 730 |  | 
| 731 | 
            +
                  def join_foreign_type
         | 
| 732 | 
            +
                    foreign_type
         | 
| 733 | 
            +
                  end
         | 
| 734 | 
            +
             | 
| 734 735 | 
             
                  private
         | 
| 735 736 | 
             
                    def can_find_inverse_of_automatically?(_)
         | 
| 736 737 | 
             
                      !polymorphic? && super
         | 
| @@ -752,8 +753,8 @@ module ActiveRecord | |
| 752 753 | 
             
                # Holds all the metadata about a :through association as it was specified
         | 
| 753 754 | 
             
                # in the Active Record class.
         | 
| 754 755 | 
             
                class ThroughReflection < AbstractReflection #:nodoc:
         | 
| 755 | 
            -
                  delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for,
         | 
| 756 | 
            -
                           :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
         | 
| 757 758 |  | 
| 758 759 | 
             
                  def initialize(delegate_reflection)
         | 
| 759 760 | 
             
                    @delegate_reflection = delegate_reflection
         | 
| @@ -839,8 +840,8 @@ module ActiveRecord | |
| 839 840 | 
             
                    source_reflection.scopes + super
         | 
| 840 841 | 
             
                  end
         | 
| 841 842 |  | 
| 842 | 
            -
                  def join_scopes(table, predicate_builder) # :nodoc:
         | 
| 843 | 
            -
                    source_reflection.join_scopes(table, predicate_builder) + super
         | 
| 843 | 
            +
                  def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
         | 
| 844 | 
            +
                    source_reflection.join_scopes(table, predicate_builder, klass) + super
         | 
| 844 845 | 
             
                  end
         | 
| 845 846 |  | 
| 846 847 | 
             
                  def has_scope?
         | 
| @@ -860,7 +861,15 @@ module ActiveRecord | |
| 860 861 | 
             
                  def association_primary_key(klass = nil)
         | 
| 861 862 | 
             
                    # Get the "actual" source reflection if the immediate source reflection has a
         | 
| 862 863 | 
             
                    # source reflection itself
         | 
| 863 | 
            -
                    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)
         | 
| 864 873 | 
             
                  end
         | 
| 865 874 |  | 
| 866 875 | 
             
                  # Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
         | 
| @@ -909,7 +918,7 @@ module ActiveRecord | |
| 909 918 |  | 
| 910 919 | 
             
                  def check_validity!
         | 
| 911 920 | 
             
                    if through_reflection.nil?
         | 
| 912 | 
            -
                      raise HasManyThroughAssociationNotFoundError.new(active_record | 
| 921 | 
            +
                      raise HasManyThroughAssociationNotFoundError.new(active_record, self)
         | 
| 913 922 | 
             
                    end
         | 
| 914 923 |  | 
| 915 924 | 
             
                    if through_reflection.polymorphic?
         | 
| @@ -965,16 +974,14 @@ module ActiveRecord | |
| 965 974 | 
             
                    collect_join_reflections(seed + [self])
         | 
| 966 975 | 
             
                  end
         | 
| 967 976 |  | 
| 968 | 
            -
                  # TODO Change this to private once we've dropped Ruby 2.2 support.
         | 
| 969 | 
            -
                  # Workaround for Ruby 2.2 "private attribute?" warning.
         | 
| 970 977 | 
             
                  protected
         | 
| 971 | 
            -
                    attr_reader :delegate_reflection
         | 
| 972 | 
            -
             | 
| 973 978 | 
             
                    def actual_source_reflection # FIXME: this is a horrible name
         | 
| 974 979 | 
             
                      source_reflection.actual_source_reflection
         | 
| 975 980 | 
             
                    end
         | 
| 976 981 |  | 
| 977 982 | 
             
                  private
         | 
| 983 | 
            +
                    attr_reader :delegate_reflection
         | 
| 984 | 
            +
             | 
| 978 985 | 
             
                    def collect_join_reflections(seed)
         | 
| 979 986 | 
             
                      a = source_reflection.add_as_source seed
         | 
| 980 987 | 
             
                      if options[:source_type]
         | 
| @@ -998,16 +1005,17 @@ module ActiveRecord | |
| 998 1005 | 
             
                end
         | 
| 999 1006 |  | 
| 1000 1007 | 
             
                class PolymorphicReflection < AbstractReflection # :nodoc:
         | 
| 1001 | 
            -
                  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
         | 
| 1002 1010 |  | 
| 1003 1011 | 
             
                  def initialize(reflection, previous_reflection)
         | 
| 1004 1012 | 
             
                    @reflection = reflection
         | 
| 1005 1013 | 
             
                    @previous_reflection = previous_reflection
         | 
| 1006 1014 | 
             
                  end
         | 
| 1007 1015 |  | 
| 1008 | 
            -
                  def join_scopes(table, predicate_builder) # :nodoc:
         | 
| 1016 | 
            +
                  def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
         | 
| 1009 1017 | 
             
                    scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
         | 
| 1010 | 
            -
                    scopes << build_scope(table, predicate_builder).instance_exec(nil, &source_type_scope)
         | 
| 1018 | 
            +
                    scopes << build_scope(table, predicate_builder, klass).instance_exec(nil, &source_type_scope)
         | 
| 1011 1019 | 
             
                  end
         | 
| 1012 1020 |  | 
| 1013 1021 | 
             
                  def constraints
         | 
| @@ -1023,7 +1031,7 @@ module ActiveRecord | |
| 1023 1031 | 
             
                end
         | 
| 1024 1032 |  | 
| 1025 1033 | 
             
                class RuntimeReflection < AbstractReflection # :nodoc:
         | 
| 1026 | 
            -
                  delegate :scope, :type, :constraints, : | 
| 1034 | 
            +
                  delegate :scope, :type, :constraints, :join_foreign_key, to: :@reflection
         | 
| 1027 1035 |  | 
| 1028 1036 | 
             
                  def initialize(reflection, association)
         | 
| 1029 1037 | 
             
                    @reflection = reflection
         | 
| @@ -1035,7 +1043,11 @@ module ActiveRecord | |
| 1035 1043 | 
             
                  end
         | 
| 1036 1044 |  | 
| 1037 1045 | 
             
                  def aliased_table
         | 
| 1038 | 
            -
                     | 
| 1046 | 
            +
                    klass.arel_table
         | 
| 1047 | 
            +
                  end
         | 
| 1048 | 
            +
             | 
| 1049 | 
            +
                  def join_primary_key(klass = self.klass)
         | 
| 1050 | 
            +
                    @reflection.join_primary_key(klass)
         | 
| 1039 1051 | 
             
                  end
         | 
| 1040 1052 |  | 
| 1041 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 |  | 
| @@ -251,27 +258,29 @@ module ActiveRecord | |
| 251 258 | 
             
                      end
         | 
| 252 259 | 
             
                    end
         | 
| 253 260 |  | 
| 254 | 
            -
                     | 
| 255 | 
            -
             | 
| 261 | 
            +
                    batch_relation = relation.where(
         | 
| 262 | 
            +
                      predicate_builder[primary_key, primary_key_offset, order == :desc ? :lt : :gt]
         | 
| 263 | 
            +
                    )
         | 
| 256 264 | 
             
                  end
         | 
| 257 265 | 
             
                end
         | 
| 258 266 |  | 
| 259 267 | 
             
                private
         | 
| 260 | 
            -
             | 
| 261 | 
            -
             | 
| 262 | 
            -
                    if  | 
| 263 | 
            -
                      attr = Relation::QueryAttribute.new(primary_key, start, klass.type_for_attribute(primary_key))
         | 
| 264 | 
            -
                      relation = relation.where(arel_attribute(primary_key).gteq(Arel::Nodes::BindParam.new(attr)))
         | 
| 265 | 
            -
                    end
         | 
| 266 | 
            -
                    if finish
         | 
| 267 | 
            -
                      attr = Relation::QueryAttribute.new(primary_key, finish, klass.type_for_attribute(primary_key))
         | 
| 268 | 
            -
                      relation = relation.where(arel_attribute(primary_key).lteq(Arel::Nodes::BindParam.new(attr)))
         | 
| 269 | 
            -
                    end
         | 
| 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
         | 
| 270 271 | 
             
                    relation
         | 
| 271 272 | 
             
                  end
         | 
| 272 273 |  | 
| 273 | 
            -
                  def  | 
| 274 | 
            -
                     | 
| 274 | 
            +
                  def apply_start_limit(relation, start, order)
         | 
| 275 | 
            +
                    relation.where(predicate_builder[primary_key, start, order == :desc ? :lteq : :gteq])
         | 
| 276 | 
            +
                  end
         | 
| 277 | 
            +
             | 
| 278 | 
            +
                  def apply_finish_limit(relation, finish, order)
         | 
| 279 | 
            +
                    relation.where(predicate_builder[primary_key, finish, order == :desc ? :gteq : :lteq])
         | 
| 280 | 
            +
                  end
         | 
| 281 | 
            +
             | 
| 282 | 
            +
                  def batch_order(order)
         | 
| 283 | 
            +
                    table[primary_key].public_send(order)
         | 
| 275 284 | 
             
                  end
         | 
| 276 285 |  | 
| 277 286 | 
             
                  def act_on_ignored_order(error_on_ignore)
         |