activerecord 7.2.0 → 8.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +189 -745
  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 +3 -2
  9. data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
  10. data/lib/active_record/associations/join_dependency.rb +5 -5
  11. data/lib/active_record/associations/preloader/association.rb +2 -2
  12. data/lib/active_record/associations/singular_association.rb +8 -3
  13. data/lib/active_record/associations.rb +34 -4
  14. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  15. data/lib/active_record/attribute_assignment.rb +9 -1
  16. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -0
  17. data/lib/active_record/attributes.rb +6 -5
  18. data/lib/active_record/autosave_association.rb +69 -27
  19. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +16 -10
  20. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
  21. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
  22. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +23 -44
  23. data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
  24. data/lib/active_record/connection_adapters/abstract/query_cache.rb +53 -18
  25. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  26. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  27. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +26 -5
  28. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
  29. data/lib/active_record/connection_adapters/abstract_adapter.rb +24 -25
  30. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +20 -38
  31. data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
  32. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
  33. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +44 -46
  34. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +42 -98
  35. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -8
  36. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -42
  37. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  38. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  39. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +0 -1
  40. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +50 -6
  41. data/lib/active_record/connection_adapters/postgresql_adapter.rb +38 -90
  42. data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
  43. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +76 -100
  44. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  45. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +13 -0
  46. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +8 -1
  47. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -12
  48. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
  49. data/lib/active_record/connection_adapters/trilogy_adapter.rb +0 -17
  50. data/lib/active_record/connection_handling.rb +22 -0
  51. data/lib/active_record/core.rb +16 -9
  52. data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
  53. data/lib/active_record/encryption/config.rb +3 -1
  54. data/lib/active_record/encryption/encryptable_record.rb +5 -5
  55. data/lib/active_record/encryption/encrypted_attribute_type.rb +12 -3
  56. data/lib/active_record/encryption/encryptor.rb +16 -9
  57. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  58. data/lib/active_record/encryption/key_provider.rb +1 -1
  59. data/lib/active_record/encryption/scheme.rb +8 -1
  60. data/lib/active_record/encryption.rb +2 -0
  61. data/lib/active_record/enum.rb +8 -0
  62. data/lib/active_record/errors.rb +13 -5
  63. data/lib/active_record/fixtures.rb +0 -1
  64. data/lib/active_record/future_result.rb +14 -10
  65. data/lib/active_record/gem_version.rb +3 -3
  66. data/lib/active_record/insert_all.rb +1 -1
  67. data/lib/active_record/migration/command_recorder.rb +22 -5
  68. data/lib/active_record/migration/compatibility.rb +5 -2
  69. data/lib/active_record/migration.rb +35 -33
  70. data/lib/active_record/model_schema.rb +6 -3
  71. data/lib/active_record/nested_attributes.rb +11 -2
  72. data/lib/active_record/persistence.rb +128 -130
  73. data/lib/active_record/query_logs.rb +97 -39
  74. data/lib/active_record/query_logs_formatter.rb +17 -28
  75. data/lib/active_record/querying.rb +6 -6
  76. data/lib/active_record/railtie.rb +8 -14
  77. data/lib/active_record/reflection.rb +19 -10
  78. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  79. data/lib/active_record/relation/batches.rb +135 -75
  80. data/lib/active_record/relation/calculations.rb +24 -19
  81. data/lib/active_record/relation/delegation.rb +25 -14
  82. data/lib/active_record/relation/finder_methods.rb +18 -18
  83. data/lib/active_record/relation/merger.rb +8 -8
  84. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  85. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  86. data/lib/active_record/relation/predicate_builder.rb +6 -1
  87. data/lib/active_record/relation/query_methods.rb +58 -37
  88. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  89. data/lib/active_record/relation/spawn_methods.rb +1 -1
  90. data/lib/active_record/relation.rb +72 -61
  91. data/lib/active_record/result.rb +68 -7
  92. data/lib/active_record/sanitization.rb +7 -6
  93. data/lib/active_record/schema_dumper.rb +5 -0
  94. data/lib/active_record/schema_migration.rb +2 -1
  95. data/lib/active_record/scoping/named.rb +6 -2
  96. data/lib/active_record/statement_cache.rb +12 -12
  97. data/lib/active_record/store.rb +7 -3
  98. data/lib/active_record/tasks/database_tasks.rb +36 -16
  99. data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
  100. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
  101. data/lib/active_record/test_fixtures.rb +12 -0
  102. data/lib/active_record/token_for.rb +1 -1
  103. data/lib/active_record/validations/uniqueness.rb +9 -8
  104. data/lib/active_record.rb +15 -0
  105. data/lib/arel/collectors/bind.rb +1 -1
  106. metadata +14 -14
