activerecord 7.1.4.2 → 7.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +515 -2397
  3. data/README.rdoc +15 -15
  4. data/examples/performance.rb +2 -2
  5. data/lib/active_record/association_relation.rb +1 -1
  6. data/lib/active_record/associations/alias_tracker.rb +25 -19
  7. data/lib/active_record/associations/association.rb +9 -8
  8. data/lib/active_record/associations/belongs_to_association.rb +14 -7
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  10. data/lib/active_record/associations/builder/belongs_to.rb +1 -0
  11. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
  12. data/lib/active_record/associations/builder/has_many.rb +3 -4
  13. data/lib/active_record/associations/builder/has_one.rb +3 -4
  14. data/lib/active_record/associations/collection_association.rb +6 -4
  15. data/lib/active_record/associations/collection_proxy.rb +14 -1
  16. data/lib/active_record/associations/has_many_association.rb +1 -1
  17. data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
  18. data/lib/active_record/associations/join_dependency.rb +1 -1
  19. data/lib/active_record/associations/nested_error.rb +47 -0
  20. data/lib/active_record/associations/preloader/association.rb +2 -1
  21. data/lib/active_record/associations/preloader/branch.rb +7 -1
  22. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  23. data/lib/active_record/associations/singular_association.rb +6 -0
  24. data/lib/active_record/associations/through_association.rb +1 -1
  25. data/lib/active_record/associations.rb +33 -16
  26. data/lib/active_record/attribute_assignment.rb +1 -11
  27. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  28. data/lib/active_record/attribute_methods/dirty.rb +1 -1
  29. data/lib/active_record/attribute_methods/primary_key.rb +23 -55
  30. data/lib/active_record/attribute_methods/read.rb +4 -16
  31. data/lib/active_record/attribute_methods/serialization.rb +4 -24
  32. data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -6
  33. data/lib/active_record/attribute_methods/write.rb +3 -3
  34. data/lib/active_record/attribute_methods.rb +60 -71
  35. data/lib/active_record/attributes.rb +55 -42
  36. data/lib/active_record/autosave_association.rb +13 -32
  37. data/lib/active_record/base.rb +2 -3
  38. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
  39. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
  40. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +248 -65
  41. data/lib/active_record/connection_adapters/abstract/database_statements.rb +34 -17
  42. data/lib/active_record/connection_adapters/abstract/query_cache.rb +159 -74
  43. data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
  44. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  45. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +14 -5
  46. data/lib/active_record/connection_adapters/abstract/transaction.rb +60 -57
  47. data/lib/active_record/connection_adapters/abstract_adapter.rb +18 -46
  48. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +32 -6
  49. data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
  50. data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
  51. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -1
  52. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +11 -5
  53. data/lib/active_record/connection_adapters/mysql2_adapter.rb +5 -23
  54. data/lib/active_record/connection_adapters/pool_config.rb +7 -6
  55. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
  56. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  57. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  58. data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
  59. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +20 -0
  60. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -11
  61. data/lib/active_record/connection_adapters/postgresql_adapter.rb +26 -21
  62. data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
  63. data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
  64. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
  65. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +44 -46
  66. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  67. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
  68. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  69. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +25 -2
  70. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +107 -75
  71. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +12 -6
  72. data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -48
  73. data/lib/active_record/connection_adapters.rb +121 -0
  74. data/lib/active_record/connection_handling.rb +56 -41
  75. data/lib/active_record/core.rb +52 -36
  76. data/lib/active_record/counter_cache.rb +18 -9
  77. data/lib/active_record/database_configurations/connection_url_resolver.rb +7 -2
  78. data/lib/active_record/database_configurations/database_config.rb +15 -4
  79. data/lib/active_record/database_configurations/hash_config.rb +38 -34
  80. data/lib/active_record/database_configurations/url_config.rb +20 -1
  81. data/lib/active_record/database_configurations.rb +1 -1
  82. data/lib/active_record/delegated_type.rb +24 -0
  83. data/lib/active_record/dynamic_matchers.rb +2 -2
  84. data/lib/active_record/encryption/encryptable_record.rb +2 -2
  85. data/lib/active_record/encryption/encrypted_attribute_type.rb +22 -2
  86. data/lib/active_record/encryption/encryptor.rb +17 -2
  87. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  88. data/lib/active_record/encryption/message_serializer.rb +4 -0
  89. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  90. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  91. data/lib/active_record/enum.rb +11 -2
  92. data/lib/active_record/errors.rb +16 -11
  93. data/lib/active_record/explain.rb +13 -24
  94. data/lib/active_record/fixtures.rb +37 -31
  95. data/lib/active_record/future_result.rb +8 -4
  96. data/lib/active_record/gem_version.rb +3 -3
  97. data/lib/active_record/inheritance.rb +4 -2
  98. data/lib/active_record/insert_all.rb +18 -15
  99. data/lib/active_record/integration.rb +4 -1
  100. data/lib/active_record/internal_metadata.rb +48 -34
  101. data/lib/active_record/locking/optimistic.rb +7 -6
  102. data/lib/active_record/log_subscriber.rb +0 -21
  103. data/lib/active_record/message_pack.rb +1 -1
  104. data/lib/active_record/migration/command_recorder.rb +2 -3
  105. data/lib/active_record/migration/compatibility.rb +5 -3
  106. data/lib/active_record/migration/default_strategy.rb +4 -5
  107. data/lib/active_record/migration/pending_migration_connection.rb +2 -2
  108. data/lib/active_record/migration.rb +85 -76
  109. data/lib/active_record/model_schema.rb +28 -67
  110. data/lib/active_record/nested_attributes.rb +11 -3
  111. data/lib/active_record/normalization.rb +3 -7
  112. data/lib/active_record/persistence.rb +30 -352
  113. data/lib/active_record/query_cache.rb +18 -6
  114. data/lib/active_record/query_logs.rb +15 -0
  115. data/lib/active_record/querying.rb +21 -9
  116. data/lib/active_record/railtie.rb +48 -57
  117. data/lib/active_record/railties/controller_runtime.rb +13 -4
  118. data/lib/active_record/railties/databases.rake +41 -44
  119. data/lib/active_record/reflection.rb +90 -35
  120. data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
  121. data/lib/active_record/relation/batches.rb +3 -3
  122. data/lib/active_record/relation/calculations.rb +94 -61
  123. data/lib/active_record/relation/delegation.rb +8 -11
  124. data/lib/active_record/relation/finder_methods.rb +16 -2
  125. data/lib/active_record/relation/merger.rb +4 -6
  126. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  127. data/lib/active_record/relation/predicate_builder.rb +3 -3
  128. data/lib/active_record/relation/query_methods.rb +196 -57
  129. data/lib/active_record/relation/record_fetch_warning.rb +3 -0
  130. data/lib/active_record/relation/spawn_methods.rb +2 -18
  131. data/lib/active_record/relation/where_clause.rb +7 -19
  132. data/lib/active_record/relation.rb +496 -72
  133. data/lib/active_record/result.rb +31 -44
  134. data/lib/active_record/runtime_registry.rb +39 -0
  135. data/lib/active_record/sanitization.rb +24 -19
  136. data/lib/active_record/schema.rb +8 -6
  137. data/lib/active_record/schema_dumper.rb +19 -9
  138. data/lib/active_record/schema_migration.rb +30 -14
  139. data/lib/active_record/signed_id.rb +11 -1
  140. data/lib/active_record/statement_cache.rb +7 -7
  141. data/lib/active_record/table_metadata.rb +1 -10
  142. data/lib/active_record/tasks/database_tasks.rb +76 -59
  143. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  144. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  145. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
  146. data/lib/active_record/test_fixtures.rb +81 -91
  147. data/lib/active_record/testing/query_assertions.rb +121 -0
  148. data/lib/active_record/timestamp.rb +1 -1
  149. data/lib/active_record/token_for.rb +22 -12
  150. data/lib/active_record/touch_later.rb +1 -1
  151. data/lib/active_record/transaction.rb +68 -0
  152. data/lib/active_record/transactions.rb +43 -14
  153. data/lib/active_record/translation.rb +0 -2
  154. data/lib/active_record/type/serialized.rb +1 -3
  155. data/lib/active_record/type_caster/connection.rb +4 -4
  156. data/lib/active_record/validations/associated.rb +9 -3
  157. data/lib/active_record/validations/uniqueness.rb +14 -10
  158. data/lib/active_record/validations.rb +4 -1
  159. data/lib/active_record.rb +149 -40
  160. data/lib/arel/alias_predication.rb +1 -1
  161. data/lib/arel/collectors/bind.rb +2 -0
  162. data/lib/arel/collectors/composite.rb +7 -0
  163. data/lib/arel/collectors/sql_string.rb +1 -1
  164. data/lib/arel/collectors/substitute_binds.rb +1 -1
  165. data/lib/arel/nodes/binary.rb +0 -6
  166. data/lib/arel/nodes/bound_sql_literal.rb +9 -5
  167. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  168. data/lib/arel/nodes/node.rb +4 -3
  169. data/lib/arel/nodes/sql_literal.rb +7 -0
  170. data/lib/arel/nodes.rb +2 -2
  171. data/lib/arel/predications.rb +1 -1
  172. data/lib/arel/select_manager.rb +1 -1
  173. data/lib/arel/tree_manager.rb +3 -2
  174. data/lib/arel/update_manager.rb +2 -1
  175. data/lib/arel/visitors/dot.rb +1 -0
  176. data/lib/arel/visitors/mysql.rb +9 -4
  177. data/lib/arel/visitors/postgresql.rb +1 -12
  178. data/lib/arel/visitors/to_sql.rb +29 -16
  179. data/lib/arel.rb +7 -3
  180. metadata +20 -15
