activerecord 6.0.6 → 6.1.0

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 (242) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +783 -910
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -3
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +22 -14
  7. data/lib/active_record/associations/alias_tracker.rb +19 -15
  8. data/lib/active_record/associations/association.rb +43 -26
  9. data/lib/active_record/associations/association_scope.rb +11 -15
  10. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  12. data/lib/active_record/associations/builder/association.rb +9 -3
  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 +19 -13
  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 +29 -14
  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 +13 -5
  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 +114 -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 +32 -7
  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 +2 -24
  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 +65 -22
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  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 +110 -30
  56. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +49 -72
  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 +31 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -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 +1 -1
  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 +1 -1
  70. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
  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 +63 -0
  74. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  75. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  76. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -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/money.rb +2 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  88. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  91. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  92. data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
  93. data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
  94. data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
  95. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -5
  96. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  97. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  98. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
  99. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
  100. data/lib/active_record/connection_adapters.rb +50 -0
  101. data/lib/active_record/connection_handling.rb +210 -71
  102. data/lib/active_record/core.rb +223 -66
  103. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  104. data/lib/active_record/database_configurations/database_config.rb +52 -9
  105. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  106. data/lib/active_record/database_configurations/url_config.rb +15 -40
  107. data/lib/active_record/database_configurations.rb +124 -85
  108. data/lib/active_record/delegated_type.rb +209 -0
  109. data/lib/active_record/destroy_association_async_job.rb +36 -0
  110. data/lib/active_record/enum.rb +27 -10
  111. data/lib/active_record/errors.rb +47 -12
  112. data/lib/active_record/explain.rb +9 -4
  113. data/lib/active_record/explain_subscriber.rb +1 -1
  114. data/lib/active_record/fixture_set/file.rb +10 -17
  115. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  116. data/lib/active_record/fixture_set/render_context.rb +1 -1
  117. data/lib/active_record/fixture_set/table_row.rb +2 -2
  118. data/lib/active_record/fixtures.rb +54 -8
  119. data/lib/active_record/gem_version.rb +2 -2
  120. data/lib/active_record/inheritance.rb +40 -18
  121. data/lib/active_record/insert_all.rb +34 -5
  122. data/lib/active_record/integration.rb +3 -5
  123. data/lib/active_record/internal_metadata.rb +16 -7
  124. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  125. data/lib/active_record/locking/optimistic.rb +13 -16
  126. data/lib/active_record/locking/pessimistic.rb +6 -2
  127. data/lib/active_record/log_subscriber.rb +26 -8
  128. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  129. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  130. data/lib/active_record/middleware/database_selector.rb +4 -1
  131. data/lib/active_record/migration/command_recorder.rb +47 -27
  132. data/lib/active_record/migration/compatibility.rb +67 -17
  133. data/lib/active_record/migration.rb +113 -83
  134. data/lib/active_record/model_schema.rb +88 -13
  135. data/lib/active_record/nested_attributes.rb +2 -3
  136. data/lib/active_record/no_touching.rb +1 -1
  137. data/lib/active_record/persistence.rb +50 -45
  138. data/lib/active_record/query_cache.rb +15 -5
  139. data/lib/active_record/querying.rb +11 -6
  140. data/lib/active_record/railtie.rb +64 -44
  141. data/lib/active_record/railties/databases.rake +266 -95
  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 +100 -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 +3 -3
  153. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  154. data/lib/active_record/relation/predicate_builder.rb +57 -33
  155. data/lib/active_record/relation/query_methods.rb +318 -195
  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 +104 -57
  159. data/lib/active_record/relation.rb +90 -64
  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/named.rb +1 -17
  166. data/lib/active_record/secure_token.rb +16 -8
  167. data/lib/active_record/serialization.rb +5 -3
  168. data/lib/active_record/signed_id.rb +116 -0
  169. data/lib/active_record/statement_cache.rb +20 -4
  170. data/lib/active_record/store.rb +2 -2
  171. data/lib/active_record/suppressor.rb +2 -2
  172. data/lib/active_record/table_metadata.rb +39 -51
  173. data/lib/active_record/tasks/database_tasks.rb +139 -113
  174. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  175. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  176. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  177. data/lib/active_record/test_databases.rb +5 -4
  178. data/lib/active_record/test_fixtures.rb +36 -33
  179. data/lib/active_record/timestamp.rb +4 -6
  180. data/lib/active_record/touch_later.rb +21 -21
  181. data/lib/active_record/transactions.rb +15 -64
  182. data/lib/active_record/type/serialized.rb +6 -2
  183. data/lib/active_record/type.rb +8 -1
  184. data/lib/active_record/type_caster/connection.rb +0 -1
  185. data/lib/active_record/type_caster/map.rb +8 -5
  186. data/lib/active_record/validations/associated.rb +1 -1
  187. data/lib/active_record/validations/numericality.rb +35 -0
  188. data/lib/active_record/validations/uniqueness.rb +24 -4
  189. data/lib/active_record/validations.rb +1 -0
  190. data/lib/active_record.rb +7 -14
  191. data/lib/arel/attributes/attribute.rb +4 -0
  192. data/lib/arel/collectors/bind.rb +5 -0
  193. data/lib/arel/collectors/composite.rb +8 -0
  194. data/lib/arel/collectors/sql_string.rb +7 -0
  195. data/lib/arel/collectors/substitute_binds.rb +7 -0
  196. data/lib/arel/nodes/binary.rb +82 -8
  197. data/lib/arel/nodes/bind_param.rb +8 -0
  198. data/lib/arel/nodes/casted.rb +21 -9
  199. data/lib/arel/nodes/equality.rb +6 -9
  200. data/lib/arel/nodes/grouping.rb +3 -0
  201. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  202. data/lib/arel/nodes/in.rb +8 -1
  203. data/lib/arel/nodes/infix_operation.rb +13 -1
  204. data/lib/arel/nodes/join_source.rb +1 -1
  205. data/lib/arel/nodes/node.rb +7 -6
  206. data/lib/arel/nodes/ordering.rb +27 -0
  207. data/lib/arel/nodes/sql_literal.rb +3 -0
  208. data/lib/arel/nodes/table_alias.rb +7 -3
  209. data/lib/arel/nodes/unary.rb +0 -1
  210. data/lib/arel/nodes.rb +3 -1
  211. data/lib/arel/predications.rb +12 -18
  212. data/lib/arel/select_manager.rb +1 -2
  213. data/lib/arel/table.rb +13 -5
  214. data/lib/arel/visitors/dot.rb +14 -2
  215. data/lib/arel/visitors/mysql.rb +11 -1
  216. data/lib/arel/visitors/postgresql.rb +15 -4
  217. data/lib/arel/visitors/to_sql.rb +89 -78
  218. data/lib/arel/visitors.rb +0 -7
  219. data/lib/arel.rb +5 -13
  220. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  221. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  222. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  223. data/lib/rails/generators/active_record/migration.rb +6 -1
  224. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  225. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  226. metadata +28 -30
  227. data/lib/active_record/advisory_lock_base.rb +0 -18
  228. data/lib/active_record/attribute_decorators.rb +0 -88
  229. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  230. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  231. data/lib/active_record/define_callbacks.rb +0 -22
  232. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  233. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  234. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  235. data/lib/arel/attributes.rb +0 -22
  236. data/lib/arel/visitors/depth_first.rb +0 -203
  237. data/lib/arel/visitors/ibm_db.rb +0 -34
  238. data/lib/arel/visitors/informix.rb +0 -62
  239. data/lib/arel/visitors/mssql.rb +0 -156
  240. data/lib/arel/visitors/oracle.rb +0 -158
  241. data/lib/arel/visitors/oracle12.rb +0 -65
  242. 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
  #
