activerecord 6.0.5.1 → 6.1.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (243) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1163 -774
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/active_record/aggregations.rb +5 -5
  6. data/lib/active_record/association_relation.rb +30 -12
  7. data/lib/active_record/associations/alias_tracker.rb +19 -15
  8. data/lib/active_record/associations/association.rb +49 -26
  9. data/lib/active_record/associations/association_scope.rb +18 -20
  10. data/lib/active_record/associations/belongs_to_association.rb +23 -10
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
  12. data/lib/active_record/associations/builder/association.rb +32 -5
  13. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
  16. data/lib/active_record/associations/builder/has_many.rb +6 -2
  17. data/lib/active_record/associations/builder/has_one.rb +11 -14
  18. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  19. data/lib/active_record/associations/collection_association.rb +32 -18
  20. data/lib/active_record/associations/collection_proxy.rb +12 -5
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -2
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  24. data/lib/active_record/associations/has_one_association.rb +15 -1
  25. data/lib/active_record/associations/join_dependency/join_association.rb +37 -21
  26. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +63 -49
  28. data/lib/active_record/associations/preloader/association.rb +14 -8
  29. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  30. data/lib/active_record/associations/preloader.rb +5 -3
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations.rb +118 -11
  33. data/lib/active_record/attribute_assignment.rb +10 -8
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  35. data/lib/active_record/attribute_methods/dirty.rb +1 -11
  36. data/lib/active_record/attribute_methods/primary_key.rb +6 -2
  37. data/lib/active_record/attribute_methods/query.rb +3 -6
  38. data/lib/active_record/attribute_methods/read.rb +8 -11
  39. data/lib/active_record/attribute_methods/serialization.rb +11 -5
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
  41. data/lib/active_record/attribute_methods/write.rb +12 -20
  42. data/lib/active_record/attribute_methods.rb +64 -54
  43. data/lib/active_record/attributes.rb +33 -8
  44. data/lib/active_record/autosave_association.rb +47 -30
  45. data/lib/active_record/base.rb +2 -14
  46. data/lib/active_record/callbacks.rb +152 -22
  47. data/lib/active_record/coders/yaml_column.rb +16 -6
  48. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
  49. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -23
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -8
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -35
  53. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +114 -26
  56. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +228 -83
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +92 -33
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +52 -76
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
  61. data/lib/active_record/connection_adapters/column.rb +15 -1
  62. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  63. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +24 -24
  65. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
  67. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
  68. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  69. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
  70. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -4
  71. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
  73. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  74. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  75. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  76. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +14 -53
  77. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  78. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  79. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  80. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  86. data/lib/active_record/connection_adapters/postgresql/quoting.rb +30 -4
  87. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  88. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  89. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  90. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  91. data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -64
  92. data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
  93. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  94. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +32 -5
  95. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  96. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  97. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
  98. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
  99. data/lib/active_record/connection_adapters.rb +52 -0
  100. data/lib/active_record/connection_handling.rb +218 -71
  101. data/lib/active_record/core.rb +265 -64
  102. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  103. data/lib/active_record/database_configurations/database_config.rb +52 -9
  104. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  105. data/lib/active_record/database_configurations/url_config.rb +15 -40
  106. data/lib/active_record/database_configurations.rb +125 -85
  107. data/lib/active_record/delegated_type.rb +209 -0
  108. data/lib/active_record/destroy_association_async_job.rb +36 -0
  109. data/lib/active_record/enum.rb +69 -34
  110. data/lib/active_record/errors.rb +47 -12
  111. data/lib/active_record/explain.rb +9 -4
  112. data/lib/active_record/explain_subscriber.rb +1 -1
  113. data/lib/active_record/fixture_set/file.rb +10 -17
  114. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  115. data/lib/active_record/fixture_set/render_context.rb +1 -1
  116. data/lib/active_record/fixture_set/table_row.rb +2 -2
  117. data/lib/active_record/fixtures.rb +58 -9
  118. data/lib/active_record/gem_version.rb +3 -3
  119. data/lib/active_record/inheritance.rb +40 -18
  120. data/lib/active_record/insert_all.rb +38 -5
  121. data/lib/active_record/integration.rb +3 -5
  122. data/lib/active_record/internal_metadata.rb +18 -7
  123. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  124. data/lib/active_record/locking/optimistic.rb +24 -17
  125. data/lib/active_record/locking/pessimistic.rb +6 -2
  126. data/lib/active_record/log_subscriber.rb +27 -8
  127. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  128. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  129. data/lib/active_record/middleware/database_selector.rb +4 -1
  130. data/lib/active_record/migration/command_recorder.rb +47 -27
  131. data/lib/active_record/migration/compatibility.rb +72 -18
  132. data/lib/active_record/migration.rb +114 -84
  133. data/lib/active_record/model_schema.rb +89 -14
  134. data/lib/active_record/nested_attributes.rb +2 -3
  135. data/lib/active_record/no_touching.rb +1 -1
  136. data/lib/active_record/persistence.rb +50 -45
  137. data/lib/active_record/query_cache.rb +15 -5
  138. data/lib/active_record/querying.rb +11 -6
  139. data/lib/active_record/railtie.rb +61 -59
  140. data/lib/active_record/railties/console_sandbox.rb +2 -4
  141. data/lib/active_record/railties/databases.rake +279 -101
  142. data/lib/active_record/readonly_attributes.rb +4 -0
  143. data/lib/active_record/reflection.rb +60 -44
  144. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  145. data/lib/active_record/relation/batches.rb +38 -31
  146. data/lib/active_record/relation/calculations.rb +104 -43
  147. data/lib/active_record/relation/finder_methods.rb +44 -14
  148. data/lib/active_record/relation/from_clause.rb +1 -1
  149. data/lib/active_record/relation/merger.rb +20 -23
  150. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  151. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  152. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  153. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  154. data/lib/active_record/relation/predicate_builder.rb +61 -38
  155. data/lib/active_record/relation/query_methods.rb +324 -196
  156. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  157. data/lib/active_record/relation/spawn_methods.rb +8 -7
  158. data/lib/active_record/relation/where_clause.rb +111 -61
  159. data/lib/active_record/relation.rb +100 -81
  160. data/lib/active_record/result.rb +41 -33
  161. data/lib/active_record/runtime_registry.rb +2 -2
  162. data/lib/active_record/sanitization.rb +6 -17
  163. data/lib/active_record/schema_dumper.rb +34 -4
  164. data/lib/active_record/schema_migration.rb +2 -8
  165. data/lib/active_record/scoping/default.rb +1 -3
  166. data/lib/active_record/scoping/named.rb +1 -17
  167. data/lib/active_record/secure_token.rb +16 -8
  168. data/lib/active_record/serialization.rb +5 -3
  169. data/lib/active_record/signed_id.rb +116 -0
  170. data/lib/active_record/statement_cache.rb +20 -4
  171. data/lib/active_record/store.rb +8 -3
  172. data/lib/active_record/suppressor.rb +2 -2
  173. data/lib/active_record/table_metadata.rb +42 -51
  174. data/lib/active_record/tasks/database_tasks.rb +140 -113
  175. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  176. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  177. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  178. data/lib/active_record/test_databases.rb +5 -4
  179. data/lib/active_record/test_fixtures.rb +79 -31
  180. data/lib/active_record/timestamp.rb +4 -6
  181. data/lib/active_record/touch_later.rb +21 -21
  182. data/lib/active_record/transactions.rb +19 -66
  183. data/lib/active_record/type/serialized.rb +6 -2
  184. data/lib/active_record/type.rb +8 -1
  185. data/lib/active_record/type_caster/connection.rb +0 -1
  186. data/lib/active_record/type_caster/map.rb +8 -5
  187. data/lib/active_record/validations/associated.rb +1 -1
  188. data/lib/active_record/validations/numericality.rb +35 -0
  189. data/lib/active_record/validations/uniqueness.rb +24 -4
  190. data/lib/active_record/validations.rb +1 -0
  191. data/lib/active_record.rb +7 -14
  192. data/lib/arel/attributes/attribute.rb +4 -0
  193. data/lib/arel/collectors/bind.rb +5 -0
  194. data/lib/arel/collectors/composite.rb +8 -0
  195. data/lib/arel/collectors/sql_string.rb +7 -0
  196. data/lib/arel/collectors/substitute_binds.rb +7 -0
  197. data/lib/arel/nodes/binary.rb +82 -8
  198. data/lib/arel/nodes/bind_param.rb +8 -0
  199. data/lib/arel/nodes/casted.rb +21 -9
  200. data/lib/arel/nodes/equality.rb +6 -9
  201. data/lib/arel/nodes/grouping.rb +3 -0
  202. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  203. data/lib/arel/nodes/in.rb +8 -1
  204. data/lib/arel/nodes/infix_operation.rb +13 -1
  205. data/lib/arel/nodes/join_source.rb +1 -1
  206. data/lib/arel/nodes/node.rb +7 -6
  207. data/lib/arel/nodes/ordering.rb +27 -0
  208. data/lib/arel/nodes/sql_literal.rb +3 -0
  209. data/lib/arel/nodes/table_alias.rb +7 -3
  210. data/lib/arel/nodes/unary.rb +0 -1
  211. data/lib/arel/nodes.rb +3 -1
  212. data/lib/arel/predications.rb +12 -18
  213. data/lib/arel/select_manager.rb +1 -2
  214. data/lib/arel/table.rb +13 -5
  215. data/lib/arel/visitors/dot.rb +14 -2
  216. data/lib/arel/visitors/mysql.rb +11 -1
  217. data/lib/arel/visitors/postgresql.rb +15 -4
  218. data/lib/arel/visitors/to_sql.rb +89 -78
  219. data/lib/arel/visitors.rb +0 -7
  220. data/lib/arel.rb +5 -13
  221. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  222. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  223. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  224. data/lib/rails/generators/active_record/migration.rb +6 -1
  225. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  226. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  227. metadata +24 -25
  228. data/lib/active_record/advisory_lock_base.rb +0 -18
  229. data/lib/active_record/attribute_decorators.rb +0 -88
  230. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  231. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  232. data/lib/active_record/define_callbacks.rb +0 -22
  233. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  234. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  235. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  236. data/lib/arel/attributes.rb +0 -22
  237. data/lib/arel/visitors/depth_first.rb +0 -203
  238. data/lib/arel/visitors/ibm_db.rb +0 -34
  239. data/lib/arel/visitors/informix.rb +0 -62
  240. data/lib/arel/visitors/mssql.rb +0 -156
  241. data/lib/arel/visitors/oracle.rb +0 -158
  242. data/lib/arel/visitors/oracle12.rb +0 -65
  243. data/lib/arel/visitors/where_sql.rb +0 -22