@@ -110,6 +110,12 @@ module ActiveRecord
110
110
  # assert_raise(StandardError) { web_sites(:reddit) }
111
111
  # end
112
112
  #
113
+ # If the model names conflicts with a +TestCase+ methods, you can use the generic +fixture+ accessor
114
+ #
115
+ # test "generic find" do
116
+ # assert_equal "Ruby on Rails", fixture(:web_sites, :rubyonrails).name
117
+ # end
118
+ #
113
119
  # Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the
114
120
  # following tests:
115
121
  #
@@ -492,8 +498,8 @@ module ActiveRecord
492
498
  # # app/models/book_orders.rb
493
499
  # class BookOrder < ApplicationRecord
494
500
  # self.primary_key = [:shop_id, :id]
495
- # belongs_to :order, query_constraints: [:shop_id, :order_id]
496
- # belongs_to :book, query_constraints: [:author_id, :book_id]
501
+ # belongs_to :order, foreign_key: [:shop_id, :order_id]
502
+ # belongs_to :book, foreign_key: [:author_id, :book_id]
497
503
  # end
498
504
  #
499
505
  # <code></code>
@@ -553,24 +559,24 @@ module ActiveRecord
553
559
  @@all_cached_fixtures.clear
554
560
  end
555
561
 
556
- def cache_for_connection(connection)
557
- @@all_cached_fixtures[connection]
562
+ def cache_for_connection_pool(connection_pool)
563
+ @@all_cached_fixtures[connection_pool]
558
564
  end