@@ -89,6 +89,7 @@ module ActiveRecord
89
89
  class_attribute :belongs_to_required_by_default, instance_accessor: false
90
90
 
91
91
  class_attribute :strict_loading_by_default, instance_accessor: false, default: false
92
+ class_attribute :strict_loading_mode, instance_accessor: false, default: :all
92
93
 
93
94
  class_attribute :has_many_inversing, instance_accessor: false, default: false
94
95
 
@@ -103,7 +104,7 @@ module ActiveRecord
103
104
  class_attribute :shard_selector, instance_accessor: false, default: nil
104
105
 
105
106
  # Specifies the attributes that will be included in the output of the #inspect method
106
- class_attribute :attributes_for_inspect, instance_accessor: false, default: [:id]
107
+ class_attribute :attributes_for_inspect, instance_accessor: false, default: :all
107
108
 
108
109
  def self.application_record_class? # :nodoc:
109
110
  if ActiveRecord.application_record_class
@@ -349,12 +350,12 @@ module ActiveRecord
349
350
 
350
351
  # Returns a string like 'Post(id:integer, title:string, body:text)'
351
352
  def inspect # :nodoc:
352
- if self == Base
353
+ if self == Base || singleton_class?
353
354
  super
354
355
  elsif abstract_class?
355
356
  "#{super}(abstract)"
356
- elsif !connected?
357
- "#{super} (call '#{super}.lease_connection' to establish a connection)"
357
+ elsif !schema_loaded? && !connected?
358
+ "#{super} (call '#{super}.load_schema' to load schema informations)"
358
359
  elsif table_exists?
359
360
  attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ", "
360
361
  "#{super}(#{attr_list})"
@@ -431,8 +432,8 @@ module ActiveRecord
431
432
  where(wheres).limit(1)
432
433
  }
433
434
 
434
- begin
435
- statement.execute(values.flatten, connection, allow_retry: true).first
435
+ statement.execute(values.flatten, connection, allow_retry: true).then do |r|
436
+ r.first
436
437
  rescue TypeError
437
438
  raise ActiveRecord::StatementInvalid
438
439
  end
@@ -731,7 +732,7 @@ module ActiveRecord
731
732
 
732
733
  # Returns the full contents of the record as a nicely formatted string.
733
734
  def full_inspect
734
- inspect_with_attributes(attribute_names)
735
+ inspect_with_attributes(all_attributes_for_inspect)
735
736
  end
736
737
 
737
738
  # Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
@@ -784,7 +785,7 @@ module ActiveRecord
784
785
 
785
786
  @primary_key = klass.primary_key
786
787
  @strict_loading = klass.strict_loading_by_default
787
- @strict_loading_mode = :all
788
+ @strict_loading_mode = klass.strict_loading_mode
788
789
 
789
790
  klass.define_attribute_methods
790
791
  end
@@ -823,7 +824,13 @@ module ActiveRecord
823
824
  end
824
825
 
825
826
  def attributes_for_inspect
826
- self.class.attributes_for_inspect == :all ? attribute_names : self.class.attributes_for_inspect
827
+ self.class.attributes_for_inspect == :all ? all_attributes_for_inspect : self.class.attributes_for_inspect
828
+ end
829
+
830
+ def all_attributes_for_inspect
831
+ return [] unless @attributes
832
+
833
+ attribute_names
827
834
  end
828
835
  end
829
836
  end
@@ -45,7 +45,7 @@ module ActiveRecord
45
45
  attr_reader :uri
46
46
 
47
47
  def uri_parser
48
- @uri_parser ||= URI::Parser.new
48
+ @uri_parser ||= URI::RFC2396_Parser.new
49
49
  end
