activerecord 7.2.2.1 → 8.1.2
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 +564 -753
- data/README.rdoc +2 -2
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/association.rb +35 -11
- data/lib/active_record/associations/belongs_to_association.rb +18 -2
- 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 +10 -8
- 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/join_association.rb +25 -27
- 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 +17 -4
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
- data/lib/active_record/attribute_methods.rb +24 -19
- data/lib/active_record/attributes.rb +40 -26
- data/lib/active_record/autosave_association.rb +91 -39
- data/lib/active_record/base.rb +3 -4
- 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 +458 -117
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +136 -74
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +44 -11
- 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 +37 -36
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -29
- data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
- data/lib/active_record/connection_adapters/abstract_adapter.rb +175 -87
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +77 -58
- 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 +7 -9
- 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 +10 -11
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
- 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 +28 -45
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +140 -64
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -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 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +112 -42
- 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 +2 -19
- data/lib/active_record/connection_adapters.rb +1 -56
- data/lib/active_record/connection_handling.rb +37 -10
- data/lib/active_record/core.rb +61 -25
- data/lib/active_record/counter_cache.rb +34 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- 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 +19 -19
- 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 +9 -9
- data/lib/active_record/encryption/encrypted_attribute_type.rb +12 -3
- data/lib/active_record/encryption/encryptor.rb +49 -28
- 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 +46 -42
- data/lib/active_record/errors.rb +36 -12
- 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/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +2 -4
- data/lib/active_record/future_result.rb +13 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +1 -1
- data/lib/active_record/insert_all.rb +12 -7
- 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 +44 -11
- 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 +50 -43
- 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 +104 -52
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +12 -12
- data/lib/active_record/railtie.rb +37 -32
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +26 -37
- 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 +80 -63
- data/lib/active_record/relation/delegation.rb +25 -15
- data/lib/active_record/relation/finder_methods.rb +54 -37
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -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 +4 -2
- data/lib/active_record/relation/query_methods.rb +156 -95
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +10 -11
- data/lib/active_record/relation.rb +122 -80
- 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 +47 -22
- 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/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +47 -18
- 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 +14 -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 +39 -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 +15 -2
- data/lib/active_record/type/serialized.rb +11 -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 +85 -50
- 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 +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/delete_statement.rb +4 -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/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/select_manager.rb +13 -4
- data/lib/arel/table.rb +3 -7
- data/lib/arel/update_manager.rb +5 -0
- data/lib/arel/visitors/dot.rb +2 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +6 -22
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +17 -17
- 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
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
module ActiveRecord
|
|
5
4
|
module ConnectionAdapters # :nodoc:
|
|
6
5
|
# Abstract representation of an index definition on a table. Instances of
|
|
@@ -76,7 +75,7 @@ module ActiveRecord
|
|
|
76
75
|
# are typically created by methods in TableDefinition, and added to the
|
|
77
76
|
# +columns+ attribute of said TableDefinition object, in order to be used
|
|
78
77
|
# for generating a number of table creation or table changing SQL statements.
|
|
79
|
-
ColumnDefinition = Struct.new(:name, :type, :options, :sql_type) do # :nodoc:
|
|
78
|
+
ColumnDefinition = Struct.new(:name, :type, :options, :sql_type, :cast_type) do # :nodoc:
|
|
80
79
|
self::OPTION_NAMES = [
|
|
81
80
|
:limit,
|
|
82
81
|
:precision,
|
|
@@ -109,6 +108,10 @@ module ActiveRecord
|
|
|
109
108
|
def aliased_types(name, fallback)
|
|
110
109
|
"timestamp" == name ? :datetime : fallback
|
|
111
110
|
end
|
|
111
|
+
|
|
112
|
+
def fetch_cast_type(connection)
|
|
113
|
+
cast_type
|
|
114
|
+
end
|
|
112
115
|
end
|
|
113
116
|
|
|
114
117
|
AddColumnDefinition = Struct.new(:column) # :nodoc:
|
|
@@ -160,6 +163,8 @@ module ActiveRecord
|
|
|
160
163
|
end
|
|
161
164
|
|
|
162
165
|
def defined_for?(to_table: nil, validate: nil, **options)
|
|
166
|
+
options = options.slice(*self.options.keys)
|
|
167
|
+
|
|
163
168
|
(to_table.nil? || to_table.to_s == self.to_table) &&
|
|
164
169
|
(validate.nil? || validate == self.options.fetch(:validate, validate)) &&
|
|
165
170
|
options.all? { |k, v| Array(self.options[k]).map(&:to_s) == Array(v).map(&:to_s) }
|
|
@@ -186,6 +191,8 @@ module ActiveRecord
|
|
|
186
191
|
end
|
|
187
192
|
|
|
188
193
|
def defined_for?(name:, expression: nil, validate: nil, **options)
|
|
194
|
+
options = options.slice(*self.options.keys)
|
|
195
|
+
|
|
189
196
|
self.name == name.to_s &&
|
|
190
197
|
(validate.nil? || validate == self.options.fetch(:validate, validate)) &&
|
|
191
198
|
options.all? { |k, v| self.options[k].to_s == v.to_s }
|
|
@@ -300,44 +307,32 @@ module ActiveRecord
|
|
|
300
307
|
module ColumnMethods
|
|
301
308
|
extend ActiveSupport::Concern
|
|
302
309
|
|
|
303
|
-
# Appends a primary key definition to the table definition.
|
|
304
|
-
# Can be called multiple times, but this is probably not a good idea.
|
|
305
|
-
def primary_key(name, type = :primary_key, **options)
|
|
306
|
-
column(name, type, **options.merge(primary_key: true))
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
##
|
|
310
|
-
# :method: column
|
|
311
|
-
# :call-seq: column(name, type, **options)
|
|
312
|
-
#
|
|
313
|
-
# Appends a column or columns of a specified type.
|
|
314
|
-
#
|
|
315
|
-
# t.string(:goat)
|
|
316
|
-
# t.string(:goat, :sheep)
|
|
317
|
-
#
|
|
318
|
-
# See TableDefinition#column
|
|
319
|
-
|
|
320
|
-
included do
|
|
321
|
-
define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
|
|
322
|
-
:float, :integer, :json, :string, :text, :time, :timestamp, :virtual
|
|
323
|
-
|
|
324
|
-
alias :blob :binary
|
|
325
|
-
alias :numeric :decimal
|
|
326
|
-
end
|
|
327
|
-
|
|
328
310
|
class_methods do
|
|
329
|
-
|
|
330
|
-
column_types
|
|
331
|
-
|
|
311
|
+
private
|
|
312
|
+
def define_column_methods(*column_types) # :nodoc:
|
|
313
|
+
column_types.each do |column_type|
|
|
314
|
+
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
332
315
|
def #{column_type}(*names, **options)
|
|
333
316
|
raise ArgumentError, "Missing column name(s) for #{column_type}" if names.empty?
|
|
334
317
|
names.each { |name| column(name, :#{column_type}, **options) }
|
|
335
318
|
end
|
|
336
|
-
|
|
319
|
+
RUBY
|
|
320
|
+
end
|
|
337
321
|
end
|
|
338
|
-
end
|
|
339
|
-
private :define_column_methods
|
|
340
322
|
end
|
|
323
|
+
extend ClassMethods
|
|
324
|
+
|
|
325
|
+
# Appends a primary key definition to the table definition.
|
|
326
|
+
# Can be called multiple times, but this is probably not a good idea.
|
|
327
|
+
def primary_key(name, type = :primary_key, **options)
|
|
328
|
+
column(name, type, **options, primary_key: true)
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
|
|
332
|
+
:float, :integer, :json, :string, :text, :time, :timestamp, :virtual
|
|
333
|
+
|
|
334
|
+
alias :blob :binary
|
|
335
|
+
alias :numeric :decimal
|
|
341
336
|
end
|
|
342
337
|
|
|
343
338
|
# = Active Record Connection Adapters \Table \Definition
|
|
@@ -348,7 +343,7 @@ module ActiveRecord
|
|
|
348
343
|
# Inside migration files, the +t+ object in {create_table}[rdoc-ref:SchemaStatements#create_table]
|
|
349
344
|
# is actually of this type:
|
|
350
345
|
#
|
|
351
|
-
# class SomeMigration < ActiveRecord::Migration[
|
|
346
|
+
# class SomeMigration < ActiveRecord::Migration[8.1]
|
|
352
347
|
# def up
|
|
353
348
|
# create_table :foo do |t|
|
|
354
349
|
# puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
|
|
@@ -431,7 +426,7 @@ module ActiveRecord
|
|
|
431
426
|
#
|
|
432
427
|
# == Examples
|
|
433
428
|
#
|
|
434
|
-
# # Assuming
|
|
429
|
+
# # Assuming `td` is an instance of TableDefinition
|
|
435
430
|
# td.column(:granted, :boolean, index: true)
|
|
436
431
|
#
|
|
437
432
|
# == Short-hand examples
|
|
@@ -622,6 +617,7 @@ module ActiveRecord
|
|
|
622
617
|
attr_reader :adds
|
|
623
618
|
attr_reader :foreign_key_adds, :foreign_key_drops
|
|
624
619
|
attr_reader :check_constraint_adds, :check_constraint_drops
|
|
620
|
+
attr_reader :constraint_drops
|
|
625
621
|
|
|
626
622
|
def initialize(td)
|
|
627
623
|
@td = td
|
|
@@ -630,6 +626,7 @@ module ActiveRecord
|
|
|
630
626
|
@foreign_key_drops = []
|
|
631
627
|
@check_constraint_adds = []
|
|
632
628
|
@check_constraint_drops = []
|
|
629
|
+
@constraint_drops = []
|
|
633
630
|
end
|
|
634
631
|
|
|
635
632
|
def name; @td.name; end
|
|
@@ -650,6 +647,10 @@ module ActiveRecord
|
|
|
650
647
|
@check_constraint_drops << constraint_name
|
|
651
648
|
end
|
|
652
649
|
|
|
650
|
+
def drop_constraint(constraint_name)
|
|
651
|
+
@constraint_drops << constraint_name
|
|
652
|
+
end
|
|
653
|
+
|
|
653
654
|
def add_column(name, type, **options)
|
|
654
655
|
name = name.to_s
|
|
655
656
|
type = type.to_sym
|
|
@@ -756,7 +757,7 @@ module ActiveRecord
|
|
|
756
757
|
# end
|
|
757
758
|
#
|
|
758
759
|
# See {connection.index_exists?}[rdoc-ref:SchemaStatements#index_exists?]
|
|
759
|
-
def index_exists?(column_name, **options)
|
|
760
|
+
def index_exists?(column_name = nil, **options)
|
|
760
761
|
@base.index_exists?(name, column_name, **options)
|
|
761
762
|
end
|
|
762
763
|
|
|
@@ -85,7 +85,8 @@ module ActiveRecord
|
|
|
85
85
|
|
|
86
86
|
def schema_default(column)
|
|
87
87
|
return unless column.has_default?
|
|
88
|
-
|
|
88
|
+
# TODO: Remove fetch_cast_type and the need for connection after we release 8.1.
|
|
89
|
+
type = column.fetch_cast_type(@connection)
|
|
89
90
|
default = type.deserialize(column.default)
|
|
90
91
|
if default.nil?
|
|
91
92
|
schema_expression(column)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "active_support/core_ext/string/access"
|
|
4
|
+
require "active_support/core_ext/string/filters"
|
|
4
5
|
require "openssl"
|
|
5
6
|
|
|
6
7
|
module ActiveRecord
|
|
@@ -99,7 +100,7 @@ module ActiveRecord
|
|
|
99
100
|
# # Check a valid index exists (PostgreSQL only)
|
|
100
101
|
# index_exists?(:suppliers, :company_id, valid: true)
|
|
101
102
|
#
|
|
102
|
-
def index_exists?(table_name, column_name, **options)
|
|
103
|
+
def index_exists?(table_name, column_name = nil, **options)
|
|
103
104
|
indexes(table_name).any? { |i| i.defined_for?(column_name, **options) }
|
|
104
105
|
end
|
|
105
106
|
|
|
@@ -186,6 +187,9 @@ module ActiveRecord
|
|
|
186
187
|
# Join tables for {ActiveRecord::Base.has_and_belongs_to_many}[rdoc-ref:Associations::ClassMethods#has_and_belongs_to_many] should set it to false.
|
|
187
188
|
#
|
|
188
189
|
# A Symbol can be used to specify the type of the generated primary key column.
|
|
190
|
+
#
|
|
191
|
+
# A Hash can be used to specify the generated primary key column creation options.
|
|
192
|
+
# See {add_column}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_column] for available options.
|
|
189
193
|
# [<tt>:primary_key</tt>]
|
|
190
194
|
# The name of the primary key, if one is to be added automatically.
|
|
191
195
|
# Defaults to +id+. If <tt>:id</tt> is false, then this option is ignored.
|
|
@@ -345,11 +349,22 @@ module ActiveRecord
|
|
|
345
349
|
# # Creates a table called 'assemblies_parts' with no id.
|
|
346
350
|
# create_join_table(:assemblies, :parts)
|
|
347
351
|
#
|
|
352
|
+
# # Creates a table called 'paper_boxes_papers' with no id.
|
|
353
|
+
# create_join_table('papers', 'paper_boxes')
|
|
354
|
+
#
|
|
355
|
+
# A duplicate prefix is combined into a single prefix. This is useful for
|
|
356
|
+
# namespaced models like Music::Artist and Music::Record:
|
|
357
|
+
#
|
|
358
|
+
# # Creates a table called 'music_artists_records' with no id.
|
|
359
|
+
# create_join_table('music_artists', 'music_records')
|
|
360
|
+
#
|
|
361
|
+
# See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference]
|
|
362
|
+
# for details of the options you can use in +column_options+. +column_options+
|
|
363
|
+
# will be applied to both columns.
|
|
364
|
+
#
|
|
348
365
|
# You can pass an +options+ hash which can include the following keys:
|
|
349
366
|
# [<tt>:table_name</tt>]
|
|
350
367
|
# Sets the table name, overriding the default.
|
|
351
|
-
# [<tt>:column_options</tt>]
|
|
352
|
-
# Any extra options you want appended to the columns definition.
|
|
353
368
|
# [<tt>:options</tt>]
|
|
354
369
|
# Any extra options you want appended to the table definition.
|
|
355
370
|
# [<tt>:temporary</tt>]
|
|
@@ -366,6 +381,19 @@ module ActiveRecord
|
|
|
366
381
|
# t.index :category_id
|
|
367
382
|
# end
|
|
368
383
|
#
|
|
384
|
+
# ====== Add foreign keys with delete cascade
|
|
385
|
+
#
|
|
386
|
+
# create_join_table(:assemblies, :parts, column_options: { foreign_key: { on_delete: :cascade } })
|
|
387
|
+
#
|
|
388
|
+
# generates:
|
|
389
|
+
#
|
|
390
|
+
# CREATE TABLE assemblies_parts (
|
|
391
|
+
# assembly_id bigint NOT NULL,
|
|
392
|
+
# part_id bigint NOT NULL,
|
|
393
|
+
# CONSTRAINT fk_rails_0d8a572d89 FOREIGN KEY ("assembly_id") REFERENCES "assemblies" ("id") ON DELETE CASCADE,
|
|
394
|
+
# CONSTRAINT fk_rails_ec7b48402b FOREIGN KEY ("part_id") REFERENCES "parts" ("id") ON DELETE CASCADE
|
|
395
|
+
# )
|
|
396
|
+
#
|
|
369
397
|
# ====== Add a backend specific option to the generated SQL (MySQL)
|
|
370
398
|
#
|
|
371
399
|
# create_join_table(:assemblies, :parts, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
|
|
@@ -516,7 +544,7 @@ module ActiveRecord
|
|
|
516
544
|
raise NotImplementedError, "rename_table is not implemented"
|
|
517
545
|
end
|
|
518
546
|
|
|
519
|
-
# Drops a table from the database.
|
|
547
|
+
# Drops a table or tables from the database.
|
|
520
548
|
#
|
|
521
549
|
# [<tt>:force</tt>]
|
|
522
550
|
# Set to +:cascade+ to drop dependent objects as well.
|
|
@@ -527,17 +555,19 @@ module ActiveRecord
|
|
|
527
555
|
#
|
|
528
556
|
# Although this command ignores most +options+ and the block if one is given,
|
|
529
557
|
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
|
530
|
-
# In that case, +options+ and the block will be used by #create_table.
|
|
531
|
-
def drop_table(
|
|
532
|
-
|
|
533
|
-
|
|
558
|
+
# In that case, +options+ and the block will be used by #create_table except if you provide more than one table which is not supported.
|
|
559
|
+
def drop_table(*table_names, **options)
|
|
560
|
+
table_names.each do |table_name|
|
|
561
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
|
562
|
+
execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}"
|
|
563
|
+
end
|
|
534
564
|
end
|
|
535
565
|
|
|
536
566
|
# Add a new +type+ column named +column_name+ to +table_name+.
|
|
537
567
|
#
|
|
538
568
|
# See {ActiveRecord::ConnectionAdapters::TableDefinition.column}[rdoc-ref:ActiveRecord::ConnectionAdapters::TableDefinition#column].
|
|
539
569
|
#
|
|
540
|
-
# The +type+ parameter is normally one of the
|
|
570
|
+
# The +type+ parameter is normally one of the migration's native types,
|
|
541
571
|
# which is one of the following:
|
|
542
572
|
# <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
|
|
543
573
|
# <tt>:integer</tt>, <tt>:bigint</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:numeric</tt>,
|
|
@@ -844,6 +874,16 @@ module ActiveRecord
|
|
|
844
874
|
#
|
|
845
875
|
# Note: only supported by PostgreSQL.
|
|
846
876
|
#
|
|
877
|
+
# ====== Creating an index where NULLs are treated equally
|
|
878
|
+
#
|
|
879
|
+
# add_index(:people, :last_name, nulls_not_distinct: true)
|
|
880
|
+
#
|
|
881
|
+
# generates:
|
|
882
|
+
#
|
|
883
|
+
# CREATE INDEX index_people_on_last_name ON people (last_name) NULLS NOT DISTINCT
|
|
884
|
+
#
|
|
885
|
+
# Note: only supported by PostgreSQL version 15.0.0 and greater.
|
|
886
|
+
#
|
|
847
887
|
# ====== Creating an index with a specific method
|
|
848
888
|
#
|
|
849
889
|
# add_index(:developers, :name, using: 'btree')
|
|
@@ -891,6 +931,19 @@ module ActiveRecord
|
|
|
891
931
|
# Concurrently adding an index is not supported in a transaction.
|
|
892
932
|
#
|
|
893
933
|
# For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
|
|
934
|
+
#
|
|
935
|
+
# ====== Creating an index that is not used by queries
|
|
936
|
+
#
|
|
937
|
+
# add_index(:developers, :name, enabled: false)
|
|
938
|
+
#
|
|
939
|
+
# generates:
|
|
940
|
+
#
|
|
941
|
+
# CREATE INDEX index_developers_on_name ON developers (name) INVISIBLE -- MySQL
|
|
942
|
+
#
|
|
943
|
+
# CREATE INDEX index_developers_on_name ON developers (name) IGNORED -- MariaDB
|
|
944
|
+
#
|
|
945
|
+
# Note: only supported by MySQL version 8.0.0 and greater, and MariaDB version 10.6.0 and greater.
|
|
946
|
+
#
|
|
894
947
|
def add_index(table_name, column_name, **options)
|
|
895
948
|
create_index = build_create_index_definition(table_name, column_name, **options)
|
|
896
949
|
execute schema_creation.accept(create_index)
|
|
@@ -1151,9 +1204,10 @@ module ActiveRecord
|
|
|
1151
1204
|
# +:deferred+ or +:immediate+ to specify the default behavior. Defaults to +false+.
|
|
1152
1205
|
def add_foreign_key(from_table, to_table, **options)
|
|
1153
1206
|
return unless use_foreign_keys?
|
|
1154
|
-
return if options[:if_not_exists] == true && foreign_key_exists?(from_table, to_table, **options.slice(:column))
|
|
1155
1207
|
|
|
1156
1208
|
options = foreign_key_options(from_table, to_table, options)
|
|
1209
|
+
return if options[:if_not_exists] == true && foreign_key_exists?(from_table, to_table, **options.slice(:column, :primary_key))
|
|
1210
|
+
|
|
1157
1211
|
at = create_alter_table from_table
|
|
1158
1212
|
at.add_foreign_key to_table, options
|
|
1159
1213
|
|
|
@@ -1192,7 +1246,7 @@ module ActiveRecord
|
|
|
1192
1246
|
# The name of the table that contains the referenced primary key.
|
|
1193
1247
|
def remove_foreign_key(from_table, to_table = nil, **options)
|
|
1194
1248
|
return unless use_foreign_keys?
|
|
1195
|
-
return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table)
|
|
1249
|
+
return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table, **options.slice(:column))
|
|
1196
1250
|
|
|
1197
1251
|
fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
|
|
1198
1252
|
|
|
@@ -1313,7 +1367,6 @@ module ActiveRecord
|
|
|
1313
1367
|
execute schema_creation.accept(at)
|
|
1314
1368
|
end
|
|
1315
1369
|
|
|
1316
|
-
|
|
1317
1370
|
# Checks to see if a check constraint exists on a table for a given check constraint definition.
|
|
1318
1371
|
#
|
|
1319
1372
|
# check_constraint_exists?(:products, name: "price_check")
|
|
@@ -1325,7 +1378,14 @@ module ActiveRecord
|
|
|
1325
1378
|
check_constraint_for(table_name, **options).present?
|
|
1326
1379
|
end
|
|
1327
1380
|
|
|
1328
|
-
def
|
|
1381
|
+
def remove_constraint(table_name, constraint_name) # :nodoc:
|
|
1382
|
+
at = create_alter_table(table_name)
|
|
1383
|
+
at.drop_constraint(constraint_name)
|
|
1384
|
+
|
|
1385
|
+
execute schema_creation.accept(at)
|
|
1386
|
+
end
|
|
1387
|
+
|
|
1388
|
+
def dump_schema_versions # :nodoc:
|
|
1329
1389
|
versions = pool.schema_migration.versions
|
|
1330
1390
|
insert_versions_sql(versions) if versions.any?
|
|
1331
1391
|
end
|
|
@@ -1447,7 +1507,7 @@ module ActiveRecord
|
|
|
1447
1507
|
end
|
|
1448
1508
|
|
|
1449
1509
|
def add_index_options(table_name, column_name, name: nil, if_not_exists: false, internal: false, **options) # :nodoc:
|
|
1450
|
-
options.assert_valid_keys(
|
|
1510
|
+
options.assert_valid_keys(valid_index_options)
|
|
1451
1511
|
|
|
1452
1512
|
column_names = index_column_names(column_name)
|
|
1453
1513
|
|
|
@@ -1456,7 +1516,7 @@ module ActiveRecord
|
|
|
1456
1516
|
|
|
1457
1517
|
validate_index_length!(table_name, index_name, internal)
|
|
1458
1518
|
|
|
1459
|
-
index =
|
|
1519
|
+
index = create_index_definition(
|
|
1460
1520
|
table_name, index_name,
|
|
1461
1521
|
options[:unique],
|
|
1462
1522
|
column_names,
|
|
@@ -1511,6 +1571,20 @@ module ActiveRecord
|
|
|
1511
1571
|
raise NotImplementedError, "#{self.class} does not support changing column comments"
|
|
1512
1572
|
end
|
|
1513
1573
|
|
|
1574
|
+
# Enables an index to be used by queries.
|
|
1575
|
+
#
|
|
1576
|
+
# enable_index(:users, :email)
|
|
1577
|
+
def enable_index(table_name, index_name)
|
|
1578
|
+
raise NotImplementedError, "#{self.class} does not support enabling indexes"
|
|
1579
|
+
end
|
|
1580
|
+
|
|
1581
|
+
# Prevents an index from being used by queries.
|
|
1582
|
+
#
|
|
1583
|
+
# disable_index(:users, :email)
|
|
1584
|
+
def disable_index(table_name, index_name)
|
|
1585
|
+
raise NotImplementedError, "#{self.class} does not support disabling indexes"
|
|
1586
|
+
end
|
|
1587
|
+
|
|
1514
1588
|
def create_schema_dumper(options) # :nodoc:
|
|
1515
1589
|
SchemaDumper.create(self, options)
|
|
1516
1590
|
end
|
|
@@ -1577,7 +1651,7 @@ module ActiveRecord
|
|
|
1577
1651
|
name = "idx_on_#{Array(column) * '_'}"
|
|
1578
1652
|
|
|
1579
1653
|
short_limit = max_index_name_size - hashed_identifier.bytesize
|
|
1580
|
-
short_name = name.
|
|
1654
|
+
short_name = name.truncate_bytes(short_limit, omission: nil)
|
|
1581
1655
|
|
|
1582
1656
|
"#{short_name}#{hashed_identifier}"
|
|
1583
1657
|
end
|
|
@@ -1599,6 +1673,10 @@ module ActiveRecord
|
|
|
1599
1673
|
end
|
|
1600
1674
|
end
|
|
1601
1675
|
|
|
1676
|
+
def valid_index_options
|
|
1677
|
+
[:unique, :length, :order, :opclass, :where, :type, :using, :comment, :algorithm, :include, :nulls_not_distinct]
|
|
1678
|
+
end
|
|
1679
|
+
|
|
1602
1680
|
def options_for_index_columns(options)
|
|
1603
1681
|
if options.is_a?(Hash)
|
|
1604
1682
|
options.symbolize_keys
|
|
@@ -1675,6 +1753,10 @@ module ActiveRecord
|
|
|
1675
1753
|
TableDefinition.new(self, name, **options)
|
|
1676
1754
|
end
|
|
1677
1755
|
|
|
1756
|
+
def create_index_definition(table_name, name, unique, columns, **options)
|
|
1757
|
+
IndexDefinition.new(table_name, name, unique, columns, **options)
|
|
1758
|
+
end
|
|
1759
|
+
|
|
1678
1760
|
def create_alter_table(name)
|
|
1679
1761
|
AlterTable.new create_table_definition(name)
|
|
1680
1762
|
end
|
|
@@ -1737,7 +1819,20 @@ module ActiveRecord
|
|
|
1737
1819
|
|
|
1738
1820
|
def foreign_key_for(from_table, **options)
|
|
1739
1821
|
return unless use_foreign_keys?
|
|
1740
|
-
|
|
1822
|
+
|
|
1823
|
+
keys = foreign_keys(from_table)
|
|
1824
|
+
|
|
1825
|
+
if options[:_skip_column_match]
|
|
1826
|
+
return keys.find { |fk| fk.defined_for?(**options) }
|
|
1827
|
+
end
|
|
1828
|
+
|
|
1829
|
+
if options[:column].nil?
|
|
1830
|
+
default_column = foreign_key_column_for(options[:to_table], "id")
|
|
1831
|
+
matches = keys.select { |fk| fk.column == default_column }
|
|
1832
|
+
keys = matches if matches.any?
|
|
1833
|
+
end
|
|
1834
|
+
|
|
1835
|
+
keys.find { |fk| fk.defined_for?(**options) }
|
|
1741
1836
|
end
|
|
1742
1837
|
|
|
1743
1838
|
def foreign_key_for!(from_table, to_table: nil, **options)
|
|
@@ -1780,13 +1875,19 @@ module ActiveRecord
|
|
|
1780
1875
|
|
|
1781
1876
|
def validate_index_length!(table_name, new_name, internal = false)
|
|
1782
1877
|
if new_name.length > index_name_length
|
|
1783
|
-
raise ArgumentError,
|
|
1878
|
+
raise ArgumentError, <<~MSG.squish
|
|
1879
|
+
Index name '#{new_name}' on table '#{table_name}' is too long (#{new_name.length} characters); the limit
|
|
1880
|
+
is #{index_name_length} characters
|
|
1881
|
+
MSG
|
|
1784
1882
|
end
|
|
1785
1883
|
end
|
|
1786
1884
|
|
|
1787
1885
|
def validate_table_length!(table_name)
|
|
1788
1886
|
if table_name.length > table_name_length
|
|
1789
|
-
raise ArgumentError,
|
|
1887
|
+
raise ArgumentError, <<~MSG.squish
|
|
1888
|
+
Table name '#{table_name}' is too long (#{table_name.length} characters); the limit is
|
|
1889
|
+
#{table_name_length} characters
|
|
1890
|
+
MSG
|
|
1790
1891
|
end
|
|
1791
1892
|
end
|
|
1792
1893
|
|
|
@@ -1848,16 +1949,8 @@ module ActiveRecord
|
|
|
1848
1949
|
end
|
|
1849
1950
|
|
|
1850
1951
|
def insert_versions_sql(versions)
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
if versions.is_a?(Array)
|
|
1854
|
-
sql = +"INSERT INTO #{sm_table} (version) VALUES\n"
|
|
1855
|
-
sql << versions.reverse.map { |v| "(#{quote(v)})" }.join(",\n")
|
|
1856
|
-
sql << ";"
|
|
1857
|
-
sql
|
|
1858
|
-
else
|
|
1859
|
-
"INSERT INTO #{sm_table} (version) VALUES (#{quote(versions)});"
|
|
1860
|
-
end
|
|
1952
|
+
versions_formatter = ActiveRecord.schema_versions_formatter.new(self)
|
|
1953
|
+
versions_formatter.format(versions)
|
|
1861
1954
|
end
|
|
1862
1955
|
|
|
1863
1956
|
def data_source_sql(name = nil, type: nil)
|
|
@@ -112,6 +112,7 @@ module ActiveRecord
|
|
|
112
112
|
def closed?; true; end
|
|
113
113
|
def open?; false; end
|
|
114
114
|
def joinable?; false; end
|
|
115
|
+
def isolation; nil; end
|
|
115
116
|
def add_record(record, _ = true); end
|
|
116
117
|
def restartable?; false; end
|
|
117
118
|
def dirty?; false; end
|
|
@@ -123,6 +124,7 @@ module ActiveRecord
|
|
|
123
124
|
def after_commit; yield; end
|
|
124
125
|
def after_rollback; end
|
|
125
126
|
def user_transaction; ActiveRecord::Transaction::NULL_TRANSACTION; end
|
|
127
|
+
def isolation=(_); end
|
|
126
128
|
end
|
|
127
129
|
|
|
128
130
|
class Transaction # :nodoc:
|
|
@@ -150,6 +152,15 @@ module ActiveRecord
|
|
|
150
152
|
|
|
151
153
|
delegate :invalidate!, :invalidated?, to: :@state
|
|
152
154
|
|
|
155
|
+
# Returns the isolation level if it was explicitly set, nil otherwise
|
|
156
|
+
def isolation
|
|
157
|
+
@isolation_level
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def isolation=(isolation) # :nodoc:
|
|
161
|
+
@isolation_level = isolation
|
|
162
|
+
end
|
|
163
|
+
|
|
153
164
|
def initialize(connection, isolation: nil, joinable: true, run_commit_callbacks: false)
|
|
154
165
|
super()
|
|
155
166
|
@connection = connection
|
|
@@ -175,11 +186,11 @@ module ActiveRecord
|
|
|
175
186
|
end
|
|
176
187
|
|
|
177
188
|
def open?
|
|
178
|
-
|
|
189
|
+
!closed?
|
|
179
190
|
end
|
|
180
191
|
|
|
181
192
|
def closed?
|
|
182
|
-
|
|
193
|
+
@state.finalized?
|
|
183
194
|
end
|
|
184
195
|
|
|
185
196
|
def add_record(record, ensure_finalize = true)
|
|
@@ -386,7 +397,7 @@ module ActiveRecord
|
|
|
386
397
|
@parent.state.add_child(@state)
|
|
387
398
|
end
|
|
388
399
|
|
|
389
|
-
delegate :materialize!, :materialized?, :restart, to: :@parent
|
|
400
|
+
delegate :materialize!, :materialized?, :restart, :isolation, to: :@parent
|
|
390
401
|
|
|
391
402
|
def rollback
|
|
392
403
|
@state.rollback!
|
|
@@ -405,6 +416,7 @@ module ActiveRecord
|
|
|
405
416
|
def initialize(connection, savepoint_name, parent_transaction, **options)
|
|
406
417
|
super(connection, **options)
|
|
407
418
|
|
|
419
|
+
@parent_transaction = parent_transaction
|
|
408
420
|
parent_transaction.state.add_child(@state)
|
|
409
421
|
|
|
410
422
|
if isolation_level
|
|
@@ -414,6 +426,15 @@ module ActiveRecord
|
|
|
414
426
|
@savepoint_name = savepoint_name
|
|
415
427
|
end
|
|
416
428
|
|
|
429
|
+
# Delegates to parent transaction's isolation level
|
|
430
|
+
def isolation
|
|
431
|
+
@parent_transaction.isolation
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def isolation=(isolation) # :nodoc:
|
|
435
|
+
@parent_transaction.isolation = isolation
|
|
436
|
+
end
|
|
437
|
+
|
|
417
438
|
def materialize!
|
|
418
439
|
connection.create_savepoint(savepoint_name)
|
|
419
440
|
super
|
|
@@ -448,10 +469,14 @@ module ActiveRecord
|
|
|
448
469
|
# = Active Record Real \Transaction
|
|
449
470
|
class RealTransaction < Transaction
|
|
450
471
|
def materialize!
|
|
451
|
-
if
|
|
452
|
-
|
|
472
|
+
if joinable?
|
|
473
|
+
if isolation_level
|
|
474
|
+
connection.begin_isolated_db_transaction(isolation_level)
|
|
475
|
+
else
|
|
476
|
+
connection.begin_db_transaction
|
|
477
|
+
end
|
|
453
478
|
else
|
|
454
|
-
connection.
|
|
479
|
+
connection.begin_deferred_transaction(isolation_level)
|
|
455
480
|
end
|
|
456
481
|
|
|
457
482
|
super
|
|
@@ -472,13 +497,19 @@ module ActiveRecord
|
|
|
472
497
|
end
|
|
473
498
|
|
|
474
499
|
def rollback
|
|
475
|
-
|
|
500
|
+
if materialized?
|
|
501
|
+
connection.rollback_db_transaction
|
|
502
|
+
connection.reset_isolation_level if isolation_level
|
|
503
|
+
end
|
|
476
504
|
@state.full_rollback!
|
|
477
505
|
@instrumenter.finish(:rollback) if materialized?
|
|
478
506
|
end
|
|
479
507
|
|
|
480
508
|
def commit
|
|
481
|
-
|
|
509
|
+
if materialized?
|
|
510
|
+
connection.commit_db_transaction
|
|
511
|
+
connection.reset_isolation_level if isolation_level
|
|
512
|
+
end
|
|
482
513
|
@state.full_commit!
|
|
483
514
|
@instrumenter.finish(:commit) if materialized?
|
|
484
515
|
end
|
|
@@ -610,6 +641,7 @@ module ActiveRecord
|
|
|
610
641
|
end
|
|
611
642
|
|
|
612
643
|
def within_new_transaction(isolation: nil, joinable: true)
|
|
644
|
+
isolation ||= @connection.pool.pool_transaction_isolation_level
|
|
613
645
|
@connection.lock.synchronize do
|
|
614
646
|
transaction = begin_transaction(isolation: isolation, joinable: joinable)
|
|
615
647
|
begin
|