activerecord 6.0.6.1 → 6.1.7.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1152 -779
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/active_record/aggregations.rb +5 -5
- data/lib/active_record/association_relation.rb +30 -12
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +49 -26
- data/lib/active_record/associations/association_scope.rb +18 -20
- data/lib/active_record/associations/belongs_to_association.rb +23 -10
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
- data/lib/active_record/associations/builder/association.rb +32 -5
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +32 -18
- data/lib/active_record/associations/collection_proxy.rb +12 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +37 -21
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +63 -49
- data/lib/active_record/associations/preloader/association.rb +14 -8
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations.rb +118 -11
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +11 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +33 -8
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +152 -22
- data/lib/active_record/coders/yaml_column.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -23
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +114 -26
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +228 -83
- data/lib/active_record/connection_adapters/abstract/transaction.rb +92 -33
- data/lib/active_record/connection_adapters/abstract_adapter.rb +52 -76
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +24 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -4
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +14 -53
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +30 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -64
- data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +32 -5
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +218 -71
- data/lib/active_record/core.rb +264 -63
- data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -40
- data/lib/active_record/database_configurations.rb +125 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +69 -34
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -2
- data/lib/active_record/fixtures.rb +58 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +38 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +18 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +24 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -8
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +72 -18
- data/lib/active_record/migration.rb +114 -84
- data/lib/active_record/model_schema.rb +89 -14
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +279 -101
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/calculations.rb +104 -43
- data/lib/active_record/relation/finder_methods.rb +44 -14
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +20 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +61 -38
- data/lib/active_record/relation/query_methods.rb +322 -196
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +111 -61
- data/lib/active_record/relation.rb +100 -81
- data/lib/active_record/result.rb +41 -33
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/default.rb +1 -3
- data/lib/active_record/scoping/named.rb +1 -17
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -51
- data/lib/active_record/tasks/database_tasks.rb +140 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +79 -31
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +19 -66
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -14
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -13
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
- data/lib/rails/generators/active_record/migration.rb +6 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +25 -26
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
@@ -1,8 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_record/migration/join_table"
|
4
3
|
require "active_support/core_ext/string/access"
|
5
|
-
require "active_support/deprecation"
|
6
4
|
require "digest/sha2"
|
7
5
|
|
8
6
|
module ActiveRecord
|
@@ -98,10 +96,14 @@ module ActiveRecord
|
|
98
96
|
# # Check an index with a custom name exists
|
99
97
|
# index_exists?(:suppliers, :company_id, name: "idx_company_id")
|
100
98
|
#
|
101
|
-
def index_exists?(table_name, column_name, options
|
102
|
-
column_names = Array(column_name).map(&:to_s)
|
99
|
+
def index_exists?(table_name, column_name, **options)
|
103
100
|
checks = []
|
104
|
-
|
101
|
+
|
102
|
+
if column_name.present?
|
103
|
+
column_names = Array(column_name).map(&:to_s)
|
104
|
+
checks << lambda { |i| Array(i.columns) == column_names }
|
105
|
+
end
|
106
|
+
|
105
107
|
checks << lambda { |i| i.unique } if options[:unique]
|
106
108
|
checks << lambda { |i| i.name == options[:name].to_s } if options[:name]
|
107
109
|
|
@@ -291,37 +293,42 @@ module ActiveRecord
|
|
291
293
|
# SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id
|
292
294
|
#
|
293
295
|
# See also TableDefinition#column for details on how to create columns.
|
294
|
-
def create_table(table_name, **options)
|
295
|
-
td = create_table_definition(table_name, **options)
|
296
|
+
def create_table(table_name, id: :primary_key, primary_key: nil, force: nil, **options)
|
297
|
+
td = create_table_definition(table_name, **extract_table_options!(options))
|
296
298
|
|
297
|
-
if
|
298
|
-
pk =
|
299
|
-
|
299
|
+
if id && !td.as
|
300
|
+
pk = primary_key || Base.get_primary_key(table_name.to_s.singularize)
|
301
|
+
|
302
|
+
if id.is_a?(Hash)
|
303
|
+
options.merge!(id.except(:type))
|
304
|
+
id = id.fetch(:type, :primary_key)
|
300
305
|
end
|
301
306
|
|
302
307
|
if pk.is_a?(Array)
|
303
308
|
td.primary_keys pk
|
304
309
|
else
|
305
|
-
td.primary_key pk,
|
310
|
+
td.primary_key pk, id, **options
|
306
311
|
end
|
307
312
|
end
|
308
313
|
|
309
314
|
yield td if block_given?
|
310
315
|
|
311
|
-
if
|
312
|
-
drop_table(table_name,
|
316
|
+
if force
|
317
|
+
drop_table(table_name, force: force, if_exists: true)
|
318
|
+
else
|
319
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
313
320
|
end
|
314
321
|
|
315
322
|
result = execute schema_creation.accept td
|
316
323
|
|
317
324
|
unless supports_indexes_in_create?
|
318
325
|
td.indexes.each do |column_name, index_options|
|
319
|
-
add_index(table_name, column_name, index_options)
|
326
|
+
add_index(table_name, column_name, **index_options, if_not_exists: td.if_not_exists)
|
320
327
|
end
|
321
328
|
end
|
322
329
|
|
323
330
|
if supports_comments? && !supports_comments_in_create?
|
324
|
-
if table_comment =
|
331
|
+
if table_comment = td.comment.presence
|
325
332
|
change_table_comment(table_name, table_comment)
|
326
333
|
end
|
327
334
|
|
@@ -420,6 +427,12 @@ module ActiveRecord
|
|
420
427
|
# t.column :name, :string, limit: 60
|
421
428
|
# end
|
422
429
|
#
|
430
|
+
# ====== Change type of a column
|
431
|
+
#
|
432
|
+
# change_table(:suppliers) do |t|
|
433
|
+
# t.change :metadata, :json
|
434
|
+
# end
|
435
|
+
#
|
423
436
|
# ====== Add 2 integer columns
|
424
437
|
#
|
425
438
|
# change_table(:suppliers) do |t|
|
@@ -499,6 +512,7 @@ module ActiveRecord
|
|
499
512
|
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
500
513
|
# In that case, +options+ and the block will be used by #create_table.
|
501
514
|
def drop_table(table_name, **options)
|
515
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
502
516
|
execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}"
|
503
517
|
end
|
504
518
|
|
@@ -534,6 +548,9 @@ module ActiveRecord
|
|
534
548
|
# column will have the same collation as the table.
|
535
549
|
# * <tt>:comment</tt> -
|
536
550
|
# Specifies the comment for the column. This option is ignored by some backends.
|
551
|
+
# * <tt>:if_not_exists</tt> -
|
552
|
+
# Specifies if the column already exists to not try to re-add it. This will avoid
|
553
|
+
# duplicate column errors.
|
537
554
|
#
|
538
555
|
# Note: The precision is the total number of significant digits,
|
539
556
|
# and the scale is the number of digits that can be stored following
|
@@ -554,8 +571,6 @@ module ActiveRecord
|
|
554
571
|
# but the maximum supported <tt>:precision</tt> is 16. No default.
|
555
572
|
# * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
|
556
573
|
# Default is (38,0).
|
557
|
-
# * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
|
558
|
-
# Default unknown.
|
559
574
|
# * SqlServer: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
560
575
|
# Default (38,0).
|
561
576
|
#
|
@@ -585,20 +600,37 @@ module ActiveRecord
|
|
585
600
|
# # Defines a column with a database-specific type.
|
586
601
|
# add_column(:shapes, :triangle, 'polygon')
|
587
602
|
# # ALTER TABLE "shapes" ADD "triangle" polygon
|
603
|
+
#
|
604
|
+
# # Ignores the method call if the column exists
|
605
|
+
# add_column(:shapes, :triangle, 'polygon', if_not_exists: true)
|
588
606
|
def add_column(table_name, column_name, type, **options)
|
607
|
+
return if options[:if_not_exists] == true && column_exists?(table_name, column_name, type)
|
608
|
+
|
589
609
|
at = create_alter_table table_name
|
590
610
|
at.add_column(column_name, type, **options)
|
591
611
|
execute schema_creation.accept at
|
592
612
|
end
|
593
613
|
|
614
|
+
def add_columns(table_name, *column_names, type:, **options) # :nodoc:
|
615
|
+
column_names.each do |column_name|
|
616
|
+
add_column(table_name, column_name, type, **options)
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
594
620
|
# Removes the given columns from the table definition.
|
595
621
|
#
|
596
622
|
# remove_columns(:suppliers, :qualification, :experience)
|
597
623
|
#
|
598
|
-
|
599
|
-
|
624
|
+
# +type+ and other column options can be passed to make migration reversible.
|
625
|
+
#
|
626
|
+
# remove_columns(:suppliers, :qualification, :experience, type: :string, null: false)
|
627
|
+
def remove_columns(table_name, *column_names, type: nil, **options)
|
628
|
+
if column_names.empty?
|
629
|
+
raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)")
|
630
|
+
end
|
631
|
+
|
600
632
|
column_names.each do |column_name|
|
601
|
-
remove_column(table_name, column_name)
|
633
|
+
remove_column(table_name, column_name, type, **options)
|
602
634
|
end
|
603
635
|
end
|
604
636
|
|
@@ -610,7 +642,15 @@ module ActiveRecord
|
|
610
642
|
# to provide these in a migration's +change+ method so it can be reverted.
|
611
643
|
# In that case, +type+ and +options+ will be used by #add_column.
|
612
644
|
# Indexes on the column are automatically removed.
|
645
|
+
#
|
646
|
+
# If the options provided include an +if_exists+ key, it will be used to check if the
|
647
|
+
# column does not exist. This will silently ignore the migration rather than raising
|
648
|
+
# if the column was already used.
|
649
|
+
#
|
650
|
+
# remove_column(:suppliers, :qualification, if_exists: true)
|
613
651
|
def remove_column(table_name, column_name, type = nil, **options)
|
652
|
+
return if options[:if_exists] == true && !column_exists?(table_name, column_name)
|
653
|
+
|
614
654
|
execute "ALTER TABLE #{quote_table_name(table_name)} #{remove_column_for_alter(table_name, column_name, type, **options)}"
|
615
655
|
end
|
616
656
|
|
@@ -620,7 +660,7 @@ module ActiveRecord
|
|
620
660
|
# change_column(:suppliers, :name, :string, limit: 80)
|
621
661
|
# change_column(:accounts, :description, :text)
|
622
662
|
#
|
623
|
-
def change_column(table_name, column_name, type, options
|
663
|
+
def change_column(table_name, column_name, type, **options)
|
624
664
|
raise NotImplementedError, "change_column is not implemented"
|
625
665
|
end
|
626
666
|
|
@@ -682,7 +722,17 @@ module ActiveRecord
|
|
682
722
|
#
|
683
723
|
# generates:
|
684
724
|
#
|
685
|
-
# CREATE INDEX
|
725
|
+
# CREATE INDEX index_suppliers_on_name ON suppliers(name)
|
726
|
+
#
|
727
|
+
# ====== Creating a index which already exists
|
728
|
+
#
|
729
|
+
# add_index(:suppliers, :name, if_not_exists: true)
|
730
|
+
#
|
731
|
+
# generates:
|
732
|
+
#
|
733
|
+
# CREATE INDEX IF NOT EXISTS index_suppliers_on_name ON suppliers(name)
|
734
|
+
#
|
735
|
+
# Note: Not supported by MySQL.
|
686
736
|
#
|
687
737
|
# ====== Creating a unique index
|
688
738
|
#
|
@@ -690,7 +740,7 @@ module ActiveRecord
|
|
690
740
|
#
|
691
741
|
# generates:
|
692
742
|
#
|
693
|
-
# CREATE UNIQUE INDEX
|
743
|
+
# CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id)
|
694
744
|
#
|
695
745
|
# ====== Creating a named index
|
696
746
|
#
|
@@ -720,7 +770,7 @@ module ActiveRecord
|
|
720
770
|
#
|
721
771
|
# ====== Creating an index with a sort order (desc or asc, asc is the default)
|
722
772
|
#
|
723
|
-
# add_index(:accounts, [:branch_id, :party_id, :surname], order: {branch_id: :desc, party_id: :asc})
|
773
|
+
# add_index(:accounts, [:branch_id, :party_id, :surname], name: 'by_branch_desc_party', order: {branch_id: :desc, party_id: :asc})
|
724
774
|
#
|
725
775
|
# generates:
|
726
776
|
#
|
@@ -736,7 +786,7 @@ module ActiveRecord
|
|
736
786
|
#
|
737
787
|
# CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id) WHERE active
|
738
788
|
#
|
739
|
-
# Note: Partial indexes are only supported for PostgreSQL and SQLite
|
789
|
+
# Note: Partial indexes are only supported for PostgreSQL and SQLite.
|
740
790
|
#
|
741
791
|
# ====== Creating an index with a specific method
|
742
792
|
#
|
@@ -782,9 +832,11 @@ module ActiveRecord
|
|
782
832
|
# Concurrently adding an index is not supported in a transaction.
|
783
833
|
#
|
784
834
|
# For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
|
785
|
-
def add_index(table_name, column_name, options
|
786
|
-
|
787
|
-
|
835
|
+
def add_index(table_name, column_name, **options)
|
836
|
+
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
837
|
+
|
838
|
+
create_index = CreateIndexDefinition.new(index, algorithm, if_not_exists)
|
839
|
+
execute schema_creation.accept(create_index)
|
788
840
|
end
|
789
841
|
|
790
842
|
# Removes the given index from the table.
|
@@ -805,6 +857,15 @@ module ActiveRecord
|
|
805
857
|
#
|
806
858
|
# remove_index :accounts, name: :by_branch_party
|
807
859
|
#
|
860
|
+
# Removes the index on +branch_id+ named +by_branch_party+ in the +accounts+ table.
|
861
|
+
#
|
862
|
+
# remove_index :accounts, :branch_id, name: :by_branch_party
|
863
|
+
#
|
864
|
+
# Checks if the index exists before trying to remove it. Will silently ignore indexes that
|
865
|
+
# don't exist.
|
866
|
+
#
|
867
|
+
# remove_index :accounts, if_exists: true
|
868
|
+
#
|
808
869
|
# Removes the index named +by_branch_party+ in the +accounts+ table +concurrently+.
|
809
870
|
#
|
810
871
|
# remove_index :accounts, name: :by_branch_party, algorithm: :concurrently
|
@@ -814,8 +875,11 @@ module ActiveRecord
|
|
814
875
|
# Concurrently removing an index is not supported in a transaction.
|
815
876
|
#
|
816
877
|
# For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
|
817
|
-
def remove_index(table_name,
|
818
|
-
|
878
|
+
def remove_index(table_name, column_name = nil, **options)
|
879
|
+
return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
|
880
|
+
|
881
|
+
index_name = index_name_for_remove(table_name, column_name, options)
|
882
|
+
|
819
883
|
execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
|
820
884
|
end
|
821
885
|
|
@@ -826,6 +890,8 @@ module ActiveRecord
|
|
826
890
|
# rename_index :people, 'index_people_on_last_name', 'index_users_on_last_name'
|
827
891
|
#
|
828
892
|
def rename_index(table_name, old_name, new_name)
|
893
|
+
old_name = old_name.to_s
|
894
|
+
new_name = new_name.to_s
|
829
895
|
validate_index_length!(table_name, new_name)
|
830
896
|
|
831
897
|
# this is a naive implementation; some DBs may support this more efficiently (PostgreSQL, for instance)
|
@@ -867,7 +933,9 @@ module ActiveRecord
|
|
867
933
|
# Add an appropriate index. Defaults to true.
|
868
934
|
# See #add_index for usage of this option.
|
869
935
|
# [<tt>:foreign_key</tt>]
|
870
|
-
# Add an appropriate foreign key constraint. Defaults to false
|
936
|
+
# Add an appropriate foreign key constraint. Defaults to false, pass true
|
937
|
+
# to add. In case the join table can't be inferred from the association
|
938
|
+
# pass <tt>:to_table</tt> with the appropriate table name.
|
871
939
|
# [<tt>:polymorphic</tt>]
|
872
940
|
# Whether an additional +_type+ column should be added. Defaults to false.
|
873
941
|
# [<tt>:null</tt>]
|
@@ -899,7 +967,7 @@ module ActiveRecord
|
|
899
967
|
#
|
900
968
|
# ====== Create a supplier_id column and a foreign key to the firms table
|
901
969
|
#
|
902
|
-
# add_reference(:products, :supplier, foreign_key: {to_table: :firms})
|
970
|
+
# add_reference(:products, :supplier, foreign_key: { to_table: :firms })
|
903
971
|
#
|
904
972
|
def add_reference(table_name, ref_name, **options)
|
905
973
|
ReferenceDefinition.new(ref_name, **options).add_to(update_table_definition(table_name, self))
|
@@ -1061,6 +1129,60 @@ module ActiveRecord
|
|
1061
1129
|
options
|
1062
1130
|
end
|
1063
1131
|
|
1132
|
+
# Returns an array of check constraints for the given table.
|
1133
|
+
# The check constraints are represented as CheckConstraintDefinition objects.
|
1134
|
+
def check_constraints(table_name)
|
1135
|
+
raise NotImplementedError
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
# Adds a new check constraint to the table. +expression+ is a String
|
1139
|
+
# representation of verifiable boolean condition.
|
1140
|
+
#
|
1141
|
+
# add_check_constraint :products, "price > 0", name: "price_check"
|
1142
|
+
#
|
1143
|
+
# generates:
|
1144
|
+
#
|
1145
|
+
# ALTER TABLE "products" ADD CONSTRAINT price_check CHECK (price > 0)
|
1146
|
+
#
|
1147
|
+
# The +options+ hash can include the following keys:
|
1148
|
+
# [<tt>:name</tt>]
|
1149
|
+
# The constraint name. Defaults to <tt>chk_rails_<identifier></tt>.
|
1150
|
+
# [<tt>:validate</tt>]
|
1151
|
+
# (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
|
1152
|
+
def add_check_constraint(table_name, expression, **options)
|
1153
|
+
return unless supports_check_constraints?
|
1154
|
+
|
1155
|
+
options = check_constraint_options(table_name, expression, options)
|
1156
|
+
at = create_alter_table(table_name)
|
1157
|
+
at.add_check_constraint(expression, options)
|
1158
|
+
|
1159
|
+
execute schema_creation.accept(at)
|
1160
|
+
end
|
1161
|
+
|
1162
|
+
def check_constraint_options(table_name, expression, options) # :nodoc:
|
1163
|
+
options = options.dup
|
1164
|
+
options[:name] ||= check_constraint_name(table_name, expression: expression, **options)
|
1165
|
+
options
|
1166
|
+
end
|
1167
|
+
|
1168
|
+
# Removes the given check constraint from the table.
|
1169
|
+
#
|
1170
|
+
# remove_check_constraint :products, name: "price_check"
|
1171
|
+
#
|
1172
|
+
# The +expression+ parameter will be ignored if present. It can be helpful
|
1173
|
+
# to provide this in a migration's +change+ method so it can be reverted.
|
1174
|
+
# In that case, +expression+ will be used by #add_check_constraint.
|
1175
|
+
def remove_check_constraint(table_name, expression = nil, **options)
|
1176
|
+
return unless supports_check_constraints?
|
1177
|
+
|
1178
|
+
chk_name_to_delete = check_constraint_for!(table_name, expression: expression, **options).name
|
1179
|
+
|
1180
|
+
at = create_alter_table(table_name)
|
1181
|
+
at.drop_check_constraint(chk_name_to_delete)
|
1182
|
+
|
1183
|
+
execute schema_creation.accept(at)
|
1184
|
+
end
|
1185
|
+
|
1064
1186
|
def dump_schema_information # :nodoc:
|
1065
1187
|
versions = schema_migration.all_versions
|
1066
1188
|
insert_versions_sql(versions) if versions.any?
|
@@ -1070,13 +1192,7 @@ module ActiveRecord
|
|
1070
1192
|
{ primary_key: true }
|
1071
1193
|
end
|
1072
1194
|
|
1073
|
-
def assume_migrated_upto_version(version
|
1074
|
-
unless migrations_paths.nil?
|
1075
|
-
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
1076
|
-
Passing migrations_paths to #assume_migrated_upto_version is deprecated and will be removed in Rails 6.1.
|
1077
|
-
MSG
|
1078
|
-
end
|
1079
|
-
|
1195
|
+
def assume_migrated_upto_version(version)
|
1080
1196
|
version = version.to_i
|
1081
1197
|
sm_table = quote_table_name(schema_migration.table_name)
|
1082
1198
|
|
@@ -1169,36 +1285,43 @@ module ActiveRecord
|
|
1169
1285
|
Table.new(table_name, base)
|
1170
1286
|
end
|
1171
1287
|
|
1172
|
-
def add_index_options(table_name, column_name,
|
1173
|
-
|
1288
|
+
def add_index_options(table_name, column_name, name: nil, if_not_exists: false, internal: false, **options) # :nodoc:
|
1289
|
+
options.assert_valid_keys(:unique, :length, :order, :opclass, :where, :type, :using, :comment, :algorithm)
|
1174
1290
|
|
1175
|
-
|
1291
|
+
column_names = index_column_names(column_name)
|
1176
1292
|
|
1177
|
-
|
1178
|
-
index_type ||= options[:unique] ? "UNIQUE" : ""
|
1179
|
-
index_name = options[:name].to_s if options.key?(:name)
|
1293
|
+
index_name = name&.to_s
|
1180
1294
|
index_name ||= index_name(table_name, column_names)
|
1181
1295
|
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1296
|
+
validate_index_length!(table_name, index_name, internal)
|
1297
|
+
|
1298
|
+
index = IndexDefinition.new(
|
1299
|
+
table_name, index_name,
|
1300
|
+
options[:unique],
|
1301
|
+
column_names,
|
1302
|
+
lengths: options[:length] || {},
|
1303
|
+
orders: options[:order] || {},
|
1304
|
+
opclasses: options[:opclass] || {},
|
1305
|
+
where: options[:where],
|
1306
|
+
type: options[:type],
|
1307
|
+
using: options[:using],
|
1308
|
+
comment: options[:comment]
|
1309
|
+
)
|
1310
|
+
|
1311
|
+
[index, index_algorithm(options[:algorithm]), if_not_exists]
|
1312
|
+
end
|
1193
1313
|
|
1194
|
-
|
1314
|
+
def index_algorithm(algorithm) # :nodoc:
|
1315
|
+
index_algorithms.fetch(algorithm) do
|
1316
|
+
raise ArgumentError, "Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}"
|
1317
|
+
end if algorithm
|
1318
|
+
end
|
1195
1319
|
|
1196
|
-
|
1197
|
-
|
1320
|
+
def quoted_columns_for_index(column_names, options) # :nodoc:
|
1321
|
+
quoted_columns = column_names.each_with_object({}) do |name, result|
|
1322
|
+
result[name.to_sym] = quote_column_name(name).dup
|
1198
1323
|
end
|
1199
|
-
|
1200
|
-
|
1201
|
-
[index_name, index_type, index_columns, index_options, algorithm, using, comment]
|
1324
|
+
add_options_for_index_columns(quoted_columns, **options).values.join(", ")
|
1202
1325
|
end
|
1203
1326
|
|
1204
1327
|
def options_include_default?(options)
|
@@ -1259,25 +1382,20 @@ module ActiveRecord
|
|
1259
1382
|
quoted_columns
|
1260
1383
|
end
|
1261
1384
|
|
1262
|
-
def
|
1263
|
-
return [
|
1264
|
-
|
1265
|
-
quoted_columns = Hash[column_names.map { |name| [name.to_sym, quote_column_name(name).dup] }]
|
1266
|
-
add_options_for_index_columns(quoted_columns, **options).values
|
1267
|
-
end
|
1268
|
-
|
1269
|
-
def index_name_for_remove(table_name, options = {})
|
1270
|
-
return options[:name] if can_remove_index_by_name?(options)
|
1385
|
+
def index_name_for_remove(table_name, column_name, options)
|
1386
|
+
return options[:name] if can_remove_index_by_name?(column_name, options)
|
1271
1387
|
|
1272
1388
|
checks = []
|
1273
1389
|
|
1274
|
-
if options.is_a?(
|
1275
|
-
|
1276
|
-
column_names =
|
1390
|
+
if !options.key?(:name) && column_name.is_a?(String) && /\W/.match?(column_name)
|
1391
|
+
options[:name] = index_name(table_name, column_name)
|
1392
|
+
column_names = []
|
1277
1393
|
else
|
1278
|
-
column_names = index_column_names(options)
|
1394
|
+
column_names = index_column_names(column_name || options[:column])
|
1279
1395
|
end
|
1280
1396
|
|
1397
|
+
checks << lambda { |i| i.name == options[:name].to_s } if options.key?(:name)
|
1398
|
+
|
1281
1399
|
if column_names.present?
|
1282
1400
|
checks << lambda { |i| index_name(table_name, i.columns) == index_name(table_name, column_names) }
|
1283
1401
|
end
|
@@ -1322,14 +1440,18 @@ module ActiveRecord
|
|
1322
1440
|
SchemaCreation.new(self)
|
1323
1441
|
end
|
1324
1442
|
|
1325
|
-
def create_table_definition(
|
1326
|
-
TableDefinition.new(self,
|
1443
|
+
def create_table_definition(name, **options)
|
1444
|
+
TableDefinition.new(self, name, **options)
|
1327
1445
|
end
|
1328
1446
|
|
1329
1447
|
def create_alter_table(name)
|
1330
1448
|
AlterTable.new create_table_definition(name)
|
1331
1449
|
end
|
1332
1450
|
|
1451
|
+
def extract_table_options!(options)
|
1452
|
+
options.extract!(:temporary, :if_not_exists, :options, :as, :comment, :charset, :collation)
|
1453
|
+
end
|
1454
|
+
|
1333
1455
|
def fetch_type_metadata(sql_type)
|
1334
1456
|
cast_type = lookup_cast_type(sql_type)
|
1335
1457
|
SqlTypeMetadata.new(
|
@@ -1390,11 +1512,30 @@ module ActiveRecord
|
|
1390
1512
|
end
|
1391
1513
|
end
|
1392
1514
|
|
1393
|
-
def
|
1394
|
-
|
1515
|
+
def check_constraint_name(table_name, **options)
|
1516
|
+
options.fetch(:name) do
|
1517
|
+
expression = options.fetch(:expression)
|
1518
|
+
identifier = "#{table_name}_#{expression}_chk"
|
1519
|
+
hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
|
1395
1520
|
|
1396
|
-
|
1397
|
-
|
1521
|
+
"chk_rails_#{hashed_identifier}"
|
1522
|
+
end
|
1523
|
+
end
|
1524
|
+
|
1525
|
+
def check_constraint_for(table_name, **options)
|
1526
|
+
return unless supports_check_constraints?
|
1527
|
+
chk_name = check_constraint_name(table_name, **options)
|
1528
|
+
check_constraints(table_name).detect { |chk| chk.name == chk_name }
|
1529
|
+
end
|
1530
|
+
|
1531
|
+
def check_constraint_for!(table_name, expression: nil, **options)
|
1532
|
+
check_constraint_for(table_name, expression: expression, **options) ||
|
1533
|
+
raise(ArgumentError, "Table '#{table_name}' has no check constraint for #{expression || options}")
|
1534
|
+
end
|
1535
|
+
|
1536
|
+
def validate_index_length!(table_name, new_name, internal = false)
|
1537
|
+
if new_name.length > index_name_length
|
1538
|
+
raise ArgumentError, "Index name '#{new_name}' on table '#{table_name}' is too long; the limit is #{index_name_length} characters"
|
1398
1539
|
end
|
1399
1540
|
end
|
1400
1541
|
|
@@ -1407,8 +1548,8 @@ module ActiveRecord
|
|
1407
1548
|
end
|
1408
1549
|
alias :extract_new_comment_value :extract_new_default_value
|
1409
1550
|
|
1410
|
-
def can_remove_index_by_name?(options)
|
1411
|
-
|
1551
|
+
def can_remove_index_by_name?(column_name, options)
|
1552
|
+
column_name.nil? && options.key?(:name) && options.except(:name, :algorithm).empty?
|
1412
1553
|
end
|
1413
1554
|
|
1414
1555
|
def bulk_change_table(table_name, operations)
|
@@ -1442,6 +1583,10 @@ module ActiveRecord
|
|
1442
1583
|
schema_creation.accept(AddColumnDefinition.new(cd))
|
1443
1584
|
end
|
1444
1585
|
|
1586
|
+
def rename_column_sql(table_name, column_name, new_column_name)
|
1587
|
+
"RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
|
1588
|
+
end
|
1589
|
+
|
1445
1590
|
def remove_column_for_alter(table_name, column_name, type = nil, **options)
|
1446
1591
|
"DROP COLUMN #{quote_column_name(column_name)}"
|
1447
1592
|
end
|