activerecord 6.0.3.4 → 6.1.0.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 (244) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +776 -722
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/active_record.rb +7 -14
  6. data/lib/active_record/aggregations.rb +1 -1
  7. data/lib/active_record/association_relation.rb +22 -14
  8. data/lib/active_record/associations.rb +114 -11
  9. data/lib/active_record/associations/alias_tracker.rb +19 -15
  10. data/lib/active_record/associations/association.rb +40 -29
  11. data/lib/active_record/associations/association_scope.rb +17 -15
  12. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  14. data/lib/active_record/associations/builder/association.rb +9 -3
  15. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  16. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
  18. data/lib/active_record/associations/builder/has_many.rb +6 -2
  19. data/lib/active_record/associations/builder/has_one.rb +11 -14
  20. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  21. data/lib/active_record/associations/collection_association.rb +19 -6
  22. data/lib/active_record/associations/collection_proxy.rb +13 -5
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +24 -2
  25. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  26. data/lib/active_record/associations/has_one_association.rb +15 -1
  27. data/lib/active_record/associations/join_dependency.rb +72 -50
  28. data/lib/active_record/associations/join_dependency/join_association.rb +36 -14
  29. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  30. data/lib/active_record/associations/preloader.rb +11 -5
  31. data/lib/active_record/associations/preloader/association.rb +51 -25
  32. data/lib/active_record/associations/preloader/through_association.rb +2 -2
  33. data/lib/active_record/associations/singular_association.rb +1 -1
  34. data/lib/active_record/associations/through_association.rb +1 -1
  35. data/lib/active_record/attribute_assignment.rb +10 -8
  36. data/lib/active_record/attribute_methods.rb +52 -48
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  38. data/lib/active_record/attribute_methods/dirty.rb +1 -11
  39. data/lib/active_record/attribute_methods/primary_key.rb +6 -2
  40. data/lib/active_record/attribute_methods/query.rb +3 -6
  41. data/lib/active_record/attribute_methods/read.rb +8 -11
  42. data/lib/active_record/attribute_methods/serialization.rb +4 -4
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
  44. data/lib/active_record/attribute_methods/write.rb +12 -20
  45. data/lib/active_record/attributes.rb +27 -7
  46. data/lib/active_record/autosave_association.rb +57 -40
  47. data/lib/active_record/base.rb +2 -14
  48. data/lib/active_record/callbacks.rb +32 -22
  49. data/lib/active_record/coders/yaml_column.rb +1 -1
  50. data/lib/active_record/connection_adapters.rb +50 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +186 -134
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +112 -27
  59. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  60. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -24
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +36 -69
  63. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +129 -88
  64. data/lib/active_record/connection_adapters/column.rb +15 -1
  65. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  66. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  67. data/lib/active_record/connection_adapters/mysql/database_statements.rb +23 -25
  68. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
  69. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  70. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +33 -6
  71. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  72. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  73. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +11 -7
  74. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  75. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
  76. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  77. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  78. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  79. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +13 -54
  80. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  82. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  83. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -5
  89. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  90. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  91. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  92. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  93. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  94. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  95. data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
  96. data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
  97. data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
  98. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +31 -6
  99. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  100. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  101. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +37 -4
  102. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +49 -50
  103. data/lib/active_record/connection_handling.rb +210 -71
  104. data/lib/active_record/core.rb +220 -55
  105. data/lib/active_record/database_configurations.rb +124 -85
  106. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  107. data/lib/active_record/database_configurations/database_config.rb +52 -9
  108. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  109. data/lib/active_record/database_configurations/url_config.rb +15 -40
  110. data/lib/active_record/delegated_type.rb +209 -0
  111. data/lib/active_record/destroy_association_async_job.rb +36 -0
  112. data/lib/active_record/enum.rb +27 -10
  113. data/lib/active_record/errors.rb +47 -12
  114. data/lib/active_record/explain.rb +9 -4
  115. data/lib/active_record/explain_subscriber.rb +1 -1
  116. data/lib/active_record/fixture_set/file.rb +10 -17
  117. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  118. data/lib/active_record/fixture_set/render_context.rb +1 -1
  119. data/lib/active_record/fixture_set/table_row.rb +2 -2
  120. data/lib/active_record/fixtures.rb +54 -8
  121. data/lib/active_record/gem_version.rb +3 -3
  122. data/lib/active_record/inheritance.rb +40 -18
  123. data/lib/active_record/insert_all.rb +33 -6
  124. data/lib/active_record/integration.rb +3 -5
  125. data/lib/active_record/internal_metadata.rb +15 -4
  126. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  127. data/lib/active_record/locking/optimistic.rb +22 -16
  128. data/lib/active_record/locking/pessimistic.rb +6 -2
  129. data/lib/active_record/log_subscriber.rb +26 -8
  130. data/lib/active_record/middleware/database_selector.rb +4 -1
  131. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  132. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  133. data/lib/active_record/migration.rb +113 -83
  134. data/lib/active_record/migration/command_recorder.rb +47 -27
  135. data/lib/active_record/migration/compatibility.rb +67 -17
  136. data/lib/active_record/model_schema.rb +88 -13
  137. data/lib/active_record/nested_attributes.rb +2 -3
  138. data/lib/active_record/no_touching.rb +1 -1
  139. data/lib/active_record/persistence.rb +50 -45
  140. data/lib/active_record/query_cache.rb +15 -5
  141. data/lib/active_record/querying.rb +11 -6
  142. data/lib/active_record/railtie.rb +64 -44
  143. data/lib/active_record/railties/databases.rake +253 -98
  144. data/lib/active_record/readonly_attributes.rb +4 -0
  145. data/lib/active_record/reflection.rb +70 -57
  146. data/lib/active_record/relation.rb +96 -67
  147. data/lib/active_record/relation/batches.rb +38 -31
  148. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  149. data/lib/active_record/relation/calculations.rb +101 -44
  150. data/lib/active_record/relation/delegation.rb +2 -1
  151. data/lib/active_record/relation/finder_methods.rb +45 -15
  152. data/lib/active_record/relation/from_clause.rb +1 -1
  153. data/lib/active_record/relation/merger.rb +27 -25
  154. data/lib/active_record/relation/predicate_builder.rb +57 -33
  155. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  156. data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -2
  157. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
  158. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  159. data/lib/active_record/relation/query_methods.rb +330 -195
  160. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  161. data/lib/active_record/relation/spawn_methods.rb +6 -5
  162. data/lib/active_record/relation/where_clause.rb +104 -57
  163. data/lib/active_record/result.rb +41 -33
  164. data/lib/active_record/runtime_registry.rb +2 -2
  165. data/lib/active_record/sanitization.rb +6 -17
  166. data/lib/active_record/schema_dumper.rb +34 -4
  167. data/lib/active_record/schema_migration.rb +0 -4
  168. data/lib/active_record/scoping/named.rb +6 -17
  169. data/lib/active_record/secure_token.rb +16 -8
  170. data/lib/active_record/serialization.rb +5 -3
  171. data/lib/active_record/signed_id.rb +116 -0
  172. data/lib/active_record/statement_cache.rb +20 -4
  173. data/lib/active_record/store.rb +2 -2
  174. data/lib/active_record/suppressor.rb +2 -2
  175. data/lib/active_record/table_metadata.rb +36 -52
  176. data/lib/active_record/tasks/database_tasks.rb +139 -113
  177. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  178. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  179. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  180. data/lib/active_record/test_databases.rb +5 -4
  181. data/lib/active_record/test_fixtures.rb +37 -16
  182. data/lib/active_record/timestamp.rb +4 -6
  183. data/lib/active_record/touch_later.rb +21 -21
  184. data/lib/active_record/transactions.rb +15 -64
  185. data/lib/active_record/type.rb +8 -1
  186. data/lib/active_record/type/serialized.rb +6 -2
  187. data/lib/active_record/type/time.rb +10 -0
  188. data/lib/active_record/type_caster/connection.rb +0 -1
  189. data/lib/active_record/type_caster/map.rb +8 -5
  190. data/lib/active_record/validations.rb +1 -0
  191. data/lib/active_record/validations/numericality.rb +35 -0
  192. data/lib/active_record/validations/uniqueness.rb +24 -4
  193. data/lib/arel.rb +5 -13
  194. data/lib/arel/attributes/attribute.rb +4 -0
  195. data/lib/arel/collectors/bind.rb +5 -0
  196. data/lib/arel/collectors/composite.rb +8 -0
  197. data/lib/arel/collectors/sql_string.rb +7 -0
  198. data/lib/arel/collectors/substitute_binds.rb +7 -0
  199. data/lib/arel/nodes.rb +3 -1
  200. data/lib/arel/nodes/binary.rb +82 -8
  201. data/lib/arel/nodes/bind_param.rb +8 -0
  202. data/lib/arel/nodes/casted.rb +21 -9
  203. data/lib/arel/nodes/equality.rb +6 -9
  204. data/lib/arel/nodes/grouping.rb +3 -0
  205. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  206. data/lib/arel/nodes/in.rb +8 -1
  207. data/lib/arel/nodes/infix_operation.rb +13 -1
  208. data/lib/arel/nodes/join_source.rb +1 -1
  209. data/lib/arel/nodes/node.rb +7 -6
  210. data/lib/arel/nodes/ordering.rb +27 -0
  211. data/lib/arel/nodes/sql_literal.rb +3 -0
  212. data/lib/arel/nodes/table_alias.rb +7 -3
  213. data/lib/arel/nodes/unary.rb +0 -1
  214. data/lib/arel/predications.rb +12 -18
  215. data/lib/arel/select_manager.rb +1 -2
  216. data/lib/arel/table.rb +13 -5
  217. data/lib/arel/visitors.rb +0 -7
  218. data/lib/arel/visitors/dot.rb +14 -2
  219. data/lib/arel/visitors/mysql.rb +11 -1
  220. data/lib/arel/visitors/postgresql.rb +15 -4
  221. data/lib/arel/visitors/to_sql.rb +89 -78
  222. data/lib/rails/generators/active_record/migration.rb +6 -1
  223. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  224. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  225. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  226. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  227. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  228. metadata +29 -30
  229. data/lib/active_record/advisory_lock_base.rb +0 -18
  230. data/lib/active_record/attribute_decorators.rb +0 -88
  231. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  232. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  233. data/lib/active_record/define_callbacks.rb +0 -22
  234. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  235. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  236. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  237. data/lib/arel/attributes.rb +0 -22
  238. data/lib/arel/visitors/depth_first.rb +0 -203
  239. data/lib/arel/visitors/ibm_db.rb +0 -34
  240. data/lib/arel/visitors/informix.rb +0 -62
  241. data/lib/arel/visitors/mssql.rb +0 -156
  242. data/lib/arel/visitors/oracle.rb +0 -158
  243. data/lib/arel/visitors/oracle12.rb +0 -65
  244. data/lib/arel/visitors/where_sql.rb +0 -22
