activerecord 7.2.2 → 8.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +173 -920
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/associations/association.rb +25 -5
  5. data/lib/active_record/associations/builder/association.rb +7 -6
  6. data/lib/active_record/associations/collection_association.rb +10 -8
  7. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  8. data/lib/active_record/associations/has_many_through_association.rb +4 -9
  9. data/lib/active_record/associations/preloader/association.rb +2 -2
  10. data/lib/active_record/associations/singular_association.rb +8 -3
  11. data/lib/active_record/associations.rb +50 -32
  12. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  13. data/lib/active_record/autosave_association.rb +69 -27
  14. data/lib/active_record/callbacks.rb +1 -1
  15. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +16 -10
  16. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
  17. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
  18. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +0 -27
  19. data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
  20. data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -2
  21. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  22. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  23. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +27 -6
  24. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
  25. data/lib/active_record/connection_adapters/abstract_adapter.rb +24 -25
  26. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +23 -45
  27. data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
  28. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
  29. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -45
  30. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +42 -98
  31. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -8
  32. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -42
  33. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  34. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +0 -1
  35. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +50 -8
  36. data/lib/active_record/connection_adapters/postgresql_adapter.rb +41 -93
  37. data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
  38. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +76 -100
  39. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  40. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +13 -0
  41. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +8 -1
  42. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -12
  43. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
  44. data/lib/active_record/connection_adapters/trilogy_adapter.rb +0 -17
  45. data/lib/active_record/connection_handling.rb +22 -0
  46. data/lib/active_record/core.rb +7 -32
  47. data/lib/active_record/encryption/config.rb +3 -1
  48. data/lib/active_record/encryption/encryptable_record.rb +4 -4
  49. data/lib/active_record/encryption/encrypted_attribute_type.rb +10 -1
  50. data/lib/active_record/encryption/encryptor.rb +15 -8
  51. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  52. data/lib/active_record/encryption/scheme.rb +8 -1
  53. data/lib/active_record/errors.rb +13 -5
  54. data/lib/active_record/fixtures.rb +0 -1
  55. data/lib/active_record/future_result.rb +14 -10
  56. data/lib/active_record/gem_version.rb +4 -4
  57. data/lib/active_record/insert_all.rb +1 -1
  58. data/lib/active_record/marshalling.rb +1 -4
  59. data/lib/active_record/migration/command_recorder.rb +22 -5
  60. data/lib/active_record/migration/compatibility.rb +5 -2
  61. data/lib/active_record/migration.rb +35 -33
  62. data/lib/active_record/model_schema.rb +1 -1
  63. data/lib/active_record/nested_attributes.rb +4 -6
  64. data/lib/active_record/persistence.rb +128 -130
  65. data/lib/active_record/query_cache.rb +5 -4
  66. data/lib/active_record/query_logs.rb +98 -40
  67. data/lib/active_record/query_logs_formatter.rb +17 -28
  68. data/lib/active_record/querying.rb +6 -6
  69. data/lib/active_record/railtie.rb +3 -4
  70. data/lib/active_record/reflection.rb +9 -7
  71. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  72. data/lib/active_record/relation/batches.rb +132 -72
  73. data/lib/active_record/relation/calculations.rb +25 -20
  74. data/lib/active_record/relation/delegation.rb +25 -14
  75. data/lib/active_record/relation/finder_methods.rb +18 -18
  76. data/lib/active_record/relation/merger.rb +8 -8
  77. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  78. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  79. data/lib/active_record/relation/predicate_builder.rb +5 -0
  80. data/lib/active_record/relation/query_methods.rb +81 -75
  81. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  82. data/lib/active_record/relation/spawn_methods.rb +1 -1
  83. data/lib/active_record/relation.rb +72 -61
  84. data/lib/active_record/result.rb +68 -7
  85. data/lib/active_record/sanitization.rb +7 -6
  86. data/lib/active_record/schema_dumper.rb +5 -0
  87. data/lib/active_record/schema_migration.rb +2 -1
  88. data/lib/active_record/scoping/named.rb +5 -2
  89. data/lib/active_record/statement_cache.rb +12 -12
  90. data/lib/active_record/store.rb +7 -3
  91. data/lib/active_record/tasks/database_tasks.rb +24 -15
  92. data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
  93. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
  94. data/lib/active_record/test_fixtures.rb +12 -0
  95. data/lib/active_record/testing/query_assertions.rb +2 -2
  96. data/lib/active_record/token_for.rb +1 -1
  97. data/lib/active_record/validations/uniqueness.rb +8 -8
  98. data/lib/active_record.rb +15 -0
  99. data/lib/arel/collectors/bind.rb +1 -1
  100. data/lib/arel/visitors/sqlite.rb +0 -25
  101. metadata +10 -10
