activerecord 7.2.3 → 8.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +612 -1055
- data/README.rdoc +1 -1
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/association.rb +35 -11
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +17 -4
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +1 -1
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +1 -1
- data/lib/active_record/associations/collection_proxy.rb +22 -4
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +3 -0
- data/lib/active_record/associations/has_many_through_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +4 -2
- data/lib/active_record/associations/preloader/association.rb +2 -2
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +1 -0
- data/lib/active_record/associations/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +192 -24
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/primary_key.rb +4 -8
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +16 -3
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
- data/lib/active_record/attributes.rb +3 -0
- data/lib/active_record/autosave_association.rb +69 -27
- data/lib/active_record/base.rb +1 -2
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +412 -88
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +137 -75
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +27 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +32 -35
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -32
- data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
- data/lib/active_record/connection_adapters/abstract_adapter.rb +150 -91
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +63 -52
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +73 -46
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -10
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -45
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +14 -33
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +71 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +139 -63
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +78 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
- data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +13 -14
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +102 -37
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +38 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -18
- data/lib/active_record/connection_adapters.rb +1 -56
- data/lib/active_record/connection_handling.rb +25 -2
- data/lib/active_record/core.rb +33 -17
- data/lib/active_record/counter_cache.rb +33 -8
- data/lib/active_record/database_configurations/database_config.rb +9 -1
- data/lib/active_record/database_configurations/hash_config.rb +67 -9
- data/lib/active_record/database_configurations/url_config.rb +13 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +1 -1
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +8 -8
- data/lib/active_record/encryption/encrypted_attribute_type.rb +11 -2
- data/lib/active_record/encryption/encryptor.rb +28 -8
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +9 -2
- data/lib/active_record/enum.rb +33 -30
- data/lib/active_record/errors.rb +33 -9
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +73 -0
- data/lib/active_record/fixtures.rb +2 -4
- data/lib/active_record/future_result.rb +15 -9
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +1 -1
- data/lib/active_record/insert_all.rb +14 -9
- data/lib/active_record/locking/optimistic.rb +8 -1
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +3 -13
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +45 -12
- data/lib/active_record/migration/compatibility.rb +37 -24
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration.rb +48 -42
- data/lib/active_record/model_schema.rb +38 -13
- data/lib/active_record/nested_attributes.rb +6 -6
- data/lib/active_record/persistence.rb +162 -133
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +100 -52
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +8 -8
- data/lib/active_record/railtie.rb +35 -30
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +26 -38
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +53 -21
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +147 -73
- data/lib/active_record/relation/calculations.rb +52 -40
- data/lib/active_record/relation/delegation.rb +25 -15
- data/lib/active_record/relation/finder_methods.rb +40 -24
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -9
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +22 -7
- data/lib/active_record/relation/query_attribute.rb +3 -1
- data/lib/active_record/relation/query_methods.rb +140 -86
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +2 -9
- data/lib/active_record/relation.rb +107 -75
- data/lib/active_record/result.rb +109 -24
- data/lib/active_record/runtime_registry.rb +42 -58
- data/lib/active_record/sanitization.rb +9 -6
- data/lib/active_record/schema_dumper.rb +18 -11
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/signed_id.rb +43 -15
- data/lib/active_record/statement_cache.rb +24 -20
- data/lib/active_record/store.rb +51 -22
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +6 -23
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +85 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
- data/lib/active_record/tasks/postgresql_database_tasks.rb +7 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
- data/lib/active_record/test_databases.rb +14 -4
- data/lib/active_record/test_fixtures.rb +39 -2
- data/lib/active_record/testing/query_assertions.rb +8 -2
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transaction.rb +2 -5
- data/lib/active_record/transactions.rb +37 -16
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +13 -2
- data/lib/active_record/type/serialized.rb +16 -4
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +2 -1
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +84 -49
- data/lib/arel/alias_predication.rb +2 -0
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/crud.rb +6 -11
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/node.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/predications.rb +1 -3
- data/lib/arel/select_manager.rb +7 -2
- data/lib/arel/table.rb +3 -7
- data/lib/arel/visitors/dot.rb +0 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +3 -21
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +16 -13
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -163
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
|
@@ -97,7 +97,7 @@ module ActiveRecord
|
|
|
97
97
|
# Returns the first class in the inheritance hierarchy that descends from either an
|
|
98
98
|
# abstract class or from <tt>ActiveRecord::Base</tt>.
|
|
99
99
|
#
|
|
100
|
-
# Consider the following
|
|
100
|
+
# Consider the following behavior:
|
|
101
101
|
#
|
|
102
102
|
# class ApplicationRecord < ActiveRecord::Base
|
|
103
103
|
# self.abstract_class = true
|
|
@@ -11,7 +11,7 @@ module ActiveRecord
|
|
|
11
11
|
def execute(relation, ...)
|
|
12
12
|
relation.model.with_connection do |c|
|
|
13
13
|
new(relation, c, ...).execute
|
|
14
|
-
end
|
|
14
|
+
end.tap { relation.reset }
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
|
|
@@ -39,7 +39,7 @@ module ActiveRecord
|
|
|
39
39
|
@returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
|
|
40
40
|
@returning = false if @returning == []
|
|
41
41
|
|
|
42
|
-
@unique_by = find_unique_index_for(@unique_by)
|
|
42
|
+
@unique_by = find_unique_index_for(@unique_by) if @on_duplicate != :raise
|
|
43
43
|
|
|
44
44
|
configure_on_duplicate_update_logic
|
|
45
45
|
ensure_valid_options_for_connection!
|
|
@@ -48,7 +48,7 @@ module ActiveRecord
|
|
|
48
48
|
def execute
|
|
49
49
|
return ActiveRecord::Result.empty if inserts.empty?
|
|
50
50
|
|
|
51
|
-
message = +"#{model} "
|
|
51
|
+
message = +"#{model.name} "
|
|
52
52
|
message << "Bulk " if inserts.many?
|
|
53
53
|
message << (on_duplicate == :update ? "Upsert" : "Insert")
|
|
54
54
|
connection.exec_insert_all to_sql, message
|
|
@@ -225,7 +225,7 @@ module ActiveRecord
|
|
|
225
225
|
class Builder # :nodoc:
|
|
226
226
|
attr_reader :model
|
|
227
227
|
|
|
228
|
-
delegate :skip_duplicates?, :update_duplicates?, :keys, :keys_including_timestamps, :record_timestamps?, to: :insert_all
|
|
228
|
+
delegate :skip_duplicates?, :update_duplicates?, :keys, :keys_including_timestamps, :record_timestamps?, :primary_keys, to: :insert_all
|
|
229
229
|
|
|
230
230
|
def initialize(insert_all)
|
|
231
231
|
@insert_all, @model, @connection = insert_all, insert_all.model, insert_all.connection
|
|
@@ -236,11 +236,16 @@ module ActiveRecord
|
|
|
236
236
|
end
|
|
237
237
|
|
|
238
238
|
def values_list
|
|
239
|
-
types =
|
|
239
|
+
types = extract_types_for(keys_including_timestamps)
|
|
240
240
|
|
|
241
241
|
values_list = insert_all.map_key_with_value do |key, value|
|
|
242
|
-
|
|
243
|
-
|
|
242
|
+
if Arel::Nodes::SqlLiteral === value
|
|
243
|
+
value
|
|
244
|
+
elsif primary_keys.include?(key) && value.nil?
|
|
245
|
+
connection.default_insert_value(model.columns_hash[key])
|
|
246
|
+
else
|
|
247
|
+
ActiveModel::Type::SerializeCastValue.serialize(type = types[key], type.cast(value))
|
|
248
|
+
end
|
|
244
249
|
end
|
|
245
250
|
|
|
246
251
|
connection.visitor.compile(Arel::Nodes::ValuesList.new(values_list))
|
|
@@ -303,8 +308,8 @@ module ActiveRecord
|
|
|
303
308
|
format_columns(insert_all.keys_including_timestamps)
|
|
304
309
|
end
|
|
305
310
|
|
|
306
|
-
def
|
|
307
|
-
columns = @model.
|
|
311
|
+
def extract_types_for(keys)
|
|
312
|
+
columns = @model.columns_hash
|
|
308
313
|
|
|
309
314
|
unknown_column = (keys - columns.keys).first
|
|
310
315
|
raise UnknownAttributeError.new(model.new, unknown_column) if unknown_column
|
|
@@ -9,7 +9,7 @@ module ActiveRecord
|
|
|
9
9
|
# it was opened, an ActiveRecord::StaleObjectError exception is thrown if that has occurred
|
|
10
10
|
# and the update is ignored.
|
|
11
11
|
#
|
|
12
|
-
# Check out
|
|
12
|
+
# Check out ActiveRecord::Locking::Pessimistic for an alternative.
|
|
13
13
|
#
|
|
14
14
|
# == Usage
|
|
15
15
|
#
|
|
@@ -101,6 +101,13 @@ module ActiveRecord
|
|
|
101
101
|
attribute_names = attribute_names.dup if attribute_names.frozen?
|
|
102
102
|
attribute_names << locking_column
|
|
103
103
|
|
|
104
|
+
if self[locking_column].nil?
|
|
105
|
+
raise(<<-MSG.squish)
|
|
106
|
+
For optimistic locking, locking_column ('#{locking_column}') can't be nil.
|
|
107
|
+
Are you missing a default value or validation on '#{locking_column}'?
|
|
108
|
+
MSG
|
|
109
|
+
end
|
|
110
|
+
|
|
104
111
|
self[locking_column] += 1
|
|
105
112
|
|
|
106
113
|
affected_rows = self.class._update_record(
|
|
@@ -67,6 +67,10 @@ module ActiveRecord
|
|
|
67
67
|
# or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns
|
|
68
68
|
# the locked record.
|
|
69
69
|
def lock!(lock = true)
|
|
70
|
+
if self.class.current_preventing_writes
|
|
71
|
+
raise ActiveRecord::ReadOnlyError, "Lock query attempted while in readonly mode"
|
|
72
|
+
end
|
|
73
|
+
|
|
70
74
|
if persisted?
|
|
71
75
|
if has_changes_to_save?
|
|
72
76
|
raise(<<-MSG.squish)
|
|
@@ -79,6 +83,7 @@ module ActiveRecord
|
|
|
79
83
|
|
|
80
84
|
reload(lock: lock)
|
|
81
85
|
end
|
|
86
|
+
|
|
82
87
|
self
|
|
83
88
|
end
|
|
84
89
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module ActiveRecord
|
|
4
|
-
class LogSubscriber < ActiveSupport::LogSubscriber
|
|
4
|
+
class LogSubscriber < ActiveSupport::LogSubscriber # :nodoc:
|
|
5
5
|
IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"]
|
|
6
6
|
|
|
7
7
|
class_attribute :backtrace_cleaner, default: ActiveSupport::BacktraceCleaner.new
|
|
@@ -126,18 +126,8 @@ module ActiveRecord
|
|
|
126
126
|
end
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
Thread.each_caller_location do |location|
|
|
132
|
-
frame = backtrace_cleaner.clean_frame(location)
|
|
133
|
-
return frame if frame
|
|
134
|
-
end
|
|
135
|
-
nil
|
|
136
|
-
end
|
|
137
|
-
else
|
|
138
|
-
def query_source_location
|
|
139
|
-
backtrace_cleaner.clean(caller(1).lazy).first
|
|
140
|
-
end
|
|
129
|
+
def query_source_location
|
|
130
|
+
backtrace_cleaner.first_clean_frame
|
|
141
131
|
end
|
|
142
132
|
|
|
143
133
|
def filter(name, value)
|
|
@@ -9,25 +9,40 @@ module ActiveRecord
|
|
|
9
9
|
# shard to switch to and allows for applications to write custom strategies
|
|
10
10
|
# for swapping if needed.
|
|
11
11
|
#
|
|
12
|
-
#
|
|
13
|
-
# that can be used by the middleware to alter behavior. +lock+ is
|
|
14
|
-
# true by default and will prohibit the request from switching shards once
|
|
15
|
-
# inside the block. If +lock+ is false, then shard swapping will be allowed.
|
|
16
|
-
# For tenant based sharding, +lock+ should always be true to prevent application
|
|
17
|
-
# code from mistakenly switching between tenants.
|
|
12
|
+
# == Setup
|
|
18
13
|
#
|
|
19
|
-
#
|
|
14
|
+
# Applications must provide a resolver that will provide application-specific logic for
|
|
15
|
+
# selecting the appropriate shard. Setting +config.active_record.shard_resolver+ will cause
|
|
16
|
+
# Rails to add ShardSelector to the default middleware stack.
|
|
20
17
|
#
|
|
21
|
-
#
|
|
18
|
+
# The resolver, along with any configuration options, can be set in the application
|
|
19
|
+
# configuration using an initializer like so:
|
|
22
20
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
21
|
+
# Rails.application.configure do
|
|
22
|
+
# config.active_record.shard_selector = { lock: false, class_name: "AnimalsRecord" }
|
|
23
|
+
# config.active_record.shard_resolver = ->(request) {
|
|
24
|
+
# subdomain = request.subdomain
|
|
25
|
+
# tenant = Tenant.find_by_subdomain!(subdomain)
|
|
26
|
+
# tenant.shard
|
|
27
|
+
# }
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# == Configuration
|
|
31
|
+
#
|
|
32
|
+
# The behavior of ShardSelector can be altered through some configuration options.
|
|
33
|
+
#
|
|
34
|
+
# [+lock:+]
|
|
35
|
+
# +lock+ is true by default and will prohibit the request from switching shards once inside
|
|
36
|
+
# the block. If +lock+ is false, then shard switching will be allowed. For tenant based
|
|
37
|
+
# sharding, +lock+ should always be true to prevent application code from mistakenly switching
|
|
38
|
+
# between tenants.
|
|
39
|
+
#
|
|
40
|
+
# [+class_name:+]
|
|
41
|
+
# +class_name+ is the name of the abstract connection class to switch. By
|
|
42
|
+
# default, the ShardSelector will use ActiveRecord::Base, but if the
|
|
43
|
+
# application has multiple databases, then this option should be set to
|
|
44
|
+
# the name of the sharded database's abstract connection class.
|
|
25
45
|
#
|
|
26
|
-
# config.active_record.shard_resolver = ->(request) {
|
|
27
|
-
# subdomain = request.subdomain
|
|
28
|
-
# tenant = Tenant.find_by_subdomain!(subdomain)
|
|
29
|
-
# tenant.shard
|
|
30
|
-
# }
|
|
31
46
|
class ShardSelector
|
|
32
47
|
def initialize(app, resolver, options = {})
|
|
33
48
|
@app = app
|
|
@@ -53,8 +68,10 @@ module ActiveRecord
|
|
|
53
68
|
end
|
|
54
69
|
|
|
55
70
|
def set_shard(shard, &block)
|
|
56
|
-
ActiveRecord::Base
|
|
57
|
-
|
|
71
|
+
klass = options[:class_name]&.constantize || ActiveRecord::Base
|
|
72
|
+
|
|
73
|
+
klass.connected_to(shard: shard.to_sym) do
|
|
74
|
+
klass.prohibit_shard_swapping(options.fetch(:lock, true), &block)
|
|
58
75
|
end
|
|
59
76
|
end
|
|
60
77
|
end
|
|
@@ -22,10 +22,12 @@ module ActiveRecord
|
|
|
22
22
|
# * change_table_comment (must supply a +:from+ and +:to+ option)
|
|
23
23
|
# * create_enum
|
|
24
24
|
# * create_join_table
|
|
25
|
+
# * create_virtual_table
|
|
25
26
|
# * create_table
|
|
26
27
|
# * disable_extension
|
|
27
28
|
# * drop_enum (must supply a list of values)
|
|
28
29
|
# * drop_join_table
|
|
30
|
+
# * drop_virtual_table (must supply options)
|
|
29
31
|
# * drop_table (must supply a block)
|
|
30
32
|
# * enable_extension
|
|
31
33
|
# * remove_column (must supply a type)
|
|
@@ -38,10 +40,12 @@ module ActiveRecord
|
|
|
38
40
|
# * remove_reference
|
|
39
41
|
# * remove_timestamps
|
|
40
42
|
# * rename_column
|
|
41
|
-
# * rename_enum
|
|
43
|
+
# * rename_enum
|
|
42
44
|
# * rename_enum_value (must supply a +:from+ and +:to+ option)
|
|
43
45
|
# * rename_index
|
|
44
46
|
# * rename_table
|
|
47
|
+
# * enable_index
|
|
48
|
+
# * disable_index
|
|
45
49
|
class CommandRecorder
|
|
46
50
|
ReversibleAndIrreversibleMethods = [
|
|
47
51
|
:create_table, :create_join_table, :rename_table, :add_column, :remove_column,
|
|
@@ -55,6 +59,9 @@ module ActiveRecord
|
|
|
55
59
|
:add_exclusion_constraint, :remove_exclusion_constraint,
|
|
56
60
|
:add_unique_constraint, :remove_unique_constraint,
|
|
57
61
|
:create_enum, :drop_enum, :rename_enum, :add_enum_value, :rename_enum_value,
|
|
62
|
+
:create_schema, :drop_schema,
|
|
63
|
+
:create_virtual_table, :drop_virtual_table,
|
|
64
|
+
:enable_index, :disable_index
|
|
58
65
|
]
|
|
59
66
|
include JoinTable
|
|
60
67
|
|
|
@@ -135,7 +142,7 @@ module ActiveRecord
|
|
|
135
142
|
recorder.reverting = @reverting
|
|
136
143
|
yield recorder.delegate.update_table_definition(table_name, recorder)
|
|
137
144
|
commands = recorder.commands
|
|
138
|
-
@commands << [:change_table, [table_name], -> t { bulk_change_table(
|
|
145
|
+
@commands << [:change_table, [table_name], -> t { bulk_change_table(t.name, commands.reverse) }]
|
|
139
146
|
else
|
|
140
147
|
yield delegate.update_table_definition(table_name, self)
|
|
141
148
|
end
|
|
@@ -163,7 +170,9 @@ module ActiveRecord
|
|
|
163
170
|
add_exclusion_constraint: :remove_exclusion_constraint,
|
|
164
171
|
add_unique_constraint: :remove_unique_constraint,
|
|
165
172
|
enable_extension: :disable_extension,
|
|
166
|
-
create_enum: :drop_enum
|
|
173
|
+
create_enum: :drop_enum,
|
|
174
|
+
create_schema: :drop_schema,
|
|
175
|
+
create_virtual_table: :drop_virtual_table
|
|
167
176
|
}.each do |cmd, inv|
|
|
168
177
|
[[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
|
|
169
178
|
class_eval <<-EOV, __FILE__, __LINE__ + 1
|
|
@@ -177,6 +186,16 @@ module ActiveRecord
|
|
|
177
186
|
|
|
178
187
|
include StraightReversions
|
|
179
188
|
|
|
189
|
+
def invert_enable_index(args)
|
|
190
|
+
table_name, index_name = args
|
|
191
|
+
[:disable_index, [table_name, index_name]]
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def invert_disable_index(args)
|
|
195
|
+
table_name, index_name = args
|
|
196
|
+
[:enable_index, [table_name, index_name]]
|
|
197
|
+
end
|
|
198
|
+
|
|
180
199
|
def invert_transaction(args, &block)
|
|
181
200
|
sub_recorder = CommandRecorder.new(delegate)
|
|
182
201
|
sub_recorder.revert(&block)
|
|
@@ -196,13 +215,20 @@ module ActiveRecord
|
|
|
196
215
|
end
|
|
197
216
|
|
|
198
217
|
def invert_drop_table(args, &block)
|
|
199
|
-
|
|
200
|
-
|
|
218
|
+
options = args.extract_options!
|
|
219
|
+
options.delete(:if_exists)
|
|
220
|
+
|
|
221
|
+
if args.size > 1
|
|
222
|
+
raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given a single table name."
|
|
201
223
|
end
|
|
202
|
-
|
|
224
|
+
|
|
225
|
+
if args.size == 1 && options == {} && block == nil
|
|
203
226
|
raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
|
|
204
227
|
end
|
|
205
|
-
|
|
228
|
+
|
|
229
|
+
args << options unless options.empty?
|
|
230
|
+
|
|
231
|
+
super(args, &block)
|
|
206
232
|
end
|
|
207
233
|
|
|
208
234
|
def invert_rename_table(args)
|
|
@@ -353,13 +379,13 @@ module ActiveRecord
|
|
|
353
379
|
end
|
|
354
380
|
|
|
355
381
|
def invert_rename_enum(args)
|
|
356
|
-
name,
|
|
382
|
+
name, new_name, = args
|
|
357
383
|
|
|
358
|
-
|
|
359
|
-
|
|
384
|
+
if new_name.is_a?(Hash) && new_name.key?(:to)
|
|
385
|
+
new_name = new_name[:to]
|
|
360
386
|
end
|
|
361
387
|
|
|
362
|
-
[:rename_enum, [
|
|
388
|
+
[:rename_enum, [new_name, name]]
|
|
363
389
|
end
|
|
364
390
|
|
|
365
391
|
def invert_rename_enum_value(args)
|
|
@@ -369,7 +395,14 @@ module ActiveRecord
|
|
|
369
395
|
raise ActiveRecord::IrreversibleMigration, "rename_enum_value is only reversible if given a :from and :to option."
|
|
370
396
|
end
|
|
371
397
|
|
|
372
|
-
[:
|
|
398
|
+
options[:to], options[:from] = options[:from], options[:to]
|
|
399
|
+
[:rename_enum_value, [type_name, options]]
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
def invert_drop_virtual_table(args)
|
|
403
|
+
_enum, values = args.dup.tap(&:extract_options!)
|
|
404
|
+
raise ActiveRecord::IrreversibleMigration, "drop_virtual_table is only reversible if given options." unless values
|
|
405
|
+
super
|
|
373
406
|
end
|
|
374
407
|
|
|
375
408
|
def respond_to_missing?(method, _)
|
|
@@ -21,7 +21,7 @@ module ActiveRecord
|
|
|
21
21
|
# New migration functionality that will never be backward compatible should be added directly to `ActiveRecord::Migration`.
|
|
22
22
|
#
|
|
23
23
|
# There are classes for each prior Rails version. Each class descends from the *next* Rails version, so:
|
|
24
|
-
# 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2
|
|
24
|
+
# 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2 < 8.0 < 8.1
|
|
25
25
|
#
|
|
26
26
|
# If you are introducing new migration functionality that should only apply from Rails 7 onward, then you should
|
|
27
27
|
# find the class that immediately precedes it (6.1), and override the relevant migration methods to undo your changes.
|
|
@@ -29,7 +29,34 @@ module ActiveRecord
|
|
|
29
29
|
# For example, Rails 6 added a default value for the `precision` option on datetime columns. So in this file, the `V5_2`
|
|
30
30
|
# class sets the value of `precision` to `nil` if it's not explicitly provided. This way, the default value will not apply
|
|
31
31
|
# for migrations written for 5.2, but will for migrations written for 6.0.
|
|
32
|
-
|
|
32
|
+
V8_1 = Current
|
|
33
|
+
|
|
34
|
+
class V8_0 < V8_1
|
|
35
|
+
module RemoveForeignKeyColumnMatch
|
|
36
|
+
def remove_foreign_key(*args, **options)
|
|
37
|
+
options[:_skip_column_match] = true
|
|
38
|
+
super
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
module TableDefinition
|
|
43
|
+
def remove_foreign_key(to_table = nil, **options)
|
|
44
|
+
options[:_skip_column_match] = true
|
|
45
|
+
super
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
include RemoveForeignKeyColumnMatch
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
def compatible_table_definition(t)
|
|
53
|
+
t.singleton_class.prepend(TableDefinition)
|
|
54
|
+
super
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
class V7_2 < V8_0
|
|
59
|
+
end
|
|
33
60
|
|
|
34
61
|
class V7_1 < V7_2
|
|
35
62
|
end
|
|
@@ -151,9 +178,7 @@ module ActiveRecord
|
|
|
151
178
|
|
|
152
179
|
private
|
|
153
180
|
def compatible_table_definition(t)
|
|
154
|
-
|
|
155
|
-
prepend TableDefinition
|
|
156
|
-
end
|
|
181
|
+
t.singleton_class.prepend(TableDefinition)
|
|
157
182
|
super
|
|
158
183
|
end
|
|
159
184
|
end
|
|
@@ -214,9 +239,7 @@ module ActiveRecord
|
|
|
214
239
|
|
|
215
240
|
private
|
|
216
241
|
def compatible_table_definition(t)
|
|
217
|
-
|
|
218
|
-
prepend TableDefinition
|
|
219
|
-
end
|
|
242
|
+
t.singleton_class.prepend(TableDefinition)
|
|
220
243
|
super
|
|
221
244
|
end
|
|
222
245
|
end
|
|
@@ -257,9 +280,7 @@ module ActiveRecord
|
|
|
257
280
|
|
|
258
281
|
private
|
|
259
282
|
def compatible_table_definition(t)
|
|
260
|
-
|
|
261
|
-
prepend TableDefinition
|
|
262
|
-
end
|
|
283
|
+
t.singleton_class.prepend(TableDefinition)
|
|
263
284
|
super
|
|
264
285
|
end
|
|
265
286
|
end
|
|
@@ -305,17 +326,13 @@ module ActiveRecord
|
|
|
305
326
|
|
|
306
327
|
private
|
|
307
328
|
def compatible_table_definition(t)
|
|
308
|
-
|
|
309
|
-
prepend TableDefinition
|
|
310
|
-
end
|
|
329
|
+
t.singleton_class.prepend(TableDefinition)
|
|
311
330
|
super
|
|
312
331
|
end
|
|
313
332
|
|
|
314
333
|
def command_recorder
|
|
315
334
|
recorder = super
|
|
316
|
-
|
|
317
|
-
prepend CommandRecorder
|
|
318
|
-
end
|
|
335
|
+
recorder.singleton_class.prepend(CommandRecorder)
|
|
319
336
|
recorder
|
|
320
337
|
end
|
|
321
338
|
end
|
|
@@ -403,9 +420,7 @@ module ActiveRecord
|
|
|
403
420
|
|
|
404
421
|
private
|
|
405
422
|
def compatible_table_definition(t)
|
|
406
|
-
|
|
407
|
-
prepend TableDefinition
|
|
408
|
-
end
|
|
423
|
+
t.singleton_class.prepend(TableDefinition)
|
|
409
424
|
super
|
|
410
425
|
end
|
|
411
426
|
end
|
|
@@ -439,7 +454,7 @@ module ActiveRecord
|
|
|
439
454
|
super
|
|
440
455
|
end
|
|
441
456
|
|
|
442
|
-
def index_exists?(table_name, column_name, **options)
|
|
457
|
+
def index_exists?(table_name, column_name = nil, **options)
|
|
443
458
|
column_names = Array(column_name).map(&:to_s)
|
|
444
459
|
options[:name] =
|
|
445
460
|
if options[:name].present?
|
|
@@ -457,9 +472,7 @@ module ActiveRecord
|
|
|
457
472
|
|
|
458
473
|
private
|
|
459
474
|
def compatible_table_definition(t)
|
|
460
|
-
|
|
461
|
-
prepend TableDefinition
|
|
462
|
-
end
|
|
475
|
+
t.singleton_class.prepend(TableDefinition)
|
|
463
476
|
super
|
|
464
477
|
end
|
|
465
478
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
class Migration
|
|
5
|
+
# This class is used by the schema dumper to format versions information.
|
|
6
|
+
#
|
|
7
|
+
# The class receives the current +connection+ when initialized.
|
|
8
|
+
class DefaultSchemaVersionsFormatter # :nodoc:
|
|
9
|
+
def initialize(connection)
|
|
10
|
+
@connection = connection
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def format(versions)
|
|
14
|
+
sm_table = connection.quote_table_name(connection.pool.schema_migration.table_name)
|
|
15
|
+
|
|
16
|
+
if versions.is_a?(Array)
|
|
17
|
+
sql = +"INSERT INTO #{sm_table} (version) VALUES\n"
|
|
18
|
+
sql << versions.reverse.map { |v| "(#{connection.quote(v)})" }.join(",\n")
|
|
19
|
+
sql << ";"
|
|
20
|
+
sql
|
|
21
|
+
else
|
|
22
|
+
"INSERT INTO #{sm_table} (version) VALUES (#{connection.quote(versions)});"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
attr_reader :connection
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|