@@ -448,7 +447,7 @@ module ActiveRecord
448
447
 
449
448
  stmt = Arel::UpdateManager.new
450
449
  stmt.table(arel.join_sources.empty? ? table : arel.source)
451
- stmt.key = arel_attribute(primary_key)
450
+ stmt.key = table[primary_key]
452
451
  stmt.take(arel.limit)
453
452
  stmt.offset(arel.offset)
454
453
  stmt.order(*arel.orders)
@@ -458,7 +457,7 @@ module ActiveRecord
458
457
  if klass.locking_enabled? &&
459
458
  !updates.key?(klass.locking_column) &&
460
459
  !updates.key?(klass.locking_column.to_sym)
461
- attr = arel_attribute(klass.locking_column)
460
+ attr = table[klass.locking_column]
462
461
  updates[attr.name] = _increment_attribute(attr)
463
462
  end
464
463
  stmt.set _substitute_values(updates)
@@ -477,12 +476,24 @@ module ActiveRecord
477
476
  end
478
477
  end
479
478
 
480
- def update_counters(counters) # :nodoc:
479
+ # Updates the counters of the records in the current relation.
480
+ #
481
+ # ==== Parameters
482
+ #
483
+ # * +counter+ - A Hash containing the names of the fields to update as keys and the amount to update as values.
484
+ # * <tt>:touch</tt> option - Touch the timestamp columns when updating.
485
+ # * If attributes names are passed, they are updated along with update_at/on attributes.
486
+ #
487
+ # ==== Examples
488
+ #
489
+ # # For Posts by a given author increment the comment_count by 1.
490
+ # Post.where(author_id: author.id).update_counters(comment_count: 1)
491
+ def update_counters(counters)
481
492
  touch = counters.delete(:touch)