559
565
 
560
- def fixture_is_cached?(connection, table_name)
561
- cache_for_connection(connection)[table_name]
566
+ def fixture_is_cached?(connection_pool, table_name)
567
+ cache_for_connection_pool(connection_pool)[table_name]
562
568
  end
563
569
 
564
- def cached_fixtures(connection, keys_to_fetch = nil)
570
+ def cached_fixtures(connection_pool, keys_to_fetch = nil)
565
571
  if keys_to_fetch
566
- cache_for_connection(connection).values_at(*keys_to_fetch)
572
+ cache_for_connection_pool(connection_pool).values_at(*keys_to_fetch)
567
573
  else
568
- cache_for_connection(connection).values
574
+ cache_for_connection_pool(connection_pool).values
569
575
  end
570
576
  end
571
577
 
572
- def cache_fixtures(connection, fixtures_map)
573
- cache_for_connection(connection).update(fixtures_map)
578
+ def cache_fixtures(connection_pool, fixtures_map)
579
+ cache_for_connection_pool(connection_pool).update(fixtures_map)
574
580
  end
575
581
 
576
582
  def instantiate_fixtures(object, fixture_set, load_instances = true)
@@ -588,15 +594,13 @@ module ActiveRecord
588
594
  end
589
595
  end
590
596
 
591
- def create_fixtures(fixtures_directories, fixture_set_names, class_names = {}, config = ActiveRecord::Base, &block)
597
+ def create_fixtures(fixtures_directories, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
592
598
  fixture_set_names = Array(fixture_set_names).map(&:to_s)
593
599
  class_names.stringify_keys!
594
600
 
595
- # FIXME: Apparently JK uses this.
596
- connection = block_given? ? block : lambda { ActiveRecord::Base.connection }
597
-
601
+ connection_pool = config.connection_pool
598
602
  fixture_files_to_read = fixture_set_names.reject do |fs_name|
599
- fixture_is_cached?(connection.call, fs_name)
603
+ fixture_is_cached?(connection_pool, fs_name)
600
604
  end
601
605
 
602
606
  if fixture_files_to_read.any?
@@ -604,11 +608,11 @@ module ActiveRecord
604
608
  Array(fixtures_directories),
605
609
  fixture_files_to_read,
606
610
  class_names,
607
- connection,
611
+ connection_pool,
608
612
  )
