activerecord 7.0.8.7 → 7.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1339 -1572
- data/MIT-LICENSE +1 -1
- data/README.rdoc +15 -16
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +18 -3
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +16 -11
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +20 -13
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency.rb +10 -8
- data/lib/active_record/associations/preloader/association.rb +27 -6
- data/lib/active_record/associations/preloader.rb +12 -9
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +193 -97
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +40 -26
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +18 -5
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +105 -21
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +55 -9
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +10 -24
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +163 -88
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +63 -43
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +109 -32
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +60 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +289 -122
- data/lib/active_record/connection_adapters/abstract/transaction.rb +280 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +502 -91
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +200 -108
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -143
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -12
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -29
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +9 -6
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +351 -54
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +336 -168
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +42 -36
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +4 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -7
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +162 -77
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +71 -94
- data/lib/active_record/core.rb +128 -138
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +22 -12
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +86 -33
- data/lib/active_record/delegated_type.rb +8 -3
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +2 -0
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +36 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +17 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -54
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +2 -2
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/scheme.rb +19 -22
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +113 -26
- data/lib/active_record/errors.rb +89 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +119 -71
- data/lib/active_record/future_result.rb +30 -5
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +55 -8
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +118 -30
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +5 -7
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +100 -4
- data/lib/active_record/migration/compatibility.rb +131 -5
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration.rb +213 -109
- data/lib/active_record/model_schema.rb +47 -27
- data/lib/active_record/nested_attributes.rb +28 -3
- data/lib/active_record/normalization.rb +158 -0
- data/lib/active_record/persistence.rb +183 -33
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +77 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +15 -2
- data/lib/active_record/railtie.rb +107 -45
- data/lib/active_record/railties/controller_runtime.rb +10 -5
- data/lib/active_record/railties/databases.rake +139 -145
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +169 -45
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +152 -63
- data/lib/active_record/relation/delegation.rb +22 -8
- data/lib/active_record/relation/finder_methods.rb +85 -15
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -2
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +26 -14
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +351 -62
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +76 -35
- data/lib/active_record/result.rb +19 -5
- data/lib/active_record/runtime_registry.rb +10 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +41 -7
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +2 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +7 -5
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +10 -1
- data/lib/active_record/tasks/database_tasks.rb +127 -105
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -7
- data/lib/active_record/test_fixtures.rb +113 -96
- data/lib/active_record/timestamp.rb +26 -14
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +36 -10
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +47 -2
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +121 -16
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +0 -8
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +81 -17
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +52 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
data/lib/active_record/enum.rb
CHANGED
@@ -111,23 +111,79 @@ module ActiveRecord
|
|
111
111
|
#
|
112
112
|
# conversation.comments_inactive!
|
113
113
|
# conversation.comments_active? # => false
|
114
|
+
#
|
115
|
+
# If you want to disable the auto-generated methods on the model, you can do
|
116
|
+
# so by setting the +:instance_methods+ option to false:
|
117
|
+
#
|
118
|
+
# class Conversation < ActiveRecord::Base
|
119
|
+
# enum :status, [ :active, :archived ], instance_methods: false
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# If you want the enum value to be validated before saving, use the option +:validate+:
|
123
|
+
#
|
124
|
+
# class Conversation < ActiveRecord::Base
|
125
|
+
# enum :status, [ :active, :archived ], validate: true
|
126
|
+
# end
|
127
|
+
#
|
128
|
+
# conversation = Conversation.new
|
129
|
+
#
|
130
|
+
# conversation.status = :unknown
|
131
|
+
# conversation.valid? # => false
|
132
|
+
#
|
133
|
+
# conversation.status = nil
|
134
|
+
# conversation.valid? # => false
|
135
|
+
#
|
136
|
+
# conversation.status = :active
|
137
|
+
# conversation.valid? # => true
|
138
|
+
#
|
139
|
+
# It is also possible to pass additional validation options:
|
140
|
+
#
|
141
|
+
# class Conversation < ActiveRecord::Base
|
142
|
+
# enum :status, [ :active, :archived ], validate: { allow_nil: true }
|
143
|
+
# end
|
144
|
+
#
|
145
|
+
# conversation = Conversation.new
|
146
|
+
#
|
147
|
+
# conversation.status = :unknown
|
148
|
+
# conversation.valid? # => false
|
149
|
+
#
|
150
|
+
# conversation.status = nil
|
151
|
+
# conversation.valid? # => true
|
152
|
+
#
|
153
|
+
# conversation.status = :active
|
154
|
+
# conversation.valid? # => true
|
155
|
+
#
|
156
|
+
# Otherwise +ArgumentError+ will raise:
|
157
|
+
#
|
158
|
+
# class Conversation < ActiveRecord::Base
|
159
|
+
# enum :status, [ :active, :archived ]
|
160
|
+
# end
|
161
|
+
#
|
162
|
+
# conversation = Conversation.new
|
163
|
+
#
|
164
|
+
# conversation.status = :unknown # 'unknown' is not a valid status (ArgumentError)
|
114
165
|
module Enum
|
115
166
|
def self.extended(base) # :nodoc:
|
116
167
|
base.class_attribute(:defined_enums, instance_writer: false, default: {})
|
117
168
|
end
|
118
169
|
|
119
|
-
def
|
120
|
-
|
121
|
-
|
170
|
+
def load_schema! # :nodoc:
|
171
|
+
attributes_to_define_after_schema_loads.each do |name, (cast_type, _default)|
|
172
|
+
unless columns_hash.key?(name)
|
173
|
+
cast_type = cast_type[type_for_attribute(name)] if Proc === cast_type
|
174
|
+
raise "Unknown enum attribute '#{name}' for #{self.name}" if Enum::EnumType === cast_type
|
175
|
+
end
|
176
|
+
end
|
122
177
|
end
|
123
178
|
|
124
179
|
class EnumType < Type::Value # :nodoc:
|
125
180
|
delegate :type, to: :subtype
|
126
181
|
|
127
|
-
def initialize(name, mapping, subtype)
|
182
|
+
def initialize(name, mapping, subtype, raise_on_invalid_values: true)
|
128
183
|
@name = name
|
129
184
|
@mapping = mapping
|
130
185
|
@subtype = subtype
|
186
|
+
@_raise_on_invalid_values = raise_on_invalid_values
|
131
187
|
end
|
132
188
|
|
133
189
|
def cast(value)
|
@@ -153,6 +209,8 @@ module ActiveRecord
|
|
153
209
|
end
|
154
210
|
|
155
211
|
def assert_valid_value(value)
|
212
|
+
return unless @_raise_on_invalid_values
|
213
|
+
|
156
214
|
unless value.blank? || mapping.has_key?(value) || mapping.has_value?(value)
|
157
215
|
raise ArgumentError, "'#{value}' is not a valid #{name}"
|
158
216
|
end
|
@@ -170,14 +228,19 @@ module ActiveRecord
|
|
170
228
|
return _enum(name, values, **options)
|
171
229
|
end
|
172
230
|
|
173
|
-
definitions = options.slice!(:_prefix, :_suffix, :_scopes, :_default)
|
231
|
+
definitions = options.slice!(:_prefix, :_suffix, :_scopes, :_default, :_instance_methods)
|
174
232
|
options.transform_keys! { |key| :"#{key[1..-1]}" }
|
175
233
|
|
176
234
|
definitions.each { |name, values| _enum(name, values, **options) }
|
177
235
|
end
|
178
236
|
|
179
237
|
private
|
180
|
-
def
|
238
|
+
def inherited(base)
|
239
|
+
base.defined_enums = defined_enums.deep_dup
|
240
|
+
super
|
241
|
+
end
|
242
|
+
|
243
|
+
def _enum(name, values, prefix: nil, suffix: nil, scopes: true, instance_methods: true, validate: false, **options)
|
181
244
|
assert_valid_enum_definition_values(values)
|
182
245
|
# statuses = { }
|
183
246
|
enum_values = ActiveSupport::HashWithIndifferentAccess.new
|
@@ -193,7 +256,7 @@ module ActiveRecord
|
|
193
256
|
|
194
257
|
attribute(name, **options) do |subtype|
|
195
258
|
subtype = subtype.subtype if EnumType === subtype
|
196
|
-
EnumType.new(name, enum_values, subtype)
|
259
|
+
EnumType.new(name, enum_values, subtype, raise_on_invalid_values: !validate)
|
197
260
|
end
|
198
261
|
|
199
262
|
value_method_names = []
|
@@ -213,18 +276,24 @@ module ActiveRecord
|
|
213
276
|
|
214
277
|
value_method_name = "#{prefix}#{label}#{suffix}"
|
215
278
|
value_method_names << value_method_name
|
216
|
-
define_enum_methods(name, value_method_name, value, scopes)
|
279
|
+
define_enum_methods(name, value_method_name, value, scopes, instance_methods)
|
217
280
|
|
218
281
|
method_friendly_label = label.gsub(/[\W&&[:ascii:]]+/, "_")
|
219
282
|
value_method_alias = "#{prefix}#{method_friendly_label}#{suffix}"
|
220
283
|
|
221
284
|
if value_method_alias != value_method_name && !value_method_names.include?(value_method_alias)
|
222
285
|
value_method_names << value_method_alias
|
223
|
-
define_enum_methods(name, value_method_alias, value, scopes)
|
286
|
+
define_enum_methods(name, value_method_alias, value, scopes, instance_methods)
|
224
287
|
end
|
225
288
|
end
|
226
289
|
end
|
227
290
|
detect_negative_enum_conditions!(value_method_names) if scopes
|
291
|
+
|
292
|
+
if validate
|
293
|
+
validate = {} unless Hash === validate
|
294
|
+
validates_inclusion_of name, in: enum_values.keys, **validate
|
295
|
+
end
|
296
|
+
|
228
297
|
enum_values.freeze
|
229
298
|
end
|
230
299
|
|
@@ -236,21 +305,23 @@ module ActiveRecord
|
|
236
305
|
private
|
237
306
|
attr_reader :klass
|
238
307
|
|
239
|
-
def define_enum_methods(name, value_method_name, value, scopes)
|
240
|
-
|
241
|
-
|
242
|
-
|
308
|
+
def define_enum_methods(name, value_method_name, value, scopes, instance_methods)
|
309
|
+
if instance_methods
|
310
|
+
# def active?() status_for_database == 0 end
|
311
|
+
klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
|
312
|
+
define_method("#{value_method_name}?") { public_send(:"#{name}_for_database") == value }
|
243
313
|
|
244
|
-
|
245
|
-
|
246
|
-
|
314
|
+
# def active!() update!(status: 0) end
|
315
|
+
klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
|
316
|
+
define_method("#{value_method_name}!") { update!(name => value) }
|
317
|
+
end
|
247
318
|
|
248
|
-
# scope :active, -> { where(status: 0) }
|
249
|
-
# scope :not_active, -> { where.not(status: 0) }
|
250
319
|
if scopes
|
320
|
+
# scope :active, -> { where(status: 0) }
|
251
321
|
klass.send(:detect_enum_conflict!, name, value_method_name, true)
|
252
322
|
klass.scope value_method_name, -> { where(name => value) }
|
253
323
|
|
324
|
+
# scope :not_active, -> { where.not(status: 0) }
|
254
325
|
klass.send(:detect_enum_conflict!, name, "not_#{value_method_name}", true)
|
255
326
|
klass.scope "not_#{value_method_name}", -> { where.not(name => value) }
|
256
327
|
end
|
@@ -267,15 +338,29 @@ module ActiveRecord
|
|
267
338
|
end
|
268
339
|
|
269
340
|
def assert_valid_enum_definition_values(values)
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
341
|
+
case values
|
342
|
+
when Hash
|
343
|
+
if values.empty?
|
344
|
+
raise ArgumentError, "Enum values #{values} must not be empty."
|
345
|
+
end
|
346
|
+
|
347
|
+
if values.keys.any?(&:blank?)
|
348
|
+
raise ArgumentError, "Enum values #{values} must not contain a blank name."
|
349
|
+
end
|
350
|
+
when Array
|
351
|
+
if values.empty?
|
352
|
+
raise ArgumentError, "Enum values #{values} must not be empty."
|
353
|
+
end
|
354
|
+
|
355
|
+
unless values.all?(Symbol) || values.all?(String)
|
356
|
+
raise ArgumentError, "Enum values #{values} must only contain symbols or strings."
|
357
|
+
end
|
276
358
|
|
277
|
-
|
278
|
-
|
359
|
+
if values.any?(&:blank?)
|
360
|
+
raise ArgumentError, "Enum values #{values} must not contain a blank name."
|
361
|
+
end
|
362
|
+
else
|
363
|
+
raise ArgumentError, "Enum values #{values} must be either a non-empty hash or an array."
|
279
364
|
end
|
280
365
|
end
|
281
366
|
|
@@ -290,6 +375,8 @@ module ActiveRecord
|
|
290
375
|
raise_conflict_error(enum_name, method_name, type: "class")
|
291
376
|
elsif klass_method && method_defined_within?(method_name, Relation)
|
292
377
|
raise_conflict_error(enum_name, method_name, type: "class", source: Relation.name)
|
378
|
+
elsif klass_method && method_name.to_sym == :id
|
379
|
+
raise_conflict_error(enum_name, method_name)
|
293
380
|
elsif !klass_method && dangerous_attribute_method?(method_name)
|
294
381
|
raise_conflict_error(enum_name, method_name)
|
295
382
|
elsif !klass_method && method_defined_within?(method_name, _enum_methods_module, Module)
|
data/lib/active_record/errors.rb
CHANGED
@@ -7,9 +7,13 @@ module ActiveRecord
|
|
7
7
|
class ActiveRecordError < StandardError
|
8
8
|
end
|
9
9
|
|
10
|
-
#
|
11
|
-
|
12
|
-
|
10
|
+
# DEPRECATED: Previously raised when trying to use a feature in Active Record which
|
11
|
+
# requires Active Job but the gem is not present. Now raises a NameError.
|
12
|
+
include ActiveSupport::Deprecation::DeprecatedConstantAccessor
|
13
|
+
DeprecatedActiveJobRequiredError = Class.new(ActiveRecordError) # :nodoc:
|
14
|
+
deprecate_constant "ActiveJobRequiredError", "ActiveRecord::DeprecatedActiveJobRequiredError",
|
15
|
+
message: "ActiveRecord::ActiveJobRequiredError has been deprecated. If Active Job is not present, a NameError will be raised instead.",
|
16
|
+
deprecator: ActiveRecord.deprecator
|
13
17
|
|
14
18
|
# Raised when the single-table inheritance mechanism fails to locate the subclass
|
15
19
|
# (for example due to improper usage of column that
|
@@ -51,10 +55,31 @@ module ActiveRecord
|
|
51
55
|
class AdapterNotFound < ActiveRecordError
|
52
56
|
end
|
53
57
|
|
58
|
+
# Superclass for all errors raised from an Active Record adapter.
|
59
|
+
class AdapterError < ActiveRecordError
|
60
|
+
def initialize(message = nil, connection_pool: nil)
|
61
|
+
@connection_pool = connection_pool
|
62
|
+
super(message)
|
63
|
+
end
|
64
|
+
|
65
|
+
attr_reader :connection_pool
|
66
|
+
end
|
67
|
+
|
54
68
|
# Raised when connection to the database could not been established (for example when
|
55
69
|
# {ActiveRecord::Base.connection=}[rdoc-ref:ConnectionHandling#connection]
|
56
70
|
# is given a +nil+ object).
|
57
|
-
class ConnectionNotEstablished <
|
71
|
+
class ConnectionNotEstablished < AdapterError
|
72
|
+
def initialize(message = nil, connection_pool: nil)
|
73
|
+
super(message, connection_pool: connection_pool)
|
74
|
+
end
|
75
|
+
|
76
|
+
def set_pool(connection_pool)
|
77
|
+
unless @connection_pool
|
78
|
+
@connection_pool = connection_pool
|
79
|
+
end
|
80
|
+
|
81
|
+
self
|
82
|
+
end
|
58
83
|
end
|
59
84
|
|
60
85
|
# Raised when a connection could not be obtained within the connection
|
@@ -90,7 +115,7 @@ module ActiveRecord
|
|
90
115
|
# Raised when a pool was unable to get ahold of all its connections
|
91
116
|
# to perform a "group" action such as
|
92
117
|
# {ActiveRecord::Base.connection_pool.disconnect!}[rdoc-ref:ConnectionAdapters::ConnectionPool#disconnect!]
|
93
|
-
# or {ActiveRecord::Base.clear_reloadable_connections!}[rdoc-ref:ConnectionAdapters::ConnectionHandler#clear_reloadable_connections!].
|
118
|
+
# or {ActiveRecord::Base.connection_handler.clear_reloadable_connections!}[rdoc-ref:ConnectionAdapters::ConnectionHandler#clear_reloadable_connections!].
|
94
119
|
class ExclusiveConnectionTimeoutError < ConnectionTimeoutError
|
95
120
|
end
|
96
121
|
|
@@ -155,14 +180,23 @@ module ActiveRecord
|
|
155
180
|
# Superclass for all database execution errors.
|
156
181
|
#
|
157
182
|
# Wraps the underlying database error as +cause+.
|
158
|
-
class StatementInvalid <
|
159
|
-
def initialize(message = nil, sql: nil, binds: nil)
|
160
|
-
super(message || $!&.message)
|
183
|
+
class StatementInvalid < AdapterError
|
184
|
+
def initialize(message = nil, sql: nil, binds: nil, connection_pool: nil)
|
185
|
+
super(message || $!&.message, connection_pool: connection_pool)
|
161
186
|
@sql = sql
|
162
187
|
@binds = binds
|
163
188
|
end
|
164
189
|
|
165
190
|
attr_reader :sql, :binds
|
191
|
+
|
192
|
+
def set_query(sql, binds)
|
193
|
+
unless @sql
|
194
|
+
@sql = sql
|
195
|
+
@binds = binds
|
196
|
+
end
|
197
|
+
|
198
|
+
self
|
199
|
+
end
|
166
200
|
end
|
167
201
|
|
168
202
|
# Defunct wrapper class kept for compatibility.
|
@@ -189,8 +223,13 @@ module ActiveRecord
|
|
189
223
|
foreign_key: nil,
|
190
224
|
target_table: nil,
|
191
225
|
primary_key: nil,
|
192
|
-
primary_key_column: nil
|
226
|
+
primary_key_column: nil,
|
227
|
+
query_parser: nil,
|
228
|
+
connection_pool: nil
|
193
229
|
)
|
230
|
+
@original_message = message
|
231
|
+
@query_parser = query_parser
|
232
|
+
|
194
233
|
if table
|
195
234
|
type = primary_key_column.bigint? ? :bigint : primary_key_column.type
|
196
235
|
msg = <<~EOM.squish
|
@@ -208,7 +247,24 @@ module ActiveRecord
|
|
208
247
|
if message
|
209
248
|
msg << "\nOriginal message: #{message}"
|
210
249
|
end
|
211
|
-
|
250
|
+
|
251
|
+
super(msg, sql: sql, binds: binds, connection_pool: connection_pool)
|
252
|
+
end
|
253
|
+
|
254
|
+
def set_query(sql, binds)
|
255
|
+
if @query_parser && !@sql
|
256
|
+
self.class.new(
|
257
|
+
message: @original_message,
|
258
|
+
sql: sql,
|
259
|
+
binds: binds,
|
260
|
+
connection_pool: @connection_pool,
|
261
|
+
**@query_parser.call(sql)
|
262
|
+
).tap do |exception|
|
263
|
+
exception.set_backtrace backtrace
|
264
|
+
end
|
265
|
+
else
|
266
|
+
super
|
267
|
+
end
|
212
268
|
end
|
213
269
|
end
|
214
270
|
|
@@ -224,6 +280,19 @@ module ActiveRecord
|
|
224
280
|
class RangeError < StatementInvalid
|
225
281
|
end
|
226
282
|
|
283
|
+
# Raised when a statement produces an SQL warning.
|
284
|
+
class SQLWarning < AdapterError
|
285
|
+
attr_reader :code, :level
|
286
|
+
attr_accessor :sql
|
287
|
+
|
288
|
+
def initialize(message = nil, code = nil, level = nil, sql = nil, connection_pool = nil)
|
289
|
+
super(message, connection_pool: connection_pool)
|
290
|
+
@code = code
|
291
|
+
@level = level
|
292
|
+
@sql = sql
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
227
296
|
# Raised when the number of placeholders in an SQL fragment passed to
|
228
297
|
# {ActiveRecord::Base.where}[rdoc-ref:QueryMethods#where]
|
229
298
|
# does not match the number of values supplied.
|
@@ -242,16 +311,16 @@ module ActiveRecord
|
|
242
311
|
ActiveRecord::Tasks::DatabaseTasks.create_current
|
243
312
|
end
|
244
313
|
|
245
|
-
def initialize(message = nil)
|
246
|
-
super(message || "Database not found")
|
314
|
+
def initialize(message = nil, connection_pool: nil)
|
315
|
+
super(message || "Database not found", connection_pool: connection_pool)
|
247
316
|
end
|
248
317
|
|
249
318
|
class << self
|
250
319
|
def db_error(db_name)
|
251
320
|
NoDatabaseError.new(<<~MSG)
|
252
|
-
We could not find your database: #{db_name}.
|
321
|
+
We could not find your database: #{db_name}. Available database configurations can be found in config/database.yml file.
|
253
322
|
|
254
|
-
To resolve this
|
323
|
+
To resolve this error:
|
255
324
|
|
256
325
|
- Did you create the database for this app, or delete it? You may need to create your database.
|
257
326
|
- Has the database name changed? Check your database.yml config has the correct database name.
|
@@ -407,7 +476,7 @@ module ActiveRecord
|
|
407
476
|
# * You are joining an existing open transaction
|
408
477
|
# * You are creating a nested (savepoint) transaction
|
409
478
|
#
|
410
|
-
# The mysql2 and postgresql adapters support setting the transaction isolation level.
|
479
|
+
# The mysql2, trilogy, and postgresql adapters support setting the transaction isolation level.
|
411
480
|
class TransactionIsolationError < ActiveRecordError
|
412
481
|
end
|
413
482
|
|
@@ -461,6 +530,11 @@ module ActiveRecord
|
|
461
530
|
class AdapterTimeout < QueryAborted
|
462
531
|
end
|
463
532
|
|
533
|
+
# ConnectionFailed will be raised when the network connection to the
|
534
|
+
# database fails while sending a query or waiting for its result.
|
535
|
+
class ConnectionFailed < QueryAborted
|
536
|
+
end
|
537
|
+
|
464
538
|
# UnknownAttributeReference is raised when an unknown and potentially unsafe
|
465
539
|
# value is passed to a query method. For example, passing a non column name
|
466
540
|
# value to a relation's #order method might cause this exception.
|
@@ -16,15 +16,15 @@ module ActiveRecord
|
|
16
16
|
|
17
17
|
# Makes the adapter execute EXPLAIN for the tuples of queries and bindings.
|
18
18
|
# Returns a formatted string ready to be logged.
|
19
|
-
def exec_explain(queries) # :nodoc:
|
19
|
+
def exec_explain(queries, options = []) # :nodoc:
|
20
20
|
str = queries.map do |sql, binds|
|
21
|
-
msg = +"
|
21
|
+
msg = +"#{build_explain_clause(options)} #{sql}"
|
22
22
|
unless binds.empty?
|
23
23
|
msg << " "
|
24
24
|
msg << binds.map { |attr| render_bind(attr) }.inspect
|
25
25
|
end
|
26
26
|
msg << "\n"
|
27
|
-
msg <<
|
27
|
+
msg << connection_explain(sql, binds, options)
|
28
28
|
end.join("\n")
|
29
29
|
|
30
30
|
# Overriding inspect to be more human readable, especially in the console.
|
@@ -50,5 +50,25 @@ module ActiveRecord
|
|
50
50
|
|
51
51
|
[attr&.name, value]
|
52
52
|
end
|
53
|
+
|
54
|
+
def build_explain_clause(options = [])
|
55
|
+
if connection.respond_to?(:build_explain_clause, true)
|
56
|
+
connection.build_explain_clause(options)
|
57
|
+
else
|
58
|
+
"EXPLAIN for:"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def connection_explain(sql, binds, options)
|
63
|
+
if connection.method(:explain).parameters.size == 2
|
64
|
+
ActiveRecord.deprecator.warn(<<~MSG.squish)
|
65
|
+
The current database adapter, #{connection.adapter_name}, does not support explain options.
|
66
|
+
To remove this warning, the adapter must implement `build_explain_clause(options = [])`.
|
67
|
+
MSG
|
68
|
+
connection.explain(sql, binds)
|
69
|
+
else
|
70
|
+
connection.explain(sql, binds, options)
|
71
|
+
end
|
72
|
+
end
|
53
73
|
end
|
54
74
|
end
|
@@ -12,12 +12,22 @@ module ActiveRecord
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def primary_key_type
|
15
|
-
@primary_key_type ||= @model_class &&
|
15
|
+
@primary_key_type ||= @model_class && column_type(@model_class.primary_key)
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
19
|
-
@
|
20
|
-
|
18
|
+
def column_type(column_name)
|
19
|
+
@column_type ||= {}
|
20
|
+
return @column_type[column_name] if @column_type.key?(column_name)
|
21
|
+
|
22
|
+
@column_type[column_name] = @model_class && @model_class.type_for_attribute(column_name).type
|
23
|
+
end
|
24
|
+
|
25
|
+
def has_column?(column_name)
|
26
|
+
column_names.include?(column_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def column_names
|
30
|
+
@column_names ||= @model_class ? @model_class.columns.map(&:name).to_set : Set.new
|
21
31
|
end
|
22
32
|
|
23
33
|
def timestamp_column_names
|
@@ -87,7 +87,7 @@ module ActiveRecord
|
|
87
87
|
return unless model_class
|
88
88
|
fill_timestamps
|
89
89
|
interpolate_label
|
90
|
-
generate_primary_key
|
90
|
+
model_class.composite_primary_key? ? generate_composite_primary_key : generate_primary_key
|
91
91
|
resolve_enums
|
92
92
|
resolve_sti_reflections
|
93
93
|
end
|
@@ -117,14 +117,26 @@ module ActiveRecord
|
|
117
117
|
end
|
118
118
|
|
119
119
|
def generate_primary_key
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
120
|
+
pk = model_metadata.primary_key_name
|
121
|
+
|
122
|
+
unless column_defined?(pk)
|
123
|
+
@row[pk] = ActiveRecord::FixtureSet.identify(@label, model_metadata.column_type(pk))
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def generate_composite_primary_key
|
128
|
+
composite_key = ActiveRecord::FixtureSet.composite_identify(@label, model_metadata.primary_key_name)
|
129
|
+
composite_key.each do |column, value|
|
130
|
+
next if column_defined?(column)
|
131
|
+
|
132
|
+
@row[column] = value
|
125
133
|
end
|
126
134
|
end
|
127
135
|
|
136
|
+
def column_defined?(col)
|
137
|
+
!model_metadata.has_column?(col) || @row.include?(col)
|
138
|
+
end
|
139
|
+
|
128
140
|
def resolve_enums
|
129
141
|
reflection_class.defined_enums.each do |name, values|
|
130
142
|
if @row.include?(name)
|
@@ -151,8 +163,17 @@ module ActiveRecord
|
|
151
163
|
raise PrimaryKeyError.new(@label, association, value)
|
152
164
|
end
|
153
165
|
|
154
|
-
|
155
|
-
|
166
|
+
if fk_name.is_a?(Array)
|
167
|
+
composite_key = ActiveRecord::FixtureSet.composite_identify(value, fk_name)
|
168
|
+
composite_key.each do |column, value|
|
169
|
+
next if column_defined?(column)
|
170
|
+
|
171
|
+
@row[column] = value
|
172
|
+
end
|
173
|
+
else
|
174
|
+
fk_type = reflection_class.type_for_attribute(fk_name).type
|
175
|
+
@row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
|
176
|
+
end
|
156
177
|
end
|
157
178
|
when :has_many
|
158
179
|
if association.options[:through]
|