@@ -7,7 +7,7 @@ module ActiveRecord
7
7
  :order, :joins, :left_outer_joins, :references,
8
8
  :extending, :unscope, :optimizer_hints, :annotate]
9
9
 
10
- SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
10
+ SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering, :strict_loading,
11
11
  :reverse_order, :distinct, :create_with, :skip_query_cache]
12
12
 
13
13
  CLAUSE_METHODS = [:where, :having, :from]
@@ -28,7 +28,6 @@ module ActiveRecord
28
28
  @klass = klass
29
29
  @table = table
30
30
  @values = values
31
- @offsets = {}
32
31
  @loaded = false
33
32
  @predicate_builder = predicate_builder
34
33
  @delegate_to_klass = false
@@ -40,8 +39,9 @@ module ActiveRecord
40
39
  end
41
40
 
42
41
  def arel_attribute(name) # :nodoc:
43
- klass.arel_attribute(name, table)
42
+ table[name]
44
43
  end
44
+ deprecate :arel_attribute
45
45
 
46
46
  def bind_attribute(name, value) # :nodoc:
47
47
  if reflection = klass._reflect_on_association(name)
@@ -49,7 +49,7 @@ module ActiveRecord
49
49
  value = value.read_attribute(reflection.klass.primary_key) unless value.nil?
