activerecord 6.0.0.beta1 → 6.0.1.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +529 -10
  3. data/README.rdoc +3 -1
  4. data/lib/active_record.rb +7 -1
  5. data/lib/active_record/association_relation.rb +15 -6
  6. data/lib/active_record/associations.rb +4 -3
  7. data/lib/active_record/associations/association.rb +27 -2
  8. data/lib/active_record/associations/builder/association.rb +14 -18
  9. data/lib/active_record/associations/builder/belongs_to.rb +5 -2
  10. data/lib/active_record/associations/builder/collection_association.rb +5 -15
  11. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -1
  12. data/lib/active_record/associations/builder/has_many.rb +2 -0
  13. data/lib/active_record/associations/builder/has_one.rb +35 -1
  14. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  15. data/lib/active_record/associations/collection_association.rb +5 -6
  16. data/lib/active_record/associations/collection_proxy.rb +13 -42
  17. data/lib/active_record/associations/has_many_association.rb +1 -9
  18. data/lib/active_record/associations/has_many_through_association.rb +4 -11
  19. data/lib/active_record/associations/join_dependency.rb +14 -9
  20. data/lib/active_record/associations/join_dependency/join_association.rb +21 -7
  21. data/lib/active_record/associations/preloader.rb +12 -7
  22. data/lib/active_record/associations/preloader/association.rb +37 -34
  23. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  24. data/lib/active_record/attribute_methods.rb +3 -53
  25. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  26. data/lib/active_record/attribute_methods/dirty.rb +47 -14
  27. data/lib/active_record/attribute_methods/primary_key.rb +7 -15
  28. data/lib/active_record/attribute_methods/query.rb +2 -3
  29. data/lib/active_record/attribute_methods/read.rb +3 -9
  30. data/lib/active_record/attribute_methods/write.rb +6 -12
  31. data/lib/active_record/attributes.rb +13 -0
  32. data/lib/active_record/autosave_association.rb +21 -7
  33. data/lib/active_record/base.rb +0 -1
  34. data/lib/active_record/callbacks.rb +3 -3
  35. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +134 -23
  36. data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
  37. data/lib/active_record/connection_adapters/abstract/database_statements.rb +105 -70
  38. data/lib/active_record/connection_adapters/abstract/query_cache.rb +12 -5
  39. data/lib/active_record/connection_adapters/abstract/quoting.rb +63 -6
  40. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -2
  41. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +51 -40
  42. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
  43. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +95 -30
  44. data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
  45. data/lib/active_record/connection_adapters/abstract_adapter.rb +115 -35
  46. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +106 -138
  47. data/lib/active_record/connection_adapters/column.rb +17 -13
  48. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  49. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +3 -3
  50. data/lib/active_record/connection_adapters/mysql/database_statements.rb +48 -8
  51. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  52. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  53. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  54. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +66 -5
  55. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  56. data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -5
  57. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
  58. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -2
  59. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  60. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  61. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
  62. data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -3
  63. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
  64. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +98 -89
  65. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +47 -63
  66. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
  67. data/lib/active_record/connection_adapters/postgresql_adapter.rb +95 -24
  68. data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
  69. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  70. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
  71. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -2
  72. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -2
  73. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +73 -118
  74. data/lib/active_record/connection_handling.rb +40 -17
  75. data/lib/active_record/core.rb +35 -24
  76. data/lib/active_record/database_configurations.rb +99 -50
  77. data/lib/active_record/database_configurations/hash_config.rb +11 -11
  78. data/lib/active_record/database_configurations/url_config.rb +21 -16
  79. data/lib/active_record/dynamic_matchers.rb +1 -1
  80. data/lib/active_record/enum.rb +15 -0
  81. data/lib/active_record/errors.rb +18 -13
  82. data/lib/active_record/fixtures.rb +11 -6
  83. data/lib/active_record/gem_version.rb +2 -2
  84. data/lib/active_record/inheritance.rb +1 -1
  85. data/lib/active_record/insert_all.rb +179 -0
  86. data/lib/active_record/integration.rb +13 -1
  87. data/lib/active_record/internal_metadata.rb +5 -1
  88. data/lib/active_record/locking/optimistic.rb +3 -4
  89. data/lib/active_record/log_subscriber.rb +1 -1
  90. data/lib/active_record/middleware/database_selector.rb +75 -0
  91. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  92. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  93. data/lib/active_record/migration.rb +62 -44
  94. data/lib/active_record/migration/command_recorder.rb +28 -14
  95. data/lib/active_record/migration/compatibility.rb +72 -63
  96. data/lib/active_record/model_schema.rb +3 -0
  97. data/lib/active_record/persistence.rb +212 -19
  98. data/lib/active_record/querying.rb +18 -14
  99. data/lib/active_record/railtie.rb +9 -1
  100. data/lib/active_record/railties/collection_cache_association_loading.rb +3 -3
  101. data/lib/active_record/railties/databases.rake +124 -25
  102. data/lib/active_record/reflection.rb +18 -32
  103. data/lib/active_record/relation.rb +185 -35
  104. data/lib/active_record/relation/calculations.rb +40 -44
  105. data/lib/active_record/relation/delegation.rb +23 -31
  106. data/lib/active_record/relation/finder_methods.rb +23 -14
  107. data/lib/active_record/relation/merger.rb +11 -16
  108. data/lib/active_record/relation/query_attribute.rb +5 -3
  109. data/lib/active_record/relation/query_methods.rb +230 -69
  110. data/lib/active_record/relation/spawn_methods.rb +1 -1
  111. data/lib/active_record/relation/where_clause.rb +10 -10
  112. data/lib/active_record/sanitization.rb +33 -4
  113. data/lib/active_record/schema.rb +1 -1
  114. data/lib/active_record/schema_dumper.rb +10 -1
  115. data/lib/active_record/schema_migration.rb +1 -1
  116. data/lib/active_record/scoping.rb +6 -7
  117. data/lib/active_record/scoping/default.rb +7 -15
  118. data/lib/active_record/scoping/named.rb +10 -2
  119. data/lib/active_record/statement_cache.rb +2 -2
  120. data/lib/active_record/store.rb +48 -0
  121. data/lib/active_record/table_metadata.rb +9 -13
  122. data/lib/active_record/tasks/database_tasks.rb +109 -6
  123. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -1
  124. data/lib/active_record/test_databases.rb +1 -16
  125. data/lib/active_record/test_fixtures.rb +2 -2
  126. data/lib/active_record/timestamp.rb +35 -19
  127. data/lib/active_record/touch_later.rb +4 -2
  128. data/lib/active_record/transactions.rb +56 -46
  129. data/lib/active_record/type_caster/connection.rb +16 -10
  130. data/lib/active_record/validations.rb +1 -0
  131. data/lib/active_record/validations/uniqueness.rb +4 -4
  132. data/lib/arel.rb +18 -4
  133. data/lib/arel/insert_manager.rb +3 -3
  134. data/lib/arel/nodes.rb +2 -1
  135. data/lib/arel/nodes/and.rb +1 -1
  136. data/lib/arel/nodes/case.rb +1 -1
  137. data/lib/arel/nodes/comment.rb +29 -0
  138. data/lib/arel/nodes/select_core.rb +16 -12
  139. data/lib/arel/nodes/unary.rb +1 -0
  140. data/lib/arel/nodes/values_list.rb +2 -17
  141. data/lib/arel/select_manager.rb +10 -10
  142. data/lib/arel/visitors/depth_first.rb +7 -2
  143. data/lib/arel/visitors/dot.rb +7 -2
  144. data/lib/arel/visitors/ibm_db.rb +13 -0
  145. data/lib/arel/visitors/informix.rb +6 -0
  146. data/lib/arel/visitors/mssql.rb +15 -1
  147. data/lib/arel/visitors/oracle12.rb +4 -5
  148. data/lib/arel/visitors/postgresql.rb +4 -10
  149. data/lib/arel/visitors/to_sql.rb +107 -131
  150. data/lib/arel/visitors/visitor.rb +9 -5
  151. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
  152. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  153. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  154. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  155. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  156. metadata +19 -12
  157. data/lib/active_record/collection_cache_key.rb +0 -53
  158. data/lib/arel/nodes/values.rb +0 -16