609
- cache_fixtures(connection.call, fixtures_map)
613
+ cache_fixtures(connection_pool, fixtures_map)
610
614
  end
611
- cached_fixtures(connection.call, fixture_set_names)
615
+ cached_fixtures(connection_pool, fixture_set_names)
612
616
  end
613
617
 
614
618
  # Returns a consistent, platform-independent identifier for +label+.
@@ -641,7 +645,7 @@ module ActiveRecord
641
645
  end
642
646
 
643
647
  private
644
- def read_and_insert(fixtures_directories, fixture_files, class_names, connection) # :nodoc:
648
+ def read_and_insert(fixtures_directories, fixture_files, class_names, connection_pool) # :nodoc:
645
649
  fixtures_map = {}
646
650
  directory_glob = "{#{fixtures_directories.join(",")}}"
647
651
  fixture_sets = fixture_files.map do |fixture_set_name|
@@ -655,21 +659,21 @@ module ActiveRecord
655
659
  end
656
660
  update_all_loaded_fixtures(fixtures_map)
657
661
 
658
- insert(fixture_sets, connection)
662
+ insert(fixture_sets, connection_pool)
659
663
 
660
664
  fixtures_map
661
665
  end
662
666
 
663
- def insert(fixture_sets, connection) # :nodoc:
664
- fixture_sets_by_connection = fixture_sets.group_by do |fixture_set|
667
+ def insert(fixture_sets, connection_pool) # :nodoc:
668
+ fixture_sets_by_pool = fixture_sets.group_by do |fixture_set|
665
669
  if fixture_set.model_class
666
- fixture_set.model_class.connection
670
+ fixture_set.model_class.connection_pool
667
671
  else
668
- connection.call
672
+ connection_pool
669
673
  end
670
674
  end
671
675
 
672
- fixture_sets_by_connection.each do |conn, set|
676
+ fixture_sets_by_pool.each do |pool, set|
673
677
  table_rows_for_connection = Hash.new { |h, k| h[k] = [] }
674
678
 
675
679
  set.each do |fixture_set|
@@ -678,13 +682,15 @@ module ActiveRecord
678
682
  end
679
683
  end
680
684
 
681
- conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
685
+ pool.with_connection do |conn|
686
+ conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
682
687
 
683
- check_all_foreign_keys_valid!(conn)
688
+ check_all_foreign_keys_valid!(conn)
684
689
 
685
- # Cap primary key sequences to max(pk).
686
- if conn.respond_to?(:reset_pk_sequence!)
687
- set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
690
+ # Cap primary key sequences to max(pk).
691
+ if conn.respond_to?(:reset_pk_sequence!)
692
+ set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
693
+ end
688
694
  end
689
695
  end
690
696
  end
@@ -32,8 +32,11 @@ module ActiveRecord
32
32
 
33
33
  def instrument(name, payload = {}, &block)
34
34
  event = @instrumenter.new_event(name, payload)
35
- @events << event
36
- event.record(&block)
35
+ begin
36
+ event.record(&block)
37
+ ensure
38
+ @events << event
39
+ end
37
40
  end
38
41
 
39
42
  def flush
@@ -57,7 +60,6 @@ module ActiveRecord
57
60
  end
58
61
 
59
62
  delegate :empty?, :to_a, to: :result
60
- delegate_missing_to :result
61
63
 
62
64
  attr_reader :lock_wait
63
65
 
@@ -140,7 +142,9 @@ module ActiveRecord
140
142
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
141
143
  @mutex.synchronize do
142
144
  if pending?
143
- execute_query(@pool.connection)
145
+ @pool.with_connection do |connection|
146
+ execute_query(connection)
147
+ end
144
148
  else
145
149
  @lock_wait = (Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - start)
146
150
  end
@@ -8,9 +8,9 @@ module ActiveRecord
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 7
11
- MINOR = 1
12
- TINY = 4
13
- PRE = "2"
11
+ MINOR = 2
12
+ TINY = 0
13
+ PRE = "beta1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -165,7 +165,7 @@ module ActiveRecord
165
165
 
