activerecord 6.1.7.6 → 7.0.8
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 +1570 -1016
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +33 -17
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +15 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +20 -22
- data/lib/active_record/associations/collection_proxy.rb +15 -5
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +8 -5
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +23 -15
- data/lib/active_record/associations/preloader/association.rb +186 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -14
- data/lib/active_record/associations/preloader.rb +39 -113
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +138 -100
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +49 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +8 -6
- data/lib/active_record/attribute_methods/serialization.rb +57 -19
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +19 -22
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +8 -23
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +14 -16
- data/lib/active_record/coders/yaml_column.rb +4 -8
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +52 -23
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +82 -25
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +144 -82
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +115 -85
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +37 -25
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -23
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +4 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +19 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -17
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +76 -73
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +40 -21
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -106
- data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +33 -18
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +19 -17
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +98 -36
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +49 -55
- data/lib/active_record/core.rb +123 -148
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +12 -9
- data/lib/active_record/database_configurations/hash_config.rb +63 -5
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +15 -32
- data/lib/active_record/delegated_type.rb +53 -12
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +67 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +206 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +90 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +50 -43
- data/lib/active_record/errors.rb +67 -4
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +41 -6
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +20 -23
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +5 -5
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +80 -14
- data/lib/active_record/integration.rb +4 -3
- data/lib/active_record/internal_metadata.rb +1 -5
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +36 -21
- data/lib/active_record/locking/pessimistic.rb +10 -4
- data/lib/active_record/log_subscriber.rb +23 -7
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +18 -6
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +8 -9
- data/lib/active_record/migration/compatibility.rb +93 -46
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +167 -87
- data/lib/active_record/model_schema.rb +58 -59
- data/lib/active_record/nested_attributes.rb +13 -12
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +231 -61
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +149 -0
- data/lib/active_record/querying.rb +16 -6
- data/lib/active_record/railtie.rb +136 -22
- data/lib/active_record/railties/controller_runtime.rb +4 -5
- data/lib/active_record/railties/databases.rake +78 -136
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +80 -49
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +6 -6
- data/lib/active_record/relation/calculations.rb +92 -60
- data/lib/active_record/relation/delegation.rb +7 -7
- data/lib/active_record/relation/finder_methods.rb +31 -35
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -1
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +28 -11
- data/lib/active_record/relation/query_methods.rb +304 -68
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +189 -88
- data/lib/active_record/result.rb +23 -11
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +17 -12
- data/lib/active_record/schema.rb +38 -23
- data/lib/active_record/schema_dumper.rb +29 -19
- data/lib/active_record/schema_migration.rb +4 -4
- data/lib/active_record/scoping/default.rb +60 -13
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +64 -34
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +3 -3
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/table_metadata.rb +6 -2
- data/lib/active_record/tasks/database_tasks.rb +127 -60
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +9 -6
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +12 -17
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +9 -5
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +4 -4
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +225 -27
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +11 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +8 -2
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +58 -2
- data/lib/arel.rb +2 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +55 -11
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/string/access"
|
4
|
-
require "
|
4
|
+
require "openssl"
|
5
5
|
|
6
6
|
module ActiveRecord
|
7
7
|
module ConnectionAdapters # :nodoc:
|
@@ -29,7 +29,7 @@ module ActiveRecord
|
|
29
29
|
table_name[0...table_alias_length].tr(".", "_")
|
30
30
|
end
|
31
31
|
|
32
|
-
# Returns the relation names
|
32
|
+
# Returns the relation names usable to back Active Record models.
|
33
33
|
# For most adapters this means all #tables and #views.
|
34
34
|
def data_sources
|
35
35
|
query_values(data_source_sql, "SCHEMA")
|
@@ -98,6 +98,7 @@ module ActiveRecord
|
|
98
98
|
#
|
99
99
|
def index_exists?(table_name, column_name, **options)
|
100
100
|
checks = []
|
101
|
+
column_name = options[:column] if column_name.nil?
|
101
102
|
|
102
103
|
if column_name.present?
|
103
104
|
column_names = Array(column_name).map(&:to_s)
|
@@ -124,6 +125,9 @@ module ActiveRecord
|
|
124
125
|
# column_exists?(:suppliers, :name)
|
125
126
|
#
|
126
127
|
# # Check a column exists of a particular type
|
128
|
+
# #
|
129
|
+
# # This works for standard non-casted types (eg. string) but is unreliable
|
130
|
+
# # for types that may get cast to something else (eg. char, bigint).
|
127
131
|
# column_exists?(:suppliers, :name, :string)
|
128
132
|
#
|
129
133
|
# # Check a column exists with a specific definition
|
@@ -260,7 +264,7 @@ module ActiveRecord
|
|
260
264
|
#
|
261
265
|
# generates:
|
262
266
|
#
|
263
|
-
# CREATE TABLE
|
267
|
+
# CREATE TABLE orders (
|
264
268
|
# product_id bigint NOT NULL,
|
265
269
|
# client_id bigint NOT NULL
|
266
270
|
# );
|
@@ -518,24 +522,31 @@ module ActiveRecord
|
|
518
522
|
|
519
523
|
# Add a new +type+ column named +column_name+ to +table_name+.
|
520
524
|
#
|
525
|
+
# See {ActiveRecord::ConnectionAdapters::TableDefinition.column}[rdoc-ref:ActiveRecord::ConnectionAdapters::TableDefinition#column].
|
526
|
+
#
|
521
527
|
# The +type+ parameter is normally one of the migrations native types,
|
522
528
|
# which is one of the following:
|
523
529
|
# <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
|
524
530
|
# <tt>:integer</tt>, <tt>:bigint</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:numeric</tt>,
|
525
531
|
# <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
|
526
|
-
# <tt>:binary</tt>, <tt>:boolean</tt>.
|
532
|
+
# <tt>:binary</tt>, <tt>:blob</tt>, <tt>:boolean</tt>.
|
527
533
|
#
|
528
534
|
# You may use a type not in this list as long as it is supported by your
|
529
535
|
# database (for example, "polygon" in MySQL), but this will not be database
|
530
536
|
# agnostic and should usually be avoided.
|
531
537
|
#
|
532
538
|
# Available options are (none of these exists by default):
|
539
|
+
# * <tt>:comment</tt> -
|
540
|
+
# Specifies the comment for the column. This option is ignored by some backends.
|
541
|
+
# * <tt>:collation</tt> -
|
542
|
+
# Specifies the collation for a <tt>:string</tt> or <tt>:text</tt> column.
|
543
|
+
# If not specified, the column will have the same collation as the table.
|
544
|
+
# * <tt>:default</tt> -
|
545
|
+
# The column's default value. Use +nil+ for +NULL+.
|
533
546
|
# * <tt>:limit</tt> -
|
534
547
|
# Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column
|
535
|
-
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, and <tt>:integer</tt> columns.
|
548
|
+
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, <tt>:blob</tt>, and <tt>:integer</tt> columns.
|
536
549
|
# This option is ignored by some backends.
|
537
|
-
# * <tt>:default</tt> -
|
538
|
-
# The column's default value. Use +nil+ for +NULL+.
|
539
550
|
# * <tt>:null</tt> -
|
540
551
|
# Allows or disallows +NULL+ values in the column.
|
541
552
|
# * <tt>:precision</tt> -
|
@@ -604,7 +615,13 @@ module ActiveRecord
|
|
604
615
|
# # Ignores the method call if the column exists
|
605
616
|
# add_column(:shapes, :triangle, 'polygon', if_not_exists: true)
|
606
617
|
def add_column(table_name, column_name, type, **options)
|
607
|
-
return if options[:if_not_exists] == true && column_exists?(table_name, column_name
|
618
|
+
return if options[:if_not_exists] == true && column_exists?(table_name, column_name)
|
619
|
+
|
620
|
+
if supports_datetime_with_precision?
|
621
|
+
if type == :datetime && !options.key?(:precision)
|
622
|
+
options[:precision] = 6
|
623
|
+
end
|
624
|
+
end
|
608
625
|
|
609
626
|
at = create_alter_table table_name
|
610
627
|
at.add_column(column_name, type, **options)
|
@@ -629,9 +646,8 @@ module ActiveRecord
|
|
629
646
|
raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)")
|
630
647
|
end
|
631
648
|
|
632
|
-
column_names
|
633
|
-
|
634
|
-
end
|
649
|
+
remove_column_fragments = remove_columns_for_alter(table_name, *column_names, type: type, **options)
|
650
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{remove_column_fragments.join(', ')}"
|
635
651
|
end
|
636
652
|
|
637
653
|
# Removes the column from the table definition.
|
@@ -641,7 +657,8 @@ module ActiveRecord
|
|
641
657
|
# The +type+ and +options+ parameters will be ignored if present. It can be helpful
|
642
658
|
# to provide these in a migration's +change+ method so it can be reverted.
|
643
659
|
# In that case, +type+ and +options+ will be used by #add_column.
|
644
|
-
#
|
660
|
+
# Depending on the database you're using, indexes using this column may be
|
661
|
+
# automatically removed or modified to remove this column from the index.
|
645
662
|
#
|
646
663
|
# If the options provided include an +if_exists+ key, it will be used to check if the
|
647
664
|
# column does not exist. This will silently ignore the migration rather than raising
|
@@ -766,7 +783,7 @@ module ActiveRecord
|
|
766
783
|
#
|
767
784
|
# CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
|
768
785
|
#
|
769
|
-
# Note:
|
786
|
+
# Note: only supported by MySQL
|
770
787
|
#
|
771
788
|
# ====== Creating an index with a sort order (desc or asc, asc is the default)
|
772
789
|
#
|
@@ -901,7 +918,7 @@ module ActiveRecord
|
|
901
918
|
remove_index(table_name, name: old_name)
|
902
919
|
end
|
903
920
|
|
904
|
-
def index_name(table_name, options)
|
921
|
+
def index_name(table_name, options) # :nodoc:
|
905
922
|
if Hash === options
|
906
923
|
if options[:column]
|
907
924
|
"index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
|
@@ -1027,6 +1044,10 @@ module ActiveRecord
|
|
1027
1044
|
#
|
1028
1045
|
# ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
|
1029
1046
|
#
|
1047
|
+
# ====== Creating a foreign key, ignoring method call if the foreign key exists
|
1048
|
+
#
|
1049
|
+
# add_foreign_key(:articles, :authors, if_not_exists: true)
|
1050
|
+
#
|
1030
1051
|
# ====== Creating a foreign key on a specific column
|
1031
1052
|
#
|
1032
1053
|
# add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
|
@@ -1051,13 +1072,20 @@ module ActiveRecord
|
|
1051
1072
|
# [<tt>:name</tt>]
|
1052
1073
|
# The constraint name. Defaults to <tt>fk_rails_<identifier></tt>.
|
1053
1074
|
# [<tt>:on_delete</tt>]
|
1054
|
-
# Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade
|
1075
|
+
# Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+, and +:restrict+
|
1055
1076
|
# [<tt>:on_update</tt>]
|
1056
|
-
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade
|
1077
|
+
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+, and +:restrict+
|
1078
|
+
# [<tt>:if_not_exists</tt>]
|
1079
|
+
# Specifies if the foreign key already exists to not try to re-add it. This will avoid
|
1080
|
+
# duplicate column errors.
|
1057
1081
|
# [<tt>:validate</tt>]
|
1058
1082
|
# (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
|
1083
|
+
# [<tt>:deferrable</tt>]
|
1084
|
+
# (PostgreSQL only) Specify whether or not the foreign key should be deferrable. Valid values are booleans or
|
1085
|
+
# +:deferred+ or +:immediate+ to specify the default behavior. Defaults to +false+.
|
1059
1086
|
def add_foreign_key(from_table, to_table, **options)
|
1060
1087
|
return unless supports_foreign_keys?
|
1088
|
+
return if options[:if_not_exists] == true && foreign_key_exists?(from_table, to_table)
|
1061
1089
|
|
1062
1090
|
options = foreign_key_options(from_table, to_table, options)
|
1063
1091
|
at = create_alter_table from_table
|
@@ -1087,12 +1115,18 @@ module ActiveRecord
|
|
1087
1115
|
#
|
1088
1116
|
# remove_foreign_key :accounts, name: :special_fk_name
|
1089
1117
|
#
|
1118
|
+
# Checks if the foreign key exists before trying to remove it. Will silently ignore indexes that
|
1119
|
+
# don't exist.
|
1120
|
+
#
|
1121
|
+
# remove_foreign_key :accounts, :branches, if_exists: true
|
1122
|
+
#
|
1090
1123
|
# The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key
|
1091
1124
|
# with an addition of
|
1092
1125
|
# [<tt>:to_table</tt>]
|
1093
1126
|
# The name of the table that contains the referenced primary key.
|
1094
1127
|
def remove_foreign_key(from_table, to_table = nil, **options)
|
1095
1128
|
return unless supports_foreign_keys?
|
1129
|
+
return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table)
|
1096
1130
|
|
1097
1131
|
fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
|
1098
1132
|
|
@@ -1256,6 +1290,25 @@ module ActiveRecord
|
|
1256
1290
|
columns
|
1257
1291
|
end
|
1258
1292
|
|
1293
|
+
def distinct_relation_for_primary_key(relation) # :nodoc:
|
1294
|
+
values = columns_for_distinct(
|
1295
|
+
visitor.compile(relation.table[relation.primary_key]),
|
1296
|
+
relation.order_values
|
1297
|
+
)
|
1298
|
+
|
1299
|
+
limited = relation.reselect(values).distinct!
|
1300
|
+
limited_ids = select_rows(limited.arel, "SQL").map(&:last)
|
1301
|
+
|
1302
|
+
if limited_ids.empty?
|
1303
|
+
relation.none!
|
1304
|
+
else
|
1305
|
+
relation.where!(relation.primary_key => limited_ids)
|
1306
|
+
end
|
1307
|
+
|
1308
|
+
relation.limit_value = relation.offset_value = nil
|
1309
|
+
relation
|
1310
|
+
end
|
1311
|
+
|
1259
1312
|
# Adds timestamps (+created_at+ and +updated_at+) columns to +table_name+.
|
1260
1313
|
# Additional options (like +:null+) are forwarded to #add_column.
|
1261
1314
|
#
|
@@ -1277,11 +1330,10 @@ module ActiveRecord
|
|
1277
1330
|
# remove_timestamps(:suppliers)
|
1278
1331
|
#
|
1279
1332
|
def remove_timestamps(table_name, **options)
|
1280
|
-
|
1281
|
-
remove_column table_name, :created_at
|
1333
|
+
remove_columns table_name, :updated_at, :created_at
|
1282
1334
|
end
|
1283
1335
|
|
1284
|
-
def update_table_definition(table_name, base)
|
1336
|
+
def update_table_definition(table_name, base) # :nodoc:
|
1285
1337
|
Table.new(table_name, base)
|
1286
1338
|
end
|
1287
1339
|
|
@@ -1387,7 +1439,7 @@ module ActiveRecord
|
|
1387
1439
|
|
1388
1440
|
checks = []
|
1389
1441
|
|
1390
|
-
if !options.key?(:name) &&
|
1442
|
+
if !options.key?(:name) && expression_column_name?(column_name)
|
1391
1443
|
options[:name] = index_name(table_name, column_name)
|
1392
1444
|
column_names = []
|
1393
1445
|
else
|
@@ -1396,7 +1448,7 @@ module ActiveRecord
|
|
1396
1448
|
|
1397
1449
|
checks << lambda { |i| i.name == options[:name].to_s } if options.key?(:name)
|
1398
1450
|
|
1399
|
-
if column_names.present?
|
1451
|
+
if column_names.present? && !(options.key?(:name) && expression_column_name?(column_names))
|
1400
1452
|
checks << lambda { |i| index_name(table_name, i.columns) == index_name(table_name, column_names) }
|
1401
1453
|
end
|
1402
1454
|
|
@@ -1464,7 +1516,7 @@ module ActiveRecord
|
|
1464
1516
|
end
|
1465
1517
|
|
1466
1518
|
def index_column_names(column_names)
|
1467
|
-
if
|
1519
|
+
if expression_column_name?(column_names)
|
1468
1520
|
column_names
|
1469
1521
|
else
|
1470
1522
|
Array(column_names)
|
@@ -1472,13 +1524,18 @@ module ActiveRecord
|
|
1472
1524
|
end
|
1473
1525
|
|
1474
1526
|
def index_name_options(column_names)
|
1475
|
-
if
|
1527
|
+
if expression_column_name?(column_names)
|
1476
1528
|
column_names = column_names.scan(/\w+/).join("_")
|
1477
1529
|
end
|
1478
1530
|
|
1479
1531
|
{ column: column_names }
|
1480
1532
|
end
|
1481
1533
|
|
1534
|
+
# Try to identify whether the given column name is an expression
|
1535
|
+
def expression_column_name?(column_name)
|
1536
|
+
column_name.is_a?(String) && /\W/.match?(column_name)
|
1537
|
+
end
|
1538
|
+
|
1482
1539
|
def strip_table_name_prefix_and_suffix(table_name)
|
1483
1540
|
prefix = Base.table_name_prefix
|
1484
1541
|
suffix = Base.table_name_suffix
|
@@ -1488,7 +1545,7 @@ module ActiveRecord
|
|
1488
1545
|
def foreign_key_name(table_name, options)
|
1489
1546
|
options.fetch(:name) do
|
1490
1547
|
identifier = "#{table_name}_#{options.fetch(:column)}_fk"
|
1491
|
-
hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
|
1548
|
+
hashed_identifier = OpenSSL::Digest::SHA256.hexdigest(identifier).first(10)
|
1492
1549
|
|
1493
1550
|
"fk_rails_#{hashed_identifier}"
|
1494
1551
|
end
|
@@ -1516,7 +1573,7 @@ module ActiveRecord
|
|
1516
1573
|
options.fetch(:name) do
|
1517
1574
|
expression = options.fetch(:expression)
|
1518
1575
|
identifier = "#{table_name}_#{expression}_chk"
|
1519
|
-
hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
|
1576
|
+
hashed_identifier = OpenSSL::Digest::SHA256.hexdigest(identifier).first(10)
|
1520
1577
|
|
1521
1578
|
"chk_rails_#{hashed_identifier}"
|
1522
1579
|
end
|
@@ -73,7 +73,7 @@ module ActiveRecord
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
-
class NullTransaction
|
76
|
+
class NullTransaction # :nodoc:
|
77
77
|
def initialize; end
|
78
78
|
def state; end
|
79
79
|
def closed?; true; end
|
@@ -82,7 +82,7 @@ module ActiveRecord
|
|
82
82
|
def add_record(record, _ = true); end
|
83
83
|
end
|
84
84
|
|
85
|
-
class Transaction
|
85
|
+
class Transaction # :nodoc:
|
86
86
|
attr_reader :connection, :state, :savepoint_name, :isolation_level
|
87
87
|
attr_accessor :written
|
88
88
|
|
@@ -221,7 +221,7 @@ module ActiveRecord
|
|
221
221
|
end
|
222
222
|
end
|
223
223
|
|
224
|
-
class TransactionManager
|
224
|
+
class TransactionManager # :nodoc:
|
225
225
|
def initialize(connection)
|
226
226
|
@stack = []
|
227
227
|
@connection = connection
|
@@ -333,26 +333,19 @@ module ActiveRecord
|
|
333
333
|
# @connection still holds an open or invalid transaction, so we must not
|
334
334
|
# put it back in the pool for reuse.
|
335
335
|
@connection.throw_away! unless transaction.state.rolledback?
|
336
|
+
elsif Thread.current.status == "aborting" || (!completed && transaction.written)
|
337
|
+
# The transaction is still open but the block returned earlier.
|
338
|
+
#
|
339
|
+
# The block could return early because of a timeout or because the thread is aborting,
|
340
|
+
# so we are rolling back to make sure the timeout didn't caused the transaction to be
|
341
|
+
# committed incompletely.
|
342
|
+
rollback_transaction
|
336
343
|
else
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
Using `return`, `break` or `throw` to exit a transaction block is
|
343
|
-
deprecated without replacement. If the `throw` came from
|
344
|
-
`Timeout.timeout(duration)`, pass an exception class as a second
|
345
|
-
argument so it doesn't use `throw` to abort its block. This results
|
346
|
-
in the transaction being committed, but in the next release of Rails
|
347
|
-
it will rollback.
|
348
|
-
EOW
|
349
|
-
end
|
350
|
-
begin
|
351
|
-
commit_transaction
|
352
|
-
rescue Exception
|
353
|
-
rollback_transaction(transaction) unless transaction.state.completed?
|
354
|
-
raise
|
355
|
-
end
|
344
|
+
begin
|
345
|
+
commit_transaction
|
346
|
+
rescue Exception
|
347
|
+
rollback_transaction(transaction) unless transaction.state.completed?
|
348
|
+
raise
|
356
349
|
end
|
357
350
|
end
|
358
351
|
end
|