50
50
 
51
51
  # Converts the query parameters of the URI into a hash.
@@ -8,7 +8,8 @@ module ActiveRecord
8
8
  class Config
9
9
  attr_accessor :primary_key, :deterministic_key, :store_key_references, :key_derivation_salt, :hash_digest_class,
10
10
  :support_unencrypted_data, :encrypt_fixtures, :validate_column_size, :add_to_filter_parameters,
11
- :excluded_from_filter_parameters, :extend_queries, :previous_schemes, :forced_encoding_for_deterministic_encryption
11
+ :excluded_from_filter_parameters, :extend_queries, :previous_schemes, :forced_encoding_for_deterministic_encryption,
12
+ :compressor
12
13
 
13
14
  def initialize
14
15
  set_defaults
@@ -55,6 +56,7 @@ module ActiveRecord
55
56
  self.previous_schemes = []
56
57
  self.forced_encoding_for_deterministic_encryption = Encoding::UTF_8
57
58
  self.hash_digest_class = OpenSSL::Digest::SHA1
59
+ self.compressor = Zlib
58
60
 
59
61
  # TODO: Setting to false for now as the implementation is a bit experimental
60
62
  self.extend_queries = false
@@ -46,11 +46,11 @@ module ActiveRecord
46
46
  # * <tt>:previous</tt> - List of previous encryption schemes. When provided, they will be used in order when trying to read
47
47
  # the attribute. Each entry of the list can contain the properties supported by #encrypts. Also, when deterministic
48
48
  # encryption is used, they will be used to generate additional ciphertexts to check in the queries.
49
- def encrypts(*names, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], **context_properties)
49
+ def encrypts(*names, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], compress: true, compressor: nil, **context_properties)
50
50
  self.encrypted_attributes ||= Set.new # not using :default because the instance would be shared across classes
51
51
 
52
52
  names.each do |name|
53
- encrypt_attribute name, key_provider: key_provider, key: key, deterministic: deterministic, support_unencrypted_data: support_unencrypted_data, downcase: downcase, ignore_case: ignore_case, previous: previous, **context_properties
53
+ encrypt_attribute name, key_provider: key_provider, key: key, deterministic: deterministic, support_unencrypted_data: support_unencrypted_data, downcase: downcase, ignore_case: ignore_case, previous: previous, compress: compress, compressor: compressor, **context_properties
54
54
  end
55
55
  end
56
56
 
@@ -81,12 +81,12 @@ module ActiveRecord
81
81
  end
82
82
  end
83
83
 
84
- def encrypt_attribute(name, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], **context_properties)
84
+ def encrypt_attribute(name, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], compress: true, compressor: nil, **context_properties)
85
85
  encrypted_attributes << name.to_sym
86
86
 
87
87
  decorate_attributes([name]) do |name, cast_type|
88
88
  scheme = scheme_for key_provider: key_provider, key: key, deterministic: deterministic, support_unencrypted_data: support_unencrypted_data, \
89
- downcase: downcase, ignore_case: ignore_case, previous: previous, **context_properties
89
+ downcase: downcase, ignore_case: ignore_case, previous: previous, compress: compress, compressor: compressor, **context_properties
90
90
 
91
91
  ActiveRecord::Encryption::EncryptedAttributeType.new(scheme: scheme, cast_type: cast_type, default: columns_hash[name.to_s]&.default)
92
92
  end
@@ -123,7 +123,7 @@ module ActiveRecord
123
123
  end)
124
124
  end
125
125
 
126
- def load_schema!
126
+ def load_schema! # :nodoc:
127
127
  super
128
128
 
129
129
  add_length_validation_for_encrypted_columns if ActiveRecord::Encryption.config.validate_column_size
@@ -7,13 +7,13 @@ module ActiveRecord
7
7
  # This is the central piece that connects the encryption system with +encrypts+ declarations in the
8
8
  # model classes. Whenever you declare an attribute as encrypted, it configures an +EncryptedAttributeType+
9
9
  # for that attribute.
10
- class EncryptedAttributeType < ::ActiveRecord::Type::Text
10
+ class EncryptedAttributeType < ::ActiveModel::Type::Value
11
11
  include ActiveModel::Type::Helpers::Mutable
