activerecord 5.2.3 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +624 -548
- data/MIT-LICENSE +3 -1
- data/README.rdoc +4 -2
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +9 -2
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations.rb +19 -14
- data/lib/active_record/associations/association.rb +52 -19
- data/lib/active_record/associations/association_scope.rb +4 -6
- 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 +5 -15
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- 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 +6 -21
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -10
- data/lib/active_record/associations/has_many_through_association.rb +18 -25
- 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.rb +24 -28
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -7
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +39 -31
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -22
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -53
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +17 -24
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +16 -6
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +5 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +116 -19
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +95 -123
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +20 -11
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +133 -54
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +180 -47
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +128 -194
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +73 -13
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- 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 +129 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.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 +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +160 -74
- 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 +118 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +127 -143
- data/lib/active_record/connection_handling.rb +149 -27
- data/lib/active_record/core.rb +100 -60
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +233 -0
- 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 +79 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +37 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -1
- 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 +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +145 -472
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -3
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +10 -2
- data/lib/active_record/locking/optimistic.rb +5 -6
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +100 -81
- data/lib/active_record/migration/command_recorder.rb +50 -6
- data/lib/active_record/migration/compatibility.rb +76 -49
- data/lib/active_record/model_schema.rb +30 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +228 -24
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +32 -20
- data/lib/active_record/railtie.rb +80 -43
- 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 +196 -46
- data/lib/active_record/reflection.rb +42 -44
- data/lib/active_record/relation.rb +310 -80
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +58 -51
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +14 -27
- data/lib/active_record/relation/merger.rb +11 -20
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- 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/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +206 -78
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +14 -10
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -11
- 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 +5 -1
- data/lib/active_record/scoping.rb +8 -8
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +19 -15
- data/lib/active_record/statement_cache.rb +32 -5
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/table_metadata.rb +10 -17
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +39 -25
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +56 -65
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- 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.rb +1 -0
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/arel.rb +51 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -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.rb +68 -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/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -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.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/migration.rb +14 -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/model/model_generator.rb +1 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +107 -25
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -117,18 +117,16 @@ module ActiveRecord
|
|
117
117
|
if other.klass == relation.klass
|
118
118
|
relation.joins!(*other.joins_values)
|
119
119
|
else
|
120
|
-
|
120
|
+
associations, others = other.joins_values.partition do |join|
|
121
121
|
case join
|
122
|
-
when Hash, Symbol, Array
|
123
|
-
ActiveRecord::Associations::JoinDependency.new(
|
124
|
-
other.klass, other.table, join
|
125
|
-
)
|
126
|
-
else
|
127
|
-
join
|
122
|
+
when Hash, Symbol, Array; true
|
128
123
|
end
|
129
124
|
end
|
130
125
|
|
131
|
-
|
126
|
+
join_dependency = other.construct_join_dependency(
|
127
|
+
associations, Arel::Nodes::InnerJoin
|
128
|
+
)
|
129
|
+
relation.joins!(join_dependency, *others)
|
132
130
|
end
|
133
131
|
end
|
134
132
|
|
@@ -138,18 +136,11 @@ module ActiveRecord
|
|
138
136
|
if other.klass == relation.klass
|
139
137
|
relation.left_outer_joins!(*other.left_outer_joins_values)
|
140
138
|
else
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
)
|
147
|
-
else
|
148
|
-
join
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
relation.left_outer_joins!(*joins_dependency)
|
139
|
+
associations = other.left_outer_joins_values
|
140
|
+
join_dependency = other.construct_join_dependency(
|
141
|
+
associations, Arel::Nodes::OuterJoin
|
142
|
+
)
|
143
|
+
relation.joins!(join_dependency)
|
153
144
|
end
|
154
145
|
end
|
155
146
|
|
@@ -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,9 +62,6 @@ 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
|
|
@@ -115,6 +112,7 @@ module ActiveRecord
|
|
115
112
|
end
|
116
113
|
|
117
114
|
private
|
115
|
+
attr_reader :table
|
118
116
|
|
119
117
|
def associated_predicate_builder(association_name)
|
120
118
|
self.class.new(table.associated_table(association_name))
|
@@ -122,11 +120,11 @@ module ActiveRecord
|
|
122
120
|
|
123
121
|
def convert_dot_notation_to_hash(attributes)
|
124
122
|
dot_notation = attributes.select do |k, v|
|
125
|
-
k.include?("."
|
123
|
+
k.include?(".") && !v.is_a?(Hash)
|
126
124
|
end
|
127
125
|
|
128
126
|
dot_notation.each_key do |key|
|
129
|
-
table_name, column_name = key.split("."
|
127
|
+
table_name, column_name = key.split(".")
|
130
128
|
value = attributes.delete(key)
|
131
129
|
attributes[table_name] ||= {}
|
132
130
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/array/extract"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
class PredicateBuilder
|
5
7
|
class ArrayHandler # :nodoc:
|
@@ -11,8 +13,8 @@ module ActiveRecord
|
|
11
13
|
return attribute.in([]) if value.empty?
|
12
14
|
|
13
15
|
values = value.map { |x| x.is_a?(Base) ? x.id : x }
|
14
|
-
nils
|
15
|
-
ranges
|
16
|
+
nils = values.extract!(&:nil?)
|
17
|
+
ranges = values.extract! { |v| v.is_a?(Range) }
|
16
18
|
|
17
19
|
values_predicate =
|
18
20
|
case values.length
|
@@ -34,8 +36,7 @@ module ActiveRecord
|
|
34
36
|
array_predicates.inject(&:or)
|
35
37
|
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
private
|
39
40
|
attr_reader :predicate_builder
|
40
41
|
|
41
42
|
module NullPredicate # :nodoc:
|
@@ -12,12 +12,9 @@ module ActiveRecord
|
|
12
12
|
[associated_table.association_join_foreign_key.to_s => ids]
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
17
|
-
protected
|
15
|
+
private
|
18
16
|
attr_reader :associated_table, :value
|
19
17
|
|
20
|
-
private
|
21
18
|
def ids
|
22
19
|
case value
|
23
20
|
when Relation
|
@@ -17,12 +17,9 @@ module ActiveRecord
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
22
|
-
protected
|
20
|
+
private
|
23
21
|
attr_reader :associated_table, :values
|
24
22
|
|
25
|
-
private
|
26
23
|
def type_to_ids_mapping
|
27
24
|
default_hash = Hash.new { |hsh, key| hsh[key] = [] }
|
28
25
|
values.each_with_object(default_hash) do |value, hash|
|
@@ -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
|
@@ -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,31 @@ 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 conditions manually
|
55
|
+
(`#{ opts.keys.map { |key| ".where.not(#{key.inspect} => ...)" }.join }`).
|
56
|
+
MSG
|
57
|
+
@scope.where_clause += where_clause.invert(:nor)
|
58
|
+
else
|
59
|
+
@scope.where_clause += where_clause.invert
|
60
|
+
end
|
61
|
+
|
54
62
|
@scope
|
55
63
|
end
|
64
|
+
|
65
|
+
private
|
66
|
+
def not_behaves_as_nor?(opts)
|
67
|
+
opts.is_a?(Hash) && opts.size > 1
|
68
|
+
end
|
56
69
|
end
|
57
70
|
|
58
71
|
FROZEN_EMPTY_ARRAY = [].freeze
|
@@ -67,11 +80,13 @@ module ActiveRecord
|
|
67
80
|
end
|
68
81
|
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
69
82
|
def #{method_name} # def includes_values
|
70
|
-
|
83
|
+
default = DEFAULT_VALUES[:#{name}] # default = DEFAULT_VALUES[:includes]
|
84
|
+
@values.fetch(:#{name}, default) # @values.fetch(:includes, default)
|
71
85
|
end # end
|
72
86
|
|
73
87
|
def #{method_name}=(value) # def includes_values=(value)
|
74
|
-
|
88
|
+
assert_mutability! # assert_mutability!
|
89
|
+
@values[:#{name}] = value # @values[:includes] = value
|
75
90
|
end # end
|
76
91
|
CODE
|
77
92
|
end
|
@@ -100,7 +115,7 @@ module ActiveRecord
|
|
100
115
|
#
|
101
116
|
# === conditions
|
102
117
|
#
|
103
|
-
# If you want to add conditions to your included models you'll have
|
118
|
+
# If you want to add string conditions to your included models, you'll have
|
104
119
|
# to explicitly reference them. For example:
|
105
120
|
#
|
106
121
|
# User.includes(:posts).where('posts.name = ?', 'example')
|
@@ -111,6 +126,12 @@ module ActiveRecord
|
|
111
126
|
#
|
112
127
|
# Note that #includes works with association names while #references needs
|
113
128
|
# the actual table name.
|
129
|
+
#
|
130
|
+
# If you pass the conditions via hash, you don't need to call #references
|
131
|
+
# explicitly, as #where references the tables for you. For example, this
|
132
|
+
# will work correctly:
|
133
|
+
#
|
134
|
+
# User.includes(:posts).where(posts: { name: 'example' })
|
114
135
|
def includes(*args)
|
115
136
|
check_if_method_has_arguments!(:includes, args)
|
116
137
|
spawn.includes!(*args)
|
@@ -154,6 +175,19 @@ module ActiveRecord
|
|
154
175
|
self
|
155
176
|
end
|
156
177
|
|
178
|
+
# Extracts a named +association+ from the relation. The named association is first preloaded,
|
179
|
+
# then the individual association records are collected from the relation. Like so:
|
180
|
+
#
|
181
|
+
# account.memberships.extract_associated(:user)
|
182
|
+
# # => Returns collection of User records
|
183
|
+
#
|
184
|
+
# This is short-hand for:
|
185
|
+
#
|
186
|
+
# account.memberships.preload(:user).collect(&:user)
|
187
|
+
def extract_associated(association)
|
188
|
+
preload(association).collect(&association)
|
189
|
+
end
|
190
|
+
|
157
191
|
# Use to indicate that the given +table_names+ are referenced by an SQL string,
|
158
192
|
# and should therefore be JOINed in any query rather than loaded separately.
|
159
193
|
# This method only works in conjunction with #includes.
|
@@ -231,14 +265,33 @@ module ActiveRecord
|
|
231
265
|
end
|
232
266
|
|
233
267
|
def _select!(*fields) # :nodoc:
|
268
|
+
fields.reject!(&:blank?)
|
234
269
|
fields.flatten!
|
235
|
-
fields.map! do |field|
|
236
|
-
klass.attribute_alias?(field) ? klass.attribute_alias(field).to_sym : field
|
237
|
-
end
|
238
270
|
self.select_values += fields
|
239
271
|
self
|
240
272
|
end
|
241
273
|
|
274
|
+
# Allows you to change a previously set select statement.
|
275
|
+
#
|
276
|
+
# Post.select(:title, :body)
|
277
|
+
# # SELECT `posts`.`title`, `posts`.`body` FROM `posts`
|
278
|
+
#
|
279
|
+
# Post.select(:title, :body).reselect(:created_at)
|
280
|
+
# # SELECT `posts`.`created_at` FROM `posts`
|
281
|
+
#
|
282
|
+
# This is short-hand for <tt>unscope(:select).select(fields)</tt>.
|
283
|
+
# Note that we're unscoping the entire select statement.
|
284
|
+
def reselect(*args)
|
285
|
+
check_if_method_has_arguments!(:reselect, args)
|
286
|
+
spawn.reselect!(*args)
|
287
|
+
end
|
288
|
+
|
289
|
+
# Same as #reselect but operates on relation in-place instead of copying.
|
290
|
+
def reselect!(*args) # :nodoc:
|
291
|
+
self.select_values = args
|
292
|
+
self
|
293
|
+
end
|
294
|
+
|
242
295
|
# Allows to specify a group attribute:
|
243
296
|
#
|
244
297
|
# User.group(:name)
|
@@ -319,7 +372,7 @@ module ActiveRecord
|
|
319
372
|
|
320
373
|
# Same as #reorder but operates on relation in-place instead of copying.
|
321
374
|
def reorder!(*args) # :nodoc:
|
322
|
-
preprocess_order_args(args)
|
375
|
+
preprocess_order_args(args) unless args.all?(&:blank?)
|
323
376
|
|
324
377
|
self.reordering_value = true
|
325
378
|
self.order_values = args
|
@@ -327,8 +380,8 @@ module ActiveRecord
|
|
327
380
|
end
|
328
381
|
|
329
382
|
VALID_UNSCOPING_VALUES = Set.new([:where, :select, :group, :order, :lock,
|
330
|
-
:limit, :offset, :joins, :left_outer_joins,
|
331
|
-
:includes, :from, :readonly, :having])
|
383
|
+
:limit, :offset, :joins, :left_outer_joins, :annotate,
|
384
|
+
:includes, :from, :readonly, :having, :optimizer_hints])
|
332
385
|
|
333
386
|
# Removes an unwanted relation that is already defined on a chain of relations.
|
334
387
|
# This is useful when passing around chains of relations and would like to
|
@@ -379,7 +432,8 @@ module ActiveRecord
|
|
379
432
|
if !VALID_UNSCOPING_VALUES.include?(scope)
|
380
433
|
raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
|
381
434
|
end
|
382
|
-
|
435
|
+
assert_mutability!
|
436
|
+
@values[scope] = DEFAULT_VALUES[scope]
|
383
437
|
when Hash
|
384
438
|
scope.each do |key, target_value|
|
385
439
|
if key != :where
|
@@ -879,6 +933,29 @@ module ActiveRecord
|
|
879
933
|
self
|
880
934
|
end
|
881
935
|
|
936
|
+
# Specify optimizer hints to be used in the SELECT statement.
|
937
|
+
#
|
938
|
+
# Example (for MySQL):
|
939
|
+
#
|
940
|
+
# Topic.optimizer_hints("MAX_EXECUTION_TIME(50000)", "NO_INDEX_MERGE(topics)")
|
941
|
+
# # SELECT /*+ MAX_EXECUTION_TIME(50000) NO_INDEX_MERGE(topics) */ `topics`.* FROM `topics`
|
942
|
+
#
|
943
|
+
# Example (for PostgreSQL with pg_hint_plan):
|
944
|
+
#
|
945
|
+
# Topic.optimizer_hints("SeqScan(topics)", "Parallel(topics 8)")
|
946
|
+
# # SELECT /*+ SeqScan(topics) Parallel(topics 8) */ "topics".* FROM "topics"
|
947
|
+
def optimizer_hints(*args)
|
948
|
+
check_if_method_has_arguments!(:optimizer_hints, args)
|
949
|
+
spawn.optimizer_hints!(*args)
|
950
|
+
end
|
951
|
+
|
952
|
+
def optimizer_hints!(*args) # :nodoc:
|
953
|
+
args.flatten!
|
954
|
+
|
955
|
+
self.optimizer_hints_values |= args
|
956
|
+
self
|
957
|
+
end
|
958
|
+
|
882
959
|
# Reverse the existing order clause on the relation.
|
883
960
|
#
|
884
961
|
# User.order('name ASC').reverse_order # generated SQL has 'ORDER BY name DESC'
|
@@ -898,26 +975,52 @@ module ActiveRecord
|
|
898
975
|
self
|
899
976
|
end
|
900
977
|
|
978
|
+
def skip_preloading! # :nodoc:
|
979
|
+
self.skip_preloading_value = true
|
980
|
+
self
|
981
|
+
end
|
982
|
+
|
983
|
+
# Adds an SQL comment to queries generated from this relation. For example:
|
984
|
+
#
|
985
|
+
# User.annotate("selecting user names").select(:name)
|
986
|
+
# # SELECT "users"."name" FROM "users" /* selecting user names */
|
987
|
+
#
|
988
|
+
# User.annotate("selecting", "user", "names").select(:name)
|
989
|
+
# # SELECT "users"."name" FROM "users" /* selecting */ /* user */ /* names */
|
990
|
+
#
|
991
|
+
# The SQL block comment delimiters, "/*" and "*/", will be added automatically.
|
992
|
+
def annotate(*args)
|
993
|
+
check_if_method_has_arguments!(:annotate, args)
|
994
|
+
spawn.annotate!(*args)
|
995
|
+
end
|
996
|
+
|
997
|
+
# Like #annotate, but modifies relation in place.
|
998
|
+
def annotate!(*args) # :nodoc:
|
999
|
+
self.annotate_values += args
|
1000
|
+
self
|
1001
|
+
end
|
1002
|
+
|
901
1003
|
# Returns the Arel object associated with the relation.
|
902
1004
|
def arel(aliases = nil) # :nodoc:
|
903
1005
|
@arel ||= build_arel(aliases)
|
904
1006
|
end
|
905
1007
|
|
906
|
-
|
907
|
-
|
908
|
-
|
1008
|
+
def construct_join_dependency(associations, join_type) # :nodoc:
|
1009
|
+
ActiveRecord::Associations::JoinDependency.new(
|
1010
|
+
klass, table, associations, join_type
|
1011
|
+
)
|
909
1012
|
end
|
910
1013
|
|
911
1014
|
protected
|
1015
|
+
def build_subquery(subquery_alias, select_value) # :nodoc:
|
1016
|
+
subquery = except(:optimizer_hints).arel.as(subquery_alias)
|
912
1017
|
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
@values[name] = value
|
1018
|
+
Arel::SelectManager.new(subquery).project(select_value).tap do |arel|
|
1019
|
+
arel.optimizer_hints(*optimizer_hints_values) unless optimizer_hints_values.empty?
|
1020
|
+
end
|
917
1021
|
end
|
918
1022
|
|
919
1023
|
private
|
920
|
-
|
921
1024
|
def assert_mutability!
|
922
1025
|
raise ImmutableRelation if @loaded
|
923
1026
|
raise ImmutableRelation if defined?(@arel) && @arel
|
@@ -926,14 +1029,17 @@ module ActiveRecord
|
|
926
1029
|
def build_arel(aliases)
|
927
1030
|
arel = Arel::SelectManager.new(table)
|
928
1031
|
|
929
|
-
|
930
|
-
|
1032
|
+
if !joins_values.empty?
|
1033
|
+
build_joins(arel, joins_values.flatten, aliases)
|
1034
|
+
elsif !left_outer_joins_values.empty?
|
1035
|
+
build_left_outer_joins(arel, left_outer_joins_values.flatten, aliases)
|
1036
|
+
end
|
931
1037
|
|
932
1038
|
arel.where(where_clause.ast) unless where_clause.empty?
|
933
1039
|
arel.having(having_clause.ast) unless having_clause.empty?
|
934
1040
|
if limit_value
|
935
1041
|
limit_attribute = ActiveModel::Attribute.with_cast_value(
|
936
|
-
"LIMIT"
|
1042
|
+
"LIMIT",
|
937
1043
|
connection.sanitize_limit(limit_value),
|
938
1044
|
Type.default_value,
|
939
1045
|
)
|
@@ -941,7 +1047,7 @@ module ActiveRecord
|
|
941
1047
|
end
|
942
1048
|
if offset_value
|
943
1049
|
offset_attribute = ActiveModel::Attribute.with_cast_value(
|
944
|
-
"OFFSET"
|
1050
|
+
"OFFSET",
|
945
1051
|
offset_value.to_i,
|
946
1052
|
Type.default_value,
|
947
1053
|
)
|
@@ -953,9 +1059,11 @@ module ActiveRecord
|
|
953
1059
|
|
954
1060
|
build_select(arel)
|
955
1061
|
|
1062
|
+
arel.optimizer_hints(*optimizer_hints_values) unless optimizer_hints_values.empty?
|
956
1063
|
arel.distinct(distinct_value)
|
957
1064
|
arel.from(build_from) unless from_clause.empty?
|
958
1065
|
arel.lock(lock_value) if lock_value
|
1066
|
+
arel.comment(*annotate_values) unless annotate_values.empty?
|
959
1067
|
|
960
1068
|
arel
|
961
1069
|
end
|
@@ -975,32 +1083,56 @@ module ActiveRecord
|
|
975
1083
|
end
|
976
1084
|
end
|
977
1085
|
|
978
|
-
def
|
979
|
-
|
980
|
-
case
|
1086
|
+
def valid_association_list(associations)
|
1087
|
+
associations.each do |association|
|
1088
|
+
case association
|
981
1089
|
when Hash, Symbol, Array
|
982
|
-
|
983
|
-
when ActiveRecord::Associations::JoinDependency
|
984
|
-
:stashed_join
|
1090
|
+
# valid
|
985
1091
|
else
|
986
1092
|
raise ArgumentError, "only Hash, Symbol and Array are allowed"
|
987
1093
|
end
|
988
1094
|
end
|
1095
|
+
end
|
989
1096
|
|
1097
|
+
def build_left_outer_joins(manager, outer_joins, aliases)
|
1098
|
+
buckets = Hash.new { |h, k| h[k] = [] }
|
1099
|
+
buckets[:association_join] = valid_association_list(outer_joins)
|
990
1100
|
build_join_query(manager, buckets, Arel::Nodes::OuterJoin, aliases)
|
991
1101
|
end
|
992
1102
|
|
993
1103
|
def build_joins(manager, joins, aliases)
|
994
|
-
buckets =
|
1104
|
+
buckets = Hash.new { |h, k| h[k] = [] }
|
1105
|
+
|
1106
|
+
unless left_outer_joins_values.empty?
|
1107
|
+
left_joins = valid_association_list(left_outer_joins_values.flatten)
|
1108
|
+
buckets[:stashed_join] << construct_join_dependency(left_joins, Arel::Nodes::OuterJoin)
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
joins.map! do |join|
|
1112
|
+
if join.is_a?(String)
|
1113
|
+
table.create_string_join(Arel.sql(join.strip)) unless join.blank?
|
1114
|
+
else
|
1115
|
+
join
|
1116
|
+
end
|
1117
|
+
end.delete_if(&:blank?).uniq!
|
1118
|
+
|
1119
|
+
while joins.first.is_a?(Arel::Nodes::Join)
|
1120
|
+
join_node = joins.shift
|
1121
|
+
if join_node.is_a?(Arel::Nodes::StringJoin) && !buckets[:stashed_join].empty?
|
1122
|
+
buckets[:join_node] << join_node
|
1123
|
+
else
|
1124
|
+
buckets[:leading_join] << join_node
|
1125
|
+
end
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
joins.each do |join|
|
995
1129
|
case join
|
996
|
-
when String
|
997
|
-
:string_join
|
998
1130
|
when Hash, Symbol, Array
|
999
|
-
:association_join
|
1131
|
+
buckets[:association_join] << join
|
1000
1132
|
when ActiveRecord::Associations::JoinDependency
|
1001
|
-
:stashed_join
|
1133
|
+
buckets[:stashed_join] << join
|
1002
1134
|
when Arel::Nodes::Join
|
1003
|
-
:join_node
|
1135
|
+
buckets[:join_node] << join
|
1004
1136
|
else
|
1005
1137
|
raise "unknown class: %s" % join.class.name
|
1006
1138
|
end
|
@@ -1010,33 +1142,21 @@ module ActiveRecord
|
|
1010
1142
|
end
|
1011
1143
|
|
1012
1144
|
def build_join_query(manager, buckets, join_type, aliases)
|
1013
|
-
buckets.default = []
|
1014
|
-
|
1015
1145
|
association_joins = buckets[:association_join]
|
1016
1146
|
stashed_joins = buckets[:stashed_join]
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
join_list = join_nodes + convert_join_strings_to_ast(string_joins)
|
1021
|
-
alias_tracker = alias_tracker(join_list, aliases)
|
1022
|
-
|
1023
|
-
join_dependency = ActiveRecord::Associations::JoinDependency.new(
|
1024
|
-
klass, table, association_joins
|
1025
|
-
)
|
1147
|
+
leading_joins = buckets[:leading_join]
|
1148
|
+
join_nodes = buckets[:join_node]
|
1026
1149
|
|
1027
|
-
|
1028
|
-
|
1150
|
+
join_sources = manager.join_sources
|
1151
|
+
join_sources.concat(leading_joins) unless leading_joins.empty?
|
1029
1152
|
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1153
|
+
unless association_joins.empty? && stashed_joins.empty?
|
1154
|
+
alias_tracker = alias_tracker(leading_joins + join_nodes, aliases)
|
1155
|
+
join_dependency = construct_join_dependency(association_joins, join_type)
|
1156
|
+
join_sources.concat(join_dependency.join_constraints(stashed_joins, alias_tracker))
|
1157
|
+
end
|
1034
1158
|
|
1035
|
-
|
1036
|
-
joins
|
1037
|
-
.flatten
|
1038
|
-
.reject(&:blank?)
|
1039
|
-
.map { |join| table.create_string_join(Arel.sql(join)) }
|
1159
|
+
join_sources.concat(join_nodes) unless join_nodes.empty?
|
1040
1160
|
end
|
1041
1161
|
|
1042
1162
|
def build_select(arel)
|
@@ -1053,10 +1173,11 @@ module ActiveRecord
|
|
1053
1173
|
columns.flat_map do |field|
|
1054
1174
|
case field
|
1055
1175
|
when Symbol
|
1056
|
-
field
|
1057
|
-
|
1176
|
+
arel_column(field.to_s) do |attr_name|
|
1177
|
+
connection.quote_table_name(attr_name)
|
1178
|
+
end
|
1058
1179
|
when String
|
1059
|
-
arel_column(field)
|
1180
|
+
arel_column(field, &:itself)
|
1060
1181
|
when Proc
|
1061
1182
|
field.call
|
1062
1183
|
else
|
@@ -1066,13 +1187,13 @@ module ActiveRecord
|
|
1066
1187
|
end
|
1067
1188
|
|
1068
1189
|
def arel_column(field)
|
1069
|
-
field = klass.
|
1190
|
+
field = klass.attribute_aliases[field] || field
|
1070
1191
|
from = from_clause.name || from_clause.value
|
1071
1192
|
|
1072
1193
|
if klass.columns_hash.key?(field) && (!from || table_name_matches?(from))
|
1073
1194
|
arel_attribute(field)
|
1074
1195
|
else
|
1075
|
-
yield
|
1196
|
+
yield field
|
1076
1197
|
end
|
1077
1198
|
end
|
1078
1199
|
|
@@ -1095,7 +1216,7 @@ module ActiveRecord
|
|
1095
1216
|
o.reverse
|
1096
1217
|
when String
|
1097
1218
|
if does_not_support_reverse?(o)
|
1098
|
-
raise IrreversibleOrderError, "Order #{o.inspect}
|
1219
|
+
raise IrreversibleOrderError, "Order #{o.inspect} cannot be reversed automatically"
|
1099
1220
|
end
|
1100
1221
|
o.split(",").map! do |s|
|
1101
1222
|
s.strip!
|
@@ -1115,7 +1236,7 @@ module ActiveRecord
|
|
1115
1236
|
# Uses SQL function with multiple arguments.
|
1116
1237
|
(order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) ||
|
1117
1238
|
# Uses "nulls first" like construction.
|
1118
|
-
|
1239
|
+
/\bnulls\s+(?:first|last)\b/i.match?(order)
|
1119
1240
|
end
|
1120
1241
|
|
1121
1242
|
def build_order(arel)
|
@@ -1141,14 +1262,15 @@ module ActiveRecord
|
|
1141
1262
|
end
|
1142
1263
|
|
1143
1264
|
def preprocess_order_args(order_args)
|
1265
|
+
order_args.reject!(&:blank?)
|
1144
1266
|
order_args.map! do |arg|
|
1145
1267
|
klass.sanitize_sql_for_order(arg)
|
1146
1268
|
end
|
1147
1269
|
order_args.flatten!
|
1148
1270
|
|
1149
|
-
@klass.
|
1271
|
+
@klass.disallow_raw_sql!(
|
1150
1272
|
order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a },
|
1151
|
-
|
1273
|
+
permit: connection.column_name_with_order_matcher
|
1152
1274
|
)
|
1153
1275
|
|
1154
1276
|
validate_order_args(order_args)
|
@@ -1161,20 +1283,14 @@ module ActiveRecord
|
|
1161
1283
|
order_args.map! do |arg|
|
1162
1284
|
case arg
|
1163
1285
|
when Symbol
|
1164
|
-
arg
|
1165
|
-
arel_column(arg) {
|
1166
|
-
Arel.sql(connection.quote_table_name(arg))
|
1167
|
-
}.asc
|
1286
|
+
order_column(arg.to_s).asc
|
1168
1287
|
when Hash
|
1169
1288
|
arg.map { |field, dir|
|
1170
1289
|
case field
|
1171
1290
|
when Arel::Nodes::SqlLiteral
|
1172
1291
|
field.send(dir.downcase)
|
1173
1292
|
else
|
1174
|
-
field
|
1175
|
-
arel_column(field) {
|
1176
|
-
Arel.sql(connection.quote_table_name(field))
|
1177
|
-
}.send(dir.downcase)
|
1293
|
+
order_column(field.to_s).send(dir.downcase)
|
1178
1294
|
end
|
1179
1295
|
}
|
1180
1296
|
else
|
@@ -1183,6 +1299,16 @@ module ActiveRecord
|
|
1183
1299
|
end.flatten!
|
1184
1300
|
end
|
1185
1301
|
|
1302
|
+
def order_column(field)
|
1303
|
+
arel_column(field) do |attr_name|
|
1304
|
+
if attr_name == "count" && !group_values.empty?
|
1305
|
+
arel_attribute(attr_name)
|
1306
|
+
else
|
1307
|
+
Arel.sql(connection.quote_table_name(attr_name))
|
1308
|
+
end
|
1309
|
+
end
|
1310
|
+
end
|
1311
|
+
|
1186
1312
|
# Checks to make sure that the arguments are not blank. Note that if some
|
1187
1313
|
# blank-like object were initially passed into the query method, then this
|
1188
1314
|
# method will not raise an error.
|
@@ -1207,8 +1333,10 @@ module ActiveRecord
|
|
1207
1333
|
|
1208
1334
|
STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references]
|
1209
1335
|
def structurally_incompatible_values_for_or(other)
|
1336
|
+
values = other.values
|
1210
1337
|
STRUCTURAL_OR_METHODS.reject do |method|
|
1211
|
-
|
1338
|
+
default = DEFAULT_VALUES[method]
|
1339
|
+
@values.fetch(method, default) == values.fetch(method, default)
|
1212
1340
|
end
|
1213
1341
|
end
|
1214
1342
|
|