@@ -178,22 +178,9 @@ module ActiveRecord
178
178
  dump_db_configs = []
179
179
 
180
180
  each_current_configuration(env) do |db_config|
181
- with_temporary_pool(db_config) do
182
- begin
183
- database_initialized = migration_connection_pool.schema_migration.table_exists?
184
- rescue ActiveRecord::NoDatabaseError
185
- create(db_config)
186
- retry
187
- end
181
+ database_initialized = initialize_database(db_config)
188
182
 
189
- unless database_initialized
190
- if File.exist?(schema_dump_path(db_config))
191
- load_schema(db_config, ActiveRecord.schema_format, nil)
192
- end
193
-
194
- seed = true
195
- end
196
- end
183
+ seed = true if database_initialized
197
184
  end
198
185
 
199
186
  each_current_environment(env) do |environment|
@@ -259,6 +246,8 @@ module ActiveRecord
259
246
 
260
247
  check_target_version
261
248
 
249
+ initialize_database(migration_connection_pool.db_config)
250
+
262
251
  migration_connection_pool.migration_context.migrate(target_version) do |migration|
263
252
  if version.blank?
264
253
  scope.blank? || scope == migration.scope
@@ -667,6 +656,26 @@ module ActiveRecord
667
656
  rescue ActiveRecord::NoDatabaseError
668
657
  end
669
658
  end
659
+
660
+ def initialize_database(db_config)
661
+ with_temporary_pool(db_config) do
662
+ begin
663
+ database_already_initialized = migration_connection_pool.schema_migration.table_exists?
664
+ rescue ActiveRecord::NoDatabaseError
665
+ create(db_config)
666
+ retry
667
+ end
668
+
669
+ unless database_already_initialized
670
+ schema_dump_path = schema_dump_path(db_config)
671
+ if schema_dump_path && File.exist?(schema_dump_path)
672
+ load_schema(db_config, ActiveRecord.schema_format, nil)
673
+ end
674
+ end
675
+
676
+ !database_already_initialized
677
+ end
678
+ end
670
679
  end
671
680
  end
672
681
  end
@@ -3,8 +3,6 @@
3
3
  module ActiveRecord
4
4
  module Tasks # :nodoc:
5
5
  class MySQLDatabaseTasks # :nodoc:
6
- ER_DB_CREATE_EXISTS = 1007
7
-
8
6
  def self.using_database_configurations?
9
7
  true
10
8
  end
@@ -50,9 +50,9 @@ module ActiveRecord
50
50
  if ignore_tables.any?
51
51
  ignore_tables = connection.data_sources.select { |table| ignore_tables.any? { |pattern| pattern === table } }
52
52
  condition = ignore_tables.map { |table| connection.quote(table) }.join(", ")
53
- args << "SELECT sql FROM sqlite_master WHERE tbl_name NOT IN (#{condition}) ORDER BY tbl_name, type DESC, name"
53
+ args << "SELECT sql || ';' FROM sqlite_master WHERE tbl_name NOT IN (#{condition}) ORDER BY tbl_name, type DESC, name"
54
54
  else
55
- args << ".schema"
55
+ args << ".schema --nosys"
56
56
  end
57
57
  run_cmd("sqlite3", args, filename)
58
58
  end
@@ -137,12 +137,15 @@ module ActiveRecord
137
137
  invalidate_already_loaded_fixtures
138
138
  @loaded_fixtures = load_fixtures(config)
139
139
  end
140
+ setup_asynchronous_queries_session
140
141
 
