activerecord 7.1.5.1 → 8.0.2
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 +369 -2484
- data/README.rdoc +15 -15
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +43 -12
- data/lib/active_record/associations/belongs_to_association.rb +21 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +7 -6
- 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 +17 -9
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -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 +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +4 -3
- 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 +14 -3
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +92 -295
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- 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 +25 -61
- 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 +9 -18
- data/lib/active_record/attribute_methods.rb +71 -75
- data/lib/active_record/attributes.rb +63 -49
- data/lib/active_record/autosave_association.rb +92 -57
- 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 +48 -122
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +286 -77
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +119 -55
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +197 -76
- data/lib/active_record/connection_adapters/abstract/quoting.rb +66 -92
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +12 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -12
- data/lib/active_record/connection_adapters/abstract/transaction.rb +140 -67
- data/lib/active_record/connection_adapters/abstract_adapter.rb +85 -90
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +71 -52
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +56 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +92 -101
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +13 -31
- data/lib/active_record/connection_adapters/pool_config.rb +14 -13
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -41
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- 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/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +36 -20
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +75 -28
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +73 -113
- data/lib/active_record/connection_adapters/schema_cache.rb +124 -131
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +81 -97
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +29 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +35 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +183 -87
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +39 -69
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
- data/lib/active_record/connection_adapters.rb +65 -0
- data/lib/active_record/connection_handling.rb +74 -37
- data/lib/active_record/core.rb +132 -51
- data/lib/active_record/counter_cache.rb +19 -10
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +23 -4
- data/lib/active_record/database_configurations/hash_config.rb +46 -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 +41 -17
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +7 -7
- data/lib/active_record/encryption/encrypted_attribute_type.rb +33 -4
- data/lib/active_record/encryption/encryptor.rb +28 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- 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/scheme.rb +8 -1
- data/lib/active_record/enum.rb +20 -16
- data/lib/active_record/errors.rb +54 -20
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixtures.rb +37 -33
- data/lib/active_record/future_result.rb +21 -13
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +19 -16
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/log_subscriber.rb +5 -32
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +33 -14
- data/lib/active_record/migration/compatibility.rb +8 -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 +104 -98
- data/lib/active_record/model_schema.rb +32 -70
- data/lib/active_record/nested_attributes.rb +15 -9
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +127 -451
- data/lib/active_record/query_cache.rb +19 -8
- data/lib/active_record/query_logs.rb +104 -37
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +24 -12
- data/lib/active_record/railtie.rb +26 -68
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +43 -61
- data/lib/active_record/reflection.rb +112 -53
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +138 -72
- data/lib/active_record/relation/calculations.rb +122 -82
- data/lib/active_record/relation/delegation.rb +30 -22
- data/lib/active_record/relation/finder_methods.rb +32 -18
- data/lib/active_record/relation/merger.rb +12 -14
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +10 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +16 -3
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +317 -101
- data/lib/active_record/relation/spawn_methods.rb +3 -19
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +561 -119
- data/lib/active_record/result.rb +95 -46
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +31 -25
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +53 -20
- data/lib/active_record/schema_migration.rb +31 -14
- data/lib/active_record/scoping/named.rb +6 -2
- data/lib/active_record/signed_id.rb +24 -4
- data/lib/active_record/statement_cache.rb +19 -19
- data/lib/active_record/store.rb +7 -3
- data/lib/active_record/table_metadata.rb +2 -13
- data/lib/active_record/tasks/database_tasks.rb +87 -58
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -3
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +4 -3
- data/lib/active_record/test_fixtures.rb +98 -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 +72 -17
- 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 +23 -18
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +138 -57
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +4 -2
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +2 -2
- data/lib/arel/collectors/substitute_binds.rb +3 -3
- data/lib/arel/nodes/binary.rb +1 -7
- 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 +5 -4
- data/lib/arel/nodes/sql_literal.rb +8 -1
- 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/table.rb +3 -7
- 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 -16
- data/lib/active_record/relation/record_fetch_warning.rb +0 -49
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)
|
@@ -88,6 +84,19 @@ module ActiveRecord
|
|
88
84
|
class ConnectionTimeoutError < ConnectionNotEstablished
|
89
85
|
end
|
90
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
|
+
|
91
100
|
# Raised when connection to the database could not been established because it was not
|
92
101
|
# able to connect to the host or when the authorization failed.
|
93
102
|
class DatabaseConnectionError < ConnectionNotEstablished
|
@@ -137,8 +146,18 @@ module ActiveRecord
|
|
137
146
|
end
|
138
147
|
|
139
148
|
# Raised by {ActiveRecord::Base#save!}[rdoc-ref:Persistence#save!] and
|
140
|
-
# {ActiveRecord::Base.
|
141
|
-
# methods when a record
|
149
|
+
# {ActiveRecord::Base.update_attribute!}[rdoc-ref:Persistence#update_attribute!]
|
150
|
+
# methods when a record failed to validate or cannot be saved due to any of the
|
151
|
+
# <tt>before_*</tt> callbacks throwing +:abort+. See
|
152
|
+
# ActiveRecord::Callbacks for further details.
|
153
|
+
#
|
154
|
+
# class Product < ActiveRecord::Base
|
155
|
+
# before_save do
|
156
|
+
# throw :abort if price < 0
|
157
|
+
# end
|
158
|
+
# end
|
159
|
+
#
|
160
|
+
# Product.create! # => raises an ActiveRecord::RecordNotSaved
|
142
161
|
class RecordNotSaved < ActiveRecordError
|
143
162
|
attr_reader :record
|
144
163
|
|
@@ -149,15 +168,17 @@ module ActiveRecord
|
|
149
168
|
end
|
150
169
|
|
151
170
|
# Raised by {ActiveRecord::Base#destroy!}[rdoc-ref:Persistence#destroy!]
|
152
|
-
# when a
|
153
|
-
#
|
171
|
+
# when a record cannot be destroyed due to any of the
|
172
|
+
# <tt>before_destroy</tt> callbacks throwing +:abort+. See
|
173
|
+
# ActiveRecord::Callbacks for further details.
|
154
174
|
#
|
155
|
-
#
|
156
|
-
#
|
157
|
-
#
|
158
|
-
#
|
175
|
+
# class User < ActiveRecord::Base
|
176
|
+
# before_destroy do
|
177
|
+
# throw :abort if still_active?
|
178
|
+
# end
|
159
179
|
# end
|
160
180
|
#
|
181
|
+
# User.first.destroy! # => raises an ActiveRecord::RecordNotDestroyed
|
161
182
|
class RecordNotDestroyed < ActiveRecordError
|
162
183
|
attr_reader :record
|
163
184
|
|
@@ -374,6 +395,12 @@ module ActiveRecord
|
|
374
395
|
end
|
375
396
|
|
376
397
|
# Raised on attempt to lazily load records that are marked as strict loading.
|
398
|
+
#
|
399
|
+
# You can resolve this error by eager loading marked records before accessing
|
400
|
+
# them. The
|
401
|
+
# {Eager Loading Associations}[https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations]
|
402
|
+
# guide covers solutions, such as using
|
403
|
+
# {ActiveRecord::Base.includes}[rdoc-ref:QueryMethods#includes].
|
377
404
|
class StrictLoadingViolationError < ActiveRecordError
|
378
405
|
end
|
379
406
|
|
@@ -466,9 +493,9 @@ module ActiveRecord
|
|
466
493
|
# relation.loaded? # => true
|
467
494
|
#
|
468
495
|
# # Methods which try to mutate a loaded relation fail.
|
469
|
-
# relation.where!(title: 'TODO') # => ActiveRecord::
|
470
|
-
# relation.limit!(5) # => ActiveRecord::
|
471
|
-
class
|
496
|
+
# relation.where!(title: 'TODO') # => ActiveRecord::UnmodifiableRelation
|
497
|
+
# relation.limit!(5) # => ActiveRecord::UnmodifiableRelation
|
498
|
+
class UnmodifiableRelation < ActiveRecordError
|
472
499
|
end
|
473
500
|
|
474
501
|
# TransactionIsolationError will be raised under the following conditions:
|
@@ -577,4 +604,11 @@ module ActiveRecord
|
|
577
604
|
# values, such as request parameters or model attributes to query methods.
|
578
605
|
class UnknownAttributeReference < ActiveRecordError
|
579
606
|
end
|
607
|
+
|
608
|
+
# DatabaseVersionError will be raised when the database version is not supported, or when
|
609
|
+
# the database version cannot be determined.
|
610
|
+
class DatabaseVersionError < ActiveRecordError
|
611
|
+
end
|
580
612
|
end
|
613
|
+
|
614
|
+
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
|
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
require "erb"
|
4
4
|
require "yaml"
|
5
|
-
require "zlib"
|
6
|
-
require "set"
|
7
5
|
require "active_support/dependencies"
|
8
6
|
require "active_support/core_ext/digest/uuid"
|
9
7
|
require "active_record/test_fixtures"
|
@@ -110,6 +108,12 @@ module ActiveRecord
|
|
110
108
|
# assert_raise(StandardError) { web_sites(:reddit) }
|
111
109
|
# end
|
112
110
|
#
|
111
|
+
# If the model names conflicts with a +TestCase+ methods, you can use the generic +fixture+ accessor
|
112
|
+
#
|
113
|
+
# test "generic find" do
|
114
|
+
# assert_equal "Ruby on Rails", fixture(:web_sites, :rubyonrails).name
|
115
|
+
# end
|
116
|
+
#
|
113
117
|
# Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the
|
114
118
|
# following tests:
|
115
119
|
#
|
@@ -492,8 +496,8 @@ module ActiveRecord
|
|
492
496
|
# # app/models/book_orders.rb
|
493
497
|
# class BookOrder < ApplicationRecord
|
494
498
|
# self.primary_key = [:shop_id, :id]
|
495
|
-
# belongs_to :order,
|
496
|
-
# belongs_to :book,
|
499
|
+
# belongs_to :order, foreign_key: [:shop_id, :order_id]
|
500
|
+
# belongs_to :book, foreign_key: [:author_id, :book_id]
|
497
501
|
# end
|
498
502
|
#
|
499
503
|
# <code></code>
|
@@ -553,24 +557,24 @@ module ActiveRecord
|
|
553
557
|
@@all_cached_fixtures.clear
|
554
558
|
end
|
555
559
|
|
556
|
-
def
|
557
|
-
@@all_cached_fixtures[
|
560
|
+
def cache_for_connection_pool(connection_pool)
|
561
|
+
@@all_cached_fixtures[connection_pool]
|
558
562
|
end
|
559
563
|
|
560
|
-
def fixture_is_cached?(
|
561
|
-
|
564
|
+
def fixture_is_cached?(connection_pool, table_name)
|
565
|
+
cache_for_connection_pool(connection_pool)[table_name]
|
562
566
|
end
|
563
567
|
|
564
|
-
def cached_fixtures(
|
568
|
+
def cached_fixtures(connection_pool, keys_to_fetch = nil)
|
565
569
|
if keys_to_fetch
|
566
|
-
|
570
|
+
cache_for_connection_pool(connection_pool).values_at(*keys_to_fetch)
|
567
571
|
else
|
568
|
-
|
572
|
+
cache_for_connection_pool(connection_pool).values
|
569
573
|
end
|
570
574
|
end
|
571
575
|
|
572
|
-
def cache_fixtures(
|
573
|
-
|
576
|
+
def cache_fixtures(connection_pool, fixtures_map)
|
577
|
+
cache_for_connection_pool(connection_pool).update(fixtures_map)
|
574
578
|
end
|
575
579
|
|
576
580
|
def instantiate_fixtures(object, fixture_set, load_instances = true)
|
@@ -588,15 +592,13 @@ module ActiveRecord
|
|
588
592
|
end
|
589
593
|
end
|
590
594
|
|
591
|
-
def create_fixtures(fixtures_directories, fixture_set_names, class_names = {}, config = ActiveRecord::Base
|
595
|
+
def create_fixtures(fixtures_directories, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
|
592
596
|
fixture_set_names = Array(fixture_set_names).map(&:to_s)
|
593
597
|
class_names.stringify_keys!
|
594
598
|
|
595
|
-
|
596
|
-
connection = block_given? ? block : lambda { ActiveRecord::Base.connection }
|
597
|
-
|
599
|
+
connection_pool = config.connection_pool
|
598
600
|
fixture_files_to_read = fixture_set_names.reject do |fs_name|
|
599
|
-
fixture_is_cached?(
|
601
|
+
fixture_is_cached?(connection_pool, fs_name)
|
600
602
|
end
|
601
603
|
|
602
604
|
if fixture_files_to_read.any?
|
@@ -604,11 +606,11 @@ module ActiveRecord
|
|
604
606
|
Array(fixtures_directories),
|
605
607
|
fixture_files_to_read,
|
606
608
|
class_names,
|
607
|
-
|
609
|
+
connection_pool,
|
608
610
|
)
|
609
|
-
cache_fixtures(
|
611
|
+
cache_fixtures(connection_pool, fixtures_map)
|
610
612
|
end
|
611
|
-
cached_fixtures(
|
613
|
+
cached_fixtures(connection_pool, fixture_set_names)
|
612
614
|
end
|
613
615
|
|
614
616
|
# Returns a consistent, platform-independent identifier for +label+.
|
@@ -641,7 +643,7 @@ module ActiveRecord
|
|
641
643
|
end
|
642
644
|
|
643
645
|
private
|
644
|
-
def read_and_insert(fixtures_directories, fixture_files, class_names,
|
646
|
+
def read_and_insert(fixtures_directories, fixture_files, class_names, connection_pool) # :nodoc:
|
645
647
|
fixtures_map = {}
|
646
648
|
directory_glob = "{#{fixtures_directories.join(",")}}"
|
647
649
|
fixture_sets = fixture_files.map do |fixture_set_name|
|
@@ -655,21 +657,21 @@ module ActiveRecord
|
|
655
657
|
end
|
656
658
|
update_all_loaded_fixtures(fixtures_map)
|
657
659
|
|
658
|
-
insert(fixture_sets,
|
660
|
+
insert(fixture_sets, connection_pool)
|
659
661
|
|
660
662
|
fixtures_map
|
661
663
|
end
|
662
664
|
|
663
|
-
def insert(fixture_sets,
|
664
|
-
|
665
|
+
def insert(fixture_sets, connection_pool) # :nodoc:
|
666
|
+
fixture_sets_by_pool = fixture_sets.group_by do |fixture_set|
|
665
667
|
if fixture_set.model_class
|
666
|
-
fixture_set.model_class.
|
668
|
+
fixture_set.model_class.connection_pool
|
667
669
|
else
|
668
|
-
|
670
|
+
connection_pool
|
669
671
|
end
|
670
672
|
end
|
671
673
|
|
672
|
-
|
674
|
+
fixture_sets_by_pool.each do |pool, set|
|
673
675
|
table_rows_for_connection = Hash.new { |h, k| h[k] = [] }
|
674
676
|
|
675
677
|
set.each do |fixture_set|
|
@@ -678,13 +680,15 @@ module ActiveRecord
|
|
678
680
|
end
|
679
681
|
end
|
680
682
|
|
681
|
-
|
683
|
+
pool.with_connection do |conn|
|
684
|
+
conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
|
682
685
|
|
683
|
-
|
686
|
+
check_all_foreign_keys_valid!(conn)
|
684
687
|
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
+
# Cap primary key sequences to max(pk).
|
689
|
+
if conn.respond_to?(:reset_pk_sequence!)
|
690
|
+
set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
|
691
|
+
end
|
688
692
|
end
|
689
693
|
end
|
690
694
|
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
|
|
@@ -98,17 +100,21 @@ module ActiveRecord
|
|
98
100
|
def execute_or_skip
|
99
101
|
return unless pending?
|
100
102
|
|
101
|
-
@
|
102
|
-
return unless
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
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
|
+
ActiveSupport::IsolatedExecutionState[:active_record_instrumenter] = @event_buffer
|
112
|
+
|
107
113
|
execute_query(connection, async: true)
|
108
114
|
end
|
115
|
+
ensure
|
116
|
+
@mutex.unlock
|
109
117
|
end
|
110
|
-
ensure
|
111
|
-
@mutex.unlock
|
112
118
|
end
|
113
119
|
end
|
114
120
|
end
|
@@ -140,7 +146,9 @@ module ActiveRecord
|
|
140
146
|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
141
147
|
@mutex.synchronize do
|
142
148
|
if pending?
|
143
|
-
|
149
|
+
@pool.with_connection do |connection|
|
150
|
+
execute_query(connection)
|
151
|
+
end
|
144
152
|
else
|
145
153
|
@lock_wait = (Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - start)
|
146
154
|
end
|
@@ -159,7 +167,7 @@ module ActiveRecord
|
|
159
167
|
end
|
160
168
|
|
161
169
|
def exec_query(connection, *args, **kwargs)
|
162
|
-
connection.
|
170
|
+
connection.raw_exec_query(*args, **kwargs)
|
163
171
|
end
|
164
172
|
|
165
173
|
class SelectAll < FutureResult # :nodoc:
|
@@ -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
|
@@ -237,7 +240,7 @@ module ActiveRecord
|
|
237
240
|
|
238
241
|
values_list = insert_all.map_key_with_value do |key, value|
|
239
242
|
next value if Arel::Nodes::SqlLiteral === value
|
240
|
-
|
243
|
+
ActiveModel::Type::SerializeCastValue.serialize(type = types[key], type.cast(value))
|
241
244
|
end
|
242
245
|
|
243
246
|
connection.visitor.compile(Arel::Nodes::ValuesList.new(values_list))
|
@@ -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
|
|