@@ -8,6 +8,7 @@ module ActiveRecord
8
8
  #
9
9
  # * add_column
10
10
  # * add_foreign_key
11
+ # * add_check_constraint
11
12
  # * add_index
12
13
  # * add_reference
13
14
  # * add_timestamps
@@ -25,6 +26,7 @@ module ActiveRecord
25
26
  # * remove_column (must supply a type)
26
27
  # * remove_columns (must specify at least one column name or more)
27
28
  # * remove_foreign_key (must supply a second table)
29
+ # * remove_check_constraint
28
30
  # * remove_index
29
31
  # * remove_reference
30
32
  # * remove_timestamps
@@ -39,7 +41,8 @@ module ActiveRecord
39
41
  :drop_join_table, :drop_table, :execute_block, :enable_extension, :disable_extension,
40
42
  :change_column, :execute, :remove_columns, :change_column_null,
41
43
  :add_foreign_key, :remove_foreign_key,
42
- :change_column_comment, :change_table_comment
44
+ :change_column_comment, :change_table_comment,
45
+ :add_check_constraint, :remove_check_constraint
43
46
  ]
44
47
  include JoinTable
45
48
 
@@ -85,6 +88,11 @@ module ActiveRecord
85
88
  # recorder.inverse_of(:rename_table, [:old, :new])