166
166
  # Returns whether this class is an abstract class or not.
167
167
  def abstract_class?
168
- defined?(@abstract_class) && @abstract_class == true
168
+ @abstract_class == true
169
169
  end
170
170
 
171
171
  # Sets the application record class for Active Record
@@ -202,7 +202,9 @@ module ActiveRecord
202
202
  "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
203
203
  "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
204
204
  "Please rename this column if you didn't intend it to be used for storing the inheritance class " \
205
- "or overwrite #{name}.inheritance_column to use another column for that information."
205
+ "or overwrite #{name}.inheritance_column to use another column for that information. " \
206
+ "If you wish to disable single-table inheritance for #{name} set " \
207
+ "#{name}.inheritance_column to nil"
206
208
  end
207
209
 
208
210
  # Returns the value to be stored in the polymorphic type column for Polymorphic Associations.
@@ -7,8 +7,17 @@ module ActiveRecord
7
7
  attr_reader :model, :connection, :inserts, :keys
8
8
  attr_reader :on_duplicate, :update_only, :returning, :unique_by, :update_sql
9
9
 
10
- def initialize(model, inserts, on_duplicate:, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
11
- @model, @connection, @inserts = model, model.connection, inserts.map(&:stringify_keys)
10
+ class << self
11
+ def execute(relation, ...)
12
+ relation.model.with_connection do |c|
13
+ new(relation, c, ...).execute
14
+ end
15
+ end
16
+ end
17
+
18
+ def initialize(relation, connection, inserts, on_duplicate:, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
19
+ @relation = relation
20
+ @model, @connection, @inserts = relation.model, connection, inserts.map(&:stringify_keys)
12
21
  @on_duplicate, @update_only, @returning, @unique_by = on_duplicate, update_only, returning, unique_by
13
22
  @record_timestamps = record_timestamps.nil? ? model.record_timestamps : record_timestamps
14
23
 
@@ -23,10 +32,8 @@ module ActiveRecord
23
32
  @keys = @inserts.first.keys
24
33
  end
25
34
 
26
- if model.scope_attributes?
27
- @scope_attributes = model.scope_attributes
28
- @keys |= @scope_attributes.keys
29
- end
35
+ @scope_attributes = relation.scope_for_create.except(@model.inheritance_column)
36
+ @keys |= @scope_attributes.keys
30
37
  @keys = @keys.to_set
31
38
 
32
39
  @returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
@@ -52,10 +59,9 @@ module ActiveRecord
52
59
  end
53
60
 
54
61
  def primary_keys
55
- Array(connection.schema_cache.primary_keys(model.table_name))
62
+ Array(@model.schema_cache.primary_keys(model.table_name))
56
63
  end
57
64
 
58
-
59
65
  def skip_duplicates?
60
66
  on_duplicate == :skip
61
67
  end
@@ -67,7 +73,7 @@ module ActiveRecord
67
73
  def map_key_with_value
68
74
  inserts.map do |attributes|
69
75
  attributes = attributes.stringify_keys
70
- attributes.merge!(scope_attributes) if scope_attributes
76
+ attributes.merge!(@scope_attributes)
71
77
  attributes.reverse_merge!(timestamps_for_create) if record_timestamps?
72
78
 
73
79
  verify_attributes(attributes)
@@ -92,8 +98,6 @@ module ActiveRecord
92
98
  end
93
99
 
94
100
  private
95
- attr_reader :scope_attributes
96
-
97
101
  def has_attribute_aliases?(attributes)
98
102
  attributes.keys.any? { |attribute| model.attribute_alias?(attribute) }
99
103
  end
@@ -163,10 +167,9 @@ module ActiveRecord
163
167
  end
164
168
 
165
169
  def unique_indexes
166
- connection.schema_cache.indexes(model.table_name).select(&:unique)
170
+ @model.schema_cache.indexes(model.table_name).select(&:unique)
167
171
  end
168
172
 
169
-
170
173
  def ensure_valid_options_for_connection!
171
174
  if returning && !connection.supports_insert_returning?
172
175
  raise ArgumentError, "#{connection.class} does not support :returning"
@@ -192,7 +195,7 @@ module ActiveRecord
192
195
 
193
196
 
194
197
  def readonly_columns
195
- primary_keys + model.readonly_attributes.to_a
198
+ primary_keys + model.readonly_attributes
196
199
  end
197
200
 
198
201
  def unique_by_columns
@@ -301,7 +304,7 @@ module ActiveRecord
301
304
  end
302
305
 
303
306
  def extract_types_from_columns_on(table_name, keys:)
304
- columns = connection.schema_cache.columns_hash(table_name)
307
+ columns = @model.schema_cache.columns_hash(table_name)
305
308
 
306
309
  unknown_column = (keys - columns.keys).first
307
310
  raise UnknownAttributeError.new(model.new, unknown_column) if unknown_column
@@ -178,7 +178,10 @@ module ActiveRecord
178
178
  def can_use_fast_cache_version?(timestamp)
179
179
  timestamp.is_a?(String) &&
180
180
  cache_timestamp_format == :usec &&
181
- self.class.connection.default_timezone == :utc &&
181
+ # FIXME: checking out a connection for this is wasteful
182
+ # we should store/cache this information in the schema cache
183
+ # or similar.
184
+ self.class.with_connection(&:default_timezone) == :utc &&
182
185
  !updated_at_came_from_user?
183
186
  end
184
187
 
@@ -13,17 +13,13 @@ module ActiveRecord
13
13
  class NullInternalMetadata # :nodoc:
14
14
  end
15
15
 
16
- attr_reader :connection, :arel_table
16
+ attr_reader :arel_table
17
17
 
18
- def initialize(connection)
19
- @connection = connection
18
+ def initialize(pool)
19
+ @pool = pool
20
20
  @arel_table = Arel::Table.new(table_name)
21
21
  end
22
22
 
23
- def enabled?
24
- connection.use_metadata_table?
25
- end
26
-
27
23
  def primary_key
28
24
  "key"
29
25
  end
@@ -36,50 +32,66 @@ module ActiveRecord
36
32
  "#{ActiveRecord::Base.table_name_prefix}#{ActiveRecord::Base.internal_metadata_table_name}#{ActiveRecord::Base.table_name_suffix}"
37
33
  end
38
34
 
35
+ def enabled?
36
+ @pool.db_config.use_metadata_table?
37
+ end
38
+
39
39
  def []=(key, value)
40
40
  return unless enabled?
41
41
 
42
- update_or_create_entry(key, value)
42
+ @pool.with_connection do |connection|
43
+ update_or_create_entry(connection, key, value)
44
+ end
43
45
  end
44
46
 
45
47
  def [](key)
46
48
  return unless enabled?
47
49
 
48
- if entry = select_entry(key)
49
- entry[value_key]
50
+ @pool.with_connection do |connection|
51
+ if entry = select_entry(connection, key)
52
+ entry[value_key]
53
+ end
50
54
  end
51
55
  end
52
56
 
53
57
  def delete_all_entries
54
58
  dm = Arel::DeleteManager.new(arel_table)
55
59
 
56
- connection.delete(dm, "#{self.class} Destroy")
60
+ @pool.with_connection do |connection|
61
+ connection.delete(dm, "#{self.class} Destroy")
62
+ end
57
63
  end
58
64
 
59
65
  def count
60
66
  sm = Arel::SelectManager.new(arel_table)
61
67
  sm.project(*Arel::Nodes::Count.new([Arel.star]))
62
68
 
63
- connection.select_values(sm, "#{self.class} Count").first
69
+ @pool.with_connection do |connection|
70
+ connection.select_values(sm, "#{self.class} Count").first
71
+ end
64
72
  end
65
73
 
66
74
  def create_table_and_set_flags(environment, schema_sha1 = nil)
67
75
  return unless enabled?
68
76
 
69
- create_table
70
- update_or_create_entry(:environment, environment)
71
- update_or_create_entry(:schema_sha1, schema_sha1) if schema_sha1
77
+ @pool.with_connection do |connection|
78
+ create_table
79
+ update_or_create_entry(connection, :environment, environment)
80
+ update_or_create_entry(connection, :schema_sha1, schema_sha1) if schema_sha1
81
+ end
72
82
  end
73
83
 
74
84
  # Creates an internal metadata table with columns +key+ and +value+
75
85
  def create_table
76
86
  return unless enabled?
77
87
 
78
- unless connection.table_exists?(table_name)
79
- connection.create_table(table_name, id: false) do |t|
80
- t.string :key, **connection.internal_string_options_for_primary_key
81
- t.string :value
82
- t.timestamps
88
+ @pool.with_connection do |connection|
89
+ unless connection.table_exists?(table_name)
90
+ connection.create_table(table_name, id: false) do |t|
91
+ t.string :key, **connection.internal_string_options_for_primary_key
92
+ t.string :value
93
+ t.timestamps
94
+ end
83
95
  end
84
96
  end
85
97
  end
@@ -87,49 +99,51 @@ module ActiveRecord
87
99
  def drop_table
88
100
  return unless enabled?
89
101
 
90
- connection.drop_table table_name, if_exists: true
102
+ @pool.with_connection do |connection|
103
+ connection.drop_table table_name, if_exists: true
104
+ end
91
105
  end
92
106
 
93
107
  def table_exists?
94
- connection.schema_cache.data_source_exists?(table_name)
108
+ @pool.schema_cache.data_source_exists?(table_name)
95
109
  end
96
110
 
97
111
  private
98
- def update_or_create_entry(key, value)
99
- entry = select_entry(key)
112
+ def update_or_create_entry(connection, key, value)
113
+ entry = select_entry(connection, key)
100
114
 
101
115
  if entry
102
116
  if entry[value_key] != value
103
- update_entry(key, value)
117
+ update_entry(connection, key, value)
104
118
  else
105
119
  entry[value_key]
106
120
  end
107
121
  else
108
- create_entry(key, value)
122
+ create_entry(connection, key, value)
109
123
  end
110
124
  end
111
125
 
112
- def current_time
126
+ def current_time(connection)
113
127
  connection.default_timezone == :utc ? Time.now.utc : Time.now
114
128
  end
115
129
 
116
- def create_entry(key, value)
130
+ def create_entry(connection, key, value)
117
131
  im = Arel::InsertManager.new(arel_table)
118
132
  im.insert [
119
133
  [arel_table[primary_key], key],
120
134
  [arel_table[value_key], value],
121
- [arel_table[:created_at], current_time],
122
- [arel_table[:updated_at], current_time]
135
+ [arel_table[:created_at], current_time(connection)],
136
+ [arel_table[:updated_at], current_time(connection)]
123
137
  ]
124
138
 
125
139
  connection.insert(im, "#{self.class} Create", primary_key, key)
126
140
  end
127
141
 
128
- def update_entry(key, new_value)
142
+ def update_entry(connection, key, new_value)
129
143
  um = Arel::UpdateManager.new(arel_table)
130
144
  um.set [
131
145
  [arel_table[value_key], new_value],
132
- [arel_table[:updated_at], current_time]
146
+ [arel_table[:updated_at], current_time(connection)]
133
147
  ]
134
148
 
135
149
  um.where(arel_table[primary_key].eq(key))
@@ -137,9 +151,9 @@ module ActiveRecord
137
151
  connection.update(um, "#{self.class} Update")
138
152
  end
139
153
 
140
- def select_entry(key)
154
+ def select_entry(connection, key)
141
155
  sm = Arel::SelectManager.new(arel_table)
142
- sm.project(Arel::Nodes::SqlLiteral.new("*"))
156
+ sm.project(Arel::Nodes::SqlLiteral.new("*", retryable: true))
143
157
  sm.where(arel_table[primary_key].eq(Arel::Nodes::BindParam.new(key)))
144
158
  sm.order(arel_table[primary_key].asc)
145
159
  sm.limit = 1
@@ -182,14 +182,15 @@ module ActiveRecord
182
182
  super
183
183
  end
184
184
 
185
- def define_attribute(name, cast_type, **) # :nodoc:
186
- if lock_optimistically && name == locking_column
187
- cast_type = LockingType.new(cast_type)
185
+ private
186
+ def hook_attribute_type(name, cast_type)
187
+ if lock_optimistically && name == locking_column
188
+ cast_type = LockingType.new(cast_type)
189
+ end
190
+
191
+ super
188
192
  end
189
- super
190
- end
191
193
 
192
- private
193
194
  def inherited(base)
194
195
  super
195
196
  base.class_eval do
@@ -6,27 +6,6 @@ module ActiveRecord
6
6
 
7
7
  class_attribute :backtrace_cleaner, default: ActiveSupport::BacktraceCleaner.new
8
8
 
9
- def self.runtime=(value)
10
- ActiveRecord.deprecator.warn(<<-MSG.squish)
11
- ActiveRecord::LogSubscriber.runtime= is deprecated and will be removed in Rails 7.2.
12
- MSG
13
- ActiveRecord::RuntimeRegistry.sql_runtime = value
14
- end
15
-
16
- def self.runtime
17
- ActiveRecord.deprecator.warn(<<-MSG.squish)
18
- ActiveRecord::LogSubscriber.runtime is deprecated and will be removed in Rails 7.2.
19
- MSG
20
- ActiveRecord::RuntimeRegistry.sql_runtime
21
- end
22
-
23
- def self.reset_runtime
24
- ActiveRecord.deprecator.warn(<<-MSG.squish)
25
- ActiveRecord::LogSubscriber.reset_runtime is deprecated and will be removed in Rails 7.2.
26
- MSG
27
- ActiveRecord::RuntimeRegistry.reset
28
- end
29
-
30
9
  def strict_loading_violation(event)
31
10
  debug do
32
11
  owner = event.payload[:owner]
@@ -79,7 +79,7 @@ module ActiveRecord
79
79
  end
80
80
 
81
81
  def add_cached_associations(record, entry)
82
- record.class.reflections.each_value do |reflection|
82
+ record.class.normalized_reflections.each_value do |reflection|
83
83
  if record.association_cached?(reflection.name) && record.association(reflection.name).loaded?
84
84
  entry << reflection.name << encode(record.association(reflection.name).target)
85
85
  end
@@ -377,14 +377,13 @@ module ActiveRecord
377
377
  end
378
378
 
379
379
  # Forwards any missing method call to the \target.
380
- def method_missing(method, *args, &block)
380
+ def method_missing(method, ...)
381
381
  if delegate.respond_to?(method)
382
- delegate.public_send(method, *args, &block)
382
+ delegate.public_send(method, ...)
383
383
  else
384
384
  super
385
385
  end
386
386
  end
387
- ruby2_keywords(:method_missing)
388
387
  end
389
388
  end
390
389
  end
@@ -21,8 +21,7 @@ module ActiveRecord
21
21
  # New migration functionality that will never be backward compatible should be added directly to `ActiveRecord::Migration`.
22
22
  #
23
23
  # There are classes for each prior Rails version. Each class descends from the *next* Rails version, so:
24
- # 7.0 < 7.1
25
- # 5.2 < 6.0 < 6.1 < 7.0 < 7.1
24
+ # 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2
26
25
  #
27
26
  # If you are introducing new migration functionality that should only apply from Rails 7 onward, then you should
28
27
  # find the class that immediately precedes it (6.1), and override the relevant migration methods to undo your changes.
@@ -30,7 +29,10 @@ module ActiveRecord
30
29
  # For example, Rails 6 added a default value for the `precision` option on datetime columns. So in this file, the `V5_2`
31
30
  # class sets the value of `precision` to `nil` if it's not explicitly provided. This way, the default value will not apply
32
31
  # for migrations written for 5.2, but will for migrations written for 6.0.
33
- V7_1 = Current
32
+ V7_2 = Current
33
+
34
+ class V7_1 < V7_2
35
+ end
34
36
 
35
37
  class V7_0 < V7_1
36
38
  module LegacyIndexName
@@ -6,13 +6,12 @@ module ActiveRecord
6
6
  # to the connection adapter.
7
7
  class DefaultStrategy < ExecutionStrategy # :nodoc:
8
8
  private
9
- def method_missing(method, *arguments, &block)
10
- connection.send(method, *arguments, &block)
9
+ def method_missing(method, ...)
10
+ connection.send(method, ...)
11
11
  end
12
- ruby2_keywords(:method_missing)
13
12
 
14
- def respond_to_missing?(method, *)
15
- connection.respond_to?(method) || super
13
+ def respond_to_missing?(method, include_private = false)
14
+ connection.respond_to?(method, include_private) || super
16
15
  end
17
16
 
18
17
  def connection
@@ -2,10 +2,10 @@
2
2
 
3
3
  module ActiveRecord
4
4
  class PendingMigrationConnection # :nodoc:
5
- def self.establish_temporary_connection(db_config, &block)
5
+ def self.with_temporary_pool(db_config, &block)
6
6
  pool = ActiveRecord::Base.connection_handler.establish_connection(db_config, owner_name: self)
7
7
 
8
- yield pool.connection
8
+ yield pool
9
9
  ensure
10
10
  ActiveRecord::Base.connection_handler.remove_connection_pool(self.name)
11
11
  end