activerecord 6.0.5.1 → 6.1.0.rc1
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 +764 -916
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +39 -27
- data/lib/active_record/associations/association_scope.rb +11 -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 -13
- data/lib/active_record/associations/collection_proxy.rb +12 -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/join_association.rb +29 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +63 -49
- data/lib/active_record/associations/preloader/association.rb +13 -5
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations.rb +114 -11
- data/lib/active_record/attribute_assignment.rb +10 -8
- 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 +4 -4
- 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/attribute_methods.rb +52 -48
- data/lib/active_record/attributes.rb +27 -7
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +32 -22
- data/lib/active_record/coders/yaml_column.rb +2 -14
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +180 -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 +110 -30
- 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 +66 -24
- data/lib/active_record/connection_adapters/abstract_adapter.rb +31 -70
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
- 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 +22 -24
- 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 +33 -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 +3 -3
- 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 +12 -53
- 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 +2 -10
- 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/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- 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 +30 -5
- 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 +36 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +214 -58
- 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/database_configurations.rb +124 -85
- 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 +33 -23
- 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 +32 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +15 -4
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +13 -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/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +67 -17
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/model_schema.rb +88 -42
- 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 +61 -59
- data/lib/active_record/railties/databases.rake +253 -98
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +59 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/calculations.rb +100 -43
- data/lib/active_record/relation/finder_methods.rb +44 -14
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +20 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -2
- 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/predicate_builder.rb +57 -33
- data/lib/active_record/relation/query_methods.rb +319 -196
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +6 -5
- data/lib/active_record/relation/where_clause.rb +104 -57
- data/lib/active_record/relation.rb +90 -64
- 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 +0 -4
- data/lib/active_record/scoping/named.rb +1 -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 +36 -52
- 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 +36 -33
- 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/serialized.rb +6 -2
- data/lib/active_record/type.rb +8 -1
- 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/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -14
- 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/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/nodes.rb +3 -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/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/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -13
- 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/migration.rb +6 -1
- 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 +30 -32
- 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
|
@@ -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
|
@@ -7,7 +7,7 @@ module ActiveRecord
|
|
7
7
|
:order, :joins, :left_outer_joins, :references,
|
8
8
|
:extending, :unscope, :optimizer_hints, :annotate]
|
9
9
|
|
10
|
-
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
|
10
|
+
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering, :strict_loading,
|
11
11
|
:reverse_order, :distinct, :create_with, :skip_query_cache]
|
12
12
|
|
13
13
|
CLAUSE_METHODS = [:where, :having, :from]
|
@@ -28,7 +28,6 @@ module ActiveRecord
|
|
28
28
|
@klass = klass
|
29
29
|
@table = table
|
30
30
|
@values = values
|
31
|
-
@offsets = {}
|
32
31
|
@loaded = false
|
33
32
|
@predicate_builder = predicate_builder
|
34
33
|
@delegate_to_klass = false
|
@@ -40,8 +39,9 @@ module ActiveRecord
|
|
40
39
|
end
|
41
40
|
|
42
41
|
def arel_attribute(name) # :nodoc:
|
43
|
-
|
42
|
+
table[name]
|
44
43
|
end
|
44
|
+
deprecate :arel_attribute
|
45
45
|
|
46
46
|
def bind_attribute(name, value) # :nodoc:
|
47
47
|
if reflection = klass._reflect_on_association(name)
|
@@ -49,7 +49,7 @@ module ActiveRecord
|
|
49
49
|
value = value.read_attribute(reflection.klass.primary_key) unless value.nil?
|
50
50
|
end
|
51
51
|
|
52
|
-
attr =
|
52
|
+
attr = table[name]
|
53
53
|
bind = predicate_builder.build_bind_attribute(attr.name, value)
|
54
54
|
yield attr, bind
|
55
55
|
end
|
@@ -67,10 +67,9 @@ module ActiveRecord
|
|
67
67
|
# user = users.new { |user| user.name = 'Oscar' }
|
68
68
|
# user.name # => Oscar
|
69
69
|
def new(attributes = nil, &block)
|
70
|
-
block =
|
71
|
-
scoping {
|
70
|
+
block = current_scope_restoring_block(&block)
|
71
|
+
scoping { _new(attributes, &block) }
|
72
72
|
end
|
73
|
-
|
74
73
|
alias build new
|
75
74
|
|
76
75
|
# Tries to create a new record with the same scoped attributes
|
@@ -96,8 +95,8 @@ module ActiveRecord
|
|
96
95
|
if attributes.is_a?(Array)
|
97
96
|
attributes.collect { |attr| create(attr, &block) }
|
98
97
|
else
|
99
|
-
block =
|
100
|
-
scoping {
|
98
|
+
block = current_scope_restoring_block(&block)
|
99
|
+
scoping { _create(attributes, &block) }
|
101
100
|
end
|
102
101
|
end
|
103
102
|
|
@@ -111,8 +110,8 @@ module ActiveRecord
|
|
111
110
|
if attributes.is_a?(Array)
|
112
111
|
attributes.collect { |attr| create!(attr, &block) }
|
113
112
|
else
|
114
|
-
block =
|
115
|
-
scoping {
|
113
|
+
block = current_scope_restoring_block(&block)
|
114
|
+
scoping { _create!(attributes, &block) }
|
116
115
|
end
|
117
116
|
end
|
118
117
|
|
@@ -308,7 +307,7 @@ module ActiveRecord
|
|
308
307
|
# last updated record.
|
309
308
|
#
|
310
309
|
# Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
|
311
|
-
def cache_key(timestamp_column =
|
310
|
+
def cache_key(timestamp_column = "updated_at")
|
312
311
|
@cache_keys ||= {}
|
313
312
|
@cache_keys[timestamp_column] ||= klass.collection_cache_key(self, timestamp_column)
|
314
313
|
end
|
@@ -317,7 +316,7 @@ module ActiveRecord
|
|
317
316
|
query_signature = ActiveSupport::Digest.hexdigest(to_sql)
|
318
317
|
key = "#{klass.model_name.cache_key}/query-#{query_signature}"
|
319
318
|
|
320
|
-
if
|
319
|
+
if collection_cache_versioning
|
321
320
|
key
|
322
321
|
else
|
323
322
|
"#{key}-#{compute_cache_version(timestamp_column)}"
|
@@ -343,15 +342,17 @@ module ActiveRecord
|
|
343
342
|
end
|
344
343
|
|
345
344
|
def compute_cache_version(timestamp_column) # :nodoc:
|
345
|
+
timestamp_column = timestamp_column.to_s
|
346
|
+
|
346
347
|
if loaded? || distinct_value
|
347
348
|
size = records.size
|
348
349
|
if size > 0
|
349
|
-
timestamp =
|
350
|
+
timestamp = records.map { |record| record.read_attribute(timestamp_column) }.max
|
350
351
|
end
|
351
352
|
else
|
352
353
|
collection = eager_loading? ? apply_join_dependency : self
|
353
354
|
|
354
|
-
column = connection.visitor.compile(
|
355
|
+
column = connection.visitor.compile(table[timestamp_column])
|
355
356
|
select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
|
356
357
|
|
357
358
|
if collection.has_limit_or_offset?
|
@@ -365,14 +366,12 @@ module ActiveRecord
|
|
365
366
|
arel = query.arel
|
366
367
|
end
|
367
368
|
|
368
|
-
|
369
|
+
size, timestamp = connection.select_rows(arel, nil).first
|
369
370
|
|
370
|
-
if
|
371
|
+
if size
|
371
372
|
column_type = klass.type_for_attribute(timestamp_column)
|
372
|
-
timestamp = column_type.deserialize(
|
373
|
-
size = result["size"]
|
373
|
+
timestamp = column_type.deserialize(timestamp)
|
374
374
|
else
|
375
|
-
timestamp = nil
|
376
375
|
size = 0
|
377
376
|
end
|
378
377
|
end
|
@@ -407,9 +406,9 @@ module ActiveRecord
|
|
407
406
|
already_in_scope? ? yield : _scoping(self) { yield }
|
408
407
|
end
|
409
408
|
|
410
|
-
def _exec_scope(
|
409
|
+
def _exec_scope(*args, &block) # :nodoc:
|
411
410
|
@delegate_to_klass = true
|
412
|
-
_scoping(
|
411
|
+
_scoping(nil) { instance_exec(*args, &block) || self }
|
413
412
|
ensure
|
414
413
|
@delegate_to_klass = false
|
415
414
|
end
|
@@ -417,7 +416,7 @@ module ActiveRecord
|
|
417
416
|
# Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
|
418
417
|
# statement and sends it straight to the database. It does not instantiate the involved models and it does not
|
419
418
|
# trigger Active Record callbacks or validations. However, values passed to #update_all will still go through
|
420
|
-
# Active Record's normal type casting and serialization.
|
419
|
+
# Active Record's normal type casting and serialization. Returns the number of rows affected.
|
421
420
|
#
|
422
421
|
# Note: As Active Record callbacks are not triggered, this method will not automatically update +updated_at+/+updated_on+ columns.
|
423
422
|
#
|
@@ -448,7 +447,7 @@ module ActiveRecord
|
|
448
447
|
|
449
448
|
stmt = Arel::UpdateManager.new
|
450
449
|
stmt.table(arel.join_sources.empty? ? table : arel.source)
|
451
|
-
stmt.key =
|
450
|
+
stmt.key = table[primary_key]
|
452
451
|
stmt.take(arel.limit)
|
453
452
|
stmt.offset(arel.offset)
|
454
453
|
stmt.order(*arel.orders)
|
@@ -458,7 +457,7 @@ module ActiveRecord
|
|
458
457
|
if klass.locking_enabled? &&
|
459
458
|
!updates.key?(klass.locking_column) &&
|
460
459
|
!updates.key?(klass.locking_column.to_sym)
|
461
|
-
attr =
|
460
|
+
attr = table[klass.locking_column]
|
462
461
|
updates[attr.name] = _increment_attribute(attr)
|
463
462
|
end
|
464
463
|
stmt.set _substitute_values(updates)
|
@@ -477,12 +476,24 @@ module ActiveRecord
|
|
477
476
|
end
|
478
477
|
end
|
479
478
|
|
480
|
-
|
479
|
+
# Updates the counters of the records in the current relation.
|
480
|
+
#
|
481
|
+
# ==== Parameters
|
482
|
+
#
|
483
|
+
# * +counter+ - A Hash containing the names of the fields to update as keys and the amount to update as values.
|
484
|
+
# * <tt>:touch</tt> option - Touch the timestamp columns when updating.
|
485
|
+
# * If attributes names are passed, they are updated along with update_at/on attributes.
|
486
|
+
#
|
487
|
+
# ==== Examples
|
488
|
+
#
|
489
|
+
# # For Posts by a given author increment the comment_count by 1.
|
490
|
+
# Post.where(author_id: author.id).update_counters(comment_count: 1)
|
491
|
+
def update_counters(counters)
|
481
492
|
touch = counters.delete(:touch)
|
482
493
|
|
483
494
|
updates = {}
|
484
495
|
counters.each do |counter_name, value|
|
485
|
-
attr =
|
496
|
+
attr = table[counter_name]
|
486
497
|
updates[attr.name] = _increment_attribute(attr, value)
|
487
498
|
end
|
488
499
|
|
@@ -578,7 +589,7 @@ module ActiveRecord
|
|
578
589
|
|
579
590
|
stmt = Arel::DeleteManager.new
|
580
591
|
stmt.from(arel.join_sources.empty? ? table : arel.source)
|
581
|
-
stmt.key =
|
592
|
+
stmt.key = table[primary_key]
|
582
593
|
stmt.take(arel.limit)
|
583
594
|
stmt.offset(arel.offset)
|
584
595
|
stmt.order(*arel.orders)
|
@@ -623,7 +634,10 @@ module ActiveRecord
|
|
623
634
|
#
|
624
635
|
# Post.where(published: true).load # => #<ActiveRecord::Relation>
|
625
636
|
def load(&block)
|
626
|
-
|
637
|
+
unless loaded?
|
638
|
+
@records = exec_queries(&block)
|
639
|
+
@loaded = true
|
640
|
+
end
|
627
641
|
|
628
642
|
self
|
629
643
|
end
|
@@ -636,11 +650,9 @@ module ActiveRecord
|
|
636
650
|
|
637
651
|
def reset
|
638
652
|
@delegate_to_klass = false
|
639
|
-
@_deprecated_scope_source = nil
|
640
653
|
@to_sql = @arel = @loaded = @should_eager_load = nil
|
654
|
+
@offsets = @take = nil
|
641
655
|
@records = [].freeze
|
642
|
-
@offsets = {}
|
643
|
-
@take = nil
|
644
656
|
self
|
645
657
|
end
|
646
658
|
|
@@ -718,7 +730,7 @@ module ActiveRecord
|
|
718
730
|
end
|
719
731
|
|
720
732
|
def inspect
|
721
|
-
subject = loaded? ? records :
|
733
|
+
subject = loaded? ? records : annotate("loading for inspect")
|
722
734
|
entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
|
723
735
|
|
724
736
|
entries[10] = "..." if entries.size == 11
|
@@ -735,25 +747,31 @@ module ActiveRecord
|
|
735
747
|
end
|
736
748
|
|
737
749
|
def alias_tracker(joins = [], aliases = nil) # :nodoc:
|
738
|
-
|
739
|
-
|
750
|
+
ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins, aliases)
|
751
|
+
end
|
752
|
+
|
753
|
+
class StrictLoadingScope # :nodoc:
|
754
|
+
def self.empty_scope?
|
755
|
+
true
|
756
|
+
end
|
757
|
+
|
758
|
+
def self.strict_loading_value
|
759
|
+
true
|
760
|
+
end
|
740
761
|
end
|
741
762
|
|
742
763
|
def preload_associations(records) # :nodoc:
|
743
764
|
preload = preload_values
|
744
765
|
preload += includes_values unless eager_loading?
|
745
766
|
preloader = nil
|
767
|
+
scope = strict_loading_value ? StrictLoadingScope : nil
|
746
768
|
preload.each do |associations|
|
747
769
|
preloader ||= build_preloader
|
748
|
-
preloader.preload records, associations
|
770
|
+
preloader.preload records, associations, scope
|
749
771
|
end
|
750
772
|
end
|
751
773
|
|
752
|
-
attr_reader :_deprecated_scope_source # :nodoc:
|
753
|
-
|
754
774
|
protected
|
755
|
-
attr_writer :_deprecated_scope_source # :nodoc:
|
756
|
-
|
757
775
|
def load_records(records)
|
758
776
|
@records = records.freeze
|
759
777
|
@loaded = true
|
@@ -765,23 +783,29 @@ module ActiveRecord
|
|
765
783
|
|
766
784
|
private
|
767
785
|
def already_in_scope?
|
768
|
-
@delegate_to_klass &&
|
769
|
-
scope = klass.current_scope(true)
|
770
|
-
scope && !scope._deprecated_scope_source
|
771
|
-
end
|
772
|
-
end
|
773
|
-
|
774
|
-
def _deprecated_spawn(name)
|
775
|
-
spawn.tap { |scope| scope._deprecated_scope_source = name }
|
786
|
+
@delegate_to_klass && klass.current_scope(true)
|
776
787
|
end
|
777
788
|
|
778
|
-
def
|
789
|
+
def current_scope_restoring_block(&block)
|
790
|
+
current_scope = klass.current_scope(true)
|
779
791
|
-> record do
|
780
|
-
klass.current_scope =
|
792
|
+
klass.current_scope = current_scope
|
781
793
|
yield record if block_given?
|
782
794
|
end
|
783
795
|
end
|
784
796
|
|
797
|
+
def _new(attributes, &block)
|
798
|
+
klass.new(attributes, &block)
|
799
|
+
end
|
800
|
+
|
801
|
+
def _create(attributes, &block)
|
802
|
+
klass.create(attributes, &block)
|
803
|
+
end
|
804
|
+
|
805
|
+
def _create!(attributes, &block)
|
806
|
+
klass.create!(attributes, &block)
|
807
|
+
end
|
808
|
+
|
785
809
|
def _scoping(scope)
|
786
810
|
previous, klass.current_scope = klass.current_scope(true), scope
|
787
811
|
yield
|
@@ -791,7 +815,7 @@ module ActiveRecord
|
|
791
815
|
|
792
816
|
def _substitute_values(values)
|
793
817
|
values.map do |name, value|
|
794
|
-
attr =
|
818
|
+
attr = table[name]
|
795
819
|
unless Arel.arel_node?(value)
|
796
820
|
type = klass.type_for_attribute(attr.name)
|
797
821
|
value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
|
@@ -809,27 +833,29 @@ module ActiveRecord
|
|
809
833
|
|
810
834
|
def exec_queries(&block)
|
811
835
|
skip_query_cache_if_necessary do
|
812
|
-
|
813
|
-
if
|
836
|
+
records =
|
837
|
+
if where_clause.contradiction?
|
838
|
+
[]
|
839
|
+
elsif eager_loading?
|
814
840
|
apply_join_dependency do |relation, join_dependency|
|
815
841
|
if relation.null_relation?
|
816
842
|
[]
|
817
843
|
else
|
818
844
|
relation = join_dependency.apply_column_aliases(relation)
|
819
845
|
rows = connection.select_all(relation.arel, "SQL")
|
820
|
-
join_dependency.instantiate(rows, &block)
|
846
|
+
join_dependency.instantiate(rows, strict_loading_value, &block)
|
821
847
|
end.freeze
|
822
848
|
end
|
823
849
|
else
|
824
850
|
klass.find_by_sql(arel, &block).freeze
|
825
851
|
end
|
826
852
|
|
827
|
-
preload_associations(
|
853
|
+
preload_associations(records) unless skip_preloading_value
|
828
854
|
|
829
|
-
|
855
|
+
records.each(&:readonly!) if readonly_value
|
856
|
+
records.each(&:strict_loading!) if strict_loading_value
|
830
857
|
|
831
|
-
|
832
|
-
@records
|
858
|
+
records
|
833
859
|
end
|
834
860
|
end
|
835
861
|
|
@@ -848,27 +874,27 @@ module ActiveRecord
|
|
848
874
|
end
|
849
875
|
|
850
876
|
def references_eager_loaded_tables?
|
851
|
-
joined_tables =
|
877
|
+
joined_tables = build_joins([]).flat_map do |join|
|
852
878
|
if join.is_a?(Arel::Nodes::StringJoin)
|
853
879
|
tables_in_string(join.left)
|
854
880
|
else
|
855
|
-
|
881
|
+
join.left.name
|
856
882
|
end
|
857
883
|
end
|
858
884
|
|
859
|
-
joined_tables
|
885
|
+
joined_tables << table.name
|
860
886
|
|
861
887
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
862
|
-
joined_tables
|
888
|
+
joined_tables.map!(&:downcase)
|
863
889
|
|
864
|
-
(references_values - joined_tables).
|
890
|
+
!(references_values.map(&:to_s) - joined_tables).empty?
|
865
891
|
end
|
866
892
|
|
867
893
|
def tables_in_string(string)
|
868
894
|
return [] if string.blank?
|
869
895
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
870
896
|
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
|
871
|
-
string.scan(/
|
897
|
+
string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
|
872
898
|
end
|
873
899
|
end
|
874
900
|
end
|