482
493
 
483
494
  updates = {}
484
495
  counters.each do |counter_name, value|
485
- attr = arel_attribute(counter_name)
496
+ attr = table[counter_name]
486
497
  updates[attr.name] = _increment_attribute(attr, value)
487
498
  end
488
499
 
@@ -578,7 +589,7 @@ module ActiveRecord
578
589
 
579
590
  stmt = Arel::DeleteManager.new
580
591
  stmt.from(arel.join_sources.empty? ? table : arel.source)
581
- stmt.key = arel_attribute(primary_key)
592
+ stmt.key = table[primary_key]
582
593
  stmt.take(arel.limit)
583
594
  stmt.offset(arel.offset)
584
595
  stmt.order(*arel.orders)
@@ -623,7 +634,10 @@ module ActiveRecord
623
634
  #
624
635
  # Post.where(published: true).load # => #<ActiveRecord::Relation>
625
636
  def load(&block)
626
- exec_queries(&block) unless loaded?
637
+ unless loaded?
638
+ @records = exec_queries(&block)
639
+ @loaded = true
640
+ end
627
641
 
628
642
  self
629
643
  end
@@ -636,11 +650,9 @@ module ActiveRecord
636
650
 
637
651
  def reset
638
652
  @delegate_to_klass = false
639
- @_deprecated_scope_source = nil
640
653
  @to_sql = @arel = @loaded = @should_eager_load = nil
654
+ @offsets = @take = nil
641
655
  @records = [].freeze
642
- @offsets = {}
643
- @take = nil
644
656
  self
645
657
  end
646
658
 
@@ -718,7 +730,7 @@ module ActiveRecord
718
730
  end
719
731
 
720
732
  def inspect
721
- subject = loaded? ? records : self
733
+ subject = loaded? ? records : annotate("loading for inspect")
722
734
  entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
723
735
 
724
736
  entries[10] = "..." if entries.size == 11
@@ -735,25 +747,31 @@ module ActiveRecord
735
747
  end
736
748
 
737
749
  def alias_tracker(joins = [], aliases = nil) # :nodoc:
738
- joins += [aliases] if aliases
739
- ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins)
750
+ ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins, aliases)
751
+ end
752
+
753
+ class StrictLoadingScope # :nodoc:
754
+ def self.empty_scope?
755
+ true
756
+ end
757
+
758
+ def self.strict_loading_value
759
+ true
760
+ end
740
761
  end
741
762
 
742
763
  def preload_associations(records) # :nodoc:
743
764
  preload = preload_values
744
765
  preload += includes_values unless eager_loading?
745
766
  preloader = nil
767
+ scope = strict_loading_value ? StrictLoadingScope : nil
746
768
  preload.each do |associations|
747
769
  preloader ||= build_preloader
748
- preloader.preload records, associations
770
+ preloader.preload records, associations, scope
749
771
  end
750
772
  end
751
773
 
752
- attr_reader :_deprecated_scope_source # :nodoc:
753
-
754
774
  protected
755
- attr_writer :_deprecated_scope_source # :nodoc:
756
-
757
775
  def load_records(records)
758
776
  @records = records.freeze
759
777
  @loaded = true
@@ -765,23 +783,29 @@ module ActiveRecord
765
783
 
766
784
  private
767
785
  def already_in_scope?
768
- @delegate_to_klass && begin
769
- scope = klass.current_scope(true)
770
- scope && !scope._deprecated_scope_source
771
- end
772
- end
773
-
774
- def _deprecated_spawn(name)
775
- spawn.tap { |scope| scope._deprecated_scope_source = name }
786
+ @delegate_to_klass && klass.current_scope(true)
776
787
  end
