activerecord 5.2.6 → 6.0.5.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +956 -559
- data/MIT-LICENSE +3 -1
- data/README.rdoc +5 -3
- data/examples/performance.rb +1 -1
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +4 -3
- data/lib/active_record/association_relation.rb +10 -8
- data/lib/active_record/associations/alias_tracker.rb +0 -1
- data/lib/active_record/associations/association.rb +55 -19
- data/lib/active_record/associations/association_scope.rb +11 -7
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +19 -23
- data/lib/active_record/associations/collection_proxy.rb +14 -17
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -11
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +4 -4
- data/lib/active_record/associations/join_dependency.rb +47 -30
- data/lib/active_record/associations/preloader/association.rb +61 -41
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/preloader.rb +44 -33
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +21 -16
- data/lib/active_record/attribute_assignment.rb +7 -11
- data/lib/active_record/attribute_decorators.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -24
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -54
- data/lib/active_record/attribute_methods/serialization.rb +1 -2
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
- data/lib/active_record/attribute_methods/write.rb +17 -25
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attributes.rb +13 -1
- data/lib/active_record/autosave_association.rb +12 -14
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +6 -21
- data/lib/active_record/coders/yaml_column.rb +13 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -18
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +105 -72
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
- data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -217
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +63 -75
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +137 -147
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +139 -26
- data/lib/active_record/core.rb +117 -66
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +78 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +44 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +144 -474
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +13 -6
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +11 -3
- data/lib/active_record/locking/optimistic.rb +14 -7
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +8 -27
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
- data/lib/active_record/middleware/database_selector.rb +74 -0
- data/lib/active_record/migration/command_recorder.rb +54 -22
- data/lib/active_record/migration/compatibility.rb +79 -52
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +104 -85
- data/lib/active_record/model_schema.rb +62 -11
- data/lib/active_record/nested_attributes.rb +2 -4
- data/lib/active_record/no_touching.rb +9 -2
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +232 -29
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +33 -21
- data/lib/active_record/railtie.rb +95 -40
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +199 -46
- data/lib/active_record/reflection.rb +51 -51
- data/lib/active_record/relation/batches.rb +13 -11
- data/lib/active_record/relation/calculations.rb +55 -49
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +23 -28
- data/lib/active_record/relation/from_clause.rb +4 -0
- data/lib/active_record/relation/merger.rb +12 -17
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder.rb +5 -11
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +232 -69
- data/lib/active_record/relation/spawn_methods.rb +1 -2
- data/lib/active_record/relation/where_clause.rb +14 -11
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/relation.rb +326 -81
- data/lib/active_record/result.rb +30 -12
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +6 -2
- data/lib/active_record/scoping/default.rb +4 -6
- data/lib/active_record/scoping/named.rb +25 -16
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +23 -15
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +243 -0
- data/lib/active_record/timestamp.rb +39 -26
- data/lib/active_record/touch_later.rb +5 -4
- data/lib/active_record/transactions.rb +64 -73
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +0 -1
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +3 -5
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/associated.rb +0 -1
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +10 -2
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +256 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +203 -0
- data/lib/arel/visitors/dot.rb +296 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +156 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +158 -0
- data/lib/arel/visitors/oracle12.rb +65 -0
- data/lib/arel/visitors/postgresql.rb +109 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +888 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors/where_sql.rb +22 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +62 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/migration.rb +14 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +116 -29
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -3,11 +3,7 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
class PredicateBuilder
|
5
5
|
class RangeHandler # :nodoc:
|
6
|
-
|
7
|
-
def exclude_end?
|
8
|
-
false
|
9
|
-
end
|
10
|
-
end
|
6
|
+
RangeWithBinds = Struct.new(:begin, :end, :exclude_end?)
|
11
7
|
|
12
8
|
def initialize(predicate_builder)
|
13
9
|
@predicate_builder = predicate_builder
|
@@ -16,26 +12,10 @@ module ActiveRecord
|
|
16
12
|
def call(attribute, value)
|
17
13
|
begin_bind = predicate_builder.build_bind_attribute(attribute.name, value.begin)
|
18
14
|
end_bind = predicate_builder.build_bind_attribute(attribute.name, value.end)
|
19
|
-
|
20
|
-
if begin_bind.value.infinity?
|
21
|
-
if end_bind.value.infinity?
|
22
|
-
attribute.not_in([])
|
23
|
-
elsif value.exclude_end?
|
24
|
-
attribute.lt(end_bind)
|
25
|
-
else
|
26
|
-
attribute.lteq(end_bind)
|
27
|
-
end
|
28
|
-
elsif end_bind.value.infinity?
|
29
|
-
attribute.gteq(begin_bind)
|
30
|
-
elsif value.exclude_end?
|
31
|
-
attribute.gteq(begin_bind).and(attribute.lt(end_bind))
|
32
|
-
else
|
33
|
-
attribute.between(RangeWithBinds.new(begin_bind, end_bind))
|
34
|
-
end
|
15
|
+
attribute.between(RangeWithBinds.new(begin_bind, end_bind, value.exclude_end?))
|
35
16
|
end
|
36
17
|
|
37
|
-
|
38
|
-
|
18
|
+
private
|
39
19
|
attr_reader :predicate_builder
|
40
20
|
end
|
41
21
|
end
|
@@ -27,7 +27,7 @@ module ActiveRecord
|
|
27
27
|
key
|
28
28
|
else
|
29
29
|
key = key.to_s
|
30
|
-
key.split("."
|
30
|
+
key.split(".").first if key.include?(".")
|
31
31
|
end
|
32
32
|
end.compact
|
33
33
|
end
|
@@ -62,15 +62,12 @@ module ActiveRecord
|
|
62
62
|
end
|
63
63
|
|
64
64
|
protected
|
65
|
-
|
66
|
-
attr_reader :table
|
67
|
-
|
68
65
|
def expand_from_hash(attributes)
|
69
66
|
return ["1=0"] if attributes.empty?
|
70
67
|
|
71
68
|
attributes.flat_map do |key, value|
|
72
69
|
if value.is_a?(Hash) && !table.has_column?(key)
|
73
|
-
associated_predicate_builder(key).expand_from_hash(value)
|
70
|
+
table.associated_predicate_builder(key).expand_from_hash(value)
|
74
71
|
elsif table.associated_with?(key)
|
75
72
|
# Find the foreign key when using queries such as:
|
76
73
|
# Post.where(author: author)
|
@@ -115,18 +112,15 @@ module ActiveRecord
|
|
115
112
|
end
|
116
113
|
|
117
114
|
private
|
118
|
-
|
119
|
-
def associated_predicate_builder(association_name)
|
120
|
-
self.class.new(table.associated_table(association_name))
|
121
|
-
end
|
115
|
+
attr_reader :table
|
122
116
|
|
123
117
|
def convert_dot_notation_to_hash(attributes)
|
124
118
|
dot_notation = attributes.select do |k, v|
|
125
|
-
k.include?("."
|
119
|
+
k.include?(".") && !v.is_a?(Hash)
|
126
120
|
end
|
127
121
|
|
128
122
|
dot_notation.each_key do |key|
|
129
|
-
table_name, column_name = key.split("."
|
123
|
+
table_name, column_name = key.split(".")
|
130
124
|
value = attributes.delete(key)
|
131
125
|
attributes[table_name] ||= {}
|
132
126
|
|
@@ -22,22 +22,27 @@ module ActiveRecord
|
|
22
22
|
value_before_type_cast.nil? ||
|
23
23
|
type.respond_to?(:subtype, true) && value_for_database.nil?
|
24
24
|
end
|
25
|
+
rescue ::RangeError
|
25
26
|
end
|
26
27
|
|
27
|
-
def
|
28
|
-
|
29
|
-
value_for_database unless value_before_type_cast.is_a?(StatementCache::Substitute)
|
30
|
-
@_boundable = true
|
28
|
+
def infinite?
|
29
|
+
infinity?(value_before_type_cast) || infinity?(value_for_database)
|
31
30
|
rescue ::RangeError
|
32
|
-
@_boundable = false
|
33
31
|
end
|
34
32
|
|
35
|
-
def
|
36
|
-
|
33
|
+
def unboundable?
|
34
|
+
if defined?(@_unboundable)
|
35
|
+
@_unboundable
|
36
|
+
else
|
37
|
+
value_for_database unless value_before_type_cast.is_a?(StatementCache::Substitute)
|
38
|
+
@_unboundable = nil
|
39
|
+
end
|
40
|
+
rescue ::RangeError
|
41
|
+
@_unboundable = type.cast(value_before_type_cast) <=> 0
|
37
42
|
end
|
38
43
|
|
39
44
|
private
|
40
|
-
def
|
45
|
+
def infinity?(value)
|
41
46
|
value.respond_to?(:infinite?) && value.infinite?
|
42
47
|
end
|
43
48
|
end
|
@@ -41,18 +41,42 @@ module ActiveRecord
|
|
41
41
|
#
|
42
42
|
# User.where.not(name: %w(Ko1 Nobu))
|
43
43
|
# # SELECT * FROM users WHERE name NOT IN ('Ko1', 'Nobu')
|
44
|
-
#
|
45
|
-
# User.where.not(name: "Jon", role: "admin")
|
46
|
-
# # SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
|
47
44
|
def not(opts, *rest)
|
48
45
|
opts = sanitize_forbidden_attributes(opts)
|
49
46
|
|
50
47
|
where_clause = @scope.send(:where_clause_factory).build(opts, rest)
|
51
48
|
|
52
49
|
@scope.references!(PredicateBuilder.references(opts)) if Hash === opts
|
53
|
-
|
50
|
+
|
51
|
+
if not_behaves_as_nor?(opts)
|
52
|
+
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
53
|
+
NOT conditions will no longer behave as NOR in Rails 6.1.
|
54
|
+
To continue using NOR conditions, NOT each condition individually
|
55
|
+
(`#{
|
56
|
+
opts.flat_map { |key, value|
|
57
|
+
if value.is_a?(Hash) && value.size > 1
|
58
|
+
value.map { |k, v| ".where.not(#{key.inspect} => { #{k.inspect} => ... })" }
|
59
|
+
else
|
60
|
+
".where.not(#{key.inspect} => ...)"
|
61
|
+
end
|
62
|
+
}.join
|
63
|
+
}`).
|
64
|
+
MSG
|
65
|
+
@scope.where_clause += where_clause.invert(:nor)
|
66
|
+
else
|
67
|
+
@scope.where_clause += where_clause.invert
|
68
|
+
end
|
69
|
+
|
54
70
|
@scope
|
55
71
|
end
|
72
|
+
|
73
|
+
private
|
74
|
+
def not_behaves_as_nor?(opts)
|
75
|
+
return false unless opts.is_a?(Hash)
|
76
|
+
|
77
|
+
opts.any? { |k, v| v.is_a?(Hash) && v.size > 1 } ||
|
78
|
+
opts.size > 1
|
79
|
+
end
|
56
80
|
end
|
57
81
|
|
58
82
|
FROZEN_EMPTY_ARRAY = [].freeze
|
@@ -67,11 +91,13 @@ module ActiveRecord
|
|
67
91
|
end
|
68
92
|
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
69
93
|
def #{method_name} # def includes_values
|
70
|
-
|
94
|
+
default = DEFAULT_VALUES[:#{name}] # default = DEFAULT_VALUES[:includes]
|
95
|
+
@values.fetch(:#{name}, default) # @values.fetch(:includes, default)
|
71
96
|
end # end
|
72
97
|
|
73
98
|
def #{method_name}=(value) # def includes_values=(value)
|
74
|
-
|
99
|
+
assert_mutability! # assert_mutability!
|
100
|
+
@values[:#{name}] = value # @values[:includes] = value
|
75
101
|
end # end
|
76
102
|
CODE
|
77
103
|
end
|
@@ -100,7 +126,7 @@ module ActiveRecord
|
|
100
126
|
#
|
101
127
|
# === conditions
|
102
128
|
#
|
103
|
-
# If you want to add conditions to your included models you'll have
|
129
|
+
# If you want to add string conditions to your included models, you'll have
|
104
130
|
# to explicitly reference them. For example:
|
105
131
|
#
|
106
132
|
# User.includes(:posts).where('posts.name = ?', 'example')
|
@@ -111,6 +137,12 @@ module ActiveRecord
|
|
111
137
|
#
|
112
138
|
# Note that #includes works with association names while #references needs
|
113
139
|
# the actual table name.
|
140
|
+
#
|
141
|
+
# If you pass the conditions via hash, you don't need to call #references
|
142
|
+
# explicitly, as #where references the tables for you. For example, this
|
143
|
+
# will work correctly:
|
144
|
+
#
|
145
|
+
# User.includes(:posts).where(posts: { name: 'example' })
|
114
146
|
def includes(*args)
|
115
147
|
check_if_method_has_arguments!(:includes, args)
|
116
148
|
spawn.includes!(*args)
|
@@ -136,7 +168,7 @@ module ActiveRecord
|
|
136
168
|
end
|
137
169
|
|
138
170
|
def eager_load!(*args) # :nodoc:
|
139
|
-
self.eager_load_values
|
171
|
+
self.eager_load_values |= args
|
140
172
|
self
|
141
173
|
end
|
142
174
|
|
@@ -150,10 +182,23 @@ module ActiveRecord
|
|
150
182
|
end
|
151
183
|
|
152
184
|
def preload!(*args) # :nodoc:
|
153
|
-
self.preload_values
|
185
|
+
self.preload_values |= args
|
154
186
|
self
|
155
187
|
end
|
156
188
|
|
189
|
+
# Extracts a named +association+ from the relation. The named association is first preloaded,
|
190
|
+
# then the individual association records are collected from the relation. Like so:
|
191
|
+
#
|
192
|
+
# account.memberships.extract_associated(:user)
|
193
|
+
# # => Returns collection of User records
|
194
|
+
#
|
195
|
+
# This is short-hand for:
|
196
|
+
#
|
197
|
+
# account.memberships.preload(:user).collect(&:user)
|
198
|
+
def extract_associated(association)
|
199
|
+
preload(association).collect(&association)
|
200
|
+
end
|
201
|
+
|
157
202
|
# Use to indicate that the given +table_names+ are referenced by an SQL string,
|
158
203
|
# and should therefore be JOINed in any query rather than loaded separately.
|
159
204
|
# This method only works in conjunction with #includes.
|
@@ -231,11 +276,33 @@ module ActiveRecord
|
|
231
276
|
end
|
232
277
|
|
233
278
|
def _select!(*fields) # :nodoc:
|
279
|
+
fields.reject!(&:blank?)
|
234
280
|
fields.flatten!
|
235
281
|
self.select_values += fields
|
236
282
|
self
|
237
283
|
end
|
238
284
|
|
285
|
+
# Allows you to change a previously set select statement.
|
286
|
+
#
|
287
|
+
# Post.select(:title, :body)
|
288
|
+
# # SELECT `posts`.`title`, `posts`.`body` FROM `posts`
|
289
|
+
#
|
290
|
+
# Post.select(:title, :body).reselect(:created_at)
|
291
|
+
# # SELECT `posts`.`created_at` FROM `posts`
|
292
|
+
#
|
293
|
+
# This is short-hand for <tt>unscope(:select).select(fields)</tt>.
|
294
|
+
# Note that we're unscoping the entire select statement.
|
295
|
+
def reselect(*args)
|
296
|
+
check_if_method_has_arguments!(:reselect, args)
|
297
|
+
spawn.reselect!(*args)
|
298
|
+
end
|
299
|
+
|
300
|
+
# Same as #reselect but operates on relation in-place instead of copying.
|
301
|
+
def reselect!(*args) # :nodoc:
|
302
|
+
self.select_values = args
|
303
|
+
self
|
304
|
+
end
|
305
|
+
|
239
306
|
# Allows to specify a group attribute:
|
240
307
|
#
|
241
308
|
# User.group(:name)
|
@@ -316,7 +383,7 @@ module ActiveRecord
|
|
316
383
|
|
317
384
|
# Same as #reorder but operates on relation in-place instead of copying.
|
318
385
|
def reorder!(*args) # :nodoc:
|
319
|
-
preprocess_order_args(args)
|
386
|
+
preprocess_order_args(args) unless args.all?(&:blank?)
|
320
387
|
|
321
388
|
self.reordering_value = true
|
322
389
|
self.order_values = args
|
@@ -324,8 +391,8 @@ module ActiveRecord
|
|
324
391
|
end
|
325
392
|
|
326
393
|
VALID_UNSCOPING_VALUES = Set.new([:where, :select, :group, :order, :lock,
|
327
|
-
:limit, :offset, :joins, :left_outer_joins,
|
328
|
-
:includes, :from, :readonly, :having])
|
394
|
+
:limit, :offset, :joins, :left_outer_joins, :annotate,
|
395
|
+
:includes, :from, :readonly, :having, :optimizer_hints])
|
329
396
|
|
330
397
|
# Removes an unwanted relation that is already defined on a chain of relations.
|
331
398
|
# This is useful when passing around chains of relations and would like to
|
@@ -376,7 +443,8 @@ module ActiveRecord
|
|
376
443
|
if !VALID_UNSCOPING_VALUES.include?(scope)
|
377
444
|
raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
|
378
445
|
end
|
379
|
-
|
446
|
+
assert_mutability!
|
447
|
+
@values[scope] = DEFAULT_VALUES[scope]
|
380
448
|
when Hash
|
381
449
|
scope.each do |key, target_value|
|
382
450
|
if key != :where
|
@@ -431,7 +499,7 @@ module ActiveRecord
|
|
431
499
|
def joins!(*args) # :nodoc:
|
432
500
|
args.compact!
|
433
501
|
args.flatten!
|
434
|
-
self.joins_values
|
502
|
+
self.joins_values |= args
|
435
503
|
self
|
436
504
|
end
|
437
505
|
|
@@ -449,7 +517,7 @@ module ActiveRecord
|
|
449
517
|
def left_outer_joins!(*args) # :nodoc:
|
450
518
|
args.compact!
|
451
519
|
args.flatten!
|
452
|
-
self.left_outer_joins_values
|
520
|
+
self.left_outer_joins_values |= args
|
453
521
|
self
|
454
522
|
end
|
455
523
|
|
@@ -876,6 +944,29 @@ module ActiveRecord
|
|
876
944
|
self
|
877
945
|
end
|
878
946
|
|
947
|
+
# Specify optimizer hints to be used in the SELECT statement.
|
948
|
+
#
|
949
|
+
# Example (for MySQL):
|
950
|
+
#
|
951
|
+
# Topic.optimizer_hints("MAX_EXECUTION_TIME(50000)", "NO_INDEX_MERGE(topics)")
|
952
|
+
# # SELECT /*+ MAX_EXECUTION_TIME(50000) NO_INDEX_MERGE(topics) */ `topics`.* FROM `topics`
|
953
|
+
#
|
954
|
+
# Example (for PostgreSQL with pg_hint_plan):
|
955
|
+
#
|
956
|
+
# Topic.optimizer_hints("SeqScan(topics)", "Parallel(topics 8)")
|
957
|
+
# # SELECT /*+ SeqScan(topics) Parallel(topics 8) */ "topics".* FROM "topics"
|
958
|
+
def optimizer_hints(*args)
|
959
|
+
check_if_method_has_arguments!(:optimizer_hints, args)
|
960
|
+
spawn.optimizer_hints!(*args)
|
961
|
+
end
|
962
|
+
|
963
|
+
def optimizer_hints!(*args) # :nodoc:
|
964
|
+
args.flatten!
|
965
|
+
|
966
|
+
self.optimizer_hints_values |= args
|
967
|
+
self
|
968
|
+
end
|
969
|
+
|
879
970
|
# Reverse the existing order clause on the relation.
|
880
971
|
#
|
881
972
|
# User.order('name ASC').reverse_order # generated SQL has 'ORDER BY name DESC'
|
@@ -895,26 +986,52 @@ module ActiveRecord
|
|
895
986
|
self
|
896
987
|
end
|
897
988
|
|
989
|
+
def skip_preloading! # :nodoc:
|
990
|
+
self.skip_preloading_value = true
|
991
|
+
self
|
992
|
+
end
|
993
|
+
|
994
|
+
# Adds an SQL comment to queries generated from this relation. For example:
|
995
|
+
#
|
996
|
+
# User.annotate("selecting user names").select(:name)
|
997
|
+
# # SELECT "users"."name" FROM "users" /* selecting user names */
|
998
|
+
#
|
999
|
+
# User.annotate("selecting", "user", "names").select(:name)
|
1000
|
+
# # SELECT "users"."name" FROM "users" /* selecting */ /* user */ /* names */
|
1001
|
+
#
|
1002
|
+
# The SQL block comment delimiters, "/*" and "*/", will be added automatically.
|
1003
|
+
def annotate(*args)
|
1004
|
+
check_if_method_has_arguments!(:annotate, args)
|
1005
|
+
spawn.annotate!(*args)
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
# Like #annotate, but modifies relation in place.
|
1009
|
+
def annotate!(*args) # :nodoc:
|
1010
|
+
self.annotate_values += args
|
1011
|
+
self
|
1012
|
+
end
|
1013
|
+
|
898
1014
|
# Returns the Arel object associated with the relation.
|
899
1015
|
def arel(aliases = nil) # :nodoc:
|
900
1016
|
@arel ||= build_arel(aliases)
|
901
1017
|
end
|
902
1018
|
|
903
|
-
|
904
|
-
|
905
|
-
|
1019
|
+
def construct_join_dependency(associations, join_type) # :nodoc:
|
1020
|
+
ActiveRecord::Associations::JoinDependency.new(
|
1021
|
+
klass, table, associations, join_type
|
1022
|
+
)
|
906
1023
|
end
|
907
1024
|
|
908
1025
|
protected
|
1026
|
+
def build_subquery(subquery_alias, select_value) # :nodoc:
|
1027
|
+
subquery = except(:optimizer_hints).arel.as(subquery_alias)
|
909
1028
|
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
@values[name] = value
|
1029
|
+
Arel::SelectManager.new(subquery).project(select_value).tap do |arel|
|
1030
|
+
arel.optimizer_hints(*optimizer_hints_values) unless optimizer_hints_values.empty?
|
1031
|
+
end
|
914
1032
|
end
|
915
1033
|
|
916
1034
|
private
|
917
|
-
|
918
1035
|
def assert_mutability!
|
919
1036
|
raise ImmutableRelation if @loaded
|
920
1037
|
raise ImmutableRelation if defined?(@arel) && @arel
|
@@ -923,14 +1040,17 @@ module ActiveRecord
|
|
923
1040
|
def build_arel(aliases)
|
924
1041
|
arel = Arel::SelectManager.new(table)
|
925
1042
|
|
926
|
-
|
927
|
-
|
1043
|
+
if !joins_values.empty?
|
1044
|
+
build_joins(arel, joins_values.flatten, aliases)
|
1045
|
+
elsif !left_outer_joins_values.empty?
|
1046
|
+
build_left_outer_joins(arel, left_outer_joins_values.flatten, aliases)
|
1047
|
+
end
|
928
1048
|
|
929
1049
|
arel.where(where_clause.ast) unless where_clause.empty?
|
930
1050
|
arel.having(having_clause.ast) unless having_clause.empty?
|
931
1051
|
if limit_value
|
932
1052
|
limit_attribute = ActiveModel::Attribute.with_cast_value(
|
933
|
-
"LIMIT"
|
1053
|
+
"LIMIT",
|
934
1054
|
connection.sanitize_limit(limit_value),
|
935
1055
|
Type.default_value,
|
936
1056
|
)
|
@@ -938,7 +1058,7 @@ module ActiveRecord
|
|
938
1058
|
end
|
939
1059
|
if offset_value
|
940
1060
|
offset_attribute = ActiveModel::Attribute.with_cast_value(
|
941
|
-
"OFFSET"
|
1061
|
+
"OFFSET",
|
942
1062
|
offset_value.to_i,
|
943
1063
|
Type.default_value,
|
944
1064
|
)
|
@@ -950,9 +1070,11 @@ module ActiveRecord
|
|
950
1070
|
|
951
1071
|
build_select(arel)
|
952
1072
|
|
1073
|
+
arel.optimizer_hints(*optimizer_hints_values) unless optimizer_hints_values.empty?
|
953
1074
|
arel.distinct(distinct_value)
|
954
1075
|
arel.from(build_from) unless from_clause.empty?
|
955
1076
|
arel.lock(lock_value) if lock_value
|
1077
|
+
arel.comment(*annotate_values) unless annotate_values.empty?
|
956
1078
|
|
957
1079
|
arel
|
958
1080
|
end
|
@@ -972,68 +1094,101 @@ module ActiveRecord
|
|
972
1094
|
end
|
973
1095
|
end
|
974
1096
|
|
975
|
-
def
|
976
|
-
|
977
|
-
|
1097
|
+
def select_association_list(associations, stashed_joins = nil)
|
1098
|
+
result = []
|
1099
|
+
associations.each do |association|
|
1100
|
+
case association
|
978
1101
|
when Hash, Symbol, Array
|
979
|
-
|
1102
|
+
result << association
|
980
1103
|
when ActiveRecord::Associations::JoinDependency
|
981
|
-
|
1104
|
+
stashed_joins&.<< association
|
982
1105
|
else
|
983
|
-
|
1106
|
+
yield if block_given?
|
984
1107
|
end
|
985
1108
|
end
|
1109
|
+
result
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
def valid_association_list(associations, stashed_joins)
|
1113
|
+
select_association_list(associations, stashed_joins) do
|
1114
|
+
raise ArgumentError, "only Hash, Symbol and Array are allowed"
|
1115
|
+
end
|
1116
|
+
end
|
986
1117
|
|
1118
|
+
def build_left_outer_joins(manager, outer_joins, aliases)
|
1119
|
+
buckets = Hash.new { |h, k| h[k] = [] }
|
1120
|
+
buckets[:association_join] = valid_association_list(outer_joins, buckets[:stashed_join])
|
987
1121
|
build_join_query(manager, buckets, Arel::Nodes::OuterJoin, aliases)
|
988
1122
|
end
|
989
1123
|
|
1124
|
+
class ::Arel::Nodes::LeadingJoin < Arel::Nodes::InnerJoin # :nodoc:
|
1125
|
+
end
|
1126
|
+
|
990
1127
|
def build_joins(manager, joins, aliases)
|
991
|
-
buckets =
|
1128
|
+
buckets = Hash.new { |h, k| h[k] = [] }
|
1129
|
+
|
1130
|
+
unless left_outer_joins_values.empty?
|
1131
|
+
stashed_left_joins = []
|
1132
|
+
left_joins = valid_association_list(left_outer_joins_values.flatten, stashed_left_joins)
|
1133
|
+
stashed_left_joins.unshift construct_join_dependency(left_joins, Arel::Nodes::OuterJoin)
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
if joins.last.is_a?(ActiveRecord::Associations::JoinDependency)
|
1137
|
+
stashed_eager_load = joins.pop if joins.last.base_klass == klass
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
joins.map! do |join|
|
1141
|
+
if join.is_a?(String)
|
1142
|
+
table.create_string_join(Arel.sql(join.strip)) unless join.blank?
|
1143
|
+
else
|
1144
|
+
join
|
1145
|
+
end
|
1146
|
+
end.delete_if(&:blank?).uniq!
|
1147
|
+
|
1148
|
+
while joins.first.is_a?(Arel::Nodes::Join)
|
1149
|
+
join_node = joins.shift
|
1150
|
+
if !join_node.is_a?(Arel::Nodes::LeadingJoin) && (stashed_eager_load || stashed_left_joins)
|
1151
|
+
buckets[:join_node] << join_node
|
1152
|
+
else
|
1153
|
+
buckets[:leading_join] << join_node
|
1154
|
+
end
|
1155
|
+
end
|
1156
|
+
|
1157
|
+
joins.each do |join|
|
992
1158
|
case join
|
993
|
-
when String
|
994
|
-
:string_join
|
995
1159
|
when Hash, Symbol, Array
|
996
|
-
:association_join
|
1160
|
+
buckets[:association_join] << join
|
997
1161
|
when ActiveRecord::Associations::JoinDependency
|
998
|
-
:stashed_join
|
1162
|
+
buckets[:stashed_join] << join
|
999
1163
|
when Arel::Nodes::Join
|
1000
|
-
:join_node
|
1164
|
+
buckets[:join_node] << join
|
1001
1165
|
else
|
1002
1166
|
raise "unknown class: %s" % join.class.name
|
1003
1167
|
end
|
1004
1168
|
end
|
1005
1169
|
|
1170
|
+
buckets[:stashed_join].concat stashed_left_joins if stashed_left_joins
|
1171
|
+
buckets[:stashed_join] << stashed_eager_load if stashed_eager_load
|
1172
|
+
|
1006
1173
|
build_join_query(manager, buckets, Arel::Nodes::InnerJoin, aliases)
|
1007
1174
|
end
|
1008
1175
|
|
1009
1176
|
def build_join_query(manager, buckets, join_type, aliases)
|
1010
|
-
buckets.default = []
|
1011
|
-
|
1012
1177
|
association_joins = buckets[:association_join]
|
1013
1178
|
stashed_joins = buckets[:stashed_join]
|
1014
|
-
|
1015
|
-
|
1179
|
+
leading_joins = buckets[:leading_join]
|
1180
|
+
join_nodes = buckets[:join_node]
|
1016
1181
|
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
join_dependency = ActiveRecord::Associations::JoinDependency.new(
|
1021
|
-
klass, table, association_joins
|
1022
|
-
)
|
1182
|
+
join_sources = manager.join_sources
|
1183
|
+
join_sources.concat(leading_joins) unless leading_joins.empty?
|
1023
1184
|
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
alias_tracker.aliases
|
1030
|
-
end
|
1185
|
+
unless association_joins.empty? && stashed_joins.empty?
|
1186
|
+
alias_tracker = alias_tracker(leading_joins + join_nodes, aliases)
|
1187
|
+
join_dependency = construct_join_dependency(association_joins, join_type)
|
1188
|
+
join_sources.concat(join_dependency.join_constraints(stashed_joins, alias_tracker))
|
1189
|
+
end
|
1031
1190
|
|
1032
|
-
|
1033
|
-
joins
|
1034
|
-
.flatten
|
1035
|
-
.reject(&:blank?)
|
1036
|
-
.map { |join| table.create_string_join(Arel.sql(join)) }
|
1191
|
+
join_sources.concat(join_nodes) unless join_nodes.empty?
|
1037
1192
|
end
|
1038
1193
|
|
1039
1194
|
def build_select(arel)
|
@@ -1064,7 +1219,7 @@ module ActiveRecord
|
|
1064
1219
|
end
|
1065
1220
|
|
1066
1221
|
def arel_column(field)
|
1067
|
-
field = klass.
|
1222
|
+
field = klass.attribute_aliases[field] || field
|
1068
1223
|
from = from_clause.name || from_clause.value
|
1069
1224
|
|
1070
1225
|
if klass.columns_hash.key?(field) && (!from || table_name_matches?(from))
|
@@ -1075,7 +1230,9 @@ module ActiveRecord
|
|
1075
1230
|
end
|
1076
1231
|
|
1077
1232
|
def table_name_matches?(from)
|
1078
|
-
|
1233
|
+
table_name = Regexp.escape(table.name)
|
1234
|
+
quoted_table_name = Regexp.escape(connection.quote_table_name(table.name))
|
1235
|
+
/(?:\A|(?<!FROM)\s)(?:\b#{table_name}\b|#{quoted_table_name})(?!\.)/i.match?(from.to_s)
|
1079
1236
|
end
|
1080
1237
|
|
1081
1238
|
def reverse_sql_order(order_query)
|
@@ -1093,7 +1250,7 @@ module ActiveRecord
|
|
1093
1250
|
o.reverse
|
1094
1251
|
when String
|
1095
1252
|
if does_not_support_reverse?(o)
|
1096
|
-
raise IrreversibleOrderError, "Order #{o.inspect}
|
1253
|
+
raise IrreversibleOrderError, "Order #{o.inspect} cannot be reversed automatically"
|
1097
1254
|
end
|
1098
1255
|
o.split(",").map! do |s|
|
1099
1256
|
s.strip!
|
@@ -1113,7 +1270,7 @@ module ActiveRecord
|
|
1113
1270
|
# Uses SQL function with multiple arguments.
|
1114
1271
|
(order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) ||
|
1115
1272
|
# Uses "nulls first" like construction.
|
1116
|
-
|
1273
|
+
/\bnulls\s+(?:first|last)\b/i.match?(order)
|
1117
1274
|
end
|
1118
1275
|
|
1119
1276
|
def build_order(arel)
|
@@ -1139,14 +1296,15 @@ module ActiveRecord
|
|
1139
1296
|
end
|
1140
1297
|
|
1141
1298
|
def preprocess_order_args(order_args)
|
1299
|
+
order_args.reject!(&:blank?)
|
1142
1300
|
order_args.map! do |arg|
|
1143
1301
|
klass.sanitize_sql_for_order(arg)
|
1144
1302
|
end
|
1145
1303
|
order_args.flatten!
|
1146
1304
|
|
1147
|
-
@klass.
|
1305
|
+
@klass.disallow_raw_sql!(
|
1148
1306
|
order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a },
|
1149
|
-
|
1307
|
+
permit: connection.column_name_with_order_matcher
|
1150
1308
|
)
|
1151
1309
|
|
1152
1310
|
validate_order_args(order_args)
|
@@ -1207,10 +1365,15 @@ module ActiveRecord
|
|
1207
1365
|
end
|
1208
1366
|
end
|
1209
1367
|
|
1210
|
-
STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references]
|
1368
|
+
STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references, :annotate, :optimizer_hints]
|
1211
1369
|
def structurally_incompatible_values_for_or(other)
|
1370
|
+
values = other.values
|
1212
1371
|
STRUCTURAL_OR_METHODS.reject do |method|
|
1213
|
-
|
1372
|
+
default = DEFAULT_VALUES[method]
|
1373
|
+
v1, v2 = @values.fetch(method, default), values.fetch(method, default)
|
1374
|
+
v1 = v1.uniq if v1.is_a?(Array)
|
1375
|
+
v2 = v2.uniq if v2.is_a?(Array)
|
1376
|
+
v1 == v2
|
1214
1377
|
end
|
1215
1378
|
end
|
1216
1379
|
|
@@ -8,7 +8,7 @@ module ActiveRecord
|
|
8
8
|
module SpawnMethods
|
9
9
|
# This is overridden by Associations::CollectionProxy
|
10
10
|
def spawn #:nodoc:
|
11
|
-
|
11
|
+
already_in_scope? ? klass.all : clone
|
12
12
|
end
|
13
13
|
|
14
14
|
# Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an ActiveRecord::Relation.
|
@@ -67,7 +67,6 @@ module ActiveRecord
|
|
67
67
|
end
|
68
68
|
|
69
69
|
private
|
70
|
-
|
71
70
|
def relation_with(values)
|
72
71
|
result = Relation.create(klass, values: values)
|
73
72
|
result.extend(*extending_values) if extending_values.any?
|