activerecord 6.0.0 → 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 +872 -582
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record.rb +7 -13
- data/lib/active_record/aggregations.rb +1 -2
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations.rb +116 -13
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +49 -29
- 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 -3
- 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 +25 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- 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 +77 -42
- 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 +13 -8
- 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 -9
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attributes.rb +32 -8
- data/lib/active_record/autosave_association.rb +63 -44
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +86 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +4 -9
- 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 +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +263 -107
- data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
- data/lib/active_record/connection_adapters/abstract_adapter.rb +74 -76
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
- 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/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- 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 +17 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- 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 +21 -56
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- 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/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +81 -57
- 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 +38 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +211 -81
- data/lib/active_record/core.rb +237 -69
- data/lib/active_record/counter_cache.rb +4 -1
- 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 -41
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +40 -16
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- 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 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +54 -11
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +39 -10
- 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 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -9
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/migration.rb +114 -84
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +70 -20
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/model_schema.rb +120 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/databases.rake +267 -93
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation.rb +108 -67
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/calculations.rb +102 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +55 -17
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder.rb +55 -35
- 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 +340 -180
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +104 -58
- data/lib/active_record/result.rb +41 -34
- 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.rb +0 -1
- data/lib/active_record/scoping/default.rb +0 -1
- data/lib/active_record/scoping/named.rb +7 -18
- 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 +3 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -36
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +38 -16
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +22 -71
- data/lib/active_record/type.rb +8 -2
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- 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_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/arel.rb +15 -12
- 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 +17 -24
- 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 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration.rb +6 -2
- 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 +4 -4
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +27 -24
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- 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 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
@@ -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
|
@@ -67,10 +68,9 @@ module ActiveRecord
|
|
67
68
|
end
|
68
69
|
|
69
70
|
private
|
70
|
-
|
71
71
|
def relation_with(values)
|
72
|
-
result =
|
73
|
-
result.
|
72
|
+
result = spawn
|
73
|
+
result.instance_variable_set(:@values, values)
|
74
74
|
result
|
75
75
|
end
|
76
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,29 +88,59 @@ module ActiveRecord
|
|
83
88
|
end
|
84
89
|
|
85
90
|
def self.empty
|
86
|
-
@empty ||= new([])
|
91
|
+
@empty ||= new([]).freeze
|
87
92
|
end
|
88
93
|
|
89
|
-
|
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
|
112
|
+
end
|
90
113
|
|
114
|
+
protected
|
91
115
|
attr_reader :predicates
|
92
116
|
|
93
117
|
def referenced_columns
|
94
|
-
|
95
|
-
|
96
|
-
|
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
|
97
124
|
end
|
98
125
|
end
|
99
126
|
|
100
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
|
+
|
101
137
|
def equalities(predicates)
|
102
138
|
equalities = []
|
103
139
|
|
104
140
|
predicates.each do |node|
|
105
|
-
|
106
|
-
when Arel::Nodes::Equality
|
141
|
+
if equality_node?(node)
|
107
142
|
equalities << node
|
108
|
-
|
143
|
+
elsif node.is_a?(Arel::Nodes::And)
|
109
144
|
equalities.concat equalities(node.children)
|
110
145
|
end
|
111
146
|
end
|
@@ -114,37 +149,55 @@ module ActiveRecord
|
|
114
149
|
end
|
115
150
|
|
116
151
|
def predicates_unreferenced_by(other)
|
117
|
-
|
118
|
-
|
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
|
119
173
|
end
|
120
174
|
end
|
121
175
|
|
122
176
|
def equality_node?(node)
|
123
|
-
node.
|
177
|
+
!node.is_a?(String) && node.equality?
|
124
178
|
end
|
125
179
|
|
126
180
|
def invert_predicate(node)
|
127
181
|
case node
|
128
182
|
when NilClass
|
129
183
|
raise ArgumentError, "Invalid argument for .where.not(), got nil."
|
130
|
-
when Arel::Nodes::In
|
131
|
-
Arel::Nodes::NotIn.new(node.left, node.right)
|
132
|
-
when Arel::Nodes::IsNotDistinctFrom
|
133
|
-
Arel::Nodes::IsDistinctFrom.new(node.left, node.right)
|
134
|
-
when Arel::Nodes::IsDistinctFrom
|
135
|
-
Arel::Nodes::IsNotDistinctFrom.new(node.left, node.right)
|
136
|
-
when Arel::Nodes::Equality
|
137
|
-
Arel::Nodes::NotEqual.new(node.left, node.right)
|
138
184
|
when String
|
139
185
|
Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(node))
|
140
186
|
else
|
141
|
-
|
187
|
+
node.invert
|
142
188
|
end
|
143
189
|
end
|
144
190
|
|
145
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
|
+
|
146
195
|
predicates.reject do |node|
|
147
|
-
|
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
|
148
201
|
end
|
149
202
|
end
|
150
203
|
|
@@ -174,15 +227,8 @@ module ActiveRecord
|
|
174
227
|
case node
|
175
228
|
when Array
|
176
229
|
node.map { |v| extract_node_value(v) }
|
177
|
-
when Arel::Nodes::Casted, Arel::Nodes::Quoted
|
178
|
-
node.
|
179
|
-
when Arel::Nodes::BindParam
|
180
|
-
value = node.value
|
181
|
-
if value.respond_to?(:value_before_type_cast)
|
182
|
-
value.value_before_type_cast
|
183
|
-
else
|
184
|
-
value
|
185
|
-
end
|
230
|
+
when Arel::Nodes::BindParam, Arel::Nodes::Casted, Arel::Nodes::Quoted
|
231
|
+
node.value_before_type_cast
|
186
232
|
end
|
187
233
|
end
|
188
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]) }
|
@@ -132,7 +125,6 @@ module ActiveRecord
|
|
132
125
|
end
|
133
126
|
|
134
127
|
private
|
135
|
-
|
136
128
|
def column_type(name, type_overrides = {})
|
137
129
|
type_overrides.fetch(name) do
|
138
130
|
column_types.fetch(name, Type.default_value)
|
@@ -146,21 +138,36 @@ module ActiveRecord
|
|
146
138
|
# used as keys in ActiveRecord::Base's @attributes hash
|
147
139
|
columns = @columns.map(&:-@)
|
148
140
|
length = columns.length
|
141
|
+
template = nil
|
149
142
|
|
150
143
|
@rows.map { |row|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
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
|
161
170
|
end
|
162
|
-
|
163
|
-
hash
|
164
171
|
}
|
165
172
|
end
|
166
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
|