50
50
  end
51
51
 
52
- attr = arel_attribute(name)
52
+ attr = table[name]
53
53
  bind = predicate_builder.build_bind_attribute(attr.name, value)
54
54
  yield attr, bind
55
55
  end
@@ -67,10 +67,9 @@ module ActiveRecord
67
67
  # user = users.new { |user| user.name = 'Oscar' }
68
68
  # user.name # => Oscar
69
69
  def new(attributes = nil, &block)
70
- block = _deprecated_scope_block("new", &block)
71
- scoping { klass.new(attributes, &block) }
70
+ block = current_scope_restoring_block(&block)
71
+ scoping { _new(attributes, &block) }
72
72
  end
73
-
74
73
  alias build new
75
74
 
76
75
  # Tries to create a new record with the same scoped attributes
@@ -96,8 +95,8 @@ module ActiveRecord
96
95
  if attributes.is_a?(Array)
97
96
  attributes.collect { |attr| create(attr, &block) }
98
97
  else
99
- block = _deprecated_scope_block("create", &block)
100
- scoping { klass.create(attributes, &block) }
98
+ block = current_scope_restoring_block(&block)
99
+ scoping { _create(attributes, &block) }
101
100
  end
102
101
  end
103
102
 
@@ -111,8 +110,8 @@ module ActiveRecord
111
110
  if attributes.is_a?(Array)
112
111
  attributes.collect { |attr| create!(attr, &block) }
113
112
  else
114
- block = _deprecated_scope_block("create!", &block)
115
- scoping { klass.create!(attributes, &block) }
113
+ block = current_scope_restoring_block(&block)
114
+ scoping { _create!(attributes, &block) }
116
115
  end
117
116
  end
118
117
 
@@ -308,7 +307,7 @@ module ActiveRecord
308
307
  # last updated record.
309
308
  #
310
309
  # Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
311
- def cache_key(timestamp_column = :updated_at)
310
+ def cache_key(timestamp_column = "updated_at")
312
311
  @cache_keys ||= {}
313
312
  @cache_keys[timestamp_column] ||= klass.collection_cache_key(self, timestamp_column)
314
313
  end
@@ -317,7 +316,7 @@ module ActiveRecord
317
316
  query_signature = ActiveSupport::Digest.hexdigest(to_sql)
318
317
  key = "#{klass.model_name.cache_key}/query-#{query_signature}"
319
318
 