141
142
  # Instantiate fixtures for every test if requested.
142
143
  instantiate_fixtures if use_instantiated_fixtures
143
144
  end
144
145
 
145
146
  def teardown_fixtures
147
+ teardown_asynchronous_queries_session
148
+
146
149
  # Rollback changes if a transaction is active.
147
150
  if run_in_transaction?
148
151
  teardown_transactional_fixtures
@@ -154,6 +157,14 @@ module ActiveRecord
154
157
  ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
155
158
  end
156
159
 
160
+ def setup_asynchronous_queries_session
161
+ @_async_queries_session = ActiveRecord::Base.asynchronous_queries_tracker.start_session
162
+ end
163
+
164
+ def teardown_asynchronous_queries_session
165
+ ActiveRecord::Base.asynchronous_queries_tracker.finalize_session(true) if @_async_queries_session
166
+ end
167
+
157
168
  def invalidate_already_loaded_fixtures
158
169
  @@already_loaded_fixtures.clear
159
170
  end
@@ -190,6 +201,7 @@ module ActiveRecord
190
201
 
191
202
  def teardown_transactional_fixtures
192
203
  ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
204
+
193
205
  unless @fixture_connection_pools.map(&:unpin_connection!).all?
194
206
  # Something caused the transaction to be committed or rolled back
195
207
  # We can no longer trust the database is in a clean state.
@@ -52,7 +52,7 @@ module ActiveRecord
52
52
  # assert_queries_match(/LIMIT \?/) { Post.first }
53
53
  #
54
54
  # If the +:include_schema+ option is provided, any queries (including schema related)
55
- # that match the matcher are considered.
55
+ # that match the matcher are considered.
56
56
  #
57
57
  # assert_queries_match(/FROM pg_attribute/i, include_schema: true) { Post.columns }
58
58
  #
@@ -80,7 +80,7 @@ module ActiveRecord
80
80
  # assert_no_queries_match(/SELECT/i) { post.comments }
81
81
  #
82
82
  # If the +:include_schema+ option is provided, any queries (including schema related)
83
- # that match the matcher are counted.
83
+ # that match the matcher are counted.
84
84
  #
85
85
  # assert_no_queries_match(/FROM pg_attribute/i, include_schema: true) { Post.columns }
86
86
  #
@@ -40,7 +40,7 @@ module ActiveRecord
40
40
  # +nil+ if the token is invalid or the record was not found.
41
41
  def find_by_token_for(purpose, token)
42
42
  raise UnknownPrimaryKey.new(self) unless model.primary_key
43
- model.token_definitions.fetch(purpose).resolve_token(token) { |id| find_by(model.primary_key => id) }
43
+ model.token_definitions.fetch(purpose).resolve_token(token) { |id| find_by(model.primary_key => [id]) }
44
44
  end
45
45
 
46
46
  # Finds a record using a given +token+ for a predefined +purpose+. Raises
@@ -54,17 +54,17 @@ module ActiveRecord
54
54
  private
55
55
  # The check for an existing value should be run from a class that
56
56
  # isn't abstract. This means working down from the current class
57
- # (self), to the first non-abstract class. Since classes don't know
58
- # their subclasses, we have to build the hierarchy between self and
59
- # the record's class.
57
+ # (self), to the first non-abstract class.
60
58
  def find_finder_class_for(record)
61
- class_hierarchy = [record.class]
62
-
63
- while class_hierarchy.first != @klass
64
- class_hierarchy.unshift(class_hierarchy.first.superclass)
59
+ current_class = record.class
60
+ found_class = nil
61
+ loop do
62
+ found_class = current_class unless current_class.abstract_class?
63
+ break if current_class == @klass
64
+ current_class = current_class.superclass
65
65
  end
66
66
 
67
- class_hierarchy.detect { |klass| !klass.abstract_class? }
67
+ found_class
68
68
  end
69
69
 
70
70
  def validation_needed?(klass, record, attribute)
data/lib/active_record.rb CHANGED
@@ -29,6 +29,7 @@ require "active_support/ordered_options"
29
29
  require "active_model"
30
30
  require "arel"