@@ -7,7 +7,8 @@ module ActiveRecord
7
7
  module QueryCache
8
8
  class << self
9
9
  def included(base) #:nodoc:
10
- dirties_query_cache base, :insert, :update, :delete, :rollback_to_savepoint, :rollback_db_transaction
10
+ dirties_query_cache base, :insert, :update, :delete, :truncate, :truncate_tables,
11
+ :rollback_to_savepoint, :rollback_db_transaction, :exec_insert_all
11
12
 
12
13
  base.set_callback :checkout, :after, :configure_query_cache!
13
14
  base.set_callback :checkin, :after, :disable_query_cache!
@@ -17,7 +18,7 @@ module ActiveRecord
17
18
  method_names.each do |method_name|
18
19
  base.class_eval <<-end_code, __FILE__, __LINE__ + 1
19
20
  def #{method_name}(*)
20
- clear_query_cache if @query_cache_enabled
21
+ ActiveRecord::Base.clear_query_caches_for_current_thread if @query_cache_enabled
21
22
  super
22
23
  end
23
24
  end_code
@@ -32,17 +33,17 @@ module ActiveRecord
32
33
  end
33
34
 
34
35
  def enable_query_cache!
35
- @query_cache_enabled[connection_cache_key(Thread.current)] = true
36
+ @query_cache_enabled[connection_cache_key(current_thread)] = true
36
37
  connection.enable_query_cache! if active_connection?
