activerecord 5.2.8.1 → 6.0.6.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 +938 -573
- 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 +15 -6
- 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 +77 -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 +108 -67
- 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 +3 -3
- 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 +80 -61
- 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 +234 -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 +113 -26
- 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,54 @@ 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
|
+
#
|
1004
|
+
# Some escaping is performed, however untrusted user input should not be used.
|
1005
|
+
def annotate(*args)
|
1006
|
+
check_if_method_has_arguments!(:annotate, args)
|
1007
|
+
spawn.annotate!(*args)
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
# Like #annotate, but modifies relation in place.
|
1011
|
+
def annotate!(*args) # :nodoc:
|
1012
|
+
self.annotate_values += args
|
1013
|
+
self
|
1014
|
+
end
|
1015
|
+
|
898
1016
|
# Returns the Arel object associated with the relation.
|
899
1017
|
def arel(aliases = nil) # :nodoc:
|
900
1018
|
@arel ||= build_arel(aliases)
|
901
1019
|
end
|
902
1020
|
|
903
|
-
|
904
|
-
|
905
|
-
|
1021
|
+
def construct_join_dependency(associations, join_type) # :nodoc:
|
1022
|
+
ActiveRecord::Associations::JoinDependency.new(
|
1023
|
+
klass, table, associations, join_type
|
1024
|
+
)
|
906
1025
|
end
|
907
1026
|
|
908
1027
|
protected
|
1028
|
+
def build_subquery(subquery_alias, select_value) # :nodoc:
|
1029
|
+
subquery = except(:optimizer_hints).arel.as(subquery_alias)
|
909
1030
|
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
@values[name] = value
|
1031
|
+
Arel::SelectManager.new(subquery).project(select_value).tap do |arel|
|
1032
|
+
arel.optimizer_hints(*optimizer_hints_values) unless optimizer_hints_values.empty?
|
1033
|
+
end
|
914
1034
|
end
|
915
1035
|
|
916
1036
|
private
|
917
|
-
|
918
1037
|
def assert_mutability!
|
919
1038
|
raise ImmutableRelation if @loaded
|
920
1039
|
raise ImmutableRelation if defined?(@arel) && @arel
|
@@ -923,14 +1042,17 @@ module ActiveRecord
|
|
923
1042
|
def build_arel(aliases)
|
924
1043
|
arel = Arel::SelectManager.new(table)
|
925
1044
|
|
926
|
-
|
927
|
-
|
1045
|
+
if !joins_values.empty?
|
1046
|
+
build_joins(arel, joins_values.flatten, aliases)
|
1047
|
+
elsif !left_outer_joins_values.empty?
|
1048
|
+
build_left_outer_joins(arel, left_outer_joins_values.flatten, aliases)
|
1049
|
+
end
|
928
1050
|
|
929
1051
|
arel.where(where_clause.ast) unless where_clause.empty?
|
930
1052
|
arel.having(having_clause.ast) unless having_clause.empty?
|
931
1053
|
if limit_value
|
932
1054
|
limit_attribute = ActiveModel::Attribute.with_cast_value(
|
933
|
-
"LIMIT"
|
1055
|
+
"LIMIT",
|
934
1056
|
connection.sanitize_limit(limit_value),
|
935
1057
|
Type.default_value,
|
936
1058
|
)
|
@@ -938,7 +1060,7 @@ module ActiveRecord
|
|
938
1060
|
end
|
939
1061
|
if offset_value
|
940
1062
|
offset_attribute = ActiveModel::Attribute.with_cast_value(
|
941
|
-
"OFFSET"
|
1063
|
+
"OFFSET",
|
942
1064
|
offset_value.to_i,
|
943
1065
|
Type.default_value,
|
944
1066
|
)
|
@@ -950,9 +1072,11 @@ module ActiveRecord
|
|
950
1072
|
|
951
1073
|
build_select(arel)
|
952
1074
|
|
1075
|
+
arel.optimizer_hints(*optimizer_hints_values) unless optimizer_hints_values.empty?
|
953
1076
|
arel.distinct(distinct_value)
|
954
1077
|
arel.from(build_from) unless from_clause.empty?
|
955
1078
|
arel.lock(lock_value) if lock_value
|
1079
|
+
arel.comment(*annotate_values) unless annotate_values.empty?
|
956
1080
|
|
957
1081
|
arel
|
958
1082
|
end
|
@@ -972,68 +1096,101 @@ module ActiveRecord
|
|
972
1096
|
end
|
973
1097
|
end
|
974
1098
|
|
975
|
-
def
|
976
|
-
|
977
|
-
|
1099
|
+
def select_association_list(associations, stashed_joins = nil)
|
1100
|
+
result = []
|
1101
|
+
associations.each do |association|
|
1102
|
+
case association
|
978
1103
|
when Hash, Symbol, Array
|
979
|
-
|
1104
|
+
result << association
|
980
1105
|
when ActiveRecord::Associations::JoinDependency
|
981
|
-
|
1106
|
+
stashed_joins&.<< association
|
982
1107
|
else
|
983
|
-
|
1108
|
+
yield if block_given?
|
984
1109
|
end
|
985
1110
|
end
|
1111
|
+
result
|
1112
|
+
end
|
1113
|
+
|
1114
|
+
def valid_association_list(associations, stashed_joins)
|
1115
|
+
select_association_list(associations, stashed_joins) do
|
1116
|
+
raise ArgumentError, "only Hash, Symbol and Array are allowed"
|
1117
|
+
end
|
1118
|
+
end
|
986
1119
|
|
1120
|
+
def build_left_outer_joins(manager, outer_joins, aliases)
|
1121
|
+
buckets = Hash.new { |h, k| h[k] = [] }
|
1122
|
+
buckets[:association_join] = valid_association_list(outer_joins, buckets[:stashed_join])
|
987
1123
|
build_join_query(manager, buckets, Arel::Nodes::OuterJoin, aliases)
|
988
1124
|
end
|
989
1125
|
|
1126
|
+
class ::Arel::Nodes::LeadingJoin < Arel::Nodes::InnerJoin # :nodoc:
|
1127
|
+
end
|
1128
|
+
|
990
1129
|
def build_joins(manager, joins, aliases)
|
991
|
-
buckets =
|
1130
|
+
buckets = Hash.new { |h, k| h[k] = [] }
|
1131
|
+
|
1132
|
+
unless left_outer_joins_values.empty?
|
1133
|
+
stashed_left_joins = []
|
1134
|
+
left_joins = valid_association_list(left_outer_joins_values.flatten, stashed_left_joins)
|
1135
|
+
stashed_left_joins.unshift construct_join_dependency(left_joins, Arel::Nodes::OuterJoin)
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
if joins.last.is_a?(ActiveRecord::Associations::JoinDependency)
|
1139
|
+
stashed_eager_load = joins.pop if joins.last.base_klass == klass
|
1140
|
+
end
|
1141
|
+
|
1142
|
+
joins.map! do |join|
|
1143
|
+
if join.is_a?(String)
|
1144
|
+
table.create_string_join(Arel.sql(join.strip)) unless join.blank?
|
1145
|
+
else
|
1146
|
+
join
|
1147
|
+
end
|
1148
|
+
end.delete_if(&:blank?).uniq!
|
1149
|
+
|
1150
|
+
while joins.first.is_a?(Arel::Nodes::Join)
|
1151
|
+
join_node = joins.shift
|
1152
|
+
if !join_node.is_a?(Arel::Nodes::LeadingJoin) && (stashed_eager_load || stashed_left_joins)
|
1153
|
+
buckets[:join_node] << join_node
|
1154
|
+
else
|
1155
|
+
buckets[:leading_join] << join_node
|
1156
|
+
end
|
1157
|
+
end
|
1158
|
+
|
1159
|
+
joins.each do |join|
|
992
1160
|
case join
|
993
|
-
when String
|
994
|
-
:string_join
|
995
1161
|
when Hash, Symbol, Array
|
996
|
-
:association_join
|
1162
|
+
buckets[:association_join] << join
|
997
1163
|
when ActiveRecord::Associations::JoinDependency
|
998
|
-
:stashed_join
|
1164
|
+
buckets[:stashed_join] << join
|
999
1165
|
when Arel::Nodes::Join
|
1000
|
-
:join_node
|
1166
|
+
buckets[:join_node] << join
|
1001
1167
|
else
|
1002
1168
|
raise "unknown class: %s" % join.class.name
|
1003
1169
|
end
|
1004
1170
|
end
|
1005
1171
|
|
1172
|
+
buckets[:stashed_join].concat stashed_left_joins if stashed_left_joins
|
1173
|
+
buckets[:stashed_join] << stashed_eager_load if stashed_eager_load
|
1174
|
+
|
1006
1175
|
build_join_query(manager, buckets, Arel::Nodes::InnerJoin, aliases)
|
1007
1176
|
end
|
1008
1177
|
|
1009
1178
|
def build_join_query(manager, buckets, join_type, aliases)
|
1010
|
-
buckets.default = []
|
1011
|
-
|
1012
1179
|
association_joins = buckets[:association_join]
|
1013
1180
|
stashed_joins = buckets[:stashed_join]
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
join_list = join_nodes + convert_join_strings_to_ast(string_joins)
|
1018
|
-
alias_tracker = alias_tracker(join_list, aliases)
|
1181
|
+
leading_joins = buckets[:leading_join]
|
1182
|
+
join_nodes = buckets[:join_node]
|
1019
1183
|
|
1020
|
-
|
1021
|
-
|
1022
|
-
)
|
1023
|
-
|
1024
|
-
joins = join_dependency.join_constraints(stashed_joins, join_type, alias_tracker)
|
1025
|
-
joins.each { |join| manager.from(join) }
|
1026
|
-
|
1027
|
-
manager.join_sources.concat(join_list)
|
1184
|
+
join_sources = manager.join_sources
|
1185
|
+
join_sources.concat(leading_joins) unless leading_joins.empty?
|
1028
1186
|
|
1029
|
-
|
1030
|
-
|
1187
|
+
unless association_joins.empty? && stashed_joins.empty?
|
1188
|
+
alias_tracker = alias_tracker(leading_joins + join_nodes, aliases)
|
1189
|
+
join_dependency = construct_join_dependency(association_joins, join_type)
|
1190
|
+
join_sources.concat(join_dependency.join_constraints(stashed_joins, alias_tracker))
|
1191
|
+
end
|
1031
1192
|
|
1032
|
-
|
1033
|
-
joins
|
1034
|
-
.flatten
|
1035
|
-
.reject(&:blank?)
|
1036
|
-
.map { |join| table.create_string_join(Arel.sql(join)) }
|
1193
|
+
join_sources.concat(join_nodes) unless join_nodes.empty?
|
1037
1194
|
end
|
1038
1195
|
|
1039
1196
|
def build_select(arel)
|
@@ -1064,7 +1221,7 @@ module ActiveRecord
|
|
1064
1221
|
end
|
1065
1222
|
|
1066
1223
|
def arel_column(field)
|
1067
|
-
field = klass.
|
1224
|
+
field = klass.attribute_aliases[field] || field
|
1068
1225
|
from = from_clause.name || from_clause.value
|
1069
1226
|
|
1070
1227
|
if klass.columns_hash.key?(field) && (!from || table_name_matches?(from))
|
@@ -1075,7 +1232,9 @@ module ActiveRecord
|
|
1075
1232
|
end
|
1076
1233
|
|
1077
1234
|
def table_name_matches?(from)
|
1078
|
-
|
1235
|
+
table_name = Regexp.escape(table.name)
|
1236
|
+
quoted_table_name = Regexp.escape(connection.quote_table_name(table.name))
|
1237
|
+
/(?:\A|(?<!FROM)\s)(?:\b#{table_name}\b|#{quoted_table_name})(?!\.)/i.match?(from.to_s)
|
1079
1238
|
end
|
1080
1239
|
|
1081
1240
|
def reverse_sql_order(order_query)
|
@@ -1093,7 +1252,7 @@ module ActiveRecord
|
|
1093
1252
|
o.reverse
|
1094
1253
|
when String
|
1095
1254
|
if does_not_support_reverse?(o)
|
1096
|
-
raise IrreversibleOrderError, "Order #{o.inspect}
|
1255
|
+
raise IrreversibleOrderError, "Order #{o.inspect} cannot be reversed automatically"
|
1097
1256
|
end
|
1098
1257
|
o.split(",").map! do |s|
|
1099
1258
|
s.strip!
|
@@ -1113,7 +1272,7 @@ module ActiveRecord
|
|
1113
1272
|
# Uses SQL function with multiple arguments.
|
1114
1273
|
(order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) ||
|
1115
1274
|
# Uses "nulls first" like construction.
|
1116
|
-
|
1275
|
+
/\bnulls\s+(?:first|last)\b/i.match?(order)
|
1117
1276
|
end
|
1118
1277
|
|
1119
1278
|
def build_order(arel)
|
@@ -1139,14 +1298,15 @@ module ActiveRecord
|
|
1139
1298
|
end
|
1140
1299
|
|
1141
1300
|
def preprocess_order_args(order_args)
|
1301
|
+
order_args.reject!(&:blank?)
|
1142
1302
|
order_args.map! do |arg|
|
1143
1303
|
klass.sanitize_sql_for_order(arg)
|
1144
1304
|
end
|
1145
1305
|
order_args.flatten!
|
1146
1306
|
|
1147
|
-
@klass.
|
1307
|
+
@klass.disallow_raw_sql!(
|
1148
1308
|
order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a },
|
1149
|
-
|
1309
|
+
permit: connection.column_name_with_order_matcher
|
1150
1310
|
)
|
1151
1311
|
|
1152
1312
|
validate_order_args(order_args)
|
@@ -1207,10 +1367,15 @@ module ActiveRecord
|
|
1207
1367
|
end
|
1208
1368
|
end
|
1209
1369
|
|
1210
|
-
STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references]
|
1370
|
+
STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references, :annotate, :optimizer_hints]
|
1211
1371
|
def structurally_incompatible_values_for_or(other)
|
1372
|
+
values = other.values
|
1212
1373
|
STRUCTURAL_OR_METHODS.reject do |method|
|
1213
|
-
|
1374
|
+
default = DEFAULT_VALUES[method]
|
1375
|
+
v1, v2 = @values.fetch(method, default), values.fetch(method, default)
|
1376
|
+
v1 = v1.uniq if v1.is_a?(Array)
|
1377
|
+
v2 = v2.uniq if v2.is_a?(Array)
|
1378
|
+
v1 == v2
|
1214
1379
|
end
|
1215
1380
|
end
|
1216
1381
|
|
@@ -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?
|