12
12
 
13
13
  attr_reader :scheme, :cast_type
14
14
 
15
15
  delegate :key_provider, :downcase?, :deterministic?, :previous_schemes, :with_context, :fixed?, to: :scheme
16
- delegate :accessor, to: :cast_type
16
+ delegate :accessor, :type, to: :cast_type
17
17
 
18
18
  # === Options
19
19
  #
@@ -100,7 +100,7 @@ module ActiveRecord
100
100
  end
101
101
 
102
102
  def decrypt(value)
103
- text_to_database_type decrypt_as_text(value)
103
+ text_to_database_type decrypt_as_text(database_type_to_text(value))
104
104
  end
105
105
 
106
106
  def try_to_deserialize_with_previous_encrypted_types(value)
@@ -170,6 +170,15 @@ module ActiveRecord
170
170
  value
171
171
  end
172
172
  end
173
+
174
+ def database_type_to_text(value)
175
+ if value && cast_type.binary?
176
+ binary_cast_type = cast_type.serialized? ? cast_type.subtype : cast_type
177
+ binary_cast_type.deserialize(value)
178
+ else
179
+ value
180
+ end
181
+ end
173
182
  end
174
183
  end
175
184
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "openssl"
4
- require "zlib"
5
4
  require "active_support/core_ext/numeric"
6
5
 
7
6
  module ActiveRecord
@@ -12,12 +11,20 @@ module ActiveRecord
12
11
  # It interacts with a KeyProvider for getting the keys, and delegate to
13
12
  # ActiveRecord::Encryption::Cipher the actual encryption algorithm.
14
13
  class Encryptor
14
+ # The compressor to use for compressing the payload
15
+ attr_reader :compressor
16
+
15
17
  # === Options
16
18
  #
17
19
  # * <tt>:compress</tt> - Boolean indicating whether records should be compressed before encryption.
18
20
  # Defaults to +true+.
19
- def initialize(compress: true)
21
+ # * <tt>:compressor</tt> - The compressor to use.
22
+ # 1. If compressor is provided, it will be used.
23
+ # 2. If not, it will use ActiveRecord::Encryption.config.compressor which default value is +Zlib+.
24
+ # If you want to use a custom compressor, it must respond to +deflate+ and +inflate+.
25
+ def initialize(compress: true, compressor: nil)
20
26
  @compress = compress
27
+ @compressor = compressor || ActiveRecord::Encryption.config.compressor
21
28
  end
22
29
 
23
30
  # Encrypts +clean_text+ and returns the encrypted result
@@ -46,7 +53,7 @@ module ActiveRecord
46
53
  serialize_message build_encrypted_message(clear_text, key_provider: key_provider, cipher_options: cipher_options)
47
54
  end
48
55
 
49
- # Decrypts a +clean_text+ and returns the result as clean text
56
+ # Decrypts an +encrypted_text+ and returns the result as clean text
50
57
  #
51
58
  # === Options
52
59
  #
@@ -78,6 +85,10 @@ module ActiveRecord
78
85
  serializer.binary?
79
86
  end
80
87
 
88
+ def compress? # :nodoc:
89
+ @compress
90
+ end
91
+
81
92
  private
82
93
  DECRYPT_ERRORS = [OpenSSL::Cipher::CipherError, Errors::EncryptedContentIntegrity, Errors::Decryption]
83
94
  ENCODING_ERRORS = [EncodingError, Errors::Encoding]
@@ -130,12 +141,8 @@ module ActiveRecord
130
141
  end
131
142
  end
132
143
 
133
- def compress?
134
- @compress
135
- end
136
-
137
144
  def compress(data)
138
- Zlib::Deflate.deflate(data).tap do |compressed_data|
145
+ @compressor.deflate(data).tap do |compressed_data|
139
146
  compressed_data.force_encoding(data.encoding)
140
147
  end
141
148
  end
@@ -149,7 +156,7 @@ module ActiveRecord
149
156
  end
150
157
 
151
158
  def uncompress(data)
152
- Zlib::Inflate.inflate(data).tap do |uncompressed_data|
159
+ @compressor.inflate(data).tap do |uncompressed_data|
153
160
  uncompressed_data.force_encoding(data.encoding)