31
31
  require "yaml"
32
+ require "zlib"
32
33
 
33
34
  require "active_record/version"
34
35
  require "active_record/deprecator"
@@ -196,6 +197,20 @@ module ActiveRecord
196
197
  singleton_class.attr_accessor :schema_cache_ignored_tables
197
198
  self.schema_cache_ignored_tables = []
198
199
 
200
+ # Checks to see if the +table_name+ is ignored by checking
201
+ # against the +schema_cache_ignored_tables+ option.
202
+ #
203
+ # ActiveRecord.schema_cache_ignored_table?(:developers)
204
+ #
205
+ def self.schema_cache_ignored_table?(table_name)
206
+ ActiveRecord.schema_cache_ignored_tables.any? do |ignored|
207
+ ignored === table_name
208
+ end
209
+ end
210
+
211
+ singleton_class.attr_accessor :database_cli
212
+ self.database_cli = { postgresql: "psql", mysql: %w[mysql mysql5], sqlite: "sqlite3" }
213
+
199
214
  singleton_class.attr_reader :default_timezone
200
215
 
201
216
  # Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
@@ -13,7 +13,7 @@ module Arel # :nodoc: all
13
13
  self
14
14
  end
15
15
 
16
- def add_bind(bind)
16
+ def add_bind(bind, &)
17
17
  @binds << bind
18
18
  self
19
19
  end
@@ -33,31 +33,6 @@ module Arel # :nodoc: all
33
33
  collector << " IS NOT "
34
34
  visit o.right, collector
35
35
  end
36
-
37
- # Queries used in UNION should not be wrapped by parentheses,
38
- # because it is an invalid syntax in SQLite.
39
- def infix_value_with_paren(o, collector, value, suppress_parens = false)
40
- collector << "( " unless suppress_parens
41
-
42
- left = o.left.is_a?(Nodes::Grouping) ? o.left.expr : o.left
43
- collector = if left.class == o.class
44
- infix_value_with_paren(left, collector, value, true)
45
- else
46
- grouping_parentheses left, collector, false
47
- end
48
-
49
- collector << value
50
-
51
- right = o.right.is_a?(Nodes::Grouping) ? o.right.expr : o.right
52
- collector = if right.class == o.class
53
- infix_value_with_paren(right, collector, value, true)
54
- else
55
- grouping_parentheses right, collector, false
56
- end
57
-
58
- collector << " )" unless suppress_parens
59
- collector
60
- end
61
36
  end
62
37
  end
63
38
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.2
4
+ version: 8.0.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-31 00:00:00.000000000 Z
11
+ date: 2024-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 7.2.2
19
+ version: 8.0.0.beta1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 7.2.2
26
+ version: 8.0.0.beta1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activemodel
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 7.2.2
33
+ version: 8.0.0.beta1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 7.2.2
40
+ version: 8.0.0.beta1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: timeout
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -476,10 +476,10 @@ licenses:
476
476
  - MIT
477
477
  metadata:
478
478
  bug_tracker_uri: https://github.com/rails/rails/issues
479
- changelog_uri: https://github.com/rails/rails/blob/v7.2.2/activerecord/CHANGELOG.md
480
- documentation_uri: https://api.rubyonrails.org/v7.2.2/
479
+ changelog_uri: https://github.com/rails/rails/blob/v8.0.0.beta1/activerecord/CHANGELOG.md
480
+ documentation_uri: https://api.rubyonrails.org/v8.0.0.beta1/
481
481
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
482
- source_code_uri: https://github.com/rails/rails/tree/v7.2.2/activerecord
482
+ source_code_uri: https://github.com/rails/rails/tree/v8.0.0.beta1/activerecord
483
483
  rubygems_mfa_required: 'true'
484
484
  post_install_message:
485
485
  rdoc_options:
@@ -491,7 +491,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
491
491
  requirements:
492
492
  - - ">="
493
493
  - !ruby/object:Gem::Version
494
- version: 3.1.0
494
+ version: 3.2.0
495
495
  required_rubygems_version: !ruby/object:Gem::Requirement
496
496
  requirements:
497
497
  - - ">="