777
788
 
778
- def _deprecated_scope_block(name, &block)
789
+ def current_scope_restoring_block(&block)
790
+ current_scope = klass.current_scope(true)
779
791
  -> record do
780
- klass.current_scope = _deprecated_spawn(name)
792
+ klass.current_scope = current_scope
781
793
  yield record if block_given?
782
794
  end
783
795
  end
784
796
 
797
+ def _new(attributes, &block)
798
+ klass.new(attributes, &block)
799
+ end
800
+
801
+ def _create(attributes, &block)
802
+ klass.create(attributes, &block)
803
+ end
804
+
805
+ def _create!(attributes, &block)
806
+ klass.create!(attributes, &block)
807
+ end
808
+
785
809
  def _scoping(scope)
786
810
  previous, klass.current_scope = klass.current_scope(true), scope
787
811
  yield
@@ -791,7 +815,7 @@ module ActiveRecord
791
815
 
792
816
  def _substitute_values(values)
793
817
  values.map do |name, value|
794
- attr = arel_attribute(name)
818
+ attr = table[name]
795
819
  unless Arel.arel_node?(value)
796
820
  type = klass.type_for_attribute(attr.name)
797
821
  value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
@@ -809,27 +833,29 @@ module ActiveRecord
809
833
 
810
834
  def exec_queries(&block)
811
835
  skip_query_cache_if_necessary do
812
- @records =
813
- if eager_loading?
836
+ records =
837
+ if where_clause.contradiction?
838
+ []
839
+ elsif eager_loading?
814
840
  apply_join_dependency do |relation, join_dependency|
815
841
  if relation.null_relation?
816
842
  []
817
843
  else
818
844
  relation = join_dependency.apply_column_aliases(relation)
819
845
  rows = connection.select_all(relation.arel, "SQL")
820
- join_dependency.instantiate(rows, &block)
846
+ join_dependency.instantiate(rows, strict_loading_value, &block)
821
847
  end.freeze
822
848
  end
823
849
  else
824
850
  klass.find_by_sql(arel, &block).freeze
825
851
  end
826
852
 
827
- preload_associations(@records) unless skip_preloading_value
853
+ preload_associations(records) unless skip_preloading_value
828
854
 
829
- @records.each(&:readonly!) if readonly_value
855
+ records.each(&:readonly!) if readonly_value
856
+ records.each(&:strict_loading!) if strict_loading_value
830
857
 
831
- @loaded = true
832
- @records
858
+ records
833
859
  end
834
860
  end
835
861
 
@@ -848,27 +874,27 @@ module ActiveRecord
848
874
  end
849
875
 
850
876
  def references_eager_loaded_tables?
851
- joined_tables = arel.join_sources.map do |join|
877
+ joined_tables = build_joins([]).flat_map do |join|
852
878
  if join.is_a?(Arel::Nodes::StringJoin)
853
879
  tables_in_string(join.left)
854
880
  else
855
- [join.left.table_name, join.left.table_alias]
881
+ join.left.name
856
882
  end
857
883
  end
858
884
 
859
- joined_tables += [table.name, table.table_alias]
885
+ joined_tables << table.name
860
886
 
861
887
  # 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
888
+ joined_tables.map!(&:downcase)
863
889
 
864
- (references_values - joined_tables).any?
890
+ !(references_values.map(&:to_s) - joined_tables).empty?
865
891
  end
866
892
 
867
893
  def tables_in_string(string)
868
894
  return [] if string.blank?
869
895
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
870
896
  # 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_"]
897
+ string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
872
898
  end
873
899
  end
874
900
  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)
@@ -22,16 +22,10 @@ module ActiveRecord
22
22
  "#{table_name_prefix}#{schema_migrations_table_name}#{table_name_suffix}"
23
23
  end
24
24
 
25
- def table_exists?
26
- connection.table_exists?(table_name)
27
- end
28
-
29
25
  def create_table
30
- unless table_exists?
31
- version_options = connection.internal_string_options_for_primary_key
32
-
26
+ unless connection.table_exists?(table_name)
33
27
  connection.create_table(table_name, id: false) do |t|
34
- t.string :version, **version_options
28
+ t.string :version, **connection.internal_string_options_for_primary_key
35
29
  end
36
30
  end
37
31
  end