154
161
  end
155
162
  end
@@ -41,6 +41,8 @@ module ActiveRecord
41
41
  module EncryptedQuery # :nodoc:
42
42
  class << self
43
43
  def process_arguments(owner, args, check_for_additional_values)
44
+ owner = owner.model if owner.is_a?(Relation)
45
+
44
46
  return args if owner.deterministic_encrypted_attributes&.empty?
45
47
 
46
48
  if args.is_a?(Array) && (options = args.first).is_a?(Hash)
@@ -102,12 +104,12 @@ module ActiveRecord
102
104
  end
103
105
 
104
106
  def scope_for_create
105
- return super unless klass.deterministic_encrypted_attributes&.any?
107
+ return super unless model.deterministic_encrypted_attributes&.any?
106
108
 
107
109
  scope_attributes = super
108
110
  wheres = where_values_hash
109
111
 
110
- klass.deterministic_encrypted_attributes.each do |attribute_name|
112
+ model.deterministic_encrypted_attributes.each do |attribute_name|
111
113
  attribute_name = attribute_name.to_s
112
114
  values = wheres[attribute_name]
113
115
  if values.is_a?(Array) && values[1..].all?(AdditionalValue)
@@ -12,7 +12,7 @@ module ActiveRecord
12
12
  @keys = Array(keys)
13
13
  end
14
14
 
15
- # Returns the first key in the list as the active key to perform encryptions
15
+ # Returns the last key in the list as the active key to perform encryptions
16
16
  #
17
17
  # When +ActiveRecord::Encryption.config.store_key_references+ is true, the key will include
18
18
  # a public tag referencing the key itself. That key will be stored in the public
@@ -11,7 +11,7 @@ module ActiveRecord
11
11
  attr_accessor :previous_schemes
12
12
 
13
13
  def initialize(key_provider: nil, key: nil, deterministic: nil, support_unencrypted_data: nil, downcase: nil, ignore_case: nil,
14
- previous_schemes: nil, **context_properties)
14
+ previous_schemes: nil, compress: true, compressor: nil, **context_properties)
15
15
  # Initializing all attributes to +nil+ as we want to allow a "not set" semantics so that we
16
16
  # can merge schemes without overriding values with defaults. See +#merge+
17
17
 
@@ -24,8 +24,13 @@ module ActiveRecord
24
24
  @previous_schemes_param = previous_schemes
25
25
  @previous_schemes = Array.wrap(previous_schemes)
26
26
  @context_properties = context_properties
27
+ @compress = compress
28
+ @compressor = compressor
27
29
 
28
30
  validate_config!
31
+
32
+ @context_properties[:encryptor] = Encryptor.new(compress: @compress) unless @compress
33
+ @context_properties[:encryptor] = Encryptor.new(compressor: compressor) if compressor
29
34
  end
30
35
 
31
36
  def ignore_case?
@@ -78,6 +83,8 @@ module ActiveRecord
78
83
  def validate_config!
79
84
  raise Errors::Configuration, "ignore_case: can only be used with deterministic encryption" if @ignore_case && !@deterministic
80
85
  raise Errors::Configuration, "key_provider: and key: can't be used simultaneously" if @key_provider_param && @key
86
+ raise Errors::Configuration, "compressor: can't be used with compress: false" if !@compress && @compressor
87
+ raise Errors::Configuration, "compressor: can't be used with encryptor" if @compressor && @context_properties[:encryptor]
81
88
  end
82
89
 
83
90
  def key_provider_from_key
@@ -53,4 +53,6 @@ module ActiveRecord
53
53
  Cipher.eager_load!
54
54
  end
55
55
  end
56
+
57
+ ActiveSupport.run_load_hooks :active_record_encryption, Encryption
56
58
  end
@@ -240,6 +240,7 @@ module ActiveRecord
240
240
 
241
241
  def _enum(name, values, prefix: nil, suffix: nil, scopes: true, instance_methods: true, validate: false, **options)
242
242
  assert_valid_enum_definition_values(values)
243
+ assert_valid_enum_options(options)
243
244
  # statuses = { }