320
- if cache_version(timestamp_column)
319
+ if collection_cache_versioning
321
320
  key
322
321
  else
323
322
  "#{key}-#{compute_cache_version(timestamp_column)}"
@@ -343,15 +342,17 @@ module ActiveRecord
343
342
  end
344
343
 
345
344
  def compute_cache_version(timestamp_column) # :nodoc:
345
+ timestamp_column = timestamp_column.to_s
346
+
346
347
  if loaded? || distinct_value
347
348
  size = records.size
348
349
  if size > 0
349
- timestamp = max_by(&timestamp_column)._read_attribute(timestamp_column)
350
+ timestamp = records.map { |record| record.read_attribute(timestamp_column) }.max
350
351
  end
351
352
  else
352
353
  collection = eager_loading? ? apply_join_dependency : self
353
354
 
354
- column = connection.visitor.compile(arel_attribute(timestamp_column))
355
+ column = connection.visitor.compile(table[timestamp_column])
355
356
  select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
356
357
 
357
358
  if collection.has_limit_or_offset?
@@ -365,14 +366,12 @@ module ActiveRecord
365
366
  arel = query.arel
366
367
  end
367
368
 
368
- result = connection.select_one(arel, nil)
369
+ size, timestamp = connection.select_rows(arel, nil).first
369
370
 
370
- if result
371
+ if size
371
372
  column_type = klass.type_for_attribute(timestamp_column)
372
- timestamp = column_type.deserialize(result["timestamp"])
373
- size = result["size"]
373
+ timestamp = column_type.deserialize(timestamp)
374
374
  else
375
- timestamp = nil
376
375
  size = 0
377
376
  end
378
377
  end
@@ -407,9 +406,9 @@ module ActiveRecord
407
406
  already_in_scope? ? yield : _scoping(self) { yield }
408
407
  end
409
408
 
410
- def _exec_scope(name, *args, &block) # :nodoc:
409
+ def _exec_scope(*args, &block) # :nodoc:
411
410
  @delegate_to_klass = true
412
- _scoping(_deprecated_spawn(name)) { instance_exec(*args, &block) || self }
411
+ _scoping(nil) { instance_exec(*args, &block) || self }
413
412
  ensure
414
413
  @delegate_to_klass = false
415
414
  end
@@ -417,7 +416,7 @@ module ActiveRecord
417
416
  # Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
418
417
  # statement and sends it straight to the database. It does not instantiate the involved models and it does not
419
418
  # trigger Active Record callbacks or validations. However, values passed to #update_all will still go through
420
- # Active Record's normal type casting and serialization.
419
+ # Active Record's normal type casting and serialization. Returns the number of rows affected.
421
420
  #
422
421
  # Note: As Active Record callbacks are not triggered, this method will not automatically update +updated_at+/+updated_on+ columns.
423
422
  #
@@ -441,14 +440,12 @@ module ActiveRecord
441
440
  def update_all(updates)
442
441
  raise ArgumentError, "Empty list of attributes to change" if updates.blank?
443
442
 
444
- if eager_loading?
445
- relation = apply_join_dependency
446
- return relation.update_all(updates)
447
- end
443
+ arel = eager_loading? ? apply_join_dependency.arel : build_arel
444
+ arel.source.left = table
448
445
 
449
446
  stmt = Arel::UpdateManager.new
450
- stmt.table(arel.join_sources.empty? ? table : arel.source)
451
- stmt.key = arel_attribute(primary_key)
447
+ stmt.table(arel.source)
448
+ stmt.key = table[primary_key]
452
449
  stmt.take(arel.limit)
453
450
  stmt.offset(arel.offset)
454
451
  stmt.order(*arel.orders)
@@ -458,7 +455,7 @@ module ActiveRecord
458
455
  if klass.locking_enabled? &&
459
456
  !updates.key?(klass.locking_column) &&
460
457
  !updates.key?(klass.locking_column.to_sym)
461
- attr = arel_attribute(klass.locking_column)
458
+ attr = table[klass.locking_column]
462
459
  updates[attr.name] = _increment_attribute(attr)
463
460
  end
464
461
  stmt.set _substitute_values(updates)
@@ -466,7 +463,7 @@ module ActiveRecord
466
463
  stmt.set Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
467
464
  end
468
465
 
469
- @klass.connection.update stmt, "#{@klass} Update All"
466
+ klass.connection.update(stmt, "#{klass} Update All").tap { reset }
470
467
  end
471
468
 
472
469
  def update(id = :all, attributes) # :nodoc:
@@ -477,12 +474,24 @@ module ActiveRecord
477
474
  end
478
475
  end
479
476
 