37
38
  end
38
39
 
39
40
  def disable_query_cache!
40
- @query_cache_enabled.delete connection_cache_key(Thread.current)
41
+ @query_cache_enabled.delete connection_cache_key(current_thread)
41
42
  connection.disable_query_cache! if active_connection?
42
43
  end
43
44
 
44
45
  def query_cache_enabled
45
- @query_cache_enabled[connection_cache_key(Thread.current)]
46
+ @query_cache_enabled[connection_cache_key(current_thread)]
46
47
  end
47
48
  end
48
49
 
@@ -96,6 +97,11 @@ module ActiveRecord
96
97
  if @query_cache_enabled && !locked?(arel)
97
98
  arel = arel_from_relation(arel)
98
99
  sql, binds = to_sql_and_binds(arel, binds)
100
+
101
+ if preparable.nil?
102
+ preparable = prepared_statements ? visitor.preparable : false
103
+ end
104
+
99
105
  cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable) }
100
106
  else
101
107
  super
@@ -129,6 +135,7 @@ module ActiveRecord
129
135
  type_casted_binds: -> { type_casted_binds(binds) },
130
136
  name: name,
131
137
  connection_id: object_id,
138
+ connection: self,
132
139
  cached: true
133
140
  }
134
141
  end
@@ -138,15 +138,72 @@ module ActiveRecord
138
138
  "'#{quote_string(value.to_s)}'"
139
139
  end
140
140
 
141
- def type_casted_binds(binds) # :nodoc:
142
- if binds.first.is_a?(Array)
143
- binds.map { |column, value| type_cast(value, column) }
144
- else
145
- binds.map { |attr| type_cast(attr.value_for_database) }
146
- end
141
+ def sanitize_as_sql_comment(value) # :nodoc:
142
+ value.to_s.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "")
143
+ end
144
+
145
+ def column_name_matcher # :nodoc:
146
+ COLUMN_NAME
147
+ end
148
+
149
+ def column_name_with_order_matcher # :nodoc:
150
+ COLUMN_NAME_WITH_ORDER
147
151
  end
148
152
 