244
245
  enum_values = ActiveSupport::HashWithIndifferentAccess.new
245
246
  name = name.to_s
@@ -370,6 +371,13 @@ module ActiveRecord
370
371
  end
371
372
  end
372
373
 
374
+ def assert_valid_enum_options(options)
375
+ invalid_keys = options.keys & %i[_prefix _suffix _scopes _default _instance_methods]
376
+ unless invalid_keys.empty?
377
+ raise ArgumentError, "invalid option(s): #{invalid_keys.map(&:inspect).join(", ")}. Valid options are: :prefix, :suffix, :scopes, :default, :instance_methods, and :validate."
378
+ end
379
+ end
380
+
373
381
  ENUM_CONFLICT_MESSAGE = \
374
382
  "You tried to define an enum named \"%{enum}\" on the model \"%{klass}\", but " \
375
383
  "this will generate a %{type} method \"%{method}\", which is already defined " \
@@ -84,6 +84,19 @@ module ActiveRecord
84
84
  class ConnectionTimeoutError < ConnectionNotEstablished
85
85
  end
86
86
 
87
+ # Raised when a database connection pool is requested but
88
+ # has not been defined.
89
+ class ConnectionNotDefined < ConnectionNotEstablished
90
+ def initialize(message = nil, connection_name: nil, role: nil, shard: nil)
91
+ super(message)
92
+ @connection_name = connection_name
93
+ @role = role
94
+ @shard = shard
95
+ end
96
+
97
+ attr_reader :connection_name, :role, :shard
98
+ end
99
+
87
100
  # Raised when connection to the database could not been established because it was not
88
101
  # able to connect to the host or when the authorization failed.
89
102
  class DatabaseConnectionError < ConnectionNotEstablished
@@ -484,11 +497,6 @@ module ActiveRecord
484
497
  # relation.limit!(5) # => ActiveRecord::UnmodifiableRelation
485
498
  class UnmodifiableRelation < ActiveRecordError
486
499
  end
487
- deprecate_constant(
488
- :ImmutableRelation,
489
- "ActiveRecord::UnmodifiableRelation",
490
- deprecator: ActiveRecord.deprecator
491
- )
492
500
 
493
501
  # TransactionIsolationError will be raised under the following conditions:
494
502
  #
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "erb"
4
4
  require "yaml"
5
- require "zlib"
6
5
  require "set"
7
6
  require "active_support/dependencies"
8
7
  require "active_support/core_ext/digest/uuid"
@@ -100,17 +100,21 @@ module ActiveRecord
100
100
  def execute_or_skip
101
101
  return unless pending?
102
102
 
103
- @pool.with_connection do |connection|
104
- return unless @mutex.try_lock
105
- begin
106
- if pending?
107
- @event_buffer = EventBuffer.new(self, @instrumenter)
108
- connection.with_instrumenter(@event_buffer) do
109
- execute_query(connection, async: true)
103
+ @session.synchronize do
104
+ return unless pending?
105
+
106
+ @pool.with_connection do |connection|
107
+ return unless @mutex.try_lock
108
+ begin
109
+ if pending?
110
+ @event_buffer = EventBuffer.new(self, @instrumenter)
111
+ connection.with_instrumenter(@event_buffer) do
112
+ execute_query(connection, async: true)
113
+ end
110
114
  end
115
+ ensure
116
+ @mutex.unlock
111
117
  end
112
- ensure
113
- @mutex.unlock
114
118
  end
115
119
  end
116
120
  end
@@ -163,7 +167,7 @@ module ActiveRecord
163
167
  end
164
168
 
165
169
  def exec_query(connection, *args, **kwargs)
166
- connection.internal_exec_query(*args, **kwargs)
170
+ connection.raw_exec_query(*args, **kwargs)
167
171
  end
168
172
 
169
173
  class SelectAll < FutureResult # :nodoc:
@@ -7,10 +7,10 @@ module ActiveRecord
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 7
11
- MINOR = 2
10
+ MAJOR = 8
11
+ MINOR = 0
12
12
  TINY = 0
13
- PRE = nil
13
+ PRE = "beta1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -240,7 +240,7 @@ module ActiveRecord
240
240
 