480
- def update_counters(counters) # :nodoc:
477
+ # Updates the counters of the records in the current relation.
478
+ #
479
+ # ==== Parameters
480
+ #
481
+ # * +counter+ - A Hash containing the names of the fields to update as keys and the amount to update as values.
482
+ # * <tt>:touch</tt> option - Touch the timestamp columns when updating.
483
+ # * If attributes names are passed, they are updated along with update_at/on attributes.
484
+ #
485
+ # ==== Examples
486
+ #
487
+ # # For Posts by a given author increment the comment_count by 1.
488
+ # Post.where(author_id: author.id).update_counters(comment_count: 1)
489
+ def update_counters(counters)
481
490
  touch = counters.delete(:touch)
482
491
 
483
492
  updates = {}
484
493
  counters.each do |counter_name, value|
485
- attr = arel_attribute(counter_name)
494
+ attr = table[counter_name]
486
495
  updates[attr.name] = _increment_attribute(attr, value)
487
496
  end
488
497
 
@@ -571,23 +580,18 @@ module ActiveRecord
571
580
  raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
572
581
  end
573
582
 
574
- if eager_loading?
575
- relation = apply_join_dependency
576
- return relation.delete_all
577
- end
583
+ arel = eager_loading? ? apply_join_dependency.arel : build_arel
584
+ arel.source.left = table
578
585
 
579
586
  stmt = Arel::DeleteManager.new
580
- stmt.from(arel.join_sources.empty? ? table : arel.source)
581
- stmt.key = arel_attribute(primary_key)
587
+ stmt.from(arel.source)
588
+ stmt.key = table[primary_key]
582
589
  stmt.take(arel.limit)
583
590
  stmt.offset(arel.offset)
584
591
  stmt.order(*arel.orders)
585
592
  stmt.wheres = arel.constraints
586
593
 
587
- affected = @klass.connection.delete(stmt, "#{@klass} Destroy")
588
-
589
- reset
590
- affected
594
+ klass.connection.delete(stmt, "#{klass} Destroy").tap { reset }
591
595
  end
592
596
 
593
597
  # Finds and destroys all records matching the specified conditions.
@@ -623,7 +627,10 @@ module ActiveRecord
623
627
  #
624
628
  # Post.where(published: true).load # => #<ActiveRecord::Relation>
625
629
  def load(&block)
626
- exec_queries(&block) unless loaded?
630
+ unless loaded?
631
+ @records = exec_queries(&block)
632
+ @loaded = true
633
+ end
627
634
 
628
635
  self
629
636
  end
@@ -636,11 +643,10 @@ module ActiveRecord
636
643
 
637
644
  def reset
638
645
  @delegate_to_klass = false
639
- @_deprecated_scope_source = nil
640
646
  @to_sql = @arel = @loaded = @should_eager_load = nil
647
+ @offsets = @take = nil
648
+ @cache_keys = nil
641
649
  @records = [].freeze
642
- @offsets = {}
643
- @take = nil
644
650
  self
645
651
  end
646
652
 
@@ -671,8 +677,7 @@ module ActiveRecord
671
677
  end
672
678
 
673
679
  def scope_for_create
674
- hash = where_values_hash
675
- hash.delete(klass.inheritance_column) if klass.finder_needs_type_condition?
680
+ hash = where_clause.to_h(klass.table_name, equality_only: true)
676
681
  create_with_value.each { |k, v| hash[k.to_s] = v } unless create_with_value.empty?
677
682
  hash
678
683
  end
@@ -718,7 +723,7 @@ module ActiveRecord
718
723
  end
719
724
 
720
725
  def inspect
721
- subject = loaded? ? records : self
726
+ subject = loaded? ? records : annotate("loading for inspect")
722
727
  entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
723
728
 
724
729
  entries[10] = "..." if entries.size == 11
@@ -735,25 +740,31 @@ module ActiveRecord
735
740
  end
736
741
 
737
742
  def alias_tracker(joins = [], aliases = nil) # :nodoc:
738
- joins += [aliases] if aliases
739
- ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins)
743
+ ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins, aliases)
744
+ end
745
+
746
+ class StrictLoadingScope # :nodoc:
747
+ def self.empty_scope?
748
+ true
749
+ end
750
+
751
+ def self.strict_loading_value
752
+ true
753
+ end
740
754
  end
741
755
 
742
756
  def preload_associations(records) # :nodoc:
743
757
  preload = preload_values
744
758
  preload += includes_values unless eager_loading?
745
759
  preloader = nil
760
+ scope = strict_loading_value ? StrictLoadingScope : nil
746
761
  preload.each do |associations|
747
762
  preloader ||= build_preloader
748
- preloader.preload records, associations
763
+ preloader.preload records, associations, scope
749
764
  end
750
765
  end
751
766
 
752
- attr_reader :_deprecated_scope_source # :nodoc:
753
-
754
767
  protected
755
- attr_writer :_deprecated_scope_source # :nodoc:
756
-
757
768
  def load_records(records)
758
769
  @records = records.freeze
759
770
  @loaded = true
