activerecord 7.1.4.1 → 7.2.2.1
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 +643 -2274
- data/README.rdoc +15 -15
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +15 -8
- data/lib/active_record/associations/belongs_to_association.rb +14 -7
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/belongs_to.rb +1 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/collection_association.rb +7 -1
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +7 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
- data/lib/active_record/associations/join_dependency.rb +4 -4
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +2 -1
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +59 -292
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +23 -55
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +4 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
- data/lib/active_record/attribute_methods.rb +54 -63
- data/lib/active_record/attributes.rb +61 -47
- data/lib/active_record/autosave_association.rb +12 -29
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +270 -65
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +34 -17
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +189 -74
- data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -62
- data/lib/active_record/connection_adapters/abstract_adapter.rb +24 -44
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +40 -10
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +6 -0
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +16 -15
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +5 -23
- data/lib/active_record/connection_adapters/pool_config.rb +7 -6
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +17 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +29 -24
- data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +44 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +25 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +125 -75
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +15 -15
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -48
- data/lib/active_record/connection_adapters.rb +121 -0
- data/lib/active_record/connection_handling.rb +56 -41
- data/lib/active_record/core.rb +86 -38
- data/lib/active_record/counter_cache.rb +18 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
- data/lib/active_record/database_configurations/database_config.rb +19 -4
- data/lib/active_record/database_configurations/hash_config.rb +38 -34
- data/lib/active_record/database_configurations/url_config.rb +20 -1
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +24 -0
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/encryptable_record.rb +3 -3
- data/lib/active_record/encryption/encrypted_attribute_type.rb +24 -4
- data/lib/active_record/encryption/encryptor.rb +18 -3
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption.rb +2 -0
- data/lib/active_record/enum.rb +19 -2
- data/lib/active_record/errors.rb +46 -20
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixtures.rb +37 -31
- data/lib/active_record/future_result.rb +8 -4
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +18 -15
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +7 -6
- data/lib/active_record/log_subscriber.rb +0 -21
- data/lib/active_record/marshalling.rb +4 -1
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +2 -3
- data/lib/active_record/migration/compatibility.rb +5 -3
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +85 -76
- data/lib/active_record/model_schema.rb +32 -68
- data/lib/active_record/nested_attributes.rb +24 -5
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +30 -352
- data/lib/active_record/query_cache.rb +19 -8
- data/lib/active_record/query_logs.rb +15 -0
- data/lib/active_record/querying.rb +21 -9
- data/lib/active_record/railtie.rb +42 -57
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +40 -43
- data/lib/active_record/reflection.rb +98 -36
- data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
- data/lib/active_record/relation/batches.rb +14 -8
- data/lib/active_record/relation/calculations.rb +96 -63
- data/lib/active_record/relation/delegation.rb +8 -11
- data/lib/active_record/relation/finder_methods.rb +16 -2
- data/lib/active_record/relation/merger.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -3
- data/lib/active_record/relation/predicate_builder.rb +3 -3
- data/lib/active_record/relation/query_methods.rb +224 -58
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +2 -18
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +496 -72
- data/lib/active_record/result.rb +31 -44
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +24 -19
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +19 -9
- data/lib/active_record/schema_migration.rb +30 -14
- data/lib/active_record/scoping/named.rb +1 -0
- data/lib/active_record/signed_id.rb +20 -1
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/table_metadata.rb +1 -10
- data/lib/active_record/tasks/database_tasks.rb +81 -42
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
- data/lib/active_record/test_fixtures.rb +86 -89
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +2 -2
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +70 -14
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/uniqueness.rb +15 -10
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +148 -39
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/nodes/binary.rb +0 -6
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +4 -3
- data/lib/arel/nodes/sql_literal.rb +7 -0
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +29 -16
- data/lib/arel.rb +7 -3
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +18 -12
data/lib/active_record/enum.rb
CHANGED
@@ -223,6 +223,13 @@ module ActiveRecord
|
|
223
223
|
options.transform_keys! { |key| :"#{key[1..-1]}" }
|
224
224
|
|
225
225
|
definitions.each { |name, values| _enum(name, values, **options) }
|
226
|
+
|
227
|
+
ActiveRecord.deprecator.warn(<<~MSG)
|
228
|
+
Defining enums with keyword arguments is deprecated and will be removed
|
229
|
+
in Rails 8.0. Positional arguments should be used instead:
|
230
|
+
|
231
|
+
#{definitions.map { |name, values| "enum :#{name}, #{values}" }.join("\n")}
|
232
|
+
MSG
|
226
233
|
end
|
227
234
|
|
228
235
|
private
|
@@ -233,6 +240,7 @@ module ActiveRecord
|
|
233
240
|
|
234
241
|
def _enum(name, values, prefix: nil, suffix: nil, scopes: true, instance_methods: true, validate: false, **options)
|
235
242
|
assert_valid_enum_definition_values(values)
|
243
|
+
assert_valid_enum_options(options)
|
236
244
|
# statuses = { }
|
237
245
|
enum_values = ActiveSupport::HashWithIndifferentAccess.new
|
238
246
|
name = name.to_s
|
@@ -245,9 +253,11 @@ module ActiveRecord
|
|
245
253
|
detect_enum_conflict!(name, name)
|
246
254
|
detect_enum_conflict!(name, "#{name}=")
|
247
255
|
|
248
|
-
attribute(name, **options)
|
256
|
+
attribute(name, **options)
|
257
|
+
|
258
|
+
decorate_attributes([name]) do |_name, subtype|
|
249
259
|
if subtype == ActiveModel::Type.default_value
|
250
|
-
raise "Undeclared attribute type for enum '#{name}'. Enums must be" \
|
260
|
+
raise "Undeclared attribute type for enum '#{name}' in #{self.name}. Enums must be" \
|
251
261
|
" backed by a database column or declared with an explicit type" \
|
252
262
|
" via `attribute`."
|
253
263
|
end
|
@@ -361,6 +371,13 @@ module ActiveRecord
|
|
361
371
|
end
|
362
372
|
end
|
363
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
|
+
|
364
381
|
ENUM_CONFLICT_MESSAGE = \
|
365
382
|
"You tried to define an enum named \"%{enum}\" on the model \"%{klass}\", but " \
|
366
383
|
"this will generate a %{type} method \"%{method}\", which is already defined " \
|
data/lib/active_record/errors.rb
CHANGED
@@ -1,20 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/deprecation"
|
4
|
+
|
3
5
|
module ActiveRecord
|
6
|
+
include ActiveSupport::Deprecation::DeprecatedConstantAccessor
|
7
|
+
|
4
8
|
# = Active Record Errors
|
5
9
|
#
|
6
10
|
# Generic Active Record exception class.
|
7
11
|
class ActiveRecordError < StandardError
|
8
12
|
end
|
9
13
|
|
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
|
17
|
-
|
18
14
|
# Raised when the single-table inheritance mechanism fails to locate the subclass
|
19
15
|
# (for example due to improper usage of column that
|
20
16
|
# {ActiveRecord::Base.inheritance_column}[rdoc-ref:ModelSchema::ClassMethods#inheritance_column]
|
@@ -66,7 +62,7 @@ module ActiveRecord
|
|
66
62
|
end
|
67
63
|
|
68
64
|
# Raised when connection to the database could not been established (for example when
|
69
|
-
# {ActiveRecord::Base.
|
65
|
+
# {ActiveRecord::Base.lease_connection=}[rdoc-ref:ConnectionHandling#lease_connection]
|
70
66
|
# is given a +nil+ object).
|
71
67
|
class ConnectionNotEstablished < AdapterError
|
72
68
|
def initialize(message = nil, connection_pool: nil)
|
@@ -137,8 +133,18 @@ module ActiveRecord
|
|
137
133
|
end
|
138
134
|
|
139
135
|
# Raised by {ActiveRecord::Base#save!}[rdoc-ref:Persistence#save!] and
|
140
|
-
# {ActiveRecord::Base.
|
141
|
-
# methods when a record
|
136
|
+
# {ActiveRecord::Base.update_attribute!}[rdoc-ref:Persistence#update_attribute!]
|
137
|
+
# methods when a record failed to validate or cannot be saved due to any of the
|
138
|
+
# <tt>before_*</tt> callbacks throwing +:abort+. See
|
139
|
+
# ActiveRecord::Callbacks for further details.
|
140
|
+
#
|
141
|
+
# class Product < ActiveRecord::Base
|
142
|
+
# before_save do
|
143
|
+
# throw :abort if price < 0
|
144
|
+
# end
|
145
|
+
# end
|
146
|
+
#
|
147
|
+
# Product.create! # => raises an ActiveRecord::RecordNotSaved
|
142
148
|
class RecordNotSaved < ActiveRecordError
|
143
149
|
attr_reader :record
|
144
150
|
|
@@ -149,15 +155,17 @@ module ActiveRecord
|
|
149
155
|
end
|
150
156
|
|
151
157
|
# Raised by {ActiveRecord::Base#destroy!}[rdoc-ref:Persistence#destroy!]
|
152
|
-
# when a
|
153
|
-
#
|
158
|
+
# when a record cannot be destroyed due to any of the
|
159
|
+
# <tt>before_destroy</tt> callbacks throwing +:abort+. See
|
160
|
+
# ActiveRecord::Callbacks for further details.
|
154
161
|
#
|
155
|
-
#
|
156
|
-
#
|
157
|
-
#
|
158
|
-
#
|
162
|
+
# class User < ActiveRecord::Base
|
163
|
+
# before_destroy do
|
164
|
+
# throw :abort if still_active?
|
165
|
+
# end
|
159
166
|
# end
|
160
167
|
#
|
168
|
+
# User.first.destroy! # => raises an ActiveRecord::RecordNotDestroyed
|
161
169
|
class RecordNotDestroyed < ActiveRecordError
|
162
170
|
attr_reader :record
|
163
171
|
|
@@ -374,6 +382,12 @@ module ActiveRecord
|
|
374
382
|
end
|
375
383
|
|
376
384
|
# Raised on attempt to lazily load records that are marked as strict loading.
|
385
|
+
#
|
386
|
+
# You can resolve this error by eager loading marked records before accessing
|
387
|
+
# them. The
|
388
|
+
# {Eager Loading Associations}[https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations]
|
389
|
+
# guide covers solutions, such as using
|
390
|
+
# {ActiveRecord::Base.includes}[rdoc-ref:QueryMethods#includes].
|
377
391
|
class StrictLoadingViolationError < ActiveRecordError
|
378
392
|
end
|
379
393
|
|
@@ -466,10 +480,15 @@ module ActiveRecord
|
|
466
480
|
# relation.loaded? # => true
|
467
481
|
#
|
468
482
|
# # Methods which try to mutate a loaded relation fail.
|
469
|
-
# relation.where!(title: 'TODO') # => ActiveRecord::
|
470
|
-
# relation.limit!(5) # => ActiveRecord::
|
471
|
-
class
|
483
|
+
# relation.where!(title: 'TODO') # => ActiveRecord::UnmodifiableRelation
|
484
|
+
# relation.limit!(5) # => ActiveRecord::UnmodifiableRelation
|
485
|
+
class UnmodifiableRelation < ActiveRecordError
|
472
486
|
end
|
487
|
+
deprecate_constant(
|
488
|
+
:ImmutableRelation,
|
489
|
+
"ActiveRecord::UnmodifiableRelation",
|
490
|
+
deprecator: ActiveRecord.deprecator
|
491
|
+
)
|
473
492
|
|
474
493
|
# TransactionIsolationError will be raised under the following conditions:
|
475
494
|
#
|
@@ -577,4 +596,11 @@ module ActiveRecord
|
|
577
596
|
# values, such as request parameters or model attributes to query methods.
|
578
597
|
class UnknownAttributeReference < ActiveRecordError
|
579
598
|
end
|
599
|
+
|
600
|
+
# DatabaseVersionError will be raised when the database version is not supported, or when
|
601
|
+
# the database version cannot be determined.
|
602
|
+
class DatabaseVersionError < ActiveRecordError
|
603
|
+
end
|
580
604
|
end
|
605
|
+
|
606
|
+
require "active_record/associations/errors"
|
@@ -17,16 +17,17 @@ module ActiveRecord
|
|
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
19
|
def exec_explain(queries, options = []) # :nodoc:
|
20
|
-
str =
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
20
|
+
str = with_connection do |c|
|
21
|
+
queries.map do |sql, binds|
|
22
|
+
msg = +"#{build_explain_clause(c, options)} #{sql}"
|
23
|
+
unless binds.empty?
|
24
|
+
msg << " "
|
25
|
+
msg << binds.map { |attr| render_bind(c, attr) }.inspect
|
26
|
+
end
|
27
|
+
msg << "\n"
|
28
|
+
msg << c.explain(sql, binds, options)
|
29
|
+
end.join("\n")
|
30
|
+
end
|
30
31
|
# Overriding inspect to be more human readable, especially in the console.
|
31
32
|
def str.inspect
|
32
33
|
self
|
@@ -36,7 +37,7 @@ module ActiveRecord
|
|
36
37
|
end
|
37
38
|
|
38
39
|
private
|
39
|
-
def render_bind(attr)
|
40
|
+
def render_bind(connection, attr)
|
40
41
|
if ActiveModel::Attribute === attr
|
41
42
|
value = if attr.type.binary? && attr.value
|
42
43
|
"<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
|
@@ -51,24 +52,12 @@ module ActiveRecord
|
|
51
52
|
[attr&.name, value]
|
52
53
|
end
|
53
54
|
|
54
|
-
def build_explain_clause(options = [])
|
55
|
+
def build_explain_clause(connection, options = [])
|
55
56
|
if connection.respond_to?(:build_explain_clause, true)
|
56
57
|
connection.build_explain_clause(options)
|
57
58
|
else
|
58
59
|
"EXPLAIN for:"
|
59
60
|
end
|
60
61
|
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
|
73
62
|
end
|
74
63
|
end
|
@@ -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,
|
496
|
-
# belongs_to :book,
|
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
|
557
|
-
@@all_cached_fixtures[
|
562
|
+
def cache_for_connection_pool(connection_pool)
|
563
|
+
@@all_cached_fixtures[connection_pool]
|
558
564
|
end
|
559
565
|
|
560
|
-
def fixture_is_cached?(
|
561
|
-
|
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(
|
570
|
+
def cached_fixtures(connection_pool, keys_to_fetch = nil)
|
565
571
|
if keys_to_fetch
|
566
|
-
|
572
|
+
cache_for_connection_pool(connection_pool).values_at(*keys_to_fetch)
|
567
573
|
else
|
568
|
-
|
574
|
+
cache_for_connection_pool(connection_pool).values
|
569
575
|
end
|
570
576
|
end
|
571
577
|
|
572
|
-
def cache_fixtures(
|
573
|
-
|
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
|
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
|
-
|
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?(
|
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
|
-
|
611
|
+
connection_pool,
|
608
612
|
)
|
609
|
-
cache_fixtures(
|
613
|
+
cache_fixtures(connection_pool, fixtures_map)
|
610
614
|
end
|
611
|
-
cached_fixtures(
|
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,
|
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,
|
662
|
+
insert(fixture_sets, connection_pool)
|
659
663
|
|
660
664
|
fixtures_map
|
661
665
|
end
|
662
666
|
|
663
|
-
def insert(fixture_sets,
|
664
|
-
|
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.
|
670
|
+
fixture_set.model_class.connection_pool
|
667
671
|
else
|
668
|
-
|
672
|
+
connection_pool
|
669
673
|
end
|
670
674
|
end
|
671
675
|
|
672
|
-
|
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
|
-
|
685
|
+
pool.with_connection do |conn|
|
686
|
+
conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
|
682
687
|
|
683
|
-
|
688
|
+
check_all_foreign_keys_valid!(conn)
|
684
689
|
|
685
|
-
|
686
|
-
|
687
|
-
|
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
|
-
|
36
|
-
|
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
|
-
|
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
|
@@ -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
|
-
|
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
|
-
|
11
|
-
|
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
|
-
|
27
|
-
|
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(
|
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)
|
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
|
-
|
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
|
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 =
|
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
|
-
|
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
|
|