86
89
  # # => [:rename_table, [:new, :old]]
87
90
  #
91
+ # If the inverse of a command requires several commands, returns array of commands.
92
+ #
93
+ # recorder.inverse_of(:remove_columns, [:some_table, :foo, :bar, type: :string])
94
+ # # => [[:add_column, :some_table, :foo, :string], [:add_column, :some_table, :bar, :string]]
95
+ #
88
96
  # This method will raise an +IrreversibleMigration+ exception if it cannot
89
97
  # invert the +command+.
90
98
  def inverse_of(command, args, &block)
@@ -127,9 +135,11 @@ module ActiveRecord
127
135
  create_table: :drop_table,
128
136
  create_join_table: :drop_join_table,
129
137
  add_column: :remove_column,
138
+ add_index: :remove_index,
130
139
  add_timestamps: :remove_timestamps,
131
140
  add_reference: :remove_reference,
132
141
  add_foreign_key: :remove_foreign_key,
142
+ add_check_constraint: :remove_check_constraint,
133
143
  enable_extension: :disable_extension
134
144
  }.each do |cmd, inv|
135
145
  [[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
@@ -171,44 +181,49 @@ module ActiveRecord
171
181
  super
172
182
  end
173
183
 
184
+ def invert_remove_columns(args)
185
+ unless args[-1].is_a?(Hash) && args[-1].has_key?(:type)
186
+ raise ActiveRecord::IrreversibleMigration, "remove_columns is only reversible if given a type."
187
+ end
188
+
189
+ [:add_columns, args]
190
+ end
191
+
174
192
  def invert_rename_index(args)
175
- [:rename_index, [args.first] + args.last(2).reverse]
193
+ table_name, old_name, new_name = args
194
+ [:rename_index, [table_name, new_name, old_name]]
176
195
  end
177
196
 
178
197
  def invert_rename_column(args)
179
- [:rename_column, [args.first] + args.last(2).reverse]
198
+ table_name, old_name, new_name = args
199
+ [:rename_column, [table_name, new_name, old_name]]
180
200
  end
181
201
 
182
- def invert_add_index(args)
183
- table, columns, options = *args
184
- options ||= {}
185
-
186
- options_hash = options.slice(:name, :algorithm)
187
- options_hash[:column] = columns if !options_hash[:name]
202
+ def invert_remove_index(args)
203
+ options = args.extract_options!
204
+ table, columns = args
188
205
 
189
- [:remove_index, [table, options_hash]]
190
- end
206
+ columns ||= options.delete(:column)
191
207
 
192
- def invert_remove_index(args)
193
- table, options_or_column = *args
194
- if (options = options_or_column).is_a?(Hash)
195
- unless options[:column]
196
- raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
197
- end
198
- options = options.dup
199
- [:add_index, [table, options.delete(:column), options]]
200
- elsif (column = options_or_column).present?
201
- [:add_index, [table, column]]
208
+ unless columns
209
+ raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
202
210
  end
211
+
212
+ options.delete(:if_exists)
213
+
214
+ args = [table, columns]
215
+ args << options unless options.empty?
216
+
217
+ [:add_index, args]
203
218
  end
204
219
 
205
220
  alias :invert_add_belongs_to :invert_add_reference
206
221
  alias :invert_remove_belongs_to :invert_remove_reference
207
222
 
208
223
  def invert_change_column_default(args)
209
- table, column, options = *args
224
+ table, column, options = args
210
225
 
211
- unless options && options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
226
+ unless options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
212
227
  raise ActiveRecord::IrreversibleMigration, "change_column_default is only reversible if given a :from and :to option."
213
228
  end
214
229
 
@@ -235,9 +250,9 @@ module ActiveRecord
235
250
  end
236
251
 
237
252
  def invert_change_column_comment(args)
238
- table, column, options = *args
253
+ table, column, options = args
239
254
 
240
- unless options && options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
255
+ unless options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
241
256
  raise ActiveRecord::IrreversibleMigration, "change_column_comment is only reversible if given a :from and :to option."
242
257
  end
243
258
 
@@ -245,15 +260,20 @@ module ActiveRecord
245
260
  end
246
261
 
247
262
  def invert_change_table_comment(args)
248
- table, options = *args
263
+ table, options = args
249
264
 
250
- unless options && options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
265
+ unless options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
251
266
  raise ActiveRecord::IrreversibleMigration, "change_table_comment is only reversible if given a :from and :to option."
252
267
  end
253
268
 
254
269
  [:change_table_comment, [table, from: options[:to], to: options[:from]]]
255
270
  end
256
271
 
272
+ def invert_remove_check_constraint(args)
273
+ raise ActiveRecord::IrreversibleMigration, "remove_check_constraint is only reversible if given an expression." if args.size < 2
274
+ super
275
+ end
276
+
257
277
  def respond_to_missing?(method, _)
258
278
  super || delegate.respond_to?(method)
259
279
  end
@@ -13,7 +13,61 @@ module ActiveRecord
13
13
  const_get(name)
14
14
  end
15
15
 
16
- V6_0 = Current
16
+ V6_1 = Current
17
+
18
+ class V6_0 < V6_1
19
+ class ReferenceDefinition < ConnectionAdapters::ReferenceDefinition
20
+ def index_options(table_name)
21
+ as_options(index)
22
+ end
23
+ end
24
+
25
+ module TableDefinition
26
+ def references(*args, **options)
27
+ args.each do |ref_name|
28
+ ReferenceDefinition.new(ref_name, **options).add_to(self)
29
+ end
30
+ end
31
+ alias :belongs_to :references
32
+ end
33
+
34
+ def create_table(table_name, **options)
35
+ if block_given?
36
+ super { |t| yield compatible_table_definition(t) }
37
+ else
38
+ super
39
+ end
40
+ end
41
+
42
+ def change_table(table_name, **options)
43
+ if block_given?
44
+ super { |t| yield compatible_table_definition(t) }
45
+ else
46
+ super
47
+ end
48
+ end
49
+
50
+ def create_join_table(table_1, table_2, **options)
51
+ if block_given?
52
+ super { |t| yield compatible_table_definition(t) }
53
+ else
54
+ super
55
+ end
56
+ end
57
+
58
+ def add_reference(table_name, ref_name, **options)
59
+ ReferenceDefinition.new(ref_name, **options).add_to(update_table_definition(table_name, self))
60
+ end
61
+ alias :add_belongs_to :add_reference
62
+
63
+ private
64
+ def compatible_table_definition(t)
65
+ class << t
66
+ prepend TableDefinition
67
+ end
68
+ t
69
+ end
70
+ end
17
71
 
18
72
  class V5_2 < V6_0
19
73
  module TableDefinition
@@ -29,13 +83,11 @@ module ActiveRecord
29
83
  end
30
84
 
31
85
  def invert_change_column_comment(args)
32
- table_name, column_name, comment = args
33
- [:change_column_comment, [table_name, column_name, from: comment, to: comment]]
86
+ [:change_column_comment, args]
34
87
  end
35
88
 
36
89
  def invert_change_table_comment(args)
37
- table_name, comment = args
38
- [:change_table_comment, [table_name, from: comment, to: comment]]
90
+ [:change_table_comment, args]
39
91
  end
40
92
  end
41
93
 
@@ -86,9 +138,9 @@ module ActiveRecord
86
138
  end
87
139
 
88
140
  class V5_1 < V5_2
89
- def change_column(table_name, column_name, type, options = {})
141
+ def change_column(table_name, column_name, type, **options)
90
142
  if connection.adapter_name == "PostgreSQL"
91
- super(table_name, column_name, type, options.except(:default, :null, :comment))
143
+ super(table_name, column_name, type, **options.except(:default, :null, :comment))
92
144
  connection.change_column_default(table_name, column_name, options[:default]) if options.key?(:default)
93
145
  connection.change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
94
146
  connection.change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
@@ -194,7 +246,7 @@ module ActiveRecord
194
246
  super
195
247
  end
196
248
 
197
- def index_exists?(table_name, column_name, options = {})
249
+ def index_exists?(table_name, column_name, **options)
198
250
  column_names = Array(column_name).map(&:to_s)
199
251
  options[:name] =
200
252
  if options[:name].present?
@@ -205,10 +257,9 @@ module ActiveRecord
205
257
  super
206
258
  end
207
259
 
208
- def remove_index(table_name, options = {})
209
- options = { column: options } unless options.is_a?(Hash)
210
- options[:name] = index_name_for_remove(table_name, options)
211
- super(table_name, options)
260
+ def remove_index(table_name, column_name = nil, **options)
261
+ options[:name] = index_name_for_remove(table_name, column_name, options)
262
+ super
212
263
  end
213
264
 
214
265
  private
@@ -219,13 +270,12 @@ module ActiveRecord
219
270
  super
220
271
  end
221
272
 
222
- def index_name_for_remove(table_name, options = {})
223
- index_name = connection.index_name(table_name, options)
273
+ def index_name_for_remove(table_name, column_name, options)
274
+ index_name = connection.index_name(table_name, column_name || options)
224
275
 
225
276
  unless connection.index_name_exists?(table_name, index_name)
226
- if options.is_a?(Hash) && options.has_key?(:name)
227
- options_without_column = options.dup
228
- options_without_column.delete :column
277
+ if options.key?(:name)
278
+ options_without_column = options.except(:column)
229
279
  index_name_without_column = connection.index_name(table_name, options_without_column)
230
280
 
231
281
  if connection.index_name_exists?(table_name, index_name_without_column)
@@ -115,8 +115,17 @@ module ActiveRecord
115
115
  #
116
116
  # Sets the column to sort records by when no explicit order clause is used
117
117
  # during an ordered finder call. Useful when the primary key is not an
118
- # auto-incrementing integer, for example when it's a UUID. Note that using
119
- # a non-unique column can result in non-deterministic results.
118
+ # auto-incrementing integer, for example when it's a UUID. Records are subsorted
119
+ # by the primary key if it exists to ensure deterministic results.
120
+
121
+ ##
122
+ # :singleton-method: immutable_strings_by_default=
123
+ # :call-seq: immutable_strings_by_default=(bool)
124
+ #
125
+ # Determines whether columns should infer their type as `:string` or
126
+ # `:immutable_string`. This setting does not affect the behavior of
127
+ # `attribute :foo, :string`. Defaults to false.
128
+
120
129
  included do
121
130
  mattr_accessor :primary_key_prefix_type, instance_writer: false
122
131
 
@@ -126,12 +135,13 @@ module ActiveRecord
126
135
  class_attribute :internal_metadata_table_name, instance_accessor: false, default: "ar_internal_metadata"
127
136
  class_attribute :pluralize_table_names, instance_writer: false, default: true
128
137
  class_attribute :implicit_order_column, instance_accessor: false
138
+ class_attribute :immutable_strings_by_default, instance_accessor: false
129
139
 
130
140
  self.protected_environments = ["production"]
131
141
  self.inheritance_column = "type"
132
142
  self.ignored_columns = [].freeze
133
143
 
134
- delegate :type_for_attribute, to: :class
144
+ delegate :type_for_attribute, :column_for_attribute, to: :class
135
145
 
136
146
  initialize_load_schema_monitor
137
147
  end
@@ -288,7 +298,8 @@ module ActiveRecord
288
298
  # Sets the columns names the model should ignore. Ignored columns won't have attribute
289
299
  # accessors defined, and won't be referenced in SQL queries.
290
300
  def ignored_columns=(columns)
291
- @ignored_columns = columns.map(&:to_s)
301
+ reload_schema_from_cache
302
+ @ignored_columns = columns.map(&:to_s).freeze
292
303
  end
293
304
 
294
305
  def sequence_name
@@ -355,7 +366,7 @@ module ActiveRecord
355
366
 
356
367
  def columns
357
368
  load_schema
358
- @columns ||= columns_hash.values
369
+ @columns ||= columns_hash.values.freeze
359
370
  end
360
371
 
361
372
  def attribute_types # :nodoc:
@@ -380,6 +391,8 @@ module ActiveRecord
380
391
  # a string or a symbol.
381
392
  def type_for_attribute(attr_name, &block)
382
393
  attr_name = attr_name.to_s
394
+ attr_name = attribute_aliases[attr_name] || attr_name
395
+
383
396
  if block
384
397
  attribute_types.fetch(attr_name, &block)
385
398
  else
@@ -387,11 +400,31 @@ module ActiveRecord
387
400
  end
388
401
  end
389
402
 
403
+ # Returns the column object for the named attribute.
404
+ # Returns an +ActiveRecord::ConnectionAdapters::NullColumn+ if the
405
+ # named attribute does not exist.
406
+ #
407
+ # class Person < ActiveRecord::Base
408
+ # end
409
+ #
410
+ # person = Person.new
411
+ # person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
412
+ # # => #<ActiveRecord::ConnectionAdapters::Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
413
+ #
414
+ # person.column_for_attribute(:nothing)
415
+ # # => #<ActiveRecord::ConnectionAdapters::NullColumn:0xXXX @name=nil, @sql_type=nil, @cast_type=#<Type::Value>, ...>
416
+ def column_for_attribute(name)
417
+ name = name.to_s
418
+ columns_hash.fetch(name) do
419
+ ConnectionAdapters::NullColumn.new(name)
420
+ end
421
+ end
422
+
390
423
  # Returns a hash where the keys are column names and the values are
391
424
  # default values when instantiating the Active Record object for this table.
392
425
  def column_defaults
393
426
  load_schema
394
- @column_defaults ||= _default_attributes.deep_dup.to_hash
427
+ @column_defaults ||= _default_attributes.deep_dup.to_hash.freeze
395
428
  end
396
429
 
397
430
  def _default_attributes # :nodoc:
@@ -401,7 +434,7 @@ module ActiveRecord
401
434
 
402
435
  # Returns an array of column names as strings.
403
436
  def column_names
404
- @column_names ||= columns.map(&:name)
437
+ @column_names ||= columns.map(&:name).freeze
405
438
  end
406
439
 
407
440
  def symbol_column_to_string(name_symbol) # :nodoc:
@@ -415,9 +448,8 @@ module ActiveRecord
415
448
  @content_columns ||= columns.reject do |c|
416
449
  c.name == primary_key ||
417
450
  c.name == inheritance_column ||
418
- c.name.end_with?("_id") ||
419
- c.name.end_with?("_count")
420
- end
451
+ c.name.end_with?("_id", "_count")
452
+ end.freeze
421
453
  end
422
454
 
423
455
  # Resets all the cached information about columns, which will cause them
@@ -427,7 +459,7 @@ module ActiveRecord
427
459
  # when just after creating a table you want to populate it with some default
428
460
  # values, eg:
429
461
  #
430
- # class CreateJobLevels < ActiveRecord::Migration[5.0]
462
+ # class CreateJobLevels < ActiveRecord::Migration[6.0]
431
463
  # def up
432
464
  # create_table :job_levels do |t|
433
465
  # t.integer :id
@@ -485,11 +517,20 @@ module ActiveRecord
485
517
  end
486
518
 
487
519
  def load_schema!
488
- @columns_hash = connection.schema_cache.columns_hash(table_name).except(*ignored_columns)
520
+ unless table_name
521
+ raise ActiveRecord::TableNotSpecified, "#{self} has no table configured. Set one with #{self}.table_name="
522
+ end
523
+
524
+ columns_hash = connection.schema_cache.columns_hash(table_name)
525
+ columns_hash = columns_hash.except(*ignored_columns) unless ignored_columns.empty?
526
+ @columns_hash = columns_hash.freeze
489
527
  @columns_hash.each do |name, column|
528
+ type = connection.lookup_cast_type_from_column(column)
529
+ type = _convert_type_from_options(type)
530
+ warn_if_deprecated_type(column)
490
531
  define_attribute(
491
532
  name,
492
- connection.lookup_cast_type_from_column(column),
533
+ type,
493
534
  default: column.default,
494
535
  user_provided_default: false
495
536
  )
@@ -538,6 +579,40 @@ module ActiveRecord
538
579
  base_class.table_name
539
580
  end
540
581
  end
582
+
583
+ def _convert_type_from_options(type)
584
+ if immutable_strings_by_default && type.respond_to?(:to_immutable_string)
585
+ type.to_immutable_string
586
+ else
587
+ type
588
+ end
589
+ end
590
+
591
+ def warn_if_deprecated_type(column)
592
+ return if attributes_to_define_after_schema_loads.key?(column.name)
593
+ return unless column.respond_to?(:oid)
594
+
595
+ if column.array?
596
+ array_arguments = ", array: true"
597
+ else
598
+ array_arguments = ""
599
+ end
600
+
601
+ if column.sql_type.start_with?("interval")
602
+ precision_arguments = column.precision.presence && ", precision: #{column.precision}"
603
+ ActiveSupport::Deprecation.warn(<<~WARNING)
604
+ The behavior of the `:interval` type will be changing in Rails 6.2
605
+ to return an `ActiveSupport::Duration` object. If you'd like to keep
606
+ the old behavior, you can add this line to #{self.name} model:
607
+
608
+ attribute :#{column.name}, :string#{precision_arguments}#{array_arguments}
609
+
610
+ If you'd like the new behavior today, you can add this line:
611
+
612
+ attribute :#{column.name}, :interval#{precision_arguments}#{array_arguments}
613
+ WARNING
614
+ end
615
+ end
541
616
  end
542
617
  end
543
618
  end