153
+ # Regexp for column names (with or without a table name prefix).
154
+ # Matches the following:
155
+ #
156
+ # "#{table_name}.#{column_name}"
157
+ # "#{column_name}"
158
+ COLUMN_NAME = /
159
+ \A
160
+ (
161
+ (?:
162
+ # table_name.column_name | function(one or no argument)
163
+ ((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
164
+ )
165
+ (?:\s+AS\s+\w+)?
166
+ )
167
+ (?:\s*,\s*\g<1>)*
168
+ \z
169
+ /ix
170
+
171
+ # Regexp for column names with order (with or without a table name prefix,
172
+ # with or without various order modifiers). Matches the following:
173
+ #
174
+ # "#{table_name}.#{column_name}"
175
+ # "#{table_name}.#{column_name} #{direction}"
176
+ # "#{table_name}.#{column_name} #{direction} NULLS FIRST"
177
+ # "#{table_name}.#{column_name} NULLS LAST"
178
+ # "#{column_name}"
179
+ # "#{column_name} #{direction}"
180
+ # "#{column_name} #{direction} NULLS FIRST"
181
+ # "#{column_name} NULLS LAST"
182
+ COLUMN_NAME_WITH_ORDER = /
183
+ \A
184
+ (
185
+ (?:
186
+ # table_name.column_name | function(one or no argument)
187
+ ((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
188
+ )
189
+ (?:\s+ASC|\s+DESC)?
190
+ (?:\s+NULLS\s+(?:FIRST|LAST))?
191
+ )
192
+ (?:\s*,\s*\g<1>)*
193
+ \z
194
+ /ix
195
+
196
+ private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
197
+
149
198
  private
199
+ def type_casted_binds(binds)
200
+ if binds.first.is_a?(Array)
201
+ binds.map { |column, value| type_cast(value, column) }
202
+ else
203
+ binds.map { |attr| type_cast(attr.value_for_database) }
204
+ end
205
+ end
206
+
150
207
  def lookup_cast_type(sql_type)
151
208
  type_map.lookup(sql_type)
152
209
  end
@@ -15,7 +15,7 @@ module ActiveRecord
15
15
  end
16
16
 
17
17
  delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
18
- :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys_in_create?, :foreign_key_options,
18
+ :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options,
19
19
  to: :@conn, private: true
20
20
 
21
21
  private
@@ -50,7 +50,7 @@ module ActiveRecord
50
50
  statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
51
51
  end
52
52
 
53
- if supports_foreign_keys_in_create?
53
+ if supports_foreign_keys?
54
54
  statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
55
55
  end
56
56
 
@@ -127,6 +127,9 @@ module ActiveRecord
127
127
  end
128
128
 
129
129
  def foreign_key_in_create(from_table, to_table, options)
130
+ prefix = ActiveRecord::Base.table_name_prefix
131
+ suffix = ActiveRecord::Base.table_name_suffix
132
+ to_table = "#{prefix}#{to_table}#{suffix}"
130
133
  options = foreign_key_options(from_table, to_table, options)
131
134
  accept ForeignKeyDefinition.new(from_table, to_table, options)
132
135
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/deprecation"
4
-
5
3
  module ActiveRecord
6
4
  module ConnectionAdapters #:nodoc:
7
5
  # Abstract representation of an index definition on a table. Instances of
@@ -104,16 +102,12 @@ module ActiveRecord
104
102
  alias validated? validate?
105
103
 
106
104
  def export_name_on_schema_dump?
107
- name !~ ActiveRecord::SchemaDumper.fk_ignore_pattern
105
+ !ActiveRecord::SchemaDumper.fk_ignore_pattern.match?(name) if name
108
106
  end
109
107
 
110
- def defined_for?(to_table_ord = nil, to_table: nil, **options)
111
- if to_table_ord
112
- self.to_table == to_table_ord.to_s
113
- else
114
- (to_table.nil? || to_table.to_s == self.to_table) &&
115
- options.all? { |k, v| self.options[k].to_s == v.to_s }
116
- end
108
+ def defined_for?(to_table: nil, **options)
109
+ (to_table.nil? || to_table.to_s == self.to_table) &&
110
+ options.all? { |k, v| self.options[k].to_s == v.to_s }
117
111
  end
118
112
 
119
113
  private
@@ -200,41 +194,44 @@ module ActiveRecord
200
194
  end
201
195
 
202
196
  module ColumnMethods
197
+ extend ActiveSupport::Concern
198
+
203
199
  # Appends a primary key definition to the table definition.
204
200
  # Can be called multiple times, but this is probably not a good idea.
205
201
  def primary_key(name, type = :primary_key, **options)
206
202
  column(name, type, options.merge(primary_key: true))
207
203
  end
208
204
 
205
+ ##
206
+ # :method: column
207
+ # :call-seq: column(name, type, **options)
208
+ #
209
209
  # Appends a column or columns of a specified type.
210
210
  #
211
211
  # t.string(:goat)
212
212
  # t.string(:goat, :sheep)
213
213
  #
214
214
  # See TableDefinition#column
215
- [
216
- :bigint,
217
- :binary,
218
- :boolean,
219
- :date,
220
- :datetime,
221
- :decimal,
222
- :float,
223
- :integer,
224
- :json,
225
- :string,
226
- :text,
227
- :time,
228
- :timestamp,
229
- :virtual,
230
- ].each do |column_type|
231
- module_eval <<-CODE, __FILE__, __LINE__ + 1
232
- def #{column_type}(*args, **options)
233
- args.each { |name| column(name, :#{column_type}, options) }
215
+
216
+ included do
217
+ define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
218
+ :float, :integer, :json, :string, :text, :time, :timestamp, :virtual
219
+
220
+ alias :numeric :decimal
221
+ end
222
+
223
+ class_methods do
224
+ private def define_column_methods(*column_types) # :nodoc:
225
+ column_types.each do |column_type|
226
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
227
+ def #{column_type}(*names, **options)
228
+ raise ArgumentError, "Missing column name(s) for #{column_type}" if names.empty?
229
+ names.each { |name| column(name, :#{column_type}, options) }
230
+ end
231
+ RUBY
234
232
  end
235
- CODE
233
+ end
236
234
  end
237
- alias_method :numeric, :decimal
238
235
  end
239
236
 
240
237
  # Represents the schema of an SQL table in an abstract way. This class
@@ -259,10 +256,9 @@ module ActiveRecord
259
256
  include ColumnMethods
260
257
 
261
258
  attr_reader :name, :temporary, :if_not_exists, :options, :as, :comment, :indexes, :foreign_keys
262
- attr_writer :indexes
263
- deprecate :indexes=
264
259
 
265
260
  def initialize(
261
+ conn,
266
262
  name,
267
263
  temporary: false,
268
264
  if_not_exists: false,
@@ -271,6 +267,7 @@ module ActiveRecord
271
267
  comment: nil,
272
268
  **
273
269
  )
270
+ @conn = conn
274
271
  @columns_hash = {}
275
272
  @indexes = []
276
273
  @foreign_keys = []
@@ -363,7 +360,7 @@ module ActiveRecord
363
360
  # t.references :tagger, polymorphic: true
364
361
  # t.references :taggable, polymorphic: { default: 'Photo' }, index: false
365
362
  # end
366
- def column(name, type, options = {})
363
+ def column(name, type, **options)
367
364
  name = name.to_s
368
365
  type = type.to_sym if type
369
366
  options = options.dup
@@ -397,10 +394,7 @@ module ActiveRecord
397
394
  end
398
395
 
399
396
  def foreign_key(table_name, options = {}) # :nodoc:
400
- table_name_prefix = ActiveRecord::Base.table_name_prefix
401
- table_name_suffix = ActiveRecord::Base.table_name_suffix
402
- table_name = "#{table_name_prefix}#{table_name}#{table_name_suffix}"
403
- foreign_keys.push([table_name, options])
397
+ foreign_keys << [table_name, options]
404
398
  end
405
399
 
406
400
  # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
@@ -410,6 +404,10 @@ module ActiveRecord
410
404
  def timestamps(**options)
411
405
  options[:null] = false if options[:null].nil?
412
406
 
407
+ if !options.key?(:precision) && @conn.supports_datetime_with_precision?
408
+ options[:precision] = 6
409
+ end
410
+
413
411
  column(:created_at, :datetime, options)
414
412
  column(:updated_at, :datetime, options)
415
413
  end
@@ -418,6 +416,7 @@ module ActiveRecord
418
416
  #
419
417
  # t.references(:user)
420
418
  # t.belongs_to(:supplier, foreign_key: true)
419
+ # t.belongs_to(:supplier, foreign_key: true, type: :integer)
421
420
  #
422
421
  # See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
423
422
  def references(*args, **options)
@@ -517,6 +516,7 @@ module ActiveRecord
517
516
  # t.json
518
517
  # t.virtual
519
518
  # t.remove
519
+ # t.remove_foreign_key
520
520
  # t.remove_references
521
521
  # t.remove_belongs_to
522
522
  # t.remove_index
@@ -538,7 +538,7 @@ module ActiveRecord
538
538
  # t.column(:name, :string)
539
539
  #
540
540
  # See TableDefinition#column for details of the options you can use.
541
- def column(column_name, type, options = {})
541
+ def column(column_name, type, **options)
542
542
  index_options = options.delete(:index)
543
543
  @base.add_column(name, column_name, type, options)
544
544
  index(column_name, index_options.is_a?(Hash) ? index_options : {}) if index_options
@@ -680,15 +680,26 @@ module ActiveRecord
680
680
  end
681
681
  alias :remove_belongs_to :remove_references
682
682
 
683
- # Adds a foreign key.
683
+ # Adds a foreign key to the table using a supplied table name.
684
684
  #
685
685
  # t.foreign_key(:authors)
686
+ # t.foreign_key(:authors, column: :author_id, primary_key: "id")
686
687
  #
687
688
  # See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
688
689
  def foreign_key(*args)
689
690
  @base.add_foreign_key(name, *args)
690
691
  end
691
692
 
693
+ # Removes the given foreign key from the table.
694
+ #
695
+ # t.remove_foreign_key(:authors)
696
+ # t.remove_foreign_key(column: :author_id)
697
+ #
698
+ # See {connection.remove_foreign_key}[rdoc-ref:SchemaStatements#remove_foreign_key]
699
+ def remove_foreign_key(*args)
700
+ @base.remove_foreign_key(name, *args)
701
+ end
702
+
692
703
  # Checks to see if a foreign key exists.
693
704
  #
694
705
  # t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
@@ -15,7 +15,7 @@ module ActiveRecord
15
15
  def column_spec_for_primary_key(column)
16
16
  return {} if default_primary_key?(column)
17
17
  spec = { id: schema_type(column).inspect }
18
- spec.merge!(prepare_column_options(column).except!(:null))
18
+ spec.merge!(prepare_column_options(column).except!(:null, :comment))
19
19
  spec[:default] ||= "nil" if explicit_primary_key_default?(column)
20
20
  spec
21
21
  end
@@ -101,7 +101,7 @@ module ActiveRecord
101
101
  def index_exists?(table_name, column_name, options = {})
102
102
  column_names = Array(column_name).map(&:to_s)
103
103
  checks = []
104
- checks << lambda { |i| i.columns == column_names }
104
+ checks << lambda { |i| Array(i.columns) == column_names }
105
105
  checks << lambda { |i| i.unique } if options[:unique]
106
106
  checks << lambda { |i| i.name == options[:name].to_s } if options[:name]
107
107
 
@@ -130,11 +130,11 @@ module ActiveRecord
130
130
  # column_exists?(:suppliers, :name, :string, null: false)
131
131
  # column_exists?(:suppliers, :tax, :decimal, precision: 8, scale: 2)
132
132
  #
133
- def column_exists?(table_name, column_name, type = nil, options = {})
133
+ def column_exists?(table_name, column_name, type = nil, **options)
134
134
  column_name = column_name.to_s
135
135
  checks = []
136
136
  checks << lambda { |c| c.name == column_name }
137
- checks << lambda { |c| c.type == type } if type
137
+ checks << lambda { |c| c.type == type.to_sym rescue nil } if type
138
138
  column_options_keys.each do |attr|
139
139
  checks << lambda { |c| c.send(attr) == options[attr] } if options.key?(attr)
140
140
  end
@@ -302,7 +302,7 @@ module ActiveRecord
302
302
  if pk.is_a?(Array)
303
303
  td.primary_keys pk
304
304
  else
305
- td.primary_key pk, options.fetch(:id, :primary_key), options
305
+ td.primary_key pk, options.fetch(:id, :primary_key), options.except(:comment)
306
306
  end
307
307
  end
308
308
 
@@ -518,14 +518,15 @@ module ActiveRecord
518
518
  # Available options are (none of these exists by default):
519
519
  # * <tt>:limit</tt> -
520
520
  # Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column
521
- # and number of bytes for <tt>:text</tt>, <tt>:binary</tt> and <tt>:integer</tt> columns.
521
+ # and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, and <tt>:integer</tt> columns.
522
522
  # This option is ignored by some backends.
523
523
  # * <tt>:default</tt> -
524
524
  # The column's default value. Use +nil+ for +NULL+.
525
525
  # * <tt>:null</tt> -
526
526
  # Allows or disallows +NULL+ values in the column.
527
527
  # * <tt>:precision</tt> -
528
- # Specifies the precision for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
528
+ # Specifies the precision for the <tt>:decimal</tt>, <tt>:numeric</tt>,
529
+ # <tt>:datetime</tt>, and <tt>:time</tt> columns.
529
530
  # * <tt>:scale</tt> -
530
531
  # Specifies the scale for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
531
532
  # * <tt>:collation</tt> -
@@ -584,7 +585,7 @@ module ActiveRecord
584
585
  # # Defines a column with a database-specific type.
585
586
  # add_column(:shapes, :triangle, 'polygon')
586
587
  # # ALTER TABLE "shapes" ADD "triangle" polygon
587
- def add_column(table_name, column_name, type, options = {})
588
+ def add_column(table_name, column_name, type, **options)
588
589
  at = create_alter_table table_name
589
590
  at.add_column(column_name, type, options)
590
591
  execute schema_creation.accept at
@@ -770,6 +771,17 @@ module ActiveRecord
770
771
  # CREATE FULLTEXT INDEX index_developers_on_name ON developers (name) -- MySQL
771
772
  #
772
773
  # Note: only supported by MySQL.
774
+ #
775
+ # ====== Creating an index with a specific algorithm
776
+ #
777
+ # add_index(:developers, :name, algorithm: :concurrently)
778
+ # # CREATE INDEX CONCURRENTLY developers_on_name on developers (name)
779
+ #
780
+ # Note: only supported by PostgreSQL.
781
+ #
782
+ # Concurrently adding an index is not supported in a transaction.
783
+ #
784
+ # For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
773
785
  def add_index(table_name, column_name, options = {})
774
786
  index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options)
775
787
  execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options}"
@@ -793,6 +805,15 @@ module ActiveRecord
793
805
  #
794
806
  # remove_index :accounts, name: :by_branch_party
795
807
  #
808
+ # Removes the index named +by_branch_party+ in the +accounts+ table +concurrently+.
809
+ #
810
+ # remove_index :accounts, name: :by_branch_party, algorithm: :concurrently
811
+ #
812
+ # Note: only supported by PostgreSQL.
813
+ #
814
+ # Concurrently removing an index is not supported in a transaction.
815
+ #
816
+ # For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
796
817
  def remove_index(table_name, options = {})
797
818
  index_name = index_name_for_remove(table_name, options)
798
819
  execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
@@ -852,7 +873,7 @@ module ActiveRecord
852
873
  # [<tt>:null</tt>]
853
874
  # Whether the column allows nulls. Defaults to true.
854
875
  #
855
- # ====== Create a user_id bigint column without a index
876
+ # ====== Create a user_id bigint column without an index
856
877
  #
857
878
  # add_reference(:products, :user, index: false)
858
879
  #
@@ -966,7 +987,7 @@ module ActiveRecord
966
987
  # [<tt>:on_update</tt>]
967
988
  # Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
968
989
  # [<tt>:validate</tt>]
969
- # (Postgres only) Specify whether or not the constraint should be validated. Defaults to +true+.
990
+ # (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
970
991
  def add_foreign_key(from_table, to_table, options = {})
971
992
  return unless supports_foreign_keys?
972
993
 
@@ -1002,10 +1023,10 @@ module ActiveRecord
1002
1023
  # with an addition of
1003
1024
  # [<tt>:to_table</tt>]
1004
1025
  # The name of the table that contains the referenced primary key.
1005
- def remove_foreign_key(from_table, options_or_to_table = {})
1026
+ def remove_foreign_key(from_table, to_table = nil, **options)
1006
1027
  return unless supports_foreign_keys?
1007
1028
 
1008
- fk_name_to_delete = foreign_key_for!(from_table, options_or_to_table).name
1029
+ fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
1009
1030
 
1010
1031
  at = create_alter_table from_table
1011
1032
  at.drop_foreign_key fk_name_to_delete
@@ -1024,14 +1045,12 @@ module ActiveRecord
1024
1045
  # # Checks to see if a foreign key with a custom name exists.
1025
1046
  # foreign_key_exists?(:accounts, name: "special_fk_name")
1026
1047
  #
1027
- def foreign_key_exists?(from_table, options_or_to_table = {})
1028
- foreign_key_for(from_table, options_or_to_table).present?
1048
+ def foreign_key_exists?(from_table, to_table = nil, **options)
1049
+ foreign_key_for(from_table, to_table: to_table, **options).present?
1029
1050
  end
1030
1051
 
1031
1052
  def foreign_key_column_for(table_name) # :nodoc:
1032
- prefix = Base.table_name_prefix
1033
- suffix = Base.table_name_suffix
1034
- name = table_name.to_s =~ /#{prefix}(.+)#{suffix}/ ? $1 : table_name.to_s
1053
+ name = strip_table_name_prefix_and_suffix(table_name)
1035
1054
  "#{name.singularize}_id"
1036
1055
  end
1037
1056
 
@@ -1042,8 +1061,8 @@ module ActiveRecord
1042
1061
  options
1043
1062
  end
1044
1063
 
1045
- def dump_schema_information #:nodoc:
1046
- versions = ActiveRecord::SchemaMigration.all_versions
1064
+ def dump_schema_information # :nodoc:
1065
+ versions = schema_migration.all_versions
1047
1066
  insert_versions_sql(versions) if versions.any?
1048
1067
  end
1049
1068
 
@@ -1053,13 +1072,13 @@ module ActiveRecord
1053
1072
 
1054
1073
  def assume_migrated_upto_version(version, migrations_paths = nil)
1055
1074
  unless migrations_paths.nil?
1056
- ActiveSupport::Deprecation.warn(<<~MSG)
1075
+ ActiveSupport::Deprecation.warn(<<~MSG.squish)
1057
1076
  Passing migrations_paths to #assume_migrated_upto_version is deprecated and will be removed in Rails 6.1.
1058
1077
  MSG
1059
1078
  end
1060
1079
 
1061
1080
  version = version.to_i
1062
- sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name)
1081
+ sm_table = quote_table_name(schema_migration.table_name)
1063
1082
 
1064
1083
  migrated = migration_context.get_all_versions
1065
1084
  versions = migration_context.migrations.map(&:version)
@@ -1099,7 +1118,7 @@ module ActiveRecord
1099
1118
  if (0..6) === precision
1100
1119
  column_type_sql << "(#{precision})"
1101
1120
  else
1102
- raise(ActiveRecordError, "No #{native[:name]} type has precision of #{precision}. The allowed range of precision is from 0 to 6")
1121
+ raise ArgumentError, "No #{native[:name]} type has precision of #{precision}. The allowed range of precision is from 0 to 6"
1103
1122
  end
1104
1123
  elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
1105
1124
  column_type_sql << "(#{limit})"
@@ -1129,6 +1148,10 @@ module ActiveRecord
1129
1148
  def add_timestamps(table_name, options = {})
1130
1149
  options[:null] = false if options[:null].nil?
1131
1150
 
1151
+ if !options.key?(:precision) && supports_datetime_with_precision?
1152
+ options[:precision] = 6
1153
+ end
1154
+
1132
1155
  add_column table_name, :created_at, :datetime, options
1133
1156
  add_column table_name, :updated_at, :datetime, options
1134
1157
  end
@@ -1183,12 +1206,22 @@ module ActiveRecord
1183
1206
  end
1184
1207
 
1185
1208
  # Changes the comment for a table or removes it if +nil+.
1186
- def change_table_comment(table_name, comment)
1209
+ #
1210
+ # Passing a hash containing +:from+ and +:to+ will make this change
1211
+ # reversible in migration:
1212
+ #
1213
+ # change_table_comment(:posts, from: "old_comment", to: "new_comment")
1214
+ def change_table_comment(table_name, comment_or_changes)
1187
1215
  raise NotImplementedError, "#{self.class} does not support changing table comments"
1188
1216
  end
1189
1217
 
1190
1218
  # Changes the comment for a column or removes it if +nil+.
1191
- def change_column_comment(table_name, column_name, comment)
1219
+ #
1220
+ # Passing a hash containing +:from+ and +:to+ will make this change
1221
+ # reversible in migration:
1222
+ #
1223
+ # change_column_comment(:posts, :state, from: "old_comment", to: "new_comment")
1224
+ def change_column_comment(table_name, column_name, comment_or_changes)
1192
1225
  raise NotImplementedError, "#{self.class} does not support changing column comments"
1193
1226
  end
1194
1227
 
@@ -1290,7 +1323,7 @@ module ActiveRecord
1290
1323
  end
1291
1324
 
1292
1325
  def create_table_definition(*args)
1293
- TableDefinition.new(*args)
1326
+ TableDefinition.new(self, *args)
1294
1327
  end
1295
1328
 
1296
1329
  def create_alter_table(name)
@@ -1324,6 +1357,12 @@ module ActiveRecord
1324
1357
  { column: column_names }
1325
1358
  end
1326
1359
 
1360
+ def strip_table_name_prefix_and_suffix(table_name)
1361
+ prefix = Base.table_name_prefix
1362
+ suffix = Base.table_name_suffix
1363
+ table_name.to_s =~ /#{prefix}(.+)#{suffix}/ ? $1 : table_name.to_s
1364
+ end
1365
+
1327
1366
  def foreign_key_name(table_name, options)
1328
1367
  options.fetch(:name) do
1329
1368
  identifier = "#{table_name}_#{options.fetch(:column)}_fk"
@@ -1333,14 +1372,14 @@ module ActiveRecord
1333
1372
  end
1334
1373
  end
1335
1374
 
1336
- def foreign_key_for(from_table, options_or_to_table = {})
1375
+ def foreign_key_for(from_table, **options)
1337
1376
  return unless supports_foreign_keys?
1338
- foreign_keys(from_table).detect { |fk| fk.defined_for? options_or_to_table }
1377
+ foreign_keys(from_table).detect { |fk| fk.defined_for?(options) }
1339
1378
  end
1340
1379
 
1341
- def foreign_key_for!(from_table, options_or_to_table = {})
1342
- foreign_key_for(from_table, options_or_to_table) || \
1343
- raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{options_or_to_table}")
1380
+ def foreign_key_for!(from_table, to_table: nil, **options)
1381
+ foreign_key_for(from_table, to_table: to_table, **options) ||
1382
+ raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{to_table || options}")
1344
1383
  end
1345
1384
 
1346
1385
  def extract_foreign_key_action(specifier)
@@ -1366,11 +1405,37 @@ module ActiveRecord
1366
1405
  default_or_changes
1367
1406
  end
1368
1407
  end
1408
+ alias :extract_new_comment_value :extract_new_default_value
1369
1409
 
1370
1410
  def can_remove_index_by_name?(options)
1371
1411
  options.is_a?(Hash) && options.key?(:name) && options.except(:name, :algorithm).empty?
1372
1412
  end
1373
1413
 
1414
+ def bulk_change_table(table_name, operations)
1415
+ sql_fragments = []
1416
+ non_combinable_operations = []
1417
+
1418
+ operations.each do |command, args|
1419
+ table, arguments = args.shift, args
1420
+ method = :"#{command}_for_alter"
1421
+
1422
+ if respond_to?(method, true)
1423
+ sqls, procs = Array(send(method, table, *arguments)).partition { |v| v.is_a?(String) }
1424
+ sql_fragments << sqls
1425
+ non_combinable_operations.concat(procs)
1426
+ else
1427
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
1428
+ non_combinable_operations.each(&:call)
1429
+ sql_fragments = []
1430
+ non_combinable_operations = []
1431
+ send(command, table, *arguments)
1432
+ end
1433
+ end
1434
+
1435
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
1436
+ non_combinable_operations.each(&:call)
1437
+ end
1438
+
1374
1439
  def add_column_for_alter(table_name, column_name, type, options = {})
1375
1440
  td = create_table_definition(table_name)
1376
1441
  cd = td.new_column_definition(column_name, type, options)
@@ -1386,7 +1451,7 @@ module ActiveRecord
1386
1451
  end
1387
1452
 
1388
1453
  def insert_versions_sql(versions)
1389
- sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name)
1454
+ sm_table = quote_table_name(schema_migration.table_name)
1390
1455
 
1391
1456
  if versions.is_a?(Array)
1392
1457
  sql = +"INSERT INTO #{sm_table} (version) VALUES\n"