241
241
  values_list = insert_all.map_key_with_value do |key, value|
242
242
  next value if Arel::Nodes::SqlLiteral === value
243
- connection.with_yaml_fallback(types[key].serialize(value))
243
+ types[key].serialize(types[key].cast(value))
244
244
  end
245
245
 
246
246
  connection.visitor.compile(Arel::Nodes::ValuesList.new(values_list))
@@ -22,10 +22,12 @@ module ActiveRecord
22
22
  # * change_table_comment (must supply a +:from+ and +:to+ option)
23
23
  # * create_enum
24
24
  # * create_join_table
25
+ # * create_virtual_table
25
26
  # * create_table
26
27
  # * disable_extension
27
28
  # * drop_enum (must supply a list of values)
28
29
  # * drop_join_table
30
+ # * drop_virtual_table (must supply options)
29
31
  # * drop_table (must supply a block)
30
32
  # * enable_extension
31
33
  # * remove_column (must supply a type)
@@ -55,6 +57,8 @@ module ActiveRecord
55
57
  :add_exclusion_constraint, :remove_exclusion_constraint,
56
58
  :add_unique_constraint, :remove_unique_constraint,
57
59
  :create_enum, :drop_enum, :rename_enum, :add_enum_value, :rename_enum_value,
60
+ :create_schema, :drop_schema,
61
+ :create_virtual_table, :drop_virtual_table
58
62
  ]
59
63
  include JoinTable
60
64
 
@@ -163,7 +167,9 @@ module ActiveRecord
163
167
  add_exclusion_constraint: :remove_exclusion_constraint,
164
168
  add_unique_constraint: :remove_unique_constraint,
165
169
  enable_extension: :disable_extension,
166
- create_enum: :drop_enum
170
+ create_enum: :drop_enum,
171
+ create_schema: :drop_schema,
172
+ create_virtual_table: :drop_virtual_table
167
173
  }.each do |cmd, inv|
168
174
  [[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
169
175
  class_eval <<-EOV, __FILE__, __LINE__ + 1
@@ -196,13 +202,18 @@ module ActiveRecord
196
202
  end
197
203
 
198
204
  def invert_drop_table(args, &block)
199
- if args.last.is_a?(Hash)
200
- args.last.delete(:if_exists)
205
+ options = args.extract_options!
206
+ options.delete(:if_exists)
207
+
208
+ if args.size > 1
209
+ raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given a single table name."
201
210
  end
202
- if args.size == 1 && block == nil
211
+
212
+ if args.size == 1 && options == {} && block == nil
203
213
  raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
204
214
  end
205
- super
215
+
216
+ super(args.push(options), &block)
206
217
  end
207
218
 
208
219
  def invert_rename_table(args)
@@ -372,6 +383,12 @@ module ActiveRecord
372
383
  [:rename_enum_value, [type_name, from: options[:to], to: options[:from]]]
373
384
  end
374
385
 
386
+ def invert_drop_virtual_table(args)
387
+ _enum, values = args.dup.tap(&:extract_options!)
388
+ raise ActiveRecord::IrreversibleMigration, "drop_virtual_table is only reversible if given options." unless values
389
+ super
390
+ end
391
+
375
392
  def respond_to_missing?(method, _)
376
393
  super || delegate.respond_to?(method)
377
394
  end
@@ -21,7 +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
- # 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2
24
+ # 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2 < 8.0
25
25
  #
26
26
  # If you are introducing new migration functionality that should only apply from Rails 7 onward, then you should
27
27
  # find the class that immediately precedes it (6.1), and override the relevant migration methods to undo your changes.
@@ -29,7 +29,10 @@ module ActiveRecord
29
29
  # For example, Rails 6 added a default value for the `precision` option on datetime columns. So in this file, the `V5_2`
30
30
  # class sets the value of `precision` to `nil` if it's not explicitly provided. This way, the default value will not apply
31
31
  # for migrations written for 5.2, but will for migrations written for 6.0.
32
- V7_2 = Current
32
+ V8_0 = Current
33
+
34
+ class V7_2 < V8_0
35
+ end
33
36
 
34
37
  class V7_1 < V7_2
35
38
  end