@@ -765,23 +776,29 @@ module ActiveRecord
765
776
 
766
777
  private
767
778
  def already_in_scope?
768
- @delegate_to_klass && begin
769
- scope = klass.current_scope(true)
770
- scope && !scope._deprecated_scope_source
771
- end
779
+ @delegate_to_klass && klass.current_scope(true)
772
780
  end
773
781
 
774
- def _deprecated_spawn(name)
775
- spawn.tap { |scope| scope._deprecated_scope_source = name }
776
- end
777
-
778
- def _deprecated_scope_block(name, &block)
782
+ def current_scope_restoring_block(&block)
783
+ current_scope = klass.current_scope(true)
779
784
  -> record do
780
- klass.current_scope = _deprecated_spawn(name)
785
+ klass.current_scope = current_scope
781
786
  yield record if block_given?
782
787
  end
783
788
  end
784
789
 
790
+ def _new(attributes, &block)
791
+ klass.new(attributes, &block)
792
+ end
793
+
794
+ def _create(attributes, &block)
795
+ klass.create(attributes, &block)
796
+ end
797
+
798
+ def _create!(attributes, &block)
799
+ klass.create!(attributes, &block)
800
+ end
801
+
785
802
  def _scoping(scope)
786
803
  previous, klass.current_scope = klass.current_scope(true), scope
787
804
  yield
@@ -791,7 +808,7 @@ module ActiveRecord
791
808
 
792
809
  def _substitute_values(values)
793
810
  values.map do |name, value|
794
- attr = arel_attribute(name)
811
+ attr = table[name]
795
812
  unless Arel.arel_node?(value)
796
813
  type = klass.type_for_attribute(attr.name)
797
814
  value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
@@ -809,27 +826,29 @@ module ActiveRecord
809
826
 
810
827
  def exec_queries(&block)
811
828
  skip_query_cache_if_necessary do
812
- @records =
813
- if eager_loading?
829
+ records =
830
+ if where_clause.contradiction?
831
+ []
832
+ elsif eager_loading?
814
833
  apply_join_dependency do |relation, join_dependency|
815
834
  if relation.null_relation?
816
835
  []
817
836
  else
818
837
  relation = join_dependency.apply_column_aliases(relation)
819
838
  rows = connection.select_all(relation.arel, "SQL")
820
- join_dependency.instantiate(rows, &block)
839
+ join_dependency.instantiate(rows, strict_loading_value, &block)
821
840
  end.freeze
822
841
  end
823
842
  else
824
843
  klass.find_by_sql(arel, &block).freeze
825
844
  end
826
845
 
827
- preload_associations(@records) unless skip_preloading_value
846
+ preload_associations(records) unless skip_preloading_value
828
847
 
829
- @records.each(&:readonly!) if readonly_value
848
+ records.each(&:readonly!) if readonly_value
849
+ records.each(&:strict_loading!) if strict_loading_value
830
850
 
831
- @loaded = true
832
- @records
851
+ records
833
852
  end
834
853
  end
835
854
 
@@ -848,27 +867,27 @@ module ActiveRecord
848
867
  end
849
868
 
850
869
  def references_eager_loaded_tables?
851
- joined_tables = arel.join_sources.map do |join|
870
+ joined_tables = build_joins([]).flat_map do |join|
852
871
  if join.is_a?(Arel::Nodes::StringJoin)
853
872
  tables_in_string(join.left)
854
873
  else
855
- [join.left.table_name, join.left.table_alias]
874
+ join.left.name
856
875
  end
857
876
  end
858
877
 
859
- joined_tables += [table.name, table.table_alias]
878
+ joined_tables << table.name
860
879
 
861
880
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
862
- joined_tables = joined_tables.flatten.compact.map(&:downcase).uniq
881
+ joined_tables.map!(&:downcase)
863
882
 
864
- (references_values - joined_tables).any?
883
+ !(references_values.map(&:to_s) - joined_tables).empty?
865
884
  end
866
885
 
867
886
  def tables_in_string(string)
868
887
  return [] if string.blank?
869
888
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
870
889
  # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
871
- string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ["raw_sql_"]
890
+ string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
872
891
  end
873
892
  end
874
893
  end
@@ -65,16 +65,10 @@ module ActiveRecord
65
65
  end
66
66
  end
67
67
 
68
- def to_hash
69
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
70
- `ActiveRecord::Result#to_hash` has been renamed to `to_a`.
71
- `to_hash` is deprecated and will be removed in Rails 6.1.
72
- MSG
73
- to_a
74
- end
75
-
76
68
  alias :map! :map
77
69
  alias :collect! :map
70
+ deprecate "map!": :map
71
+ deprecate "collect!": :map
78
72
 
79
73
  # Returns true if there are no records, otherwise false.
80
74
  def empty?
@@ -92,31 +86,30 @@ module ActiveRecord
92
86
  hash_rows[idx]
93
87
  end
