activerecord 6.0.3.4 → 6.1.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 +799 -713
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/active_record.rb +7 -14
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations.rb +114 -11
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +44 -28
- data/lib/active_record/associations/association_scope.rb +17 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +19 -6
- data/lib/active_record/associations/collection_proxy.rb +13 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency.rb +72 -50
- data/lib/active_record/associations/join_dependency/join_association.rb +36 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/preloader.rb +11 -5
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +11 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attributes.rb +32 -7
- data/lib/active_record/autosave_association.rb +57 -40
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +152 -22
- data/lib/active_record/coders/yaml_column.rb +1 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +191 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +112 -27
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
- data/lib/active_record/connection_adapters/abstract_adapter.rb +54 -71
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +129 -88
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +23 -25
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +11 -7
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +13 -54
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -5
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +31 -6
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +37 -4
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +49 -50
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +229 -63
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -40
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +40 -16
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -2
- data/lib/active_record/fixtures.rb +54 -8
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +35 -6
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +22 -16
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +26 -8
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +67 -17
- data/lib/active_record/model_schema.rb +117 -13
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/databases.rake +266 -95
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +71 -57
- data/lib/active_record/relation.rb +96 -67
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/calculations.rb +101 -44
- data/lib/active_record/relation/delegation.rb +2 -1
- data/lib/active_record/relation/finder_methods.rb +45 -15
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +27 -25
- data/lib/active_record/relation/predicate_builder.rb +57 -33
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +330 -195
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +104 -57
- data/lib/active_record/result.rb +41 -33
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/named.rb +6 -17
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -51
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +37 -16
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +15 -64
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/arel.rb +5 -13
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/rails/generators/active_record/migration.rb +6 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +27 -28
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
@@ -16,10 +16,10 @@ module ActiveRecord
|
|
16
16
|
def exec_queries
|
17
17
|
QueryRegistry.reset
|
18
18
|
|
19
|
-
super.tap do
|
19
|
+
super.tap do |records|
|
20
20
|
if logger && warn_on_records_fetched_greater_than
|
21
|
-
if
|
22
|
-
logger.warn "Query fetched #{
|
21
|
+
if records.length > warn_on_records_fetched_greater_than
|
22
|
+
logger.warn "Query fetched #{records.size} #{@klass} records: #{QueryRegistry.queries.join(";")}"
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -28,21 +28,22 @@ module ActiveRecord
|
|
28
28
|
# # => Post.where(published: true).joins(:comments)
|
29
29
|
#
|
30
30
|
# This is mainly intended for sharing common conditions between multiple associations.
|
31
|
-
def merge(other)
|
31
|
+
def merge(other, *rest)
|
32
32
|
if other.is_a?(Array)
|
33
33
|
records & other
|
34
34
|
elsif other
|
35
|
-
spawn.merge!(other)
|
35
|
+
spawn.merge!(other, *rest)
|
36
36
|
else
|
37
37
|
raise ArgumentError, "invalid argument: #{other.inspect}."
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
def merge!(other) # :nodoc:
|
41
|
+
def merge!(other, *rest) # :nodoc:
|
42
|
+
options = rest.extract_options!
|
42
43
|
if other.is_a?(Hash)
|
43
|
-
Relation::HashMerger.new(self, other).merge
|
44
|
+
Relation::HashMerger.new(self, other, options[:rewhere]).merge
|
44
45
|
elsif other.is_a?(Relation)
|
45
|
-
Relation::Merger.new(self, other).merge
|
46
|
+
Relation::Merger.new(self, other, options[:rewhere]).merge
|
46
47
|
elsif other.respond_to?(:to_proc)
|
47
48
|
instance_exec(&other)
|
48
49
|
else
|
@@ -68,8 +69,8 @@ module ActiveRecord
|
|
68
69
|
|
69
70
|
private
|
70
71
|
def relation_with(values)
|
71
|
-
result =
|
72
|
-
result.
|
72
|
+
result = spawn
|
73
|
+
result.instance_variable_set(:@values, values)
|
73
74
|
result
|
74
75
|
end
|
75
76
|
end
|
@@ -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 Relation
|
5
7
|
class WhereClause # :nodoc:
|
@@ -10,21 +12,25 @@ module ActiveRecord
|
|
10
12
|
end
|
11
13
|
|
12
14
|
def +(other)
|
13
|
-
WhereClause.new(
|
14
|
-
predicates + other.predicates,
|
15
|
-
)
|
15
|
+
WhereClause.new(predicates + other.predicates)
|
16
16
|
end
|
17
17
|
|
18
18
|
def -(other)
|
19
|
-
WhereClause.new(
|
20
|
-
|
21
|
-
|
19
|
+
WhereClause.new(predicates - other.predicates)
|
20
|
+
end
|
21
|
+
|
22
|
+
def |(other)
|
23
|
+
WhereClause.new(predicates | other.predicates)
|
22
24
|
end
|
23
25
|
|
24
|
-
def merge(other)
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
def merge(other, rewhere = nil)
|
27
|
+
predicates = if rewhere
|
28
|
+
except_predicates(other.extract_attributes)
|
29
|
+
else
|
30
|
+
predicates_unreferenced_by(other)
|
31
|
+
end
|
32
|
+
|
33
|
+
WhereClause.new(predicates | other.predicates)
|
28
34
|
end
|
29
35
|
|
30
36
|
def except(*columns)
|
@@ -39,30 +45,31 @@ module ActiveRecord
|
|
39
45
|
if left.empty? || right.empty?
|
40
46
|
common
|
41
47
|
else
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
48
|
+
left = left.ast
|
49
|
+
left = left.expr if left.is_a?(Arel::Nodes::Grouping)
|
50
|
+
|
51
|
+
right = right.ast
|
52
|
+
right = right.expr if right.is_a?(Arel::Nodes::Grouping)
|
53
|
+
|
54
|
+
or_clause = Arel::Nodes::Or.new(left, right)
|
55
|
+
|
56
|
+
common.predicates << Arel::Nodes::Grouping.new(or_clause)
|
57
|
+
common
|
46
58
|
end
|
47
59
|
end
|
48
60
|
|
49
61
|
def to_h(table_name = nil)
|
50
|
-
equalities
|
51
|
-
|
52
|
-
equalities = equalities.select do |node|
|
53
|
-
node.left.relation.name == table_name
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
equalities.map { |node|
|
62
|
+
equalities(predicates).each_with_object({}) do |node, hash|
|
63
|
+
next if table_name&.!= node.left.relation.name
|
58
64
|
name = node.left.name.to_s
|
59
65
|
value = extract_node_value(node.right)
|
60
|
-
[name
|
61
|
-
|
66
|
+
hash[name] = value
|
67
|
+
end
|
62
68
|
end
|
63
69
|
|
64
70
|
def ast
|
65
|
-
|
71
|
+
predicates = predicates_with_wrapped_sql_literals
|
72
|
+
predicates.one? ? predicates.first : Arel::Nodes::And.new(predicates)
|
66
73
|
end
|
67
74
|
|
68
75
|
def ==(other)
|
@@ -70,11 +77,9 @@ module ActiveRecord
|
|
70
77
|
predicates == other.predicates
|
71
78
|
end
|
72
79
|
|
73
|
-
def invert
|
80
|
+
def invert
|
74
81
|
if predicates.size == 1
|
75
82
|
inverted_predicates = [ invert_predicate(predicates.first) ]
|
76
|
-
elsif as == :nor
|
77
|
-
inverted_predicates = predicates.map { |node| invert_predicate(node) }
|
78
83
|
else
|
79
84
|
inverted_predicates = [ Arel::Nodes::Not.new(ast) ]
|
80
85
|
end
|
@@ -83,28 +88,59 @@ module ActiveRecord
|
|
83
88
|
end
|
84
89
|
|
85
90
|
def self.empty
|
86
|
-
@empty ||= new([])
|
91
|
+
@empty ||= new([]).freeze
|
92
|
+
end
|
93
|
+
|
94
|
+
def contradiction?
|
95
|
+
predicates.any? do |x|
|
96
|
+
case x
|
97
|
+
when Arel::Nodes::In
|
98
|
+
Array === x.right && x.right.empty?
|
99
|
+
when Arel::Nodes::Equality
|
100
|
+
x.right.respond_to?(:unboundable?) && x.right.unboundable?
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def extract_attributes
|
106
|
+
predicates.each_with_object([]) do |node, attrs|
|
107
|
+
attr = extract_attribute(node) || begin
|
108
|
+
node.left if node.equality? && node.left.is_a?(Arel::Predications)
|
109
|
+
end
|
110
|
+
attrs << attr if attr
|
111
|
+
end
|
87
112
|
end
|
88
113
|
|
89
114
|
protected
|
90
115
|
attr_reader :predicates
|
91
116
|
|
92
117
|
def referenced_columns
|
93
|
-
|
94
|
-
|
95
|
-
|
118
|
+
predicates.each_with_object({}) do |node, hash|
|
119
|
+
attr = extract_attribute(node) || begin
|
120
|
+
node.left if equality_node?(node) && node.left.is_a?(Arel::Predications)
|
121
|
+
end
|
122
|
+
|
123
|
+
hash[attr] = node if attr
|
96
124
|
end
|
97
125
|
end
|
98
126
|
|
99
127
|
private
|
128
|
+
def extract_attribute(node)
|
129
|
+
attr_node = nil
|
130
|
+
Arel.fetch_attribute(node) do |attr|
|
131
|
+
return if attr_node&.!= attr # all attr nodes should be the same
|
132
|
+
attr_node = attr
|
133
|
+
end
|
134
|
+
attr_node
|
135
|
+
end
|
136
|
+
|
100
137
|
def equalities(predicates)
|
101
138
|
equalities = []
|
102
139
|
|
103
140
|
predicates.each do |node|
|
104
|
-
|
105
|
-
when Arel::Nodes::Equality
|
141
|
+
if equality_node?(node)
|
106
142
|
equalities << node
|
107
|
-
|
143
|
+
elsif node.is_a?(Arel::Nodes::And)
|
108
144
|
equalities.concat equalities(node.children)
|
109
145
|
end
|
110
146
|
end
|
@@ -113,37 +149,55 @@ module ActiveRecord
|
|
113
149
|
end
|
114
150
|
|
115
151
|
def predicates_unreferenced_by(other)
|
116
|
-
|
117
|
-
|
152
|
+
referenced_columns = other.referenced_columns
|
153
|
+
|
154
|
+
predicates.reject do |node|
|
155
|
+
attr = extract_attribute(node) || begin
|
156
|
+
node.left if equality_node?(node) && node.left.is_a?(Arel::Predications)
|
157
|
+
end
|
158
|
+
next false unless attr
|
159
|
+
|
160
|
+
ref = referenced_columns[attr]
|
161
|
+
next false unless ref
|
162
|
+
|
163
|
+
if equality_node?(node) && equality_node?(ref) || node == ref
|
164
|
+
true
|
165
|
+
else
|
166
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
167
|
+
Merging (#{node.to_sql}) and (#{ref.to_sql}) no longer maintain
|
168
|
+
both conditions, and will be replaced by the latter in Rails 6.2.
|
169
|
+
To migrate to Rails 6.2's behavior, use `relation.merge(other, rewhere: true)`.
|
170
|
+
MSG
|
171
|
+
false
|
172
|
+
end
|
118
173
|
end
|
119
174
|
end
|
120
175
|
|
121
176
|
def equality_node?(node)
|
122
|
-
node.
|
177
|
+
!node.is_a?(String) && node.equality?
|
123
178
|
end
|
124
179
|
|
125
180
|
def invert_predicate(node)
|
126
181
|
case node
|
127
182
|
when NilClass
|
128
183
|
raise ArgumentError, "Invalid argument for .where.not(), got nil."
|
129
|
-
when Arel::Nodes::In
|
130
|
-
Arel::Nodes::NotIn.new(node.left, node.right)
|
131
|
-
when Arel::Nodes::IsNotDistinctFrom
|
132
|
-
Arel::Nodes::IsDistinctFrom.new(node.left, node.right)
|
133
|
-
when Arel::Nodes::IsDistinctFrom
|
134
|
-
Arel::Nodes::IsNotDistinctFrom.new(node.left, node.right)
|
135
|
-
when Arel::Nodes::Equality
|
136
|
-
Arel::Nodes::NotEqual.new(node.left, node.right)
|
137
184
|
when String
|
138
185
|
Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(node))
|
139
186
|
else
|
140
|
-
|
187
|
+
node.invert
|
141
188
|
end
|
142
189
|
end
|
143
190
|
|
144
191
|
def except_predicates(columns)
|
192
|
+
attrs = columns.extract! { |node| node.is_a?(Arel::Attribute) }
|
193
|
+
non_attrs = columns.extract! { |node| node.is_a?(Arel::Predications) }
|
194
|
+
|
145
195
|
predicates.reject do |node|
|
146
|
-
|
196
|
+
if !non_attrs.empty? && node.equality? && node.left.is_a?(Arel::Predications)
|
197
|
+
non_attrs.include?(node.left)
|
198
|
+
end || Arel.fetch_attribute(node) do |attr|
|
199
|
+
attrs.include?(attr) || columns.include?(attr.name.to_s)
|
200
|
+
end
|
147
201
|
end
|
148
202
|
end
|
149
203
|
|
@@ -173,15 +227,8 @@ module ActiveRecord
|
|
173
227
|
case node
|
174
228
|
when Array
|
175
229
|
node.map { |v| extract_node_value(v) }
|
176
|
-
when Arel::Nodes::Casted, Arel::Nodes::Quoted
|
177
|
-
node.
|
178
|
-
when Arel::Nodes::BindParam
|
179
|
-
value = node.value
|
180
|
-
if value.respond_to?(:value_before_type_cast)
|
181
|
-
value.value_before_type_cast
|
182
|
-
else
|
183
|
-
value
|
184
|
-
end
|
230
|
+
when Arel::Nodes::BindParam, Arel::Nodes::Casted, Arel::Nodes::Quoted
|
231
|
+
node.value_before_type_cast
|
185
232
|
end
|
186
233
|
end
|
187
234
|
end
|
data/lib/active_record/result.rb
CHANGED
@@ -65,16 +65,10 @@ module ActiveRecord
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
def to_hash
|
69
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
70
|
-
`ActiveRecord::Result#to_hash` has been renamed to `to_a`.
|
71
|
-
`to_hash` is deprecated and will be removed in Rails 6.1.
|
72
|
-
MSG
|
73
|
-
to_a
|
74
|
-
end
|
75
|
-
|
76
68
|
alias :map! :map
|
77
69
|
alias :collect! :map
|
70
|
+
deprecate "map!": :map
|
71
|
+
deprecate "collect!": :map
|
78
72
|
|
79
73
|
# Returns true if there are no records, otherwise false.
|
80
74
|
def empty?
|
@@ -92,31 +86,30 @@ module ActiveRecord
|
|
92
86
|
hash_rows[idx]
|
93
87
|
end
|
94
88
|
|
95
|
-
# Returns the first record from the rows collection.
|
96
|
-
# If the rows collection is empty, returns +nil+.
|
97
|
-
def first
|
98
|
-
return nil if @rows.empty?
|
99
|
-
Hash[@columns.zip(@rows.first)]
|
100
|
-
end
|
101
|
-
|
102
89
|
# Returns the last record from the rows collection.
|
103
|
-
|
104
|
-
|
105
|
-
return nil if @rows.empty?
|
106
|
-
Hash[@columns.zip(@rows.last)]
|
90
|
+
def last(n = nil)
|
91
|
+
n ? hash_rows.last(n) : hash_rows.last
|
107
92
|
end
|
108
93
|
|
109
94
|
def cast_values(type_overrides = {}) # :nodoc:
|
110
95
|
if columns.one?
|
111
96
|
# Separated to avoid allocating an array per row
|
112
97
|
|
113
|
-
type =
|
98
|
+
type = if type_overrides.is_a?(Array)
|
99
|
+
type_overrides.first
|
100
|
+
else
|
101
|
+
column_type(columns.first, type_overrides)
|
102
|
+
end
|
114
103
|
|
115
104
|
rows.map do |(value)|
|
116
105
|
type.deserialize(value)
|
117
106
|
end
|
118
107
|
else
|
119
|
-
types =
|
108
|
+
types = if type_overrides.is_a?(Array)
|
109
|
+
type_overrides
|
110
|
+
else
|
111
|
+
columns.map { |name| column_type(name, type_overrides) }
|
112
|
+
end
|
120
113
|
|
121
114
|
rows.map do |values|
|
122
115
|
Array.new(values.size) { |i| types[i].deserialize(values[i]) }
|
@@ -145,21 +138,36 @@ module ActiveRecord
|
|
145
138
|
# used as keys in ActiveRecord::Base's @attributes hash
|
146
139
|
columns = @columns.map(&:-@)
|
147
140
|
length = columns.length
|
141
|
+
template = nil
|
148
142
|
|
149
143
|
@rows.map { |row|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
144
|
+
if template
|
145
|
+
# We use transform_values to build subsequent rows from the
|
146
|
+
# hash of the first row. This is faster because we avoid any
|
147
|
+
# reallocs and in Ruby 2.7+ avoid hashing entirely.
|
148
|
+
index = -1
|
149
|
+
template.transform_values do
|
150
|
+
row[index += 1]
|
151
|
+
end
|
152
|
+
else
|
153
|
+
# In the past we used Hash[columns.zip(row)]
|
154
|
+
# though elegant, the verbose way is much more efficient
|
155
|
+
# both time and memory wise cause it avoids a big array allocation
|
156
|
+
# this method is called a lot and needs to be micro optimised
|
157
|
+
hash = {}
|
158
|
+
|
159
|
+
index = 0
|
160
|
+
while index < length
|
161
|
+
hash[columns[index]] = row[index]
|
162
|
+
index += 1
|
163
|
+
end
|
164
|
+
|
165
|
+
# It's possible to select the same column twice, in which case
|
166
|
+
# we can't use a template
|
167
|
+
template = hash if hash.length == length
|
168
|
+
|
169
|
+
hash
|
160
170
|
end
|
161
|
-
|
162
|
-
hash
|
163
171
|
}
|
164
172
|
end
|
165
173
|
end
|
@@ -14,9 +14,9 @@ module ActiveRecord
|
|
14
14
|
class RuntimeRegistry # :nodoc:
|
15
15
|
extend ActiveSupport::PerThreadRegistry
|
16
16
|
|
17
|
-
attr_accessor :
|
17
|
+
attr_accessor :sql_runtime
|
18
18
|
|
19
|
-
[:
|
19
|
+
[:sql_runtime].each do |val|
|
20
20
|
class_eval %{ def self.#{val}; instance.#{val}; end }, __FILE__, __LINE__
|
21
21
|
class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
|
22
22
|
end
|
@@ -67,7 +67,7 @@ module ActiveRecord
|
|
67
67
|
)
|
68
68
|
|
69
69
|
# Ensure we aren't dealing with a subclass of String that might
|
70
|
-
# override methods we use (
|
70
|
+
# override methods we use (e.g. Arel::Nodes::SqlLiteral).
|
71
71
|
if condition.first.kind_of?(String) && !condition.first.instance_of?(String)
|
72
72
|
condition = [String.new(condition.first), *condition[1..-1]]
|
73
73
|
end
|
@@ -141,19 +141,7 @@ module ActiveRecord
|
|
141
141
|
(unexpected ||= []) << arg
|
142
142
|
end
|
143
143
|
|
144
|
-
|
145
|
-
|
146
|
-
if allow_unsafe_raw_sql == :deprecated
|
147
|
-
ActiveSupport::Deprecation.warn(
|
148
|
-
"Dangerous query method (method whose arguments are used as raw " \
|
149
|
-
"SQL) called with non-attribute argument(s): " \
|
150
|
-
"#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \
|
151
|
-
"arguments will be disallowed in Rails 6.1. This method should " \
|
152
|
-
"not be called with user-provided values, such as request " \
|
153
|
-
"parameters or model attributes. Known-safe values can be passed " \
|
154
|
-
"by wrapping them in Arel.sql()."
|
155
|
-
)
|
156
|
-
else
|
144
|
+
if unexpected
|
157
145
|
raise(ActiveRecord::UnknownAttributeReference,
|
158
146
|
"Query method called with non-attribute argument(s): " +
|
159
147
|
unexpected.map(&:inspect).join(", ")
|
@@ -193,13 +181,14 @@ module ActiveRecord
|
|
193
181
|
|
194
182
|
def quote_bound_value(value, c = connection)
|
195
183
|
if value.respond_to?(:map) && !value.acts_like?(:string)
|
196
|
-
|
197
|
-
if
|
184
|
+
values = value.map { |v| v.respond_to?(:id_for_database) ? v.id_for_database : v }
|
185
|
+
if values.empty?
|
198
186
|
c.quote(nil)
|
199
187
|
else
|
200
|
-
|
188
|
+
values.map! { |v| c.quote(v) }.join(",")
|
201
189
|
end
|
202
190
|
else
|
191
|
+
value = value.id_for_database if value.respond_to?(:id_for_database)
|
203
192
|
c.quote(value)
|
204
193
|
end
|
205
194
|
end
|