activerecord 4.2.0 → 5.2.8.1
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 +5 -5
- data/CHANGELOG.md +640 -928
- data/MIT-LICENSE +2 -2
- data/README.rdoc +10 -11
- data/examples/performance.rb +32 -31
- data/examples/simple.rb +5 -4
- data/lib/active_record/aggregations.rb +264 -247
- data/lib/active_record/association_relation.rb +24 -6
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +87 -41
- data/lib/active_record/associations/association_scope.rb +106 -132
- data/lib/active_record/associations/belongs_to_association.rb +55 -36
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +29 -38
- data/lib/active_record/associations/builder/belongs_to.rb +77 -30
- data/lib/active_record/associations/builder/collection_association.rb +14 -23
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
- data/lib/active_record/associations/builder/has_many.rb +6 -4
- data/lib/active_record/associations/builder/has_one.rb +13 -6
- data/lib/active_record/associations/builder/singular_association.rb +15 -11
- data/lib/active_record/associations/collection_association.rb +145 -266
- data/lib/active_record/associations/collection_proxy.rb +242 -138
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +35 -75
- data/lib/active_record/associations/has_many_through_association.rb +51 -69
- data/lib/active_record/associations/has_one_association.rb +39 -24
- data/lib/active_record/associations/has_one_through_association.rb +18 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
- data/lib/active_record/associations/join_dependency.rb +134 -154
- data/lib/active_record/associations/preloader/association.rb +85 -116
- data/lib/active_record/associations/preloader/through_association.rb +85 -74
- data/lib/active_record/associations/preloader.rb +83 -93
- data/lib/active_record/associations/singular_association.rb +27 -40
- data/lib/active_record/associations/through_association.rb +48 -23
- data/lib/active_record/associations.rb +1732 -1596
- data/lib/active_record/attribute_assignment.rb +58 -182
- data/lib/active_record/attribute_decorators.rb +39 -15
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -5
- data/lib/active_record/attribute_methods/dirty.rb +94 -125
- data/lib/active_record/attribute_methods/primary_key.rb +86 -71
- data/lib/active_record/attribute_methods/query.rb +4 -2
- data/lib/active_record/attribute_methods/read.rb +45 -63
- data/lib/active_record/attribute_methods/serialization.rb +40 -20
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
- data/lib/active_record/attribute_methods/write.rb +31 -46
- data/lib/active_record/attribute_methods.rb +170 -117
- data/lib/active_record/attributes.rb +201 -74
- data/lib/active_record/autosave_association.rb +118 -45
- data/lib/active_record/base.rb +60 -48
- data/lib/active_record/callbacks.rb +97 -57
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +37 -13
- data/lib/active_record/collection_cache_key.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
- data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
- data/lib/active_record/connection_adapters/column.rb +50 -41
- data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +42 -195
- data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +466 -280
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +439 -330
- data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -324
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +40 -27
- data/lib/active_record/core.rb +205 -202
- data/lib/active_record/counter_cache.rb +80 -37
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +136 -90
- data/lib/active_record/errors.rb +180 -52
- data/lib/active_record/explain.rb +23 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +35 -9
- data/lib/active_record/fixtures.rb +193 -135
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +148 -112
- data/lib/active_record/integration.rb +70 -28
- data/lib/active_record/internal_metadata.rb +45 -0
- data/lib/active_record/legacy_yaml_adapter.rb +48 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +92 -98
- data/lib/active_record/locking/pessimistic.rb +15 -3
- data/lib/active_record/log_subscriber.rb +95 -33
- data/lib/active_record/migration/command_recorder.rb +133 -90
- data/lib/active_record/migration/compatibility.rb +217 -0
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/migration.rb +594 -267
- data/lib/active_record/model_schema.rb +292 -111
- data/lib/active_record/nested_attributes.rb +266 -214
- data/lib/active_record/no_touching.rb +8 -2
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +350 -119
- data/lib/active_record/query_cache.rb +13 -24
- data/lib/active_record/querying.rb +19 -17
- data/lib/active_record/railtie.rb +117 -35
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +9 -3
- data/lib/active_record/railties/databases.rake +160 -174
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +447 -288
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +204 -55
- data/lib/active_record/relation/calculations.rb +259 -244
- data/lib/active_record/relation/delegation.rb +67 -60
- data/lib/active_record/relation/finder_methods.rb +290 -253
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +91 -68
- data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/predicate_builder.rb +118 -92
- data/lib/active_record/relation/query_attribute.rb +45 -0
- data/lib/active_record/relation/query_methods.rb +446 -389
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +18 -16
- data/lib/active_record/relation/where_clause.rb +186 -0
- data/lib/active_record/relation/where_clause_factory.rb +34 -0
- data/lib/active_record/relation.rb +287 -339
- data/lib/active_record/result.rb +54 -36
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +155 -124
- data/lib/active_record/schema.rb +30 -24
- data/lib/active_record/schema_dumper.rb +91 -87
- data/lib/active_record/schema_migration.rb +19 -19
- data/lib/active_record/scoping/default.rb +102 -84
- data/lib/active_record/scoping/named.rb +81 -32
- data/lib/active_record/scoping.rb +45 -26
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/statement_cache.rb +45 -35
- data/lib/active_record/store.rb +42 -36
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +82 -0
- data/lib/active_record/tasks/database_tasks.rb +136 -95
- data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
- data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
- data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
- data/lib/active_record/timestamp.rb +70 -38
- data/lib/active_record/touch_later.rb +64 -0
- data/lib/active_record/transactions.rb +208 -123
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +136 -0
- data/lib/active_record/type/date.rb +4 -41
- data/lib/active_record/type/date_time.rb +4 -38
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +30 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +11 -16
- data/lib/active_record/type/type_map.rb +15 -17
- data/lib/active_record/type/unsigned_integer.rb +9 -7
- data/lib/active_record/type.rb +79 -23
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +13 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +41 -32
- data/lib/active_record/validations.rb +38 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +36 -21
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -6
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
- data/lib/rails/generators/active_record/migration.rb +18 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +77 -53
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute.rb +0 -149
- data/lib/active_record/attribute_set/builder.rb +0 -86
- data/lib/active_record/attribute_set.rb +0 -77
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -30
- data/lib/active_record/type/decimal.rb +0 -40
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -55
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -36
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -101
- /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
| @@ -1,6 +1,10 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 3 | 
            -
            require  | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "active_record/relation/from_clause"
         | 
| 4 | 
            +
            require "active_record/relation/query_attribute"
         | 
| 5 | 
            +
            require "active_record/relation/where_clause"
         | 
| 6 | 
            +
            require "active_record/relation/where_clause_factory"
         | 
| 7 | 
            +
            require "active_model/forbidden_attributes_protection"
         | 
| 4 8 |  | 
| 5 9 | 
             
            module ActiveRecord
         | 
| 6 10 | 
             
              module QueryMethods
         | 
| @@ -11,6 +15,8 @@ module ActiveRecord | |
| 11 15 | 
             
                # WhereChain objects act as placeholder for queries in which #where does not have any parameter.
         | 
| 12 16 | 
             
                # In this case, #where must be chained with #not to return a new relation.
         | 
| 13 17 | 
             
                class WhereChain
         | 
| 18 | 
            +
                  include ActiveModel::ForbiddenAttributesProtection
         | 
| 19 | 
            +
             | 
| 14 20 | 
             
                  def initialize(scope)
         | 
| 15 21 | 
             
                    @scope = scope
         | 
| 16 22 | 
             
                  end
         | 
| @@ -18,7 +24,7 @@ module ActiveRecord | |
| 18 24 | 
             
                  # Returns a new relation expressing WHERE + NOT condition according to
         | 
| 19 25 | 
             
                  # the conditions in the arguments.
         | 
| 20 26 | 
             
                  #
         | 
| 21 | 
            -
                  #  | 
| 27 | 
            +
                  # #not accepts conditions as a string, array, or hash. See QueryMethods#where for
         | 
| 22 28 | 
             
                  # more details on each format.
         | 
| 23 29 | 
             
                  #
         | 
| 24 30 | 
             
                  #    User.where.not("name = 'Jon'")
         | 
| @@ -39,73 +45,37 @@ module ActiveRecord | |
| 39 45 | 
             
                  #    User.where.not(name: "Jon", role: "admin")
         | 
| 40 46 | 
             
                  #    # SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
         | 
| 41 47 | 
             
                  def not(opts, *rest)
         | 
| 42 | 
            -
                     | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
                        raise ArgumentError, 'Invalid argument for .where.not(), got nil.'
         | 
| 46 | 
            -
                      when Arel::Nodes::In
         | 
| 47 | 
            -
                        Arel::Nodes::NotIn.new(rel.left, rel.right)
         | 
| 48 | 
            -
                      when Arel::Nodes::Equality
         | 
| 49 | 
            -
                        Arel::Nodes::NotEqual.new(rel.left, rel.right)
         | 
| 50 | 
            -
                      when String
         | 
| 51 | 
            -
                        Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(rel))
         | 
| 52 | 
            -
                      else
         | 
| 53 | 
            -
                        Arel::Nodes::Not.new(rel)
         | 
| 54 | 
            -
                      end
         | 
| 55 | 
            -
                    end
         | 
| 48 | 
            +
                    opts = sanitize_forbidden_attributes(opts)
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                    where_clause = @scope.send(:where_clause_factory).build(opts, rest)
         | 
| 56 51 |  | 
| 57 52 | 
             
                    @scope.references!(PredicateBuilder.references(opts)) if Hash === opts
         | 
| 58 | 
            -
                    @scope. | 
| 53 | 
            +
                    @scope.where_clause += where_clause.invert
         | 
| 59 54 | 
             
                    @scope
         | 
| 60 55 | 
             
                  end
         | 
| 61 56 | 
             
                end
         | 
| 62 57 |  | 
| 63 | 
            -
                 | 
| 64 | 
            -
             | 
| 65 | 
            -
                    def #{name}_values                   # def select_values
         | 