94
88
 
95
- # Returns the first record from the rows collection.
96
- # If the rows collection is empty, returns +nil+.
97
- def first
98
- return nil if @rows.empty?
99
- Hash[@columns.zip(@rows.first)]
100
- end
101
-
102
89
  # Returns the last record from the rows collection.
103
- # If the rows collection is empty, returns +nil+.
104
- def last
105
- return nil if @rows.empty?
106
- Hash[@columns.zip(@rows.last)]
90
+ def last(n = nil)
91
+ n ? hash_rows.last(n) : hash_rows.last
107
92
  end
108
93
 
109
94
  def cast_values(type_overrides = {}) # :nodoc:
110
95
  if columns.one?
111
96
  # Separated to avoid allocating an array per row
112
97
 
113
- type = column_type(columns.first, type_overrides)
98
+ type = if type_overrides.is_a?(Array)
99
+ type_overrides.first
100
+ else
101
+ column_type(columns.first, type_overrides)
102
+ end
114
103
 
115
104
  rows.map do |(value)|
116
105
  type.deserialize(value)
117
106
  end
118
107
  else
119
- types = columns.map { |name| column_type(name, type_overrides) }
108
+ types = if type_overrides.is_a?(Array)
109
+ type_overrides
110
+ else
111
+ columns.map { |name| column_type(name, type_overrides) }
112
+ end
120
113
 
121
114
  rows.map do |values|
122
115
  Array.new(values.size) { |i| types[i].deserialize(values[i]) }
@@ -145,21 +138,36 @@ module ActiveRecord
145
138
  # used as keys in ActiveRecord::Base's @attributes hash
146
139
  columns = @columns.map(&:-@)
147
140
  length = columns.length
141
+ template = nil
148
142
 
149
143
  @rows.map { |row|
150
- # In the past we used Hash[columns.zip(row)]
151
- # though elegant, the verbose way is much more efficient
152
- # both time and memory wise cause it avoids a big array allocation
153
- # this method is called a lot and needs to be micro optimised
154
- hash = {}
155
-
156
- index = 0
157
- while index < length
158
- hash[columns[index]] = row[index]
159
- index += 1
144
+ if template
145
+ # We use transform_values to build subsequent rows from the
146
+ # hash of the first row. This is faster because we avoid any
147
+ # reallocs and in Ruby 2.7+ avoid hashing entirely.
148
+ index = -1
149
+ template.transform_values do
150
+ row[index += 1]
151
+ end
152
+ else
153
+ # In the past we used Hash[columns.zip(row)]
154
+ # though elegant, the verbose way is much more efficient
155
+ # both time and memory wise cause it avoids a big array allocation
156
+ # this method is called a lot and needs to be micro optimised
157
+ hash = {}
158
+
159
+ index = 0
160
+ while index < length
161
+ hash[columns[index]] = row[index]
162
+ index += 1
163
+ end
164
+
165
+ # It's possible to select the same column twice, in which case
166
+ # we can't use a template
167
+ template = hash if hash.length == length
168
+
169
+ hash
160
170
  end
161
-
162
- hash
163
171
  }
164
172
  end
165
173
  end
@@ -14,9 +14,9 @@ module ActiveRecord
14
14
  class RuntimeRegistry # :nodoc:
15
15
  extend ActiveSupport::PerThreadRegistry
16
16
 
17
- attr_accessor :connection_handler, :sql_runtime
17
+ attr_accessor :sql_runtime
18
18
 
19
- [:connection_handler, :sql_runtime].each do |val|
19
+ [:sql_runtime].each do |val|
20
20
  class_eval %{ def self.#{val}; instance.#{val}; end }, __FILE__, __LINE__
21
21
  class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
22
22
  end
@@ -67,7 +67,7 @@ module ActiveRecord
67
67
  )
68
68
 
69
69
  # Ensure we aren't dealing with a subclass of String that might
70
- # override methods we use (eg. Arel::Nodes::SqlLiteral).
70
+ # override methods we use (e.g. Arel::Nodes::SqlLiteral).
71
71
  if condition.first.kind_of?(String) && !condition.first.instance_of?(String)
72
72
  condition = [String.new(condition.first), *condition[1..-1]]
73
73
  end
@@ -141,19 +141,7 @@ module ActiveRecord
141
141
  (unexpected ||= []) << arg
142
142
  end
143
143
 
