activerecord 6.0.4.8 → 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 -883
- 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 +1 -1
- 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 +215 -49
- 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 +64 -44
- 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 -31
- 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
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
class InsertAll # :nodoc:
|
5
7
|
attr_reader :model, :connection, :inserts, :keys
|
@@ -8,13 +10,19 @@ module ActiveRecord
|
|
8
10
|
def initialize(model, inserts, on_duplicate:, returning: nil, unique_by: nil)
|
9
11
|
raise ArgumentError, "Empty list of attributes passed" if inserts.blank?
|
10
12
|
|
11
|
-
@model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s)
|
13
|
+
@model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s)
|
12
14
|
@on_duplicate, @returning, @unique_by = on_duplicate, returning, unique_by
|
13
15
|
|
16
|
+
if model.scope_attributes?
|
17
|
+
@scope_attributes = model.scope_attributes
|
18
|
+
@keys |= @scope_attributes.keys
|
19
|
+
end
|
20
|
+
@keys = @keys.to_set
|
21
|
+
|
14
22
|
@returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
|
15
23
|
@returning = false if @returning == []
|
16
24
|
|
17
|
-
@unique_by = find_unique_index_for(unique_by)
|
25
|
+
@unique_by = find_unique_index_for(unique_by)
|
18
26
|
@on_duplicate = :skip if @on_duplicate == :update && updatable_columns.empty?
|
19
27
|
|
20
28
|
ensure_valid_options_for_connection!
|
@@ -32,7 +40,7 @@ module ActiveRecord
|
|
32
40
|
end
|
33
41
|
|
34
42
|
def primary_keys
|
35
|
-
Array(model.
|
43
|
+
Array(connection.schema_cache.primary_keys(model.table_name))
|
36
44
|
end
|
37
45
|
|
38
46
|
|
@@ -47,6 +55,8 @@ module ActiveRecord
|
|
47
55
|
def map_key_with_value
|
48
56
|
inserts.map do |attributes|
|
49
57
|
attributes = attributes.stringify_keys
|
58
|
+
attributes.merge!(scope_attributes) if scope_attributes
|
59
|
+
|
50
60
|
verify_attributes(attributes)
|
51
61
|
|
52
62
|
keys.map do |key|
|
@@ -56,13 +66,18 @@ module ActiveRecord
|
|
56
66
|
end
|
57
67
|
|
58
68
|
private
|
69
|
+
attr_reader :scope_attributes
|
70
|
+
|
59
71
|
def find_unique_index_for(unique_by)
|
60
|
-
|
72
|
+
name_or_columns = unique_by || model.primary_key
|
73
|
+
match = Array(name_or_columns).map(&:to_s)
|
61
74
|
|
62
75
|
if index = unique_indexes.find { |i| match.include?(i.name) || i.columns == match }
|
63
76
|
index
|
77
|
+
elsif match == primary_keys
|
78
|
+
unique_by.nil? ? nil : ActiveRecord::ConnectionAdapters::IndexDefinition.new(model.table_name, "#{model.table_name}_primary_key", true, match)
|
64
79
|
else
|
65
|
-
raise ArgumentError, "No unique index found for #{
|
80
|
+
raise ArgumentError, "No unique index found for #{name_or_columns}"
|
66
81
|
end
|
67
82
|
end
|
68
83
|
|
@@ -151,9 +166,21 @@ module ActiveRecord
|
|
151
166
|
quote_columns(insert_all.updatable_columns)
|
152
167
|
end
|
153
168
|
|
169
|
+
def touch_model_timestamps_unless(&block)
|
170
|
+
model.send(:timestamp_attributes_for_update_in_model).map do |column_name|
|
171
|
+
if touch_timestamp_attribute?(column_name)
|
172
|
+
"#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE CURRENT_TIMESTAMP END),"
|
173
|
+
end
|
174
|
+
end.compact.join
|
175
|
+
end
|
176
|
+
|
154
177
|
private
|
155
178
|
attr_reader :connection, :insert_all
|
156
179
|
|
180
|
+
def touch_timestamp_attribute?(column_name)
|
181
|
+
update_duplicates? && !insert_all.updatable_columns.include?(column_name)
|
182
|
+
end
|
183
|
+
|
157
184
|
def columns_list
|
158
185
|
format_columns(insert_all.keys)
|
159
186
|
end
|
@@ -93,7 +93,7 @@ module ActiveRecord
|
|
93
93
|
# cache_version, but this method can be overwritten to return something else.
|
94
94
|
#
|
95
95
|
# Note, this method will return nil if ActiveRecord::Base.cache_versioning is set to
|
96
|
-
# +false
|
96
|
+
# +false+.
|
97
97
|
def cache_version
|
98
98
|
return unless cache_versioning
|
99
99
|
|
@@ -104,10 +104,8 @@ module ActiveRecord
|
|
104
104
|
elsif timestamp = updated_at
|
105
105
|
timestamp.utc.to_s(cache_timestamp_format)
|
106
106
|
end
|
107
|
-
|
108
|
-
|
109
|
-
raise ActiveModel::MissingAttributeError, "missing attribute: updated_at"
|
110
|
-
end
|
107
|
+
elsif self.class.has_attribute?("updated_at")
|
108
|
+
raise ActiveModel::MissingAttributeError, "missing attribute: updated_at"
|
111
109
|
end
|
112
110
|
end
|
113
111
|
|
@@ -6,8 +6,15 @@ require "active_record/scoping/named"
|
|
6
6
|
module ActiveRecord
|
7
7
|
# This class is used to create a table that keeps track of values and keys such
|
8
8
|
# as which environment migrations were run in.
|
9
|
+
#
|
10
|
+
# This is enabled by default. To disable this functionality set
|
11
|
+
# `use_metadata_table` to false in your database configuration.
|
9
12
|
class InternalMetadata < ActiveRecord::Base # :nodoc:
|
10
13
|
class << self
|
14
|
+
def enabled?
|
15
|
+
ActiveRecord::Base.connection.use_metadata_table?
|
16
|
+
end
|
17
|
+
|
11
18
|
def _internal?
|
12
19
|
true
|
13
20
|
end
|
@@ -21,19 +28,21 @@ module ActiveRecord
|
|
21
28
|
end
|
22
29
|
|
23
30
|
def []=(key, value)
|
31
|
+
return unless enabled?
|
32
|
+
|
24
33
|
find_or_initialize_by(key: key).update!(value: value)
|
25
34
|
end
|
26
35
|
|
27
36
|
def [](key)
|
28
|
-
|
29
|
-
end
|
37
|
+
return unless enabled?
|
30
38
|
|
31
|
-
|
32
|
-
connection.table_exists?(table_name)
|
39
|
+
where(key: key).pluck(:value).first
|
33
40
|
end
|
34
41
|
|
35
42
|
# Creates an internal metadata table with columns +key+ and +value+
|
36
43
|
def create_table
|
44
|
+
return unless enabled?
|
45
|
+
|
37
46
|
unless table_exists?
|
38
47
|
key_options = connection.internal_string_options_for_primary_key
|
39
48
|
|
@@ -46,6 +55,8 @@ module ActiveRecord
|
|
46
55
|
end
|
47
56
|
|
48
57
|
def drop_table
|
58
|
+
return unless enabled?
|
59
|
+
|
49
60
|
connection.drop_table table_name, if_exists: true
|
50
61
|
end
|
51
62
|
end
|
@@ -1,13 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
-
module LegacyYamlAdapter
|
4
|
+
module LegacyYamlAdapter # :nodoc:
|
5
5
|
def self.convert(klass, coder)
|
6
6
|
return coder unless coder.is_a?(Psych::Coder)
|
7
7
|
|
8
8
|
case coder["active_record_yaml_version"]
|
9
9
|
when 1, 2 then coder
|
10
10
|
else
|
11
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
12
|
+
YAML loading from legacy format older than Rails 5.0 is deprecated
|
13
|
+
and will be removed in Rails 6.2.
|
14
|
+
MSG
|
11
15
|
if coder["attributes"].is_a?(ActiveModel::AttributeSet)
|
12
16
|
Rails420.convert(klass, coder)
|
13
17
|
else
|
@@ -16,7 +20,7 @@ module ActiveRecord
|
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
19
|
-
module Rails420
|
23
|
+
module Rails420 # :nodoc:
|
20
24
|
def self.convert(klass, coder)
|
21
25
|
attribute_set = coder["attributes"]
|
22
26
|
|
@@ -32,7 +36,7 @@ module ActiveRecord
|
|
32
36
|
end
|
33
37
|
end
|
34
38
|
|
35
|
-
module Rails41
|
39
|
+
module Rails41 # :nodoc:
|
36
40
|
def self.convert(klass, coder)
|
37
41
|
attributes = klass.attributes_builder
|
38
42
|
.build_from_database(coder["attributes"])
|
@@ -89,7 +89,8 @@ module ActiveRecord
|
|
89
89
|
|
90
90
|
begin
|
91
91
|
locking_column = self.class.locking_column
|
92
|
-
previous_lock_value =
|
92
|
+
previous_lock_value = attribute_before_type_cast(locking_column)
|
93
|
+
attribute_names = attribute_names.dup if attribute_names.frozen?
|
93
94
|
attribute_names << locking_column
|
94
95
|
|
95
96
|
self[locking_column] += 1
|
@@ -97,7 +98,7 @@ module ActiveRecord
|
|
97
98
|
affected_rows = self.class._update_record(
|
98
99
|
attributes_with_values(attribute_names),
|
99
100
|
@primary_key => id_in_database,
|
100
|
-
locking_column =>
|
101
|
+
locking_column => @attributes[locking_column].original_value_for_database
|
101
102
|
)
|
102
103
|
|
103
104
|
if affected_rows != 1
|
@@ -120,7 +121,7 @@ module ActiveRecord
|
|
120
121
|
|
121
122
|
affected_rows = self.class._delete_record(
|
122
123
|
@primary_key => id_in_database,
|
123
|
-
locking_column =>
|
124
|
+
locking_column => attribute_before_type_cast(locking_column)
|
124
125
|
)
|
125
126
|
|
126
127
|
if affected_rows != 1
|
@@ -164,20 +165,12 @@ module ActiveRecord
|
|
164
165
|
super
|
165
166
|
end
|
166
167
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
# sub class being decorated. As such, changes to `lock_optimistically`, or
|
171
|
-
# `locking_column` would not be picked up.
|
172
|
-
def inherited(subclass)
|
173
|
-
subclass.class_eval do
|
174
|
-
is_lock_column = ->(name, _) { lock_optimistically && name == locking_column }
|
175
|
-
decorate_matching_attribute_types(is_lock_column, "_optimistic_locking") do |type|
|
176
|
-
LockingType.new(type)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
super
|
168
|
+
def define_attribute(name, cast_type, **) # :nodoc:
|
169
|
+
if lock_optimistically && name == locking_column
|
170
|
+
cast_type = LockingType.new(cast_type)
|
180
171
|
end
|
172
|
+
super
|
173
|
+
end
|
181
174
|
end
|
182
175
|
end
|
183
176
|
|
@@ -185,6 +178,10 @@ module ActiveRecord
|
|
185
178
|
# `nil` values to `lock_version`, and not result in `ActiveRecord::StaleObjectError`
|
186
179
|
# during update record.
|
187
180
|
class LockingType < DelegateClass(Type::Value) # :nodoc:
|
181
|
+
def self.new(subtype)
|
182
|
+
self === subtype ? subtype : super
|
183
|
+
end
|
184
|
+
|
188
185
|
def deserialize(value)
|
189
186
|
super.to_i
|
190
187
|
end
|
@@ -53,8 +53,12 @@ module ActiveRecord
|
|
53
53
|
# end
|
54
54
|
#
|
55
55
|
# Database-specific information on row locking:
|
56
|
-
#
|
57
|
-
#
|
56
|
+
#
|
57
|
+
# [MySQL]
|
58
|
+
# https://dev.mysql.com/doc/refman/en/innodb-locking-reads.html
|
59
|
+
#
|
60
|
+
# [PostgreSQL]
|
61
|
+
# https://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
|
58
62
|
module Pessimistic
|
59
63
|
# Obtain a row lock on this record. Reloads the record to obtain the requested
|
60
64
|
# lock. Pass an SQL locking clause to append the end of the SELECT statement
|
@@ -19,6 +19,15 @@ module ActiveRecord
|
|
19
19
|
rt
|
20
20
|
end
|
21
21
|
|
22
|
+
def strict_loading_violation(event)
|
23
|
+
debug do
|
24
|
+
owner = event.payload[:owner]
|
25
|
+
association = event.payload[:association]
|
26
|
+
|
27
|
+
color("Strict loading violation: #{association} lazily loaded on #{owner}.", RED)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
22
31
|
def sql(event)
|
23
32
|
self.class.runtime += event.duration
|
24
33
|
return unless logger.debug?
|
@@ -32,11 +41,15 @@ module ActiveRecord
|
|
32
41
|
sql = payload[:sql]
|
33
42
|
binds = nil
|
34
43
|
|
35
|
-
|
44
|
+
if payload[:binds]&.any?
|
36
45
|
casted_params = type_casted_binds(payload[:type_casted_binds])
|
37
|
-
|
38
|
-
|
39
|
-
|
46
|
+
|
47
|
+
binds = []
|
48
|
+
payload[:binds].each_with_index do |attr, i|
|
49
|
+
binds << render_bind(attr, casted_params[i])
|
50
|
+
end
|
51
|
+
binds = binds.inspect
|
52
|
+
binds.prepend(" ")
|
40
53
|
end
|
41
54
|
|
42
55
|
name = colorize_payload_name(name, payload[:name])
|
@@ -51,13 +64,18 @@ module ActiveRecord
|
|
51
64
|
end
|
52
65
|
|
53
66
|
def render_bind(attr, value)
|
54
|
-
|
67
|
+
case attr
|
68
|
+
when ActiveModel::Attribute
|
69
|
+
if attr.type.binary? && attr.value
|
70
|
+
value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
|
71
|
+
end
|
72
|
+
when Array
|
55
73
|
attr = attr.first
|
56
|
-
|
57
|
-
|
74
|
+
else
|
75
|
+
attr = nil
|
58
76
|
end
|
59
77
|
|
60
|
-
[attr
|
78
|
+
[attr&.name, value]
|
61
79
|
end
|
62
80
|
|
63
81
|
def colorize_payload_name(name, payload_name)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_record/middleware/database_selector/resolver/session"
|
4
|
+
require "active_support/core_ext/numeric/time"
|
4
5
|
|
5
6
|
module ActiveRecord
|
6
7
|
module Middleware
|
@@ -43,6 +44,10 @@ module ActiveRecord
|
|
43
44
|
write_to_primary(&blk)
|
44
45
|
end
|
45
46
|
|
47
|
+
def update_context(response)
|
48
|
+
context.save(response)
|
49
|
+
end
|
50
|
+
|
46
51
|
private
|
47
52
|
def read_from_primary(&blk)
|
48
53
|
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: true) do
|
@@ -59,11 +59,14 @@ module ActiveRecord
|
|
59
59
|
context = context_klass.call(request)
|
60
60
|
resolver = resolver_klass.call(context, options)
|
61
61
|
|
62
|
-
if reading_request?(request)
|
62
|
+
response = if reading_request?(request)
|
63
63
|
resolver.read(&blk)
|
64
64
|
else
|
65
65
|
resolver.write(&blk)
|
66
66
|
end
|
67
|
+
|
68
|
+
resolver.update_context(response)
|
69
|
+
response
|
67
70
|
end
|
68
71
|
|
69
72
|
def reading_request?(request)
|
@@ -8,6 +8,7 @@ module ActiveRecord
|
|
8
8
|
#
|
9
9
|
# * add_column
|
10
10
|
# * add_foreign_key
|
11
|
+
# * add_check_constraint
|
11
12
|
# * add_index
|
12
13
|
# * add_reference
|
13
14
|
# * add_timestamps
|
@@ -25,6 +26,7 @@ module ActiveRecord
|
|
25
26
|
# * remove_column (must supply a type)
|
26
27
|
# * remove_columns (must specify at least one column name or more)
|
27
28
|
# * remove_foreign_key (must supply a second table)
|
29
|
+
# * remove_check_constraint
|
28
30
|
# * remove_index
|
29
31
|
# * remove_reference
|
30
32
|
# * remove_timestamps
|
@@ -39,7 +41,8 @@ module ActiveRecord
|
|
39
41
|
:drop_join_table, :drop_table, :execute_block, :enable_extension, :disable_extension,
|
40
42
|
:change_column, :execute, :remove_columns, :change_column_null,
|
41
43
|
:add_foreign_key, :remove_foreign_key,
|
42
|
-
:change_column_comment, :change_table_comment
|
44
|
+
:change_column_comment, :change_table_comment,
|
45
|
+
:add_check_constraint, :remove_check_constraint
|
43
46
|
]
|
44
47
|
include JoinTable
|
45
48
|
|
@@ -85,6 +88,11 @@ module ActiveRecord
|
|
85
88
|
# recorder.inverse_of(:rename_table, [:old, :new])
|
86
89
|
# # => [:rename_table, [:new, :old]]
|
87
90
|
#
|
91
|
+
# If the inverse of a command requires several commands, returns array of commands.
|
92
|
+
#
|
93
|
+
# recorder.inverse_of(:remove_columns, [:some_table, :foo, :bar, type: :string])
|
94
|
+
# # => [[:add_column, :some_table, :foo, :string], [:add_column, :some_table, :bar, :string]]
|
95
|
+
#
|
88
96
|
# This method will raise an +IrreversibleMigration+ exception if it cannot
|
89
97
|
# invert the +command+.
|
90
98
|
def inverse_of(command, args, &block)
|
@@ -127,9 +135,11 @@ module ActiveRecord
|
|
127
135
|
create_table: :drop_table,
|
128
136
|
create_join_table: :drop_join_table,
|
129
137
|
add_column: :remove_column,
|
138
|
+
add_index: :remove_index,
|
130
139
|
add_timestamps: :remove_timestamps,
|
131
140
|
add_reference: :remove_reference,
|
132
141
|
add_foreign_key: :remove_foreign_key,
|
142
|
+
add_check_constraint: :remove_check_constraint,
|
133
143
|
enable_extension: :disable_extension
|
134
144
|
}.each do |cmd, inv|
|
135
145
|
[[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
|
@@ -171,44 +181,49 @@ module ActiveRecord
|
|
171
181
|
super
|
172
182
|
end
|
173
183
|
|
184
|
+
def invert_remove_columns(args)
|
185
|
+
unless args[-1].is_a?(Hash) && args[-1].has_key?(:type)
|
186
|
+
raise ActiveRecord::IrreversibleMigration, "remove_columns is only reversible if given a type."
|
187
|
+
end
|
188
|
+
|
189
|
+
[:add_columns, args]
|
190
|
+
end
|
191
|
+
|
174
192
|
def invert_rename_index(args)
|
175
|
-
|
193
|
+
table_name, old_name, new_name = args
|
194
|
+
[:rename_index, [table_name, new_name, old_name]]
|
176
195
|
end
|
177
196
|
|
178
197
|
def invert_rename_column(args)
|
179
|
-
|
198
|
+
table_name, old_name, new_name = args
|
199
|
+
[:rename_column, [table_name, new_name, old_name]]
|
180
200
|
end
|
181
201
|
|
182
|
-
def
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
options_hash = options.slice(:name, :algorithm)
|
187
|
-
options_hash[:column] = columns if !options_hash[:name]
|
202
|
+
def invert_remove_index(args)
|
203
|
+
options = args.extract_options!
|
204
|
+
table, columns = args
|
188
205
|
|
189
|
-
|
190
|
-
end
|
206
|
+
columns ||= options.delete(:column)
|
191
207
|
|
192
|
-
|
193
|
-
|
194
|
-
if (options = options_or_column).is_a?(Hash)
|
195
|
-
unless options[:column]
|
196
|
-
raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
|
197
|
-
end
|
198
|
-
options = options.dup
|
199
|
-
[:add_index, [table, options.delete(:column), options]]
|
200
|
-
elsif (column = options_or_column).present?
|
201
|
-
[:add_index, [table, column]]
|
208
|
+
unless columns
|
209
|
+
raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
|
202
210
|
end
|
211
|
+
|
212
|
+
options.delete(:if_exists)
|
213
|
+
|
214
|
+
args = [table, columns]
|
215
|
+
args << options unless options.empty?
|
216
|
+
|
217
|
+
[:add_index, args]
|
203
218
|
end
|
204
219
|
|
205
220
|
alias :invert_add_belongs_to :invert_add_reference
|
206
221
|
alias :invert_remove_belongs_to :invert_remove_reference
|
207
222
|
|
208
223
|
def invert_change_column_default(args)
|
209
|
-
table, column, options =
|
224
|
+
table, column, options = args
|
210
225
|
|
211
|
-
unless options
|
226
|
+
unless options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
|
212
227
|
raise ActiveRecord::IrreversibleMigration, "change_column_default is only reversible if given a :from and :to option."
|
213
228
|
end
|
214
229
|
|
@@ -235,9 +250,9 @@ module ActiveRecord
|
|
235
250
|
end
|
236
251
|
|
237
252
|
def invert_change_column_comment(args)
|
238
|
-
table, column, options =
|
253
|
+
table, column, options = args
|
239
254
|
|
240
|
-
unless options
|
255
|
+
unless options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
|
241
256
|
raise ActiveRecord::IrreversibleMigration, "change_column_comment is only reversible if given a :from and :to option."
|
242
257
|
end
|
243
258
|
|
@@ -245,15 +260,20 @@ module ActiveRecord
|
|
245
260
|
end
|
246
261
|
|
247
262
|
def invert_change_table_comment(args)
|
248
|
-
table, options =
|
263
|
+
table, options = args
|
249
264
|
|
250
|
-
unless options
|
265
|
+
unless options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
|
251
266
|
raise ActiveRecord::IrreversibleMigration, "change_table_comment is only reversible if given a :from and :to option."
|
252
267
|
end
|
253
268
|
|
254
269
|
[:change_table_comment, [table, from: options[:to], to: options[:from]]]
|
255
270
|
end
|
256
271
|
|
272
|
+
def invert_remove_check_constraint(args)
|
273
|
+
raise ActiveRecord::IrreversibleMigration, "remove_check_constraint is only reversible if given an expression." if args.size < 2
|
274
|
+
super
|
275
|
+
end
|
276
|
+
|
257
277
|
def respond_to_missing?(method, _)
|
258
278
|
super || delegate.respond_to?(method)
|
259
279
|
end
|
@@ -13,7 +13,61 @@ module ActiveRecord
|
|
13
13
|
const_get(name)
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
V6_1 = Current
|
17
|
+
|
18
|
+
class V6_0 < V6_1
|
19
|
+
class ReferenceDefinition < ConnectionAdapters::ReferenceDefinition
|
20
|
+
def index_options(table_name)
|
21
|
+
as_options(index)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module TableDefinition
|
26
|
+
def references(*args, **options)
|
27
|
+
args.each do |ref_name|
|
28
|
+
ReferenceDefinition.new(ref_name, **options).add_to(self)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
alias :belongs_to :references
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_table(table_name, **options)
|
35
|
+
if block_given?
|
36
|
+
super { |t| yield compatible_table_definition(t) }
|
37
|
+
else
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def change_table(table_name, **options)
|
43
|
+
if block_given?
|
44
|
+
super { |t| yield compatible_table_definition(t) }
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_join_table(table_1, table_2, **options)
|
51
|
+
if block_given?
|
52
|
+
super { |t| yield compatible_table_definition(t) }
|
53
|
+
else
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_reference(table_name, ref_name, **options)
|
59
|
+
ReferenceDefinition.new(ref_name, **options).add_to(update_table_definition(table_name, self))
|
60
|
+
end
|
61
|
+
alias :add_belongs_to :add_reference
|
62
|
+
|
63
|
+
private
|
64
|
+
def compatible_table_definition(t)
|
65
|
+
class << t
|
66
|
+
prepend TableDefinition
|
67
|
+
end
|
68
|
+
t
|
69
|
+
end
|
70
|
+
end
|
17
71
|
|
18
72
|
class V5_2 < V6_0
|
19
73
|
module TableDefinition
|
@@ -29,13 +83,11 @@ module ActiveRecord
|
|
29
83
|
end
|
30
84
|
|
31
85
|
def invert_change_column_comment(args)
|
32
|
-
|
33
|
-
[:change_column_comment, [table_name, column_name, from: comment, to: comment]]
|
86
|
+
[:change_column_comment, args]
|
34
87
|
end
|
35
88
|
|
36
89
|
def invert_change_table_comment(args)
|
37
|
-
|
38
|
-
[:change_table_comment, [table_name, from: comment, to: comment]]
|
90
|
+
[:change_table_comment, args]
|
39
91
|
end
|
40
92
|
end
|
41
93
|
|
@@ -86,9 +138,9 @@ module ActiveRecord
|
|
86
138
|
end
|
87
139
|
|
88
140
|
class V5_1 < V5_2
|
89
|
-
def change_column(table_name, column_name, type, options
|
141
|
+
def change_column(table_name, column_name, type, **options)
|
90
142
|
if connection.adapter_name == "PostgreSQL"
|
91
|
-
super(table_name, column_name, type, options.except(:default, :null, :comment))
|
143
|
+
super(table_name, column_name, type, **options.except(:default, :null, :comment))
|
92
144
|
connection.change_column_default(table_name, column_name, options[:default]) if options.key?(:default)
|
93
145
|
connection.change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
|
94
146
|
connection.change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
|
@@ -194,7 +246,7 @@ module ActiveRecord
|
|
194
246
|
super
|
195
247
|
end
|
196
248
|
|
197
|
-
def index_exists?(table_name, column_name, options
|
249
|
+
def index_exists?(table_name, column_name, **options)
|
198
250
|
column_names = Array(column_name).map(&:to_s)
|
199
251
|
options[:name] =
|
200
252
|
if options[:name].present?
|
@@ -205,10 +257,9 @@ module ActiveRecord
|
|
205
257
|
super
|
206
258
|
end
|
207
259
|
|
208
|
-
def remove_index(table_name,
|
209
|
-
options =
|
210
|
-
|
211
|
-
super(table_name, options)
|
260
|
+
def remove_index(table_name, column_name = nil, **options)
|
261
|
+
options[:name] = index_name_for_remove(table_name, column_name, options)
|
262
|
+
super
|
212
263
|
end
|
213
264
|
|
214
265
|
private
|
@@ -219,13 +270,12 @@ module ActiveRecord
|
|
219
270
|
super
|
220
271
|
end
|
221
272
|
|
222
|
-
def index_name_for_remove(table_name, options
|
223
|
-
index_name = connection.index_name(table_name, options)
|
273
|
+
def index_name_for_remove(table_name, column_name, options)
|
274
|
+
index_name = connection.index_name(table_name, column_name || options)
|
224
275
|
|
225
276
|
unless connection.index_name_exists?(table_name, index_name)
|
226
|
-
if options.
|
227
|
-
options_without_column = options.
|
228
|
-
options_without_column.delete :column
|
277
|
+
if options.key?(:name)
|
278
|
+
options_without_column = options.except(:column)
|
229
279
|
index_name_without_column = connection.index_name(table_name, options_without_column)
|
230
280
|
|
231
281
|
if connection.index_name_exists?(table_name, index_name_without_column)
|