| 66 | 
            -
                      @values[:#{name}] || []            #   @values[:select] || []
         | 
| 67 | 
            -
                    end                                  # end
         | 
| 68 | 
            -
                                                         #
         | 
| 69 | 
            -
                    def #{name}_values=(values)          # def select_values=(values)
         | 
| 70 | 
            -
                      raise ImmutableRelation if @loaded #   raise ImmutableRelation if @loaded
         | 
| 71 | 
            -
                      check_cached_relation
         | 
| 72 | 
            -
                      @values[:#{name}] = values         #   @values[:select] = values
         | 
| 73 | 
            -
                    end                                  # end
         | 
| 74 | 
            -
                  CODE
         | 
| 75 | 
            -
                end
         | 
| 58 | 
            +
                FROZEN_EMPTY_ARRAY = [].freeze
         | 
| 59 | 
            +
                FROZEN_EMPTY_HASH = {}.freeze
         | 
| 76 60 |  | 
| 77 | 
            -
                 | 
| 61 | 
            +
                Relation::VALUE_METHODS.each do |name|
         | 
| 62 | 
            +
                  method_name = \
         | 
| 63 | 
            +
                    case name
         | 
| 64 | 
            +
                    when *Relation::MULTI_VALUE_METHODS then "#{name}_values"
         | 
| 65 | 
            +
                    when *Relation::SINGLE_VALUE_METHODS then "#{name}_value"
         | 
| 66 | 
            +
                    when *Relation::CLAUSE_METHODS then "#{name}_clause"
         | 
| 67 | 
            +
                    end
         | 
| 78 68 | 
             
                  class_eval <<-CODE, __FILE__, __LINE__ + 1
         | 
| 79 | 
            -
                    def #{ | 
| 80 | 
            -
                       | 
| 69 | 
            +
                    def #{method_name}                   # def includes_values
         | 
| 70 | 
            +
                      get_value(#{name.inspect})         #   get_value(:includes)
         | 
| 81 71 | 
             
                    end                                  # end
         | 
| 82 | 
            -
                  CODE
         | 
| 83 | 
            -
                end
         | 
| 84 72 |  | 
| 85 | 
            -
             | 
| 86 | 
            -
             | 
| 87 | 
            -
                    def #{name}_value=(value)            # def readonly_value=(value)
         | 
| 88 | 
            -
                      raise ImmutableRelation if @loaded #   raise ImmutableRelation if @loaded
         | 
| 89 | 
            -
                      check_cached_relation
         | 
| 90 | 
            -
                      @values[:#{name}] = value          #   @values[:readonly] = value
         | 
| 73 | 
            +
                    def #{method_name}=(value)           # def includes_values=(value)
         | 
| 74 | 
            +
                      set_value(#{name.inspect}, value)  #   set_value(:includes, value)
         | 
| 91 75 | 
             
                    end                                  # end
         | 
| 92 76 | 
             
                  CODE
         | 
| 93 77 | 
             
                end
         | 
| 94 78 |  | 
| 95 | 
            -
                def check_cached_relation # :nodoc:
         | 
| 96 | 
            -
                  if defined?(@arel) && @arel
         | 
| 97 | 
            -
                    @arel = nil
         | 
| 98 | 
            -
                    ActiveSupport::Deprecation.warn(<<-MSG.squish)
         | 
| 99 | 
            -
                      Modifying already cached Relation. The cache will be reset. Use a
         | 
| 100 | 
            -
                      cloned Relation to prevent this warning.
         | 
| 101 | 
            -
                    MSG
         | 
| 102 | 
            -
                  end
         | 
| 103 | 
            -
                end
         | 
| 104 | 
            -
             | 
| 105 | 
            -
                def create_with_value # :nodoc:
         | 
| 106 | 
            -
                  @values[:create_with] || {}
         | 
| 107 | 
            -
                end
         | 
| 108 | 
            -
             | 
| 109 79 | 
             
                alias extensions extending_values
         | 
| 110 80 |  | 
| 111 81 | 
             
                # Specify relationships to be included in the result set. For
         | 
| @@ -118,7 +88,7 @@ module ActiveRecord | |
| 118 88 | 
             
                #
         | 
| 119 89 | 
             
                # allows you to access the +address+ attribute of the +User+ model without
         | 
| 120 90 | 
             
                # firing an additional query. This will often result in a
         | 
| 121 | 
            -
                # performance improvement over a simple  | 
| 91 | 
            +
                # performance improvement over a simple join.
         | 
| 122 92 | 
             
                #
         | 
| 123 93 | 
             
                # You can also specify multiple relationships, like this:
         | 
| 124 94 | 
             
                #
         | 
| @@ -139,7 +109,7 @@ module ActiveRecord | |
| 139 109 | 
             
                #
         | 
| 140 110 | 
             
                #   User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
         | 
| 141 111 | 
             
                #
         | 
| 142 | 
            -
                # Note that  | 
| 112 | 
            +
                # Note that #includes works with association names while #references needs
         | 
| 143 113 | 
             
                # the actual table name.
         | 
| 144 114 | 
             
                def includes(*args)
         | 
| 145 115 | 
             
                  check_if_method_has_arguments!(:includes, args)
         | 
| @@ -157,9 +127,9 @@ module ActiveRecord | |
| 157 127 | 
             
                # Forces eager loading by performing a LEFT OUTER JOIN on +args+:
         | 
| 158 128 | 
             
                #
         | 
| 159 129 | 
             
                #   User.eager_load(:posts)
         | 
| 160 | 
            -
                #    | 
| 161 | 
            -
                #   FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" =
         | 
| 162 | 
            -
                #   "users"."id"
         | 
| 130 | 
            +
                #   # SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, ...
         | 
| 131 | 
            +
                #   # FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" =
         | 
| 132 | 
            +
                #   # "users"."id"
         | 
| 163 133 | 
             
                def eager_load(*args)
         | 
| 164 134 | 
             
                  check_if_method_has_arguments!(:eager_load, args)
         | 
| 165 135 | 
             
                  spawn.eager_load!(*args)
         | 
| @@ -170,10 +140,10 @@ module ActiveRecord | |
| 170 140 | 
             
                  self
         | 
| 171 141 | 
             
                end
         | 
| 172 142 |  | 
| 173 | 
            -
                # Allows preloading of +args+, in the same way that  | 
| 143 | 
            +
                # Allows preloading of +args+, in the same way that #includes does:
         | 
| 174 144 | 
             
                #
         | 
| 175 145 | 
             
                #   User.preload(:posts)
         | 
| 176 | 
            -
                #    | 
| 146 | 
            +
                #   # SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (1, 2, 3)
         | 
| 177 147 | 
             
                def preload(*args)
         | 
| 178 148 | 
             
                  check_if_method_has_arguments!(:preload, args)
         | 
| 179 149 | 
             
                  spawn.preload!(*args)
         | 
| @@ -186,14 +156,14 @@ module ActiveRecord | |
| 186 156 |  | 
| 187 157 | 
             
                # Use to indicate that the given +table_names+ are referenced by an SQL string,
         | 
| 188 158 | 
             
                # and should therefore be JOINed in any query rather than loaded separately.
         | 
| 189 | 
            -
                # This method only works in conjunction with  | 
| 159 | 
            +
                # This method only works in conjunction with #includes.
         | 
| 190 160 | 
             
                # See #includes for more details.
         | 
| 191 161 | 
             
                #
         | 
| 192 162 | 
             
                #   User.includes(:posts).where("posts.name = 'foo'")
         | 
| 193 | 
            -
                #   #  | 
| 163 | 
            +
                #   # Doesn't JOIN the posts table, resulting in an error.
         | 
| 194 164 | 
             
                #
         | 
| 195 165 | 
             
                #   User.includes(:posts).where("posts.name = 'foo'").references(:posts)
         | 
| 196 | 
            -
                #   #  | 
| 166 | 
            +
                #   # Query now knows the string references posts, so adds a JOIN
         | 
| 197 167 | 
             
                def references(*table_names)
         | 
| 198 168 | 
             
                  check_if_method_has_arguments!(:references, table_names)
         | 
| 199 169 | 
             
                  spawn.references!(*table_names)
         | 
| @@ -209,12 +179,13 @@ module ActiveRecord | |
| 209 179 |  | 
| 210 180 | 
             
                # Works in two unique ways.
         | 
| 211 181 | 
             
                #
         | 
| 212 | 
            -
                # First: takes a block so it can be used just like Array#select | 
| 182 | 
            +
                # First: takes a block so it can be used just like <tt>Array#select</tt>.
         | 
| 213 183 | 
             
                #
         | 
| 214 184 | 
             
                #   Model.all.select { |m| m.field == value }
         | 
| 215 185 | 
             
                #
         | 
| 216 186 | 
             
                # This will build an array of objects from the database for the scope,
         | 
| 217 | 
            -
                # converting them into an array and iterating through them using | 
| 187 | 
            +
                # converting them into an array and iterating through them using
         | 
| 188 | 
            +
                # <tt>Array#select</tt>.
         | 
| 218 189 | 
             
                #
         | 
| 219 190 | 
             
                # Second: Modifies the SELECT statement for the query so that only certain
         | 
| 220 191 | 
             
                # fields are retrieved:
         | 
| @@ -242,24 +213,25 @@ module ActiveRecord | |
| 242 213 | 
             
                #   # => "value"
         | 
| 243 214 | 
             
                #
         | 
| 244 215 | 
             
                # Accessing attributes of an object that do not have fields retrieved by a select
         | 
| 245 | 
            -
                # except +id+ will throw  | 
| 216 | 
            +
                # except +id+ will throw ActiveModel::MissingAttributeError:
         | 
| 246 217 | 
             
                #
         | 
| 247 218 | 
             
                #   Model.select(:field).first.other_field
         | 
| 248 219 | 
             
                #   # => ActiveModel::MissingAttributeError: missing attribute: other_field
         | 
| 249 220 | 
             
                def select(*fields)
         | 
| 250 221 | 
             
                  if block_given?
         | 
| 251 | 
            -
                     | 
| 252 | 
            -
             | 
| 253 | 
            -
                     | 
| 254 | 
            -
             | 
| 222 | 
            +
                    if fields.any?
         | 
| 223 | 
            +
                      raise ArgumentError, "`select' with block doesn't take arguments."
         | 
| 224 | 
            +
                    end
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                    return super()
         | 
| 255 227 | 
             
                  end
         | 
| 228 | 
            +
             | 
| 229 | 
            +
                  raise ArgumentError, "Call `select' with at least one field" if fields.empty?
         | 
| 230 | 
            +
                  spawn._select!(*fields)
         | 
| 256 231 | 
             
                end
         | 
| 257 232 |  | 
| 258 233 | 
             
                def _select!(*fields) # :nodoc:
         | 
| 259 234 | 
             
                  fields.flatten!
         | 
| 260 | 
            -
                  fields.map! do |field|
         | 
| 261 | 
            -
                    klass.attribute_alias?(field) ? klass.attribute_alias(field) : field
         | 
| 262 | 
            -
                  end
         | 
| 263 235 | 
             
                  self.select_values += fields
         | 
| 264 236 | 
             
                  self
         | 
| 265 237 | 
             
                end
         | 
| @@ -267,22 +239,23 @@ module ActiveRecord | |
| 267 239 | 
             
                # Allows to specify a group attribute:
         | 
| 268 240 | 
             
                #
         | 
| 269 241 | 
             
                #   User.group(:name)
         | 
| 270 | 
            -
                #    | 
| 242 | 
            +
                #   # SELECT "users".* FROM "users" GROUP BY name
         | 
| 271 243 | 
             
                #
         | 
| 272 244 | 
             
                # Returns an array with distinct records based on the +group+ attribute:
         | 
| 273 245 | 
             
                #
         | 
| 274 246 | 
             
                #   User.select([:id, :name])
         | 
| 275 | 
            -
                #   => [#<User id: 1, name: "Oscar">, #<User id: 2, name: "Oscar">, #<User id: 3, name: "Foo">
         | 
| 247 | 
            +
                #   # => [#<User id: 1, name: "Oscar">, #<User id: 2, name: "Oscar">, #<User id: 3, name: "Foo">]
         | 
| 276 248 | 
             
                #
         | 
| 277 249 | 
             
                #   User.group(:name)
         | 
| 278 | 
            -
                #   => [#<User id: 3, name: "Foo", ...>, #<User id: 2, name: "Oscar", ...>]
         | 
| 250 | 
            +
                #   # => [#<User id: 3, name: "Foo", ...>, #<User id: 2, name: "Oscar", ...>]
         | 
| 279 251 | 
             
                #
         | 
| 280 252 | 
             
                #   User.group('name AS grouped_name, age')
         | 
| 281 | 
            -
                #   => [#<User id: 3, name: "Foo", age: 21, ...>, #<User id: 2, name: "Oscar", age: 21, ...>, #<User id: 5, name: "Foo", age: 23, ...>]
         | 
| 253 | 
            +
                #   # => [#<User id: 3, name: "Foo", age: 21, ...>, #<User id: 2, name: "Oscar", age: 21, ...>, #<User id: 5, name: "Foo", age: 23, ...>]
         | 
| 282 254 | 
             
                #
         | 
| 283 255 | 
             
                # Passing in an array of attributes to group by is also supported.
         | 
| 256 | 
            +
                #
         | 
| 284 257 | 
             
                #   User.select([:id, :first_name]).group(:id, :first_name).first(3)
         | 
| 285 | 
            -
                #   => [#<User id: 1, first_name: "Bill">, #<User id: 2, first_name: "Earl">, #<User id: 3, first_name: "Beto">]
         | 
| 258 | 
            +
                #   # => [#<User id: 1, first_name: "Bill">, #<User id: 2, first_name: "Earl">, #<User id: 3, first_name: "Beto">]
         | 
| 286 259 | 
             
                def group(*args)
         | 
| 287 260 | 
             
                  check_if_method_has_arguments!(:group, args)
         | 
| 288 261 | 
             
                  spawn.group!(*args)
         | 
| @@ -298,27 +271,28 @@ module ActiveRecord | |
| 298 271 | 
             
                # Allows to specify an order attribute:
         | 
| 299 272 | 
             
                #
         | 
| 300 273 | 
             
                #   User.order(:name)
         | 
| 301 | 
            -
                #    | 
| 274 | 
            +
                #   # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC
         | 
| 302 275 | 
             
                #
         | 
| 303 276 | 
             
                #   User.order(email: :desc)
         | 
| 304 | 
            -
                #    | 
| 277 | 
            +
                #   # SELECT "users".* FROM "users" ORDER BY "users"."email" DESC
         | 
| 305 278 | 
             
                #
         | 
| 306 279 | 
             
                #   User.order(:name, email: :desc)
         | 
| 307 | 
            -
                #    | 
| 280 | 
            +
                #   # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
         | 
| 308 281 | 
             
                #
         | 
| 309 282 | 
             
                #   User.order('name')
         | 
| 310 | 
            -
                #    | 
| 283 | 
            +
                #   # SELECT "users".* FROM "users" ORDER BY name
         | 
| 311 284 | 
             
                #
         | 
| 312 285 | 
             
                #   User.order('name DESC')
         | 
| 313 | 
            -
                #    | 
| 286 | 
            +
                #   # SELECT "users".* FROM "users" ORDER BY name DESC
         | 
| 314 287 | 
             
                #
         | 
| 315 288 | 
             
                #   User.order('name DESC, email')
         | 
| 316 | 
            -
                #    | 
| 289 | 
            +
                #   # SELECT "users".* FROM "users" ORDER BY name DESC, email
         | 
| 317 290 | 
             
                def order(*args)
         | 
| 318 291 | 
             
                  check_if_method_has_arguments!(:order, args)
         | 
| 319 292 | 
             
                  spawn.order!(*args)
         | 
| 320 293 | 
             
                end
         | 
| 321 294 |  | 
| 295 | 
            +
                # Same as #order but operates on relation in-place instead of copying.
         | 
| 322 296 | 
             
                def order!(*args) # :nodoc:
         | 
| 323 297 | 
             
                  preprocess_order_args(args)
         | 
| 324 298 |  | 
| @@ -340,6 +314,7 @@ module ActiveRecord | |
| 340 314 | 
             
                  spawn.reorder!(*args)
         | 
| 341 315 | 
             
                end
         | 
| 342 316 |  | 
| 317 | 
            +
                # Same as #reorder but operates on relation in-place instead of copying.
         | 
| 343 318 | 
             
                def reorder!(*args) # :nodoc:
         | 
| 344 319 | 
             
                  preprocess_order_args(args)
         | 
| 345 320 |  | 
| @@ -349,8 +324,8 @@ module ActiveRecord | |
| 349 324 | 
             
                end
         | 
| 350 325 |  | 
| 351 326 | 
             
                VALID_UNSCOPING_VALUES = Set.new([:where, :select, :group, :order, :lock,
         | 
| 352 | 
            -
                                                 :limit, :offset, :joins, : | 
| 353 | 
            -
                                                 :readonly, :having])
         | 
| 327 | 
            +
                                                 :limit, :offset, :joins, :left_outer_joins,
         | 
| 328 | 
            +
                                                 :includes, :from, :readonly, :having])
         | 
| 354 329 |  | 
| 355 330 | 
             
                # Removes an unwanted relation that is already defined on a chain of relations.
         | 
| 356 331 | 
             
                # This is useful when passing around chains of relations and would like to
         | 
| @@ -365,15 +340,15 @@ module ActiveRecord | |
| 365 340 | 
             
                #   User.order('email DESC').select('id').where(name: "John")
         | 
| 366 341 | 
             
                #       .unscope(:order, :select, :where) == User.all
         | 
| 367 342 | 
             
                #
         | 
| 368 | 
            -
                # One can additionally pass a hash as an argument to unscope specific  | 
| 343 | 
            +
                # One can additionally pass a hash as an argument to unscope specific +:where+ values.
         | 
| 369 344 | 
             
                # This is done by passing a hash with a single key-value pair. The key should be
         | 
| 370 | 
            -
                #  | 
| 345 | 
            +
                # +:where+ and the value should be the where value to unscope. For example:
         | 
| 371 346 | 
             
                #
         | 
| 372 347 | 
             
                #   User.where(name: "John", active: true).unscope(where: :name)
         | 
| 373 348 | 
             
                #       == User.where(active: true)
         | 
| 374 349 | 
             
                #
         | 
| 375 | 
            -
                # This method is similar to  | 
| 376 | 
            -
                #  | 
| 350 | 
            +
                # This method is similar to #except, but unlike
         | 
| 351 | 
            +
                # #except, it persists across merges:
         | 
| 377 352 | 
             
                #
         | 
| 378 353 | 
             
                #   User.order('email').merge(User.except(:order))
         | 
| 379 354 | 
             
                #       == User.order('email')
         | 
| @@ -383,7 +358,7 @@ module ActiveRecord | |
| 383 358 | 
             
                #
         | 
| 384 359 | 
             
                # This means it can be used in association definitions:
         | 
| 385 360 | 
             
                #
         | 
| 386 | 
            -
                #   has_many :comments, -> { unscope | 
| 361 | 
            +
                #   has_many :comments, -> { unscope(where: :trashed) }
         | 
| 387 362 | 
             
                #
         | 
| 388 363 | 
             
                def unscope(*args)
         | 
| 389 364 | 
             
                  check_if_method_has_arguments!(:unscope, args)
         | 
| @@ -397,16 +372,19 @@ module ActiveRecord | |
| 397 372 | 
             
                  args.each do |scope|
         | 
| 398 373 | 
             
                    case scope
         | 
| 399 374 | 
             
                    when Symbol
         | 
| 400 | 
            -
                       | 
| 375 | 
            +
                      scope = :left_outer_joins if scope == :left_joins
         | 
| 376 | 
            +
                      if !VALID_UNSCOPING_VALUES.include?(scope)
         | 
| 377 | 
            +
                        raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
         | 
| 378 | 
            +
                      end
         | 
| 379 | 
            +
                      set_value(scope, DEFAULT_VALUES[scope])
         | 
| 401 380 | 
             
                    when Hash
         | 
| 402 381 | 
             
                      scope.each do |key, target_value|
         | 
| 403 382 | 
             
                        if key != :where
         | 
| 404 383 | 
             
                          raise ArgumentError, "Hash arguments in .unscope(*args) must have :where as the key."
         | 
| 405 384 | 
             
                        end
         | 
| 406 385 |  | 
| 407 | 
            -
                        Array(target_value). | 
| 408 | 
            -
             | 
| 409 | 
            -
                        end
         | 
| 386 | 
            +
                        target_values = Array(target_value).map(&:to_s)
         | 
| 387 | 
            +
                        self.where_clause = where_clause.except(*target_values)
         | 
| 410 388 | 
             
                      end
         | 
| 411 389 | 
             
                    else
         | 
| 412 390 | 
             
                      raise ArgumentError, "Unrecognized scoping: #{args.inspect}. Use .unscope(where: :attribute_name) or .unscope(:order), for example."
         | 
| @@ -416,15 +394,35 @@ module ActiveRecord | |
| 416 394 | 
             
                  self
         | 
| 417 395 | 
             
                end
         | 
| 418 396 |  | 
| 419 | 
            -
                # Performs a joins on +args | 
| 397 | 
            +
                # Performs a joins on +args+. The given symbol(s) should match the name of
         | 
| 398 | 
            +
                # the association(s).
         | 
| 420 399 | 
             
                #
         | 
| 421 400 | 
             
                #   User.joins(:posts)
         | 
| 422 | 
            -
                #    | 
| 401 | 
            +
                #   # SELECT "users".*
         | 
| 402 | 
            +
                #   # FROM "users"
         | 
| 403 | 
            +
                #   # INNER JOIN "posts" ON "posts"."user_id" = "users"."id"
         | 
| 404 | 
            +
                #
         | 
| 405 | 
            +
                # Multiple joins:
         | 
| 406 | 
            +
                #
         | 
| 407 | 
            +
                #   User.joins(:posts, :account)
         | 
| 408 | 
            +
                #   # SELECT "users".*
         | 
| 409 | 
            +
                #   # FROM "users"
         | 
| 410 | 
            +
                #   # INNER JOIN "posts" ON "posts"."user_id" = "users"."id"
         | 
| 411 | 
            +
                #   # INNER JOIN "accounts" ON "accounts"."id" = "users"."account_id"
         | 
| 412 | 
            +
                #
         | 
| 413 | 
            +
                # Nested joins:
         | 
| 414 | 
            +
                #
         | 
| 415 | 
            +
                #   User.joins(posts: [:comments])
         | 
| 416 | 
            +
                #   # SELECT "users".*
         | 
| 417 | 
            +
                #   # FROM "users"
         | 
| 418 | 
            +
                #   # INNER JOIN "posts" ON "posts"."user_id" = "users"."id"
         | 
| 419 | 
            +
                #   # INNER JOIN "comments" "comments_posts"
         | 
| 420 | 
            +
                #   #   ON "comments_posts"."post_id" = "posts"."id"
         | 
| 423 421 | 
             
                #
         | 
| 424 422 | 
             
                # You can use strings in order to customize your joins:
         | 
| 425 423 | 
             
                #
         | 
| 426 424 | 
             
                #   User.joins("LEFT JOIN bookmarks ON bookmarks.bookmarkable_type = 'Post' AND bookmarks.user_id = users.id")
         | 
| 427 | 
            -
                #    | 
| 425 | 
            +
                #   # SELECT "users".* FROM "users" LEFT JOIN bookmarks ON bookmarks.bookmarkable_type = 'Post' AND bookmarks.user_id = users.id
         | 
| 428 426 | 
             
                def joins(*args)
         | 
| 429 427 | 
             
                  check_if_method_has_arguments!(:joins, args)
         | 
| 430 428 | 
             
                  spawn.joins!(*args)
         | 
| @@ -437,12 +435,21 @@ module ActiveRecord | |
| 437 435 | 
             
                  self
         | 
| 438 436 | 
             
                end
         | 
| 439 437 |  | 
| 440 | 
            -
                 | 
| 441 | 
            -
             | 
| 438 | 
            +
                # Performs a left outer joins on +args+:
         | 
| 439 | 
            +
                #
         | 
| 440 | 
            +
                #   User.left_outer_joins(:posts)
         | 
| 441 | 
            +
                #   => SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
         | 
| 442 | 
            +
                #
         | 
| 443 | 
            +
                def left_outer_joins(*args)
         | 
| 444 | 
            +
                  check_if_method_has_arguments!(__callee__, args)
         | 
| 445 | 
            +
                  spawn.left_outer_joins!(*args)
         | 
| 442 446 | 
             
                end
         | 
| 447 | 
            +
                alias :left_joins :left_outer_joins
         | 
| 443 448 |  | 
| 444 | 
            -
                def  | 
| 445 | 
            -
                   | 
| 449 | 
            +
                def left_outer_joins!(*args) # :nodoc:
         | 
| 450 | 
            +
                  args.compact!
         | 
| 451 | 
            +
                  args.flatten!
         | 
| 452 | 
            +
                  self.left_outer_joins_values += args
         | 
| 446 453 | 
             
                  self
         | 
| 447 454 | 
             
                end
         | 
| 448 455 |  | 
| @@ -489,7 +496,7 @@ module ActiveRecord | |
| 489 496 | 
             
                # than the previous methods; you are responsible for ensuring that the values in the template
         | 
| 490 497 | 
             
                # are properly quoted. The values are passed to the connector for quoting, but the caller
         | 
| 491 498 | 
             
                # is responsible for ensuring they are enclosed in quotes in the resulting SQL. After quoting,
         | 
| 492 | 
            -
                # the values are inserted using the same escapes as the Ruby core method  | 
| 499 | 
            +
                # the values are inserted using the same escapes as the Ruby core method +Kernel::sprintf+.
         | 
| 493 500 | 
             
                #
         | 
| 494 501 | 
             
                #   User.where(["name = '%s' and email = '%s'", "Joe", "joe@example.com"])
         | 
| 495 502 | 
             
                #   # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com';
         | 
| @@ -566,7 +573,7 @@ module ActiveRecord | |
| 566 573 | 
             
                # If the condition is any blank-ish object, then #where is a no-op and returns
         | 
| 567 574 | 
             
                # the current relation.
         | 
| 568 575 | 
             
                def where(opts = :chain, *rest)
         | 
| 569 | 
            -
                  if  | 
| 576 | 
            +
                  if :chain == opts
         | 
| 570 577 | 
             
                    WhereChain.new(spawn)
         | 
| 571 578 | 
             
                  elsif opts.blank?
         | 
| 572 579 | 
             
                    self
         | 
| @@ -576,27 +583,61 @@ module ActiveRecord | |
| 576 583 | 
             
                end
         | 
| 577 584 |  | 
| 578 585 | 
             
                def where!(opts, *rest) # :nodoc:
         | 
| 579 | 
            -
                   | 
| 580 | 
            -
             | 
| 581 | 
            -
             | 
| 582 | 
            -
                  end
         | 
| 583 | 
            -
             | 
| 584 | 
            -
                  self.where_values += build_where(opts, rest)
         | 
| 586 | 
            +
                  opts = sanitize_forbidden_attributes(opts)
         | 
| 587 | 
            +
                  references!(PredicateBuilder.references(opts)) if Hash === opts
         | 
| 588 | 
            +
                  self.where_clause += where_clause_factory.build(opts, rest)
         | 
| 585 589 | 
             
                  self
         | 
| 586 590 | 
             
                end
         | 
| 587 591 |  | 
| 588 592 | 
             
                # Allows you to change a previously set where condition for a given attribute, instead of appending to that condition.
         | 
| 589 593 | 
             
                #
         | 
| 590 | 
            -
                #   Post.where(trashed: true).where(trashed: false) | 
| 591 | 
            -
                #    | 
| 592 | 
            -
                #   Post.where(active: true).where(trashed: true).rewhere(trashed: false) # => WHERE `active` = 1 AND `trashed` = 0
         | 
| 594 | 
            +
                #   Post.where(trashed: true).where(trashed: false)
         | 
| 595 | 
            +
                #   # WHERE `trashed` = 1 AND `trashed` = 0
         | 
| 593 596 | 
             
                #
         | 
| 594 | 
            -
                # | 
| 595 | 
            -
                #  | 
| 597 | 
            +
                #   Post.where(trashed: true).rewhere(trashed: false)
         | 
| 598 | 
            +
                #   # WHERE `trashed` = 0
         | 
| 599 | 
            +
                #
         | 
| 600 | 
            +
                #   Post.where(active: true).where(trashed: true).rewhere(trashed: false)
         | 
| 601 | 
            +
                #   # WHERE `active` = 1 AND `trashed` = 0
         | 
| 602 | 
            +
                #
         | 
| 603 | 
            +
                # This is short-hand for <tt>unscope(where: conditions.keys).where(conditions)</tt>.
         | 
| 604 | 
            +
                # Note that unlike reorder, we're only unscoping the named conditions -- not the entire where statement.
         | 
| 596 605 | 
             
                def rewhere(conditions)
         | 
| 597 606 | 
             
                  unscope(where: conditions.keys).where(conditions)
         | 
| 598 607 | 
             
                end
         | 
| 599 608 |  | 
| 609 | 
            +
                # Returns a new relation, which is the logical union of this relation and the one passed as an
         | 
| 610 | 
            +
                # argument.
         | 
| 611 | 
            +
                #
         | 
| 612 | 
            +
                # The two relations must be structurally compatible: they must be scoping the same model, and
         | 
| 613 | 
            +
                # they must differ only by #where (if no #group has been defined) or #having (if a #group is
         | 
| 614 | 
            +
                # present). Neither relation may have a #limit, #offset, or #distinct set.
         | 
| 615 | 
            +
                #
         | 
| 616 | 
            +
                #    Post.where("id = 1").or(Post.where("author_id = 3"))
         | 
| 617 | 
            +
                #    # SELECT `posts`.* FROM `posts` WHERE ((id = 1) OR (author_id = 3))
         | 
| 618 | 
            +
                #
         | 
| 619 | 
            +
                def or(other)
         | 
| 620 | 
            +
                  unless other.is_a? Relation
         | 
| 621 | 
            +
                    raise ArgumentError, "You have passed #{other.class.name} object to #or. Pass an ActiveRecord::Relation object instead."
         | 
| 622 | 
            +
                  end
         | 
| 623 | 
            +
             | 
| 624 | 
            +
                  spawn.or!(other)
         | 
| 625 | 
            +
                end
         | 
| 626 | 
            +
             | 
| 627 | 
            +
                def or!(other) # :nodoc:
         | 
| 628 | 
            +
                  incompatible_values = structurally_incompatible_values_for_or(other)
         | 
| 629 | 
            +
             | 
| 630 | 
            +
                  unless incompatible_values.empty?
         | 
| 631 | 
            +
                    raise ArgumentError, "Relation passed to #or must be structurally compatible. Incompatible values: #{incompatible_values}"
         | 
| 632 | 
            +
                  end
         | 
| 633 | 
            +
             | 
| 634 | 
            +
                  self.where_clause = self.where_clause.or(other.where_clause)
         | 
| 635 | 
            +
                  self.having_clause = having_clause.or(other.having_clause)
         | 
| 636 | 
            +
                  self.references_values += other.references_values
         | 
| 637 | 
            +
             | 
| 638 | 
            +
                  self
         | 
| 639 | 
            +
                end
         | 
| 640 | 
            +
             | 
| 600 641 | 
             
                # Allows to specify a HAVING clause. Note that you can't use HAVING
         | 
| 601 642 | 
             
                # without also specifying a GROUP clause.
         | 
| 602 643 | 
             
                #
         | 
| @@ -606,9 +647,10 @@ module ActiveRecord | |
| 606 647 | 
             
                end
         | 
| 607 648 |  | 
| 608 649 | 
             
                def having!(opts, *rest) # :nodoc:
         | 
| 650 | 
            +
                  opts = sanitize_forbidden_attributes(opts)
         | 
| 609 651 | 
             
                  references!(PredicateBuilder.references(opts)) if Hash === opts
         | 
| 610 652 |  | 
| 611 | 
            -
                  self. | 
| 653 | 
            +
                  self.having_clause += having_clause_factory.build(opts, rest)
         | 
| 612 654 | 
             
                  self
         | 
| 613 655 | 
             
                end
         | 
| 614 656 |  | 
| @@ -643,7 +685,7 @@ module ActiveRecord | |
| 643 685 | 
             
                end
         | 
| 644 686 |  | 
| 645 687 | 
             
                # Specifies locking settings (default to +true+). For more information
         | 
| 646 | 
            -
                # on locking, please see  | 
| 688 | 
            +
                # on locking, please see ActiveRecord::Locking.
         | 
| 647 689 | 
             
                def lock(locks = true)
         | 
| 648 690 | 
             
                  spawn.lock!(locks)
         | 
| 649 691 | 
             
                end
         | 
| @@ -674,7 +716,7 @@ module ActiveRecord | |
| 674 716 | 
             
                # For example:
         | 
| 675 717 | 
             
                #
         | 
| 676 718 | 
             
                #   @posts = current_user.visible_posts.where(name: params[:name])
         | 
| 677 | 
            -
                #   #  | 
| 719 | 
            +
                #   # the visible_posts method is expected to return a chainable Relation
         | 
| 678 720 | 
             
                #
         | 
| 679 721 | 
             
                #   def visible_posts
         | 
| 680 722 | 
             
                #     case role
         | 
| @@ -688,7 +730,7 @@ module ActiveRecord | |
| 688 730 | 
             
                #   end
         | 
| 689 731 | 
             
                #
         | 
| 690 732 | 
             
                def none
         | 
| 691 | 
            -
                   | 
| 733 | 
            +
                  spawn.none!
         | 
| 692 734 | 
             
                end
         | 
| 693 735 |  | 
| 694 736 | 
             
                def none! # :nodoc:
         | 
| @@ -700,7 +742,7 @@ module ActiveRecord | |
| 700 742 | 
             
                #
         | 
| 701 743 | 
             
                #   users = User.readonly
         | 
| 702 744 | 
             
                #   users.first.save
         | 
| 703 | 
            -
                #   => ActiveRecord::ReadOnlyRecord:  | 
| 745 | 
            +
                #   => ActiveRecord::ReadOnlyRecord: User is marked as readonly
         | 
| 704 746 | 
             
                def readonly(value = true)
         | 
| 705 747 | 
             
                  spawn.readonly!(value)
         | 
| 706 748 | 
             
                end
         | 
| @@ -719,7 +761,7 @@ module ActiveRecord | |
| 719 761 | 
             
                #   users = users.create_with(name: 'DHH')
         | 
| 720 762 | 
             
                #   users.new.name # => 'DHH'
         | 
| 721 763 | 
             
                #
         | 
| 722 | 
            -
                # You can pass +nil+ to  | 
| 764 | 
            +
                # You can pass +nil+ to #create_with to reset attributes:
         | 
| 723 765 | 
             
                #
         | 
| 724 766 | 
             
                #   users = users.create_with(nil)
         | 
| 725 767 | 
             
                #   users.new.name # => 'Oscar'
         | 
| @@ -732,7 +774,7 @@ module ActiveRecord | |
| 732 774 | 
             
                    value = sanitize_forbidden_attributes(value)
         | 
| 733 775 | 
             
                    self.create_with_value = create_with_value.merge(value)
         | 
| 734 776 | 
             
                  else
         | 
| 735 | 
            -
                    self.create_with_value =  | 
| 777 | 
            +
                    self.create_with_value = FROZEN_EMPTY_HASH
         | 
| 736 778 | 
             
                  end
         | 
| 737 779 |  | 
| 738 780 | 
             
                  self
         | 
| @@ -741,46 +783,44 @@ module ActiveRecord | |
| 741 783 | 
             
                # Specifies table from which the records will be fetched. For example:
         | 
| 742 784 | 
             
                #
         | 
| 743 785 | 
             
                #   Topic.select('title').from('posts')
         | 
| 744 | 
            -
                #   #  | 
| 786 | 
            +
                #   # SELECT title FROM posts
         | 
| 745 787 | 
             
                #
         | 
| 746 788 | 
             
                # Can accept other relation objects. For example:
         | 
| 747 789 | 
             
                #
         | 
| 748 790 | 
             
                #   Topic.select('title').from(Topic.approved)
         | 
| 749 | 
            -
                #   #  | 
| 791 | 
            +
                #   # SELECT title FROM (SELECT * FROM topics WHERE approved = 't') subquery
         | 
| 750 792 | 
             
                #
         | 
| 751 793 | 
             
                #   Topic.select('a.title').from(Topic.approved, :a)
         | 
| 752 | 
            -
                #   #  | 
| 794 | 
            +
                #   # SELECT a.title FROM (SELECT * FROM topics WHERE approved = 't') a
         | 
| 753 795 | 
             
                #
         | 
| 754 796 | 
             
                def from(value, subquery_name = nil)
         | 
| 755 797 | 
             
                  spawn.from!(value, subquery_name)
         | 
| 756 798 | 
             
                end
         | 
| 757 799 |  | 
| 758 800 | 
             
                def from!(value, subquery_name = nil) # :nodoc:
         | 
| 759 | 
            -
                  self. | 
| 801 | 
            +
                  self.from_clause = Relation::FromClause.new(value, subquery_name)
         | 
| 760 802 | 
             
                  self
         | 
| 761 803 | 
             
                end
         | 
| 762 804 |  | 
| 763 805 | 
             
                # Specifies whether the records should be unique or not. For example:
         | 
| 764 806 | 
             
                #
         | 
| 765 807 | 
             
                #   User.select(:name)
         | 
| 766 | 
            -
                #   #  | 
| 808 | 
            +
                #   # Might return two records with the same name
         | 
| 767 809 | 
             
                #
         | 
| 768 810 | 
             
                #   User.select(:name).distinct
         | 
| 769 | 
            -
                #   #  | 
| 811 | 
            +
                #   # Returns 1 record per distinct name
         | 
| 770 812 | 
             
                #
         | 
| 771 813 | 
             
                #   User.select(:name).distinct.distinct(false)
         | 
| 772 | 
            -
                #   #  | 
| 814 | 
            +
                #   # You can also remove the uniqueness
         | 
| 773 815 | 
             
                def distinct(value = true)
         | 
| 774 816 | 
             
                  spawn.distinct!(value)
         | 
| 775 817 | 
             
                end
         | 
| 776 | 
            -
                alias uniq distinct
         | 
| 777 818 |  | 
| 778 819 | 
             
                # Like #distinct, but modifies relation in place.
         | 
| 779 820 | 
             
                def distinct!(value = true) # :nodoc:
         | 
| 780 821 | 
             
                  self.distinct_value = value
         | 
| 781 822 | 
             
                  self
         | 
| 782 823 | 
             
                end
         | 
| 783 | 
            -
                alias uniq! distinct!
         | 
| 784 824 |  | 
| 785 825 | 
             
                # Used to extend a scope with additional methods, either through
         | 
| 786 826 | 
             
                # a module or through a block provided.
         | 
| @@ -850,327 +890,344 @@ module ActiveRecord | |
| 850 890 | 
             
                  self
         | 
| 851 891 | 
             
                end
         | 
| 852 892 |  | 
| 853 | 
            -
                 | 
| 854 | 
            -
             | 
| 855 | 
            -
                   | 
| 893 | 
            +
                def skip_query_cache!(value = true) # :nodoc:
         | 
| 894 | 
            +
                  self.skip_query_cache_value = value
         | 
| 895 | 
            +
                  self
         | 
| 856 896 | 
             
                end
         | 
| 857 897 |  | 
| 858 | 
            -
                 | 
| 859 | 
            -
             | 
| 860 | 
            -
             | 
| 861 | 
            -
             | 
| 898 | 
            +
                # Returns the Arel object associated with the relation.
         | 
| 899 | 
            +
                def arel(aliases = nil) # :nodoc:
         | 
| 900 | 
            +
                  @arel ||= build_arel(aliases)
         | 
| 901 | 
            +
                end
         | 
| 862 902 |  | 
| 863 | 
            -
             | 
| 903 | 
            +
                # Returns a relation value with a given name
         | 
| 904 | 
            +
                def get_value(name) # :nodoc:
         | 
| 905 | 
            +
                  @values.fetch(name, DEFAULT_VALUES[name])
         | 
| 906 | 
            +
                end
         | 
| 864 907 |  | 
| 865 | 
            -
             | 
| 908 | 
            +
                protected
         | 
| 866 909 |  | 
| 867 | 
            -
                   | 
| 910 | 
            +
                  # Sets the relation value with the given name
         | 
| 911 | 
            +
                  def set_value(name, value) # :nodoc:
         | 
| 912 | 
            +
                    assert_mutability!
         | 
| 913 | 
            +
                    @values[name] = value
         | 
| 914 | 
            +
                  end
         | 
| 868 915 |  | 
| 869 | 
            -
             | 
| 870 | 
            -
                  arel.skip(offset_value.to_i) if offset_value
         | 
| 916 | 
            +
                private
         | 
| 871 917 |  | 
| 872 | 
            -
                   | 
| 918 | 
            +
                  def assert_mutability!
         | 
| 919 | 
            +
                    raise ImmutableRelation if @loaded
         | 
| 920 | 
            +
                    raise ImmutableRelation if defined?(@arel) && @arel
         | 
| 921 | 
            +
                  end
         | 
| 873 922 |  | 
| 874 | 
            -
                   | 
| 923 | 
            +
                  def build_arel(aliases)
         | 
| 924 | 
            +
                    arel = Arel::SelectManager.new(table)
         | 
| 925 | 
            +
             | 
| 926 | 
            +
                    aliases = build_joins(arel, joins_values.flatten, aliases) unless joins_values.empty?
         | 
| 927 | 
            +
                    build_left_outer_joins(arel, left_outer_joins_values.flatten, aliases) unless left_outer_joins_values.empty?
         | 
| 928 | 
            +
             | 
| 929 | 
            +
                    arel.where(where_clause.ast) unless where_clause.empty?
         | 
| 930 | 
            +
                    arel.having(having_clause.ast) unless having_clause.empty?
         | 
| 931 | 
            +
                    if limit_value
         | 
| 932 | 
            +
                      limit_attribute = ActiveModel::Attribute.with_cast_value(
         | 
| 933 | 
            +
                        "LIMIT".freeze,
         | 
| 934 | 
            +
                        connection.sanitize_limit(limit_value),
         | 
| 935 | 
            +
                        Type.default_value,
         | 
| 936 | 
            +
                      )
         | 
| 937 | 
            +
                      arel.take(Arel::Nodes::BindParam.new(limit_attribute))
         | 
| 938 | 
            +
                    end
         | 
| 939 | 
            +
                    if offset_value
         | 
| 940 | 
            +
                      offset_attribute = ActiveModel::Attribute.with_cast_value(
         | 
| 941 | 
            +
                        "OFFSET".freeze,
         | 
| 942 | 
            +
                        offset_value.to_i,
         | 
| 943 | 
            +
                        Type.default_value,
         | 
| 944 | 
            +
                      )
         | 
| 945 | 
            +
                      arel.skip(Arel::Nodes::BindParam.new(offset_attribute))
         | 
| 946 | 
            +
                    end
         | 
| 947 | 
            +
                    arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
         | 
| 875 948 |  | 
| 876 | 
            -
             | 
| 949 | 
            +
                    build_order(arel)
         | 
| 877 950 |  | 
| 878 | 
            -
             | 
| 879 | 
            -
                  arel.from(build_from) if from_value
         | 
| 880 | 
            -
                  arel.lock(lock_value) if lock_value
         | 
| 951 | 
            +
                    build_select(arel)
         | 
| 881 952 |  | 
| 882 | 
            -
             | 
| 883 | 
            -
             | 
| 953 | 
            +
                    arel.distinct(distinct_value)
         | 
| 954 | 
            +
                    arel.from(build_from) unless from_clause.empty?
         | 
| 955 | 
            +
                    arel.lock(lock_value) if lock_value
         | 
| 884 956 |  | 
| 885 | 
            -
             | 
| 886 | 
            -
                  if !VALID_UNSCOPING_VALUES.include?(scope)
         | 
| 887 | 
            -
                    raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
         | 
| 957 | 
            +
                    arel
         | 
| 888 958 | 
             
                  end
         | 
| 889 959 |  | 
| 890 | 
            -
                   | 
| 891 | 
            -
             | 
| 892 | 
            -
             | 
| 893 | 
            -
             | 
| 894 | 
            -
             | 
| 895 | 
            -
             | 
| 896 | 
            -
             | 
| 897 | 
            -
             | 
| 898 | 
            -
             | 
| 899 | 
            -
             | 
| 960 | 
            +
                  def build_from
         | 
| 961 | 
            +
                    opts = from_clause.value
         | 
| 962 | 
            +
                    name = from_clause.name
         | 
| 963 | 
            +
                    case opts
         | 
| 964 | 
            +
                    when Relation
         | 
| 965 | 
            +
                      if opts.eager_loading?
         | 
| 966 | 
            +
                        opts = opts.send(:apply_join_dependency)
         | 
| 967 | 
            +
                      end
         | 
| 968 | 
            +
                      name ||= "subquery"
         | 
| 969 | 
            +
                      opts.arel.as(name.to_s)
         | 
| 970 | 
            +
                    else
         | 
| 971 | 
            +
                      opts
         | 
| 972 | 
            +
                    end
         | 
| 900 973 | 
             
                  end
         | 
| 901 974 |  | 
| 902 | 
            -
                   | 
| 903 | 
            -
             | 
| 904 | 
            -
             | 
| 905 | 
            -
             | 
| 906 | 
            -
             | 
| 907 | 
            -
             | 
| 908 | 
            -
             | 
| 909 | 
            -
             | 
| 910 | 
            -
             | 
| 911 | 
            -
                       | 
| 912 | 
            -
                      subrelation.name == target_value
         | 
| 975 | 
            +
                  def build_left_outer_joins(manager, outer_joins, aliases)
         | 
| 976 | 
            +
                    buckets = outer_joins.group_by do |join|
         | 
| 977 | 
            +
                      case join
         | 
| 978 | 
            +
                      when Hash, Symbol, Array
         | 
| 979 | 
            +
                        :association_join
         | 
| 980 | 
            +
                      when ActiveRecord::Associations::JoinDependency
         | 
| 981 | 
            +
                        :stashed_join
         | 
| 982 | 
            +
                      else
         | 
| 983 | 
            +
                        raise ArgumentError, "only Hash, Symbol and Array are allowed"
         | 
| 984 | 
            +
                      end
         | 
| 913 985 | 
             
                    end
         | 
| 986 | 
            +
             | 
| 987 | 
            +
                    build_join_query(manager, buckets, Arel::Nodes::OuterJoin, aliases)
         | 
| 914 988 | 
             
                  end
         | 
| 915 989 |  | 
| 916 | 
            -
                   | 
| 917 | 
            -
             | 
| 990 | 
            +
                  def build_joins(manager, joins, aliases)
         | 
| 991 | 
            +
                    buckets = joins.group_by do |join|
         | 
| 992 | 
            +
                      case join
         | 
| 993 | 
            +
                      when String
         | 
| 994 | 
            +
                        :string_join
         | 
| 995 | 
            +
                      when Hash, Symbol, Array
         | 
| 996 | 
            +
                        :association_join
         | 
| 997 | 
            +
                      when ActiveRecord::Associations::JoinDependency
         | 
| 998 | 
            +
                        :stashed_join
         | 
| 999 | 
            +
                      when Arel::Nodes::Join
         | 
| 1000 | 
            +
                        :join_node
         | 
| 1001 | 
            +
                      else
         | 
| 1002 | 
            +
                        raise "unknown class: %s" % join.class.name
         | 
| 1003 | 
            +
                      end
         | 
| 1004 | 
            +
                    end
         | 
| 918 1005 |  | 
| 919 | 
            -
             | 
| 920 | 
            -
                   | 
| 1006 | 
            +
                    build_join_query(manager, buckets, Arel::Nodes::InnerJoin, aliases)
         | 
| 1007 | 
            +
                  end
         | 
| 921 1008 |  | 
| 922 | 
            -
                   | 
| 1009 | 
            +
                  def build_join_query(manager, buckets, join_type, aliases)
         | 
| 1010 | 
            +
                    buckets.default = []
         | 
| 923 1011 |  | 
| 924 | 
            -
             | 
| 925 | 
            -
                     | 
| 926 | 
            -
                     | 
| 927 | 
            -
             | 
| 928 | 
            -
                    when String
         | 
| 929 | 
            -
                      join = Arel.sql(join)
         | 
| 930 | 
            -
                    end
         | 
| 931 | 
            -
                    table.create_string_join(join)
         | 
| 932 | 
            -
                  end
         | 
| 933 | 
            -
                end
         | 
| 1012 | 
            +
                    association_joins = buckets[:association_join]
         | 
| 1013 | 
            +
                    stashed_joins     = buckets[:stashed_join]
         | 
| 1014 | 
            +
                    join_nodes        = buckets[:join_node].uniq
         | 
| 1015 | 
            +
                    string_joins      = buckets[:string_join].map(&:strip).uniq
         | 
| 934 1016 |  | 
| 935 | 
            -
             | 
| 936 | 
            -
             | 
| 937 | 
            -
                    next where if ::Arel::Nodes::Equality === where
         | 
| 938 | 
            -
                    where = Arel.sql(where) if String === where
         | 
| 939 | 
            -
                    Arel::Nodes::Grouping.new(where)
         | 
| 940 | 
            -
                  end
         | 
| 1017 | 
            +
                    join_list = join_nodes + convert_join_strings_to_ast(string_joins)
         | 
| 1018 | 
            +
                    alias_tracker = alias_tracker(join_list, aliases)
         | 
| 941 1019 |  | 
| 942 | 
            -
             | 
| 943 | 
            -
             | 
| 1020 | 
            +
                    join_dependency = ActiveRecord::Associations::JoinDependency.new(
         | 
| 1021 | 
            +
                      klass, table, association_joins
         | 
| 1022 | 
            +
                    )
         | 
| 944 1023 |  | 
| 945 | 
            -
             | 
| 946 | 
            -
             | 
| 947 | 
            -
                  when String, Array
         | 
| 948 | 
            -
                    [@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
         | 
| 949 | 
            -
                  when Hash
         | 
| 950 | 
            -
                    opts = PredicateBuilder.resolve_column_aliases(klass, opts)
         | 
| 1024 | 
            +
                    joins = join_dependency.join_constraints(stashed_joins, join_type, alias_tracker)
         | 
| 1025 | 
            +
                    joins.each { |join| manager.from(join) }
         | 
| 951 1026 |  | 
| 952 | 
            -
                     | 
| 953 | 
            -
                    self.bind_values += bind_values
         | 
| 1027 | 
            +
                    manager.join_sources.concat(join_list)
         | 
| 954 1028 |  | 
| 955 | 
            -
                     | 
| 956 | 
            -
             | 
| 1029 | 
            +
                    alias_tracker.aliases
         | 
| 1030 | 
            +
                  end
         | 
| 957 1031 |  | 
| 958 | 
            -
             | 
| 959 | 
            -
             | 
| 960 | 
            -
             | 
| 1032 | 
            +
                  def convert_join_strings_to_ast(joins)
         | 
| 1033 | 
            +
                    joins
         | 
| 1034 | 
            +
                      .flatten
         | 
| 1035 | 
            +
                      .reject(&:blank?)
         | 
| 1036 | 
            +
                      .map { |join| table.create_string_join(Arel.sql(join)) }
         | 
| 961 1037 | 
             
                  end
         | 
| 962 | 
            -
                end
         | 
| 963 1038 |  | 
| 964 | 
            -
             | 
| 965 | 
            -
             | 
| 966 | 
            -
             | 
| 967 | 
            -
                     | 
| 968 | 
            -
                       | 
| 1039 | 
            +
                  def build_select(arel)
         | 
| 1040 | 
            +
                    if select_values.any?
         | 
| 1041 | 
            +
                      arel.project(*arel_columns(select_values.uniq))
         | 
| 1042 | 
            +
                    elsif klass.ignored_columns.any?
         | 
| 1043 | 
            +
                      arel.project(*klass.column_names.map { |field| arel_attribute(field) })
         | 
| 969 1044 | 
             
                    else
         | 
| 970 | 
            -
                       | 
| 1045 | 
            +
                      arel.project(table[Arel.star])
         | 
| 971 1046 | 
             
                    end
         | 
| 972 1047 | 
             
                  end
         | 
| 973 1048 |  | 
| 974 | 
            -
                   | 
| 975 | 
            -
                     | 
| 1049 | 
            +
                  def arel_columns(columns)
         | 
| 1050 | 
            +
                    columns.flat_map do |field|
         | 
| 1051 | 
            +
                      case field
         | 
| 1052 | 
            +
                      when Symbol
         | 
| 1053 | 
            +
                        arel_column(field.to_s) do |attr_name|
         | 
| 1054 | 
            +
                          connection.quote_table_name(attr_name)
         | 
| 1055 | 
            +
                        end
         | 
| 1056 | 
            +
                      when String
         | 
| 1057 | 
            +
                        arel_column(field, &:itself)
         | 
| 1058 | 
            +
                      when Proc
         | 
| 1059 | 
            +
                        field.call
         | 
| 1060 | 
            +
                      else
         | 
| 1061 | 
            +
                        field
         | 
| 1062 | 
            +
                      end
         | 
| 1063 | 
            +
                    end
         | 
| 976 1064 | 
             
                  end
         | 
| 977 1065 |  | 
| 978 | 
            -
                   | 
| 979 | 
            -
             | 
| 1066 | 
            +
                  def arel_column(field)
         | 
| 1067 | 
            +
                    field = klass.attribute_alias(field) if klass.attribute_alias?(field)
         | 
| 1068 | 
            +
                    from = from_clause.name || from_clause.value
         | 
| 980 1069 |  | 
| 981 | 
            -
             | 
| 982 | 
            -
             | 
| 983 | 
            -
                     | 
| 1070 | 
            +
                    if klass.columns_hash.key?(field) && (!from || table_name_matches?(from))
         | 
| 1071 | 
            +
                      arel_attribute(field)
         | 
| 1072 | 
            +
                    else
         | 
| 1073 | 
            +
                      yield field
         | 
| 1074 | 
            +
                    end
         | 
| 984 1075 | 
             
                  end
         | 
| 985 1076 |  | 
| 986 | 
            -
                   | 
| 987 | 
            -
                     | 
| 988 | 
            -
                    association_new_opts, association_bind = association_relation.send(:create_binds, value)
         | 
| 989 | 
            -
                    new_opts[column] = association_new_opts
         | 
| 990 | 
            -
                    binds += association_bind
         | 
| 1077 | 
            +
                  def table_name_matches?(from)
         | 
| 1078 | 
            +
                    /(?:\A|(?<!FROM)\s)(?:\b#{table.name}\b|#{connection.quote_table_name(table.name)})(?!\.)/i.match?(from.to_s)
         | 
| 991 1079 | 
             
                  end
         | 
| 992 1080 |  | 
| 993 | 
            -
                   | 
| 994 | 
            -
             | 
| 995 | 
            -
             | 
| 996 | 
            -
             | 
| 997 | 
            -
             | 
| 998 | 
            -
             | 
| 999 | 
            -
                  table_name = table_name.to_s
         | 
| 1000 | 
            -
                  @klass._reflect_on_association(table_name) ||
         | 
| 1001 | 
            -
                    @klass._reflect_on_association(table_name.singularize)
         | 
| 1002 | 
            -
                end
         | 
| 1003 | 
            -
             | 
| 1004 | 
            -
                def build_from
         | 
| 1005 | 
            -
                  opts, name = from_value
         | 
| 1006 | 
            -
                  case opts
         | 
| 1007 | 
            -
                  when Relation
         | 
| 1008 | 
            -
                    name ||= 'subquery'
         | 
| 1009 | 
            -
                    self.bind_values = opts.bind_values + self.bind_values
         | 
| 1010 | 
            -
                    opts.arel.as(name.to_s)
         | 
| 1011 | 
            -
                  else
         | 
| 1012 | 
            -
                    opts
         | 
| 1013 | 
            -
                  end
         | 
| 1014 | 
            -
                end
         | 
| 1081 | 
            +
                  def reverse_sql_order(order_query)
         | 
| 1082 | 
            +
                    if order_query.empty?
         | 
| 1083 | 
            +
                      return [arel_attribute(primary_key).desc] if primary_key
         | 
| 1084 | 
            +
                      raise IrreversibleOrderError,
         | 
| 1085 | 
            +
                        "Relation has no current order and table has no primary key to be used as default order"
         | 
| 1086 | 
            +
                    end
         | 
| 1015 1087 |  | 
| 1016 | 
            -
             | 
| 1017 | 
            -
             | 
| 1018 | 
            -
             | 
| 1019 | 
            -
             | 
| 1020 | 
            -
                       | 
| 1021 | 
            -
             | 
| 1022 | 
            -
                       | 
| 1023 | 
            -
             | 
| 1024 | 
            -
             | 
| 1025 | 
            -
             | 
| 1026 | 
            -
             | 
| 1027 | 
            -
             | 
| 1028 | 
            -
             | 
| 1088 | 
            +
                    order_query.flat_map do |o|
         | 
| 1089 | 
            +
                      case o
         | 
| 1090 | 
            +
                      when Arel::Attribute
         | 
| 1091 | 
            +
                        o.desc
         | 
| 1092 | 
            +
                      when Arel::Nodes::Ordering
         | 
| 1093 | 
            +
                        o.reverse
         | 
| 1094 | 
            +
                      when String
         | 
| 1095 | 
            +
                        if does_not_support_reverse?(o)
         | 
| 1096 | 
            +
                          raise IrreversibleOrderError, "Order #{o.inspect} can not be reversed automatically"
         | 
| 1097 | 
            +
                        end
         | 
| 1098 | 
            +
                        o.split(",").map! do |s|
         | 
| 1099 | 
            +
                          s.strip!
         | 
| 1100 | 
            +
                          s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || (s << " DESC")
         | 
| 1101 | 
            +
                        end
         | 
| 1102 | 
            +
                      else
         | 
| 1103 | 
            +
                        o
         | 
| 1104 | 
            +
                      end
         | 
| 1029 1105 | 
             
                    end
         | 
| 1030 1106 | 
             
                  end
         | 
| 1031 1107 |  | 
| 1032 | 
            -
                   | 
| 1033 | 
            -
             | 
| 1034 | 
            -
             | 
| 1035 | 
            -
             | 
| 1108 | 
            +
                  def does_not_support_reverse?(order)
         | 
| 1109 | 
            +
                    # Account for String subclasses like Arel::Nodes::SqlLiteral that
         | 
| 1110 | 
            +
                    # override methods like #count.
         | 
| 1111 | 
            +
                    order = String.new(order) unless order.instance_of?(String)
         | 
| 1036 1112 |  | 
| 1037 | 
            -
             | 
| 1038 | 
            -
             | 
| 1039 | 
            -
             | 
| 1040 | 
            -
             | 
| 1041 | 
            -
             | 
| 1042 | 
            -
                    join_list
         | 
| 1043 | 
            -
                  )
         | 
| 1113 | 
            +
                    # Uses SQL function with multiple arguments.
         | 
| 1114 | 
            +
                    (order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) ||
         | 
| 1115 | 
            +
                      # Uses "nulls first" like construction.
         | 
| 1116 | 
            +
                      /nulls (first|last)\Z/i.match?(order)
         | 
| 1117 | 
            +
                  end
         | 
| 1044 1118 |  | 
| 1045 | 
            -
                   | 
| 1119 | 
            +
                  def build_order(arel)
         | 
| 1120 | 
            +
                    orders = order_values.uniq
         | 
| 1121 | 
            +
                    orders.reject!(&:blank?)
         | 
| 1046 1122 |  | 
| 1047 | 
            -
             | 
| 1048 | 
            -
                    info.joins.each { |join| manager.from(join) }
         | 
| 1049 | 
            -
                    manager.bind_values.concat info.binds
         | 
| 1123 | 
            +
                    arel.order(*orders) unless orders.empty?
         | 
| 1050 1124 | 
             
                  end
         | 
| 1051 1125 |  | 
| 1052 | 
            -
                   | 
| 1126 | 
            +
                  VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
         | 
| 1127 | 
            +
                                      "asc", "desc", "ASC", "DESC"].to_set # :nodoc:
         | 
| 1053 1128 |  | 
| 1054 | 
            -
                   | 
| 1055 | 
            -
             | 
| 1056 | 
            -
             | 
| 1057 | 
            -
             | 
| 1058 | 
            -
             | 
| 1059 | 
            -
             | 
| 1060 | 
            -
             | 
| 1061 | 
            -
                         | 
| 1062 | 
            -
                      else
         | 
| 1063 | 
            -
                        field
         | 
| 1129 | 
            +
                  def validate_order_args(args)
         | 
| 1130 | 
            +
                    args.each do |arg|
         | 
| 1131 | 
            +
                      next unless arg.is_a?(Hash)
         | 
| 1132 | 
            +
                      arg.each do |_key, value|
         | 
| 1133 | 
            +
                        unless VALID_DIRECTIONS.include?(value)
         | 
| 1134 | 
            +
                          raise ArgumentError,
         | 
| 1135 | 
            +
                            "Direction \"#{value}\" is invalid. Valid directions are: #{VALID_DIRECTIONS.to_a.inspect}"
         | 
| 1136 | 
            +
                        end
         | 
| 1064 1137 | 
             
                      end
         | 
| 1065 1138 | 
             
                    end
         | 
| 1139 | 
            +
                  end
         | 
| 1066 1140 |  | 
| 1067 | 
            -
             | 
| 1068 | 
            -
             | 
| 1069 | 
            -
             | 
| 1141 | 
            +
                  def preprocess_order_args(order_args)
         | 
| 1142 | 
            +
                    order_args.map! do |arg|
         | 
| 1143 | 
            +
                      klass.sanitize_sql_for_order(arg)
         | 
| 1144 | 
            +
                    end
         | 
| 1145 | 
            +
                    order_args.flatten!
         | 
| 1146 | 
            +
             | 
| 1147 | 
            +
                    @klass.enforce_raw_sql_whitelist(
         | 
| 1148 | 
            +
                      order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a },
         | 
| 1149 | 
            +
                      whitelist: AttributeMethods::ClassMethods::COLUMN_NAME_ORDER_WHITELIST
         | 
| 1150 | 
            +
                    )
         | 
| 1151 | 
            +
             | 
| 1152 | 
            +
                    validate_order_args(order_args)
         | 
| 1153 | 
            +
             | 
| 1154 | 
            +
                    references = order_args.grep(String)
         | 
| 1155 | 
            +
                    references.map! { |arg| arg =~ /^\W?(\w+)\W?\./ && $1 }.compact!
         | 
| 1156 | 
            +
                    references!(references) if references.any?
         | 
| 1157 | 
            +
             | 
| 1158 | 
            +
                    # if a symbol is given we prepend the quoted table name
         | 
| 1159 | 
            +
                    order_args.map! do |arg|
         | 
| 1160 | 
            +
                      case arg
         | 
| 1161 | 
            +
                      when Symbol
         | 
| 1162 | 
            +
                        order_column(arg.to_s).asc
         | 
| 1163 | 
            +
                      when Hash
         | 
| 1164 | 
            +
                        arg.map { |field, dir|
         | 
| 1165 | 
            +
                          case field
         | 
| 1166 | 
            +
                          when Arel::Nodes::SqlLiteral
         | 
| 1167 | 
            +
                            field.send(dir.downcase)
         | 
| 1168 | 
            +
                          else
         | 
| 1169 | 
            +
                            order_column(field.to_s).send(dir.downcase)
         | 
| 1170 | 
            +
                          end
         | 
| 1171 | 
            +
                        }
         | 
| 1172 | 
            +
                      else
         | 
| 1173 | 
            +
                        arg
         | 
| 1174 | 
            +
                      end
         | 
| 1175 | 
            +
                    end.flatten!
         | 
| 1070 1176 | 
             
                  end
         | 
| 1071 | 
            -
                end
         | 
| 1072 1177 |  | 
| 1073 | 
            -
             | 
| 1074 | 
            -
             | 
| 1075 | 
            -
             | 
| 1076 | 
            -
             | 
| 1077 | 
            -
             | 
| 1078 | 
            -
             | 
| 1079 | 
            -
                      o.reverse
         | 
| 1080 | 
            -
                    when String
         | 
| 1081 | 
            -
                      o.to_s.split(',').map! do |s|
         | 
| 1082 | 
            -
                        s.strip!
         | 
| 1083 | 
            -
                        s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC')
         | 
| 1178 | 
            +
                  def order_column(field)
         | 
| 1179 | 
            +
                    arel_column(field) do |attr_name|
         | 
| 1180 | 
            +
                      if attr_name == "count" && !group_values.empty?
         | 
| 1181 | 
            +
                        arel_attribute(attr_name)
         | 
| 1182 | 
            +
                      else
         | 
| 1183 | 
            +
                        Arel.sql(connection.quote_table_name(attr_name))
         | 
| 1084 1184 | 
             
                      end
         | 
| 1085 | 
            -
                    else
         | 
| 1086 | 
            -
                      o
         | 
| 1087 1185 | 
             
                    end
         | 
| 1088 1186 | 
             
                  end
         | 
| 1089 | 
            -
                end
         | 
| 1090 1187 |  | 
| 1091 | 
            -
             | 
| 1092 | 
            -
                   | 
| 1093 | 
            -
             | 
| 1094 | 
            -
             | 
| 1095 | 
            -
             | 
| 1096 | 
            -
                   | 
| 1097 | 
            -
                   | 
| 1098 | 
            -
             | 
| 1099 | 
            -
                   | 
| 1100 | 
            -
             | 
| 1101 | 
            -
             | 
| 1102 | 
            -
             | 
| 1103 | 
            -
             | 
| 1104 | 
            -
             | 
| 1105 | 
            -
             | 
| 1106 | 
            -
                   | 
| 1107 | 
            -
             | 
| 1108 | 
            -
                     | 
| 1109 | 
            -
                      raise ArgumentError, " | 
| 1110 | 
            -
                                           "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
         | 
| 1188 | 
            +
                  # Checks to make sure that the arguments are not blank. Note that if some
         | 
| 1189 | 
            +
                  # blank-like object were initially passed into the query method, then this
         | 
| 1190 | 
            +
                  # method will not raise an error.
         | 
| 1191 | 
            +
                  #
         | 
| 1192 | 
            +
                  # Example:
         | 
| 1193 | 
            +
                  #
         | 
| 1194 | 
            +
                  #    Post.references()   # raises an error
         | 
| 1195 | 
            +
                  #    Post.references([]) # does not raise an error
         | 
| 1196 | 
            +
                  #
         | 
| 1197 | 
            +
                  # This particular method should be called with a method_name and the args
         | 
| 1198 | 
            +
                  # passed into that method as an input. For example:
         | 
| 1199 | 
            +
                  #
         | 
| 1200 | 
            +
                  # def references(*args)
         | 
| 1201 | 
            +
                  #   check_if_method_has_arguments!("references", args)
         | 
| 1202 | 
            +
                  #   ...
         | 
| 1203 | 
            +
                  # end
         | 
| 1204 | 
            +
                  def check_if_method_has_arguments!(method_name, args)
         | 
| 1205 | 
            +
                    if args.blank?
         | 
| 1206 | 
            +
                      raise ArgumentError, "The method .#{method_name}() must contain arguments."
         | 
| 1111 1207 | 
             
                    end
         | 
| 1112 1208 | 
             
                  end
         | 
| 1113 | 
            -
                end
         | 
| 1114 | 
            -
             | 
| 1115 | 
            -
                def preprocess_order_args(order_args)
         | 
| 1116 | 
            -
                  order_args.flatten!
         | 
| 1117 | 
            -
                  validate_order_args(order_args)
         | 
| 1118 | 
            -
             | 
| 1119 | 
            -
                  references = order_args.grep(String)
         | 
| 1120 | 
            -
                  references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
         | 
| 1121 | 
            -
                  references!(references) if references.any?
         | 
| 1122 1209 |  | 
| 1123 | 
            -
                   | 
| 1124 | 
            -
                   | 
| 1125 | 
            -
                     | 
| 1126 | 
            -
             | 
| 1127 | 
            -
                      arg = klass.attribute_alias(arg) if klass.attribute_alias?(arg)
         | 
| 1128 | 
            -
                      table[arg].asc
         | 
| 1129 | 
            -
                    when Hash
         | 
| 1130 | 
            -
                      arg.map { |field, dir|
         | 
| 1131 | 
            -
                        field = klass.attribute_alias(field) if klass.attribute_alias?(field)
         | 
| 1132 | 
            -
                        table[field].send(dir.downcase)
         | 
| 1133 | 
            -
                      }
         | 
| 1134 | 
            -
                    else
         | 
| 1135 | 
            -
                      arg
         | 
| 1210 | 
            +
                  STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references]
         | 
| 1211 | 
            +
                  def structurally_incompatible_values_for_or(other)
         | 
| 1212 | 
            +
                    STRUCTURAL_OR_METHODS.reject do |method|
         | 
| 1213 | 
            +
                      get_value(method) == other.get_value(method)
         | 
| 1136 1214 | 
             
                    end
         | 
| 1137 | 
            -
                  end | 
| 1138 | 
            -
                end
         | 
| 1215 | 
            +
                  end
         | 
| 1139 1216 |  | 
| 1140 | 
            -
             | 
| 1141 | 
            -
             | 
| 1142 | 
            -
                # method will not raise an error.
         | 
| 1143 | 
            -
                #
         | 
| 1144 | 
            -
                # Example:
         | 
| 1145 | 
            -
                #
         | 
| 1146 | 
            -
                #    Post.references()   # => raises an error
         | 
| 1147 | 
            -
                #    Post.references([]) # => does not raise an error
         | 
| 1148 | 
            -
                #
         | 
| 1149 | 
            -
                # This particular method should be called with a method_name and the args
         | 
| 1150 | 
            -
                # passed into that method as an input. For example:
         | 
| 1151 | 
            -
                #
         | 
| 1152 | 
            -
                # def references(*args)
         | 
| 1153 | 
            -
                #   check_if_method_has_arguments!("references", args)
         | 
| 1154 | 
            -
                #   ...
         | 
| 1155 | 
            -
                # end
         | 
| 1156 | 
            -
                def check_if_method_has_arguments!(method_name, args)
         | 
| 1157 | 
            -
                  if args.blank?
         | 
| 1158 | 
            -
                    raise ArgumentError, "The method .#{method_name}() must contain arguments."
         | 
| 1217 | 
            +
                  def where_clause_factory
         | 
| 1218 | 
            +
                    @where_clause_factory ||= Relation::WhereClauseFactory.new(klass, predicate_builder)
         | 
| 1159 1219 | 
             
                  end
         | 
| 1160 | 
            -
             | 
| 1220 | 
            +
                  alias having_clause_factory where_clause_factory
         | 
| 1161 1221 |  | 
| 1162 | 
            -
             | 
| 1163 | 
            -
             | 
| 1164 | 
            -
             | 
| 1165 | 
            -
             | 
| 1166 | 
            -
                     | 
| 1167 | 
            -
             | 
| 1168 | 
            -
             | 
| 1169 | 
            -
             | 
| 1170 | 
            -
             | 
| 1171 | 
            -
                      end
         | 
| 1172 | 
            -
                    end
         | 
| 1222 | 
            +
                  DEFAULT_VALUES = {
         | 
| 1223 | 
            +
                    create_with: FROZEN_EMPTY_HASH,
         | 
| 1224 | 
            +
                    where: Relation::WhereClause.empty,
         | 
| 1225 | 
            +
                    having: Relation::WhereClause.empty,
         | 
| 1226 | 
            +
                    from: Relation::FromClause.empty
         | 
| 1227 | 
            +
                  }
         | 
| 1228 | 
            +
             | 
| 1229 | 
            +
                  Relation::MULTI_VALUE_METHODS.each do |value|
         | 
| 1230 | 
            +
                    DEFAULT_VALUES[value] ||= FROZEN_EMPTY_ARRAY
         | 
| 1173 1231 | 
             
                  end
         | 
| 1174 | 
            -
                end
         | 
| 1175 1232 | 
             
              end
         | 
| 1176 1233 | 
             
            end
         |