144
- return unless unexpected
145
-
146
- if allow_unsafe_raw_sql == :deprecated
147
- ActiveSupport::Deprecation.warn(
148
- "Dangerous query method (method whose arguments are used as raw " \
149
- "SQL) called with non-attribute argument(s): " \
150
- "#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \
151
- "arguments will be disallowed in Rails 6.1. This method should " \
152
- "not be called with user-provided values, such as request " \
153
- "parameters or model attributes. Known-safe values can be passed " \
154
- "by wrapping them in Arel.sql()."
155
- )
156
- else
144
+ if unexpected
157
145
  raise(ActiveRecord::UnknownAttributeReference,
158
146
  "Query method called with non-attribute argument(s): " +
159
147
  unexpected.map(&:inspect).join(", ")
@@ -193,13 +181,14 @@ module ActiveRecord
193
181
 
194
182
  def quote_bound_value(value, c = connection)
195
183
  if value.respond_to?(:map) && !value.acts_like?(:string)
196
- quoted = value.map { |v| c.quote(v) }
197
- if quoted.empty?
184
+ values = value.map { |v| v.respond_to?(:id_for_database) ? v.id_for_database : v }
185
+ if values.empty?
198
186
  c.quote(nil)
199
187
  else
200
- quoted.join(",")
188
+ values.map! { |v| c.quote(v) }.join(",")
201
189
  end
202
190
  else
191
+ value = value.id_for_database if value.respond_to?(:id_for_database)
203
192
  c.quote(value)
204
193
  end
205
194
  end
@@ -23,6 +23,12 @@ module ActiveRecord
23
23
  # should not be dumped to db/schema.rb.
24
24
  cattr_accessor :fk_ignore_pattern, default: /^fk_rails_[0-9a-f]{10}$/
25
25
 
26
+ ##
27
+ # :singleton-method:
28
+ # Specify a custom regular expression matching check constraints which name
29
+ # should not be dumped to db/schema.rb.
30
+ cattr_accessor :chk_ignore_pattern, default: /^chk_rails_[0-9a-f]{10}$/
31
+
26
32
  class << self
27
33
  def dump(connection = ActiveRecord::Base.connection, stream = STDOUT, config = ActiveRecord::Base)
28
34
  connection.create_schema_dumper(generate_options(config)).dump(stream)
@@ -72,8 +78,8 @@ module ActiveRecord
72
78
  # of editing this file, please use the migrations feature of Active Record to
73
79
  # incrementally modify your database, and then regenerate this schema definition.
74
80
  #
75
- # This file is the source Rails uses to define your schema when running `rails
76
- # db:schema:load`. When creating a new database, `rails db:schema:load` tends to
81
+ # This file is the source Rails uses to define your schema when running `bin/rails
82
+ # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
77
83
  # be faster and is potentially less error prone than running all of your
78
84
  # migrations from scratch. Old migrations may fail to apply correctly if those
79
85
  # migrations use external dependencies or application code.
@@ -125,7 +131,10 @@ HEADER
125
131
  tbl.print ", primary_key: #{pk.inspect}" unless pk == "id"
126
132
  pkcol = columns.detect { |c| c.name == pk }
127
133
  pkcolspec = column_spec_for_primary_key(pkcol)
128
- if pkcolspec.present?
134
+ unless pkcolspec.empty?
135
+ if pkcolspec != pkcolspec.slice(:id, :default)
136
+ pkcolspec = { id: { type: pkcolspec.delete(:id), **pkcolspec }.compact }
137
+ end
129
138
  tbl.print ", #{format_colspec(pkcolspec)}"
130
139
  end
131
140
  when Array
@@ -156,6 +165,7 @@ HEADER
156
165
  end
157
166
 
158
167
  indexes_in_create(table, tbl)
168
+ check_constraints_in_create(table, tbl) if @connection.supports_check_constraints?
159
169
 
160
170
  tbl.puts " end"
161
171
  tbl.puts
@@ -209,6 +219,24 @@ HEADER
209
219
  index_parts
210
220
  end
211
221
 
222
+ def check_constraints_in_create(table, stream)
223
+ if (check_constraints = @connection.check_constraints(table)).any?
224
+ add_check_constraint_statements = check_constraints.map do |check_constraint|
225
+ parts = [
226
+ "t.check_constraint #{check_constraint.expression.inspect}"
227
+ ]
228
+
229
+ if check_constraint.export_name_on_schema_dump?
230
+ parts << "name: #{check_constraint.name.inspect}"
231
+ end
232
+
233
+ " #{parts.join(', ')}"
234
+ end
235
+
236
+ stream.puts add_check_constraint_statements.sort.join("\n")
237
+ end
238
+ end
239
+
212
240
  def foreign_keys(table, stream)
213
241
  if (foreign_keys = @connection.foreign_keys(table)).any?
214
242
  add_foreign_key_statements = foreign_keys.map do |foreign_key|
@@ -240,7 +268,9 @@ HEADER
240
268
  end
241
269
 
242
270
  def format_colspec(colspec)
243
- colspec.map { |key, value| "#{key}: #{value}" }.join(", ")
271
+ colspec.map do |key, value|
272
+ "#{key}: #{ value.is_a?(Hash) ? "{ #{format_colspec(value)} }" : value }"
273
+ end.join(", ")
244
274
  end
245
275
 
246
276
  def format_options(options)