activerecord 6.1.7.4 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1055 -1170
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +33 -17
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +15 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +18 -19
- data/lib/active_record/associations/collection_proxy.rb +8 -3
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +6 -2
- data/lib/active_record/associations/preloader/association.rb +186 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +49 -13
- data/lib/active_record/associations/preloader.rb +39 -113
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +90 -82
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +49 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +7 -5
- data/lib/active_record/attribute_methods/serialization.rb +66 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +13 -14
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +6 -21
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/yaml_column.rb +2 -14
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +43 -82
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +34 -13
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +69 -18
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +97 -81
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +35 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +35 -21
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +50 -76
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +27 -16
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -107
- data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +15 -16
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +47 -53
- data/lib/active_record/core.rb +121 -146
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
- data/lib/active_record/database_configurations/database_config.rb +12 -9
- data/lib/active_record/database_configurations/hash_config.rb +63 -5
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +15 -32
- data/lib/active_record/delegated_type.rb +52 -11
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +61 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +208 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +90 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +49 -42
- data/lib/active_record/errors.rb +67 -4
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +41 -6
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +17 -20
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +80 -14
- data/lib/active_record/integration.rb +4 -3
- data/lib/active_record/internal_metadata.rb +1 -5
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/locking/pessimistic.rb +9 -3
- data/lib/active_record/log_subscriber.rb +14 -3
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +8 -3
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +89 -10
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +110 -80
- data/lib/active_record/model_schema.rb +45 -58
- data/lib/active_record/nested_attributes.rb +13 -12
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +219 -52
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +138 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +127 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +66 -129
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +67 -50
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/calculations.rb +40 -36
- data/lib/active_record/relation/delegation.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +31 -35
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +5 -11
- data/lib/active_record/relation/query_methods.rb +235 -63
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +169 -84
- data/lib/active_record/result.rb +17 -7
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +10 -3
- data/lib/active_record/schema_migration.rb +4 -4
- data/lib/active_record/scoping/default.rb +61 -12
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +64 -34
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/store.rb +1 -6
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/tasks/database_tasks.rb +116 -58
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -12
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +9 -13
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- data/lib/active_record/translation.rb +2 -2
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +1 -1
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +1 -1
- data/lib/active_record.rb +204 -28
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +11 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +8 -2
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +58 -2
- data/lib/arel.rb +2 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +58 -14
@@ -17,8 +17,8 @@ module ActiveRecord
|
|
17
17
|
QueryRegistry.reset
|
18
18
|
|
19
19
|
super.tap do |records|
|
20
|
-
if logger && warn_on_records_fetched_greater_than
|
21
|
-
if records.length > warn_on_records_fetched_greater_than
|
20
|
+
if logger && ActiveRecord.warn_on_records_fetched_greater_than
|
21
|
+
if records.length > ActiveRecord.warn_on_records_fetched_greater_than
|
22
22
|
logger.warn "Query fetched #{records.size} #{@klass} records: #{QueryRegistry.queries.join(";")}"
|
23
23
|
end
|
24
24
|
end
|
@@ -31,17 +31,15 @@ module ActiveRecord
|
|
31
31
|
end
|
32
32
|
# :startdoc:
|
33
33
|
|
34
|
-
|
35
|
-
extend
|
34
|
+
module QueryRegistry # :nodoc:
|
35
|
+
extend self
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
def initialize
|
40
|
-
@queries = []
|
37
|
+
def queries
|
38
|
+
ActiveSupport::IsolatedExecutionState[:active_record_query_registry] ||= []
|
41
39
|
end
|
42
40
|
|
43
41
|
def reset
|
44
|
-
|
42
|
+
queries.clear
|
45
43
|
end
|
46
44
|
end
|
47
45
|
end
|
@@ -7,8 +7,8 @@ require "active_record/relation/merger"
|
|
7
7
|
module ActiveRecord
|
8
8
|
module SpawnMethods
|
9
9
|
# This is overridden by Associations::CollectionProxy
|
10
|
-
def spawn
|
11
|
-
already_in_scope? ? klass.all : clone
|
10
|
+
def spawn # :nodoc:
|
11
|
+
already_in_scope?(klass.scope_registry) ? klass.all : clone
|
12
12
|
end
|
13
13
|
|
14
14
|
# Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an ActiveRecord::Relation.
|
@@ -76,6 +76,11 @@ module ActiveRecord
|
|
76
76
|
other.is_a?(WhereClause) &&
|
77
77
|
predicates == other.predicates
|
78
78
|
end
|
79
|
+
alias :eql? :==
|
80
|
+
|
81
|
+
def hash
|
82
|
+
[self.class, predicates].hash
|
83
|
+
end
|
79
84
|
|
80
85
|
def invert
|
81
86
|
if predicates.size == 1
|
@@ -158,21 +163,8 @@ module ActiveRecord
|
|
158
163
|
attr = extract_attribute(node) || begin
|
159
164
|
node.left if equality_node?(node) && node.left.is_a?(Arel::Predications)
|
160
165
|
end
|
161
|
-
|
162
|
-
|
163
|
-
ref = referenced_columns[attr]
|
164
|
-
next false unless ref
|
165
|
-
|
166
|
-
if equality_node?(node) && equality_node?(ref) || node == ref
|
167
|
-
true
|
168
|
-
else
|
169
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
170
|
-
Merging (#{node.to_sql}) and (#{ref.to_sql}) no longer maintain
|
171
|
-
both conditions, and will be replaced by the latter in Rails 7.0.
|
172
|
-
To migrate to Rails 7.0's behavior, use `relation.merge(other, rewhere: true)`.
|
173
|
-
MSG
|
174
|
-
false
|
175
|
-
end
|
166
|
+
|
167
|
+
attr && referenced_columns[attr]
|
176
168
|
end
|
177
169
|
end
|
178
170
|
|
@@ -227,11 +219,10 @@ module ActiveRecord
|
|
227
219
|
end
|
228
220
|
|
229
221
|
def extract_node_value(node)
|
230
|
-
|
231
|
-
when Array
|
232
|
-
node.map { |v| extract_node_value(v) }
|
233
|
-
when Arel::Nodes::BindParam, Arel::Nodes::Casted, Arel::Nodes::Quoted
|
222
|
+
if node.respond_to?(:value_before_type_cast)
|
234
223
|
node.value_before_type_cast
|
224
|
+
elsif Array === node
|
225
|
+
node.map { |v| extract_node_value(v) }
|
235
226
|
end
|
236
227
|
end
|
237
228
|
end
|
@@ -11,7 +11,7 @@ module ActiveRecord
|
|
11
11
|
:reverse_order, :distinct, :create_with, :skip_query_cache]
|
12
12
|
|
13
13
|
CLAUSE_METHODS = [:where, :having, :from]
|
14
|
-
INVALID_METHODS_FOR_DELETE_ALL = [:distinct
|
14
|
+
INVALID_METHODS_FOR_DELETE_ALL = [:distinct]
|
15
15
|
|
16
16
|
VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
|
17
17
|
|
@@ -31,6 +31,8 @@ module ActiveRecord
|
|
31
31
|
@loaded = false
|
32
32
|
@predicate_builder = predicate_builder
|
33
33
|
@delegate_to_klass = false
|
34
|
+
@future_result = nil
|
35
|
+
@records = nil
|
34
36
|
end
|
35
37
|
|
36
38
|
def initialize_copy(other)
|
@@ -38,11 +40,6 @@ module ActiveRecord
|
|
38
40
|
reset
|
39
41
|
end
|
40
42
|
|
41
|
-
def arel_attribute(name) # :nodoc:
|
42
|
-
table[name]
|
43
|
-
end
|
44
|
-
deprecate :arel_attribute
|
45
|
-
|
46
43
|
def bind_attribute(name, value) # :nodoc:
|
47
44
|
if reflection = klass._reflect_on_association(name)
|
48
45
|
name = reflection.foreign_key
|
@@ -67,8 +64,12 @@ module ActiveRecord
|
|
67
64
|
# user = users.new { |user| user.name = 'Oscar' }
|
68
65
|
# user.name # => Oscar
|
69
66
|
def new(attributes = nil, &block)
|
70
|
-
|
71
|
-
|
67
|
+
if attributes.is_a?(Array)
|
68
|
+
attributes.collect { |attr| new(attr, &block) }
|
69
|
+
else
|
70
|
+
block = current_scope_restoring_block(&block)
|
71
|
+
scoping { _new(attributes, &block) }
|
72
|
+
end
|
72
73
|
end
|
73
74
|
alias build new
|
74
75
|
|
@@ -148,7 +149,7 @@ module ActiveRecord
|
|
148
149
|
# above can be alternatively written this way:
|
149
150
|
#
|
150
151
|
# # Find the first user named "Scarlett" or create a new one with a
|
151
|
-
# #
|
152
|
+
# # particular last name.
|
152
153
|
# User.find_or_create_by(first_name: 'Scarlett') do |user|
|
153
154
|
# user.last_name = 'Johansson'
|
154
155
|
# end
|
@@ -175,7 +176,7 @@ module ActiveRecord
|
|
175
176
|
find_by(attributes) || create!(attributes, &block)
|
176
177
|
end
|
177
178
|
|
178
|
-
# Attempts to create a record with the given attributes in a table that has a unique constraint
|
179
|
+
# Attempts to create a record with the given attributes in a table that has a unique database constraint
|
179
180
|
# on one or several of its columns. If a row already exists with one or several of these
|
180
181
|
# unique constraints, the exception such an insertion would normally raise is caught,
|
181
182
|
# and the existing record with those attributes is found using #find_by!.
|
@@ -186,7 +187,7 @@ module ActiveRecord
|
|
186
187
|
#
|
187
188
|
# There are several drawbacks to #create_or_find_by, though:
|
188
189
|
#
|
189
|
-
# * The underlying table must have the relevant columns defined with unique constraints.
|
190
|
+
# * The underlying table must have the relevant columns defined with unique database constraints.
|
190
191
|
# * A unique constraint violation may be triggered by only one, or at least less than all,
|
191
192
|
# of the given attributes. This means that the subsequent #find_by! may fail to find a
|
192
193
|
# matching record, which will then raise an <tt>ActiveRecord::RecordNotFound</tt> exception,
|
@@ -257,13 +258,20 @@ module ActiveRecord
|
|
257
258
|
|
258
259
|
# Returns size of the records.
|
259
260
|
def size
|
260
|
-
loaded?
|
261
|
+
if loaded?
|
262
|
+
records.length
|
263
|
+
else
|
264
|
+
count(:all)
|
265
|
+
end
|
261
266
|
end
|
262
267
|
|
263
268
|
# Returns true if there are no records.
|
264
269
|
def empty?
|
265
|
-
|
266
|
-
|
270
|
+
if loaded?
|
271
|
+
records.empty?
|
272
|
+
else
|
273
|
+
!exists?
|
274
|
+
end
|
267
275
|
end
|
268
276
|
|
269
277
|
# Returns true if there are no records.
|
@@ -281,13 +289,15 @@ module ActiveRecord
|
|
281
289
|
# Returns true if there is exactly one record.
|
282
290
|
def one?
|
283
291
|
return super if block_given?
|
284
|
-
|
292
|
+
return records.one? if loaded?
|
293
|
+
limited_count == 1
|
285
294
|
end
|
286
295
|
|
287
296
|
# Returns true if there is more than one record.
|
288
297
|
def many?
|
289
298
|
return super if block_given?
|
290
|
-
|
299
|
+
return records.many? if loaded?
|
300
|
+
limited_count > 1
|
291
301
|
end
|
292
302
|
|
293
303
|
# Returns a stable cache key that can be used to identify this query.
|
@@ -344,7 +354,7 @@ module ActiveRecord
|
|
344
354
|
def compute_cache_version(timestamp_column) # :nodoc:
|
345
355
|
timestamp_column = timestamp_column.to_s
|
346
356
|
|
347
|
-
if loaded?
|
357
|
+
if loaded?
|
348
358
|
size = records.size
|
349
359
|
if size > 0
|
350
360
|
timestamp = records.map { |record| record.read_attribute(timestamp_column) }.max
|
@@ -357,6 +367,7 @@ module ActiveRecord
|
|
357
367
|
|
358
368
|
if collection.has_limit_or_offset?
|
359
369
|
query = collection.select("#{column} AS collection_cache_key_timestamp")
|
370
|
+
query._select!(table[Arel.star]) if distinct_value && collection.select_values.empty?
|
360
371
|
subquery_alias = "subquery_for_cache_key"
|
361
372
|
subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
|
362
373
|
arel = query.build_subquery(subquery_alias, select_values % subquery_column)
|
@@ -377,7 +388,7 @@ module ActiveRecord
|
|
377
388
|
end
|
378
389
|
|
379
390
|
if timestamp
|
380
|
-
"#{size}-#{timestamp.utc.
|
391
|
+
"#{size}-#{timestamp.utc.to_formatted_s(cache_timestamp_format)}"
|
381
392
|
else
|
382
393
|
"#{size}"
|
383
394
|
end
|
@@ -400,15 +411,28 @@ module ActiveRecord
|
|
400
411
|
# end
|
401
412
|
# # => SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1
|
402
413
|
#
|
414
|
+
# If <tt>all_queries: true</tt> is passed, scoping will apply to all queries
|
415
|
+
# for the relation including +update+ and +delete+ on instances.
|
416
|
+
# Once +all_queries+ is set to true it cannot be set to false in a
|
417
|
+
# nested block.
|
418
|
+
#
|
403
419
|
# Please check unscoped if you want to remove all previous scopes (including
|
404
420
|
# the default_scope) during the execution of a block.
|
405
|
-
def scoping
|
406
|
-
|
421
|
+
def scoping(all_queries: nil, &block)
|
422
|
+
registry = klass.scope_registry
|
423
|
+
if global_scope?(registry) && all_queries == false
|
424
|
+
raise ArgumentError, "Scoping is set to apply to all queries and cannot be unset in a nested block."
|
425
|
+
elsif already_in_scope?(registry)
|
426
|
+
yield
|
427
|
+
else
|
428
|
+
_scoping(self, registry, all_queries, &block)
|
429
|
+
end
|
407
430
|
end
|
408
431
|
|
409
432
|
def _exec_scope(*args, &block) # :nodoc:
|
410
433
|
@delegate_to_klass = true
|
411
|
-
|
434
|
+
registry = klass.scope_registry
|
435
|
+
_scoping(nil, registry) { instance_exec(*args, &block) || self }
|
412
436
|
ensure
|
413
437
|
@delegate_to_klass = false
|
414
438
|
end
|
@@ -440,17 +464,6 @@ module ActiveRecord
|
|
440
464
|
def update_all(updates)
|
441
465
|
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
|
442
466
|
|
443
|
-
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
444
|
-
arel.source.left = table
|
445
|
-
|
446
|
-
stmt = Arel::UpdateManager.new
|
447
|
-
stmt.table(arel.source)
|
448
|
-
stmt.key = table[primary_key]
|
449
|
-
stmt.take(arel.limit)
|
450
|
-
stmt.offset(arel.offset)
|
451
|
-
stmt.order(*arel.orders)
|
452
|
-
stmt.wheres = arel.constraints
|
453
|
-
|
454
467
|
if updates.is_a?(Hash)
|
455
468
|
if klass.locking_enabled? &&
|
456
469
|
!updates.key?(klass.locking_column) &&
|
@@ -458,11 +471,17 @@ module ActiveRecord
|
|
458
471
|
attr = table[klass.locking_column]
|
459
472
|
updates[attr.name] = _increment_attribute(attr)
|
460
473
|
end
|
461
|
-
|
474
|
+
values = _substitute_values(updates)
|
462
475
|
else
|
463
|
-
|
476
|
+
values = Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
|
464
477
|
end
|
465
478
|
|
479
|
+
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
480
|
+
arel.source.left = table
|
481
|
+
|
482
|
+
group_values_arel_columns = arel_columns(group_values.uniq)
|
483
|
+
having_clause_ast = having_clause.ast unless having_clause.empty?
|
484
|
+
stmt = arel.compile_update(values, table[primary_key], having_clause_ast, group_values_arel_columns)
|
466
485
|
klass.connection.update(stmt, "#{klass} Update All").tap { reset }
|
467
486
|
end
|
468
487
|
|
@@ -474,6 +493,14 @@ module ActiveRecord
|
|
474
493
|
end
|
475
494
|
end
|
476
495
|
|
496
|
+
def update!(id = :all, attributes) # :nodoc:
|
497
|
+
if id == :all
|
498
|
+
each { |record| record.update!(attributes) }
|
499
|
+
else
|
500
|
+
klass.update!(id, attributes)
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
477
504
|
# Updates the counters of the records in the current relation.
|
478
505
|
#
|
479
506
|
# ==== Parameters
|
@@ -583,15 +610,11 @@ module ActiveRecord
|
|
583
610
|
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
584
611
|
arel.source.left = table
|
585
612
|
|
586
|
-
|
587
|
-
|
588
|
-
stmt
|
589
|
-
stmt.take(arel.limit)
|
590
|
-
stmt.offset(arel.offset)
|
591
|
-
stmt.order(*arel.orders)
|
592
|
-
stmt.wheres = arel.constraints
|
613
|
+
group_values_arel_columns = arel_columns(group_values.uniq)
|
614
|
+
having_clause_ast = having_clause.ast unless having_clause.empty?
|
615
|
+
stmt = arel.compile_delete(table[primary_key], having_clause_ast, group_values_arel_columns)
|
593
616
|
|
594
|
-
klass.connection.delete(stmt, "#{klass}
|
617
|
+
klass.connection.delete(stmt, "#{klass} Delete All").tap { reset }
|
595
618
|
end
|
596
619
|
|
597
620
|
# Finds and destroys all records matching the specified conditions.
|
@@ -620,6 +643,32 @@ module ActiveRecord
|
|
620
643
|
where(*args).delete_all
|
621
644
|
end
|
622
645
|
|
646
|
+
# Schedule the query to be performed from a background thread pool.
|
647
|
+
#
|
648
|
+
# Post.where(published: true).load_async # => #<ActiveRecord::Relation>
|
649
|
+
def load_async
|
650
|
+
return load if !connection.async_enabled?
|
651
|
+
|
652
|
+
unless loaded?
|
653
|
+
result = exec_main_query(async: connection.current_transaction.closed?)
|
654
|
+
|
655
|
+
if result.is_a?(Array)
|
656
|
+
@records = result
|
657
|
+
else
|
658
|
+
@future_result = result
|
659
|
+
end
|
660
|
+
@loaded = true
|
661
|
+
end
|
662
|
+
|
663
|
+
self
|
664
|
+
end
|
665
|
+
|
666
|
+
# Returns <tt>true</tt> if the relation was scheduled on the background
|
667
|
+
# thread pool.
|
668
|
+
def scheduled?
|
669
|
+
!!@future_result
|
670
|
+
end
|
671
|
+
|
623
672
|
# Causes the records to be loaded from the database if they have not
|
624
673
|
# been loaded already. You can use this if for some reason you need
|
625
674
|
# to explicitly load some records before actually using them. The
|
@@ -627,7 +676,7 @@ module ActiveRecord
|
|
627
676
|
#
|
628
677
|
# Post.where(published: true).load # => #<ActiveRecord::Relation>
|
629
678
|
def load(&block)
|
630
|
-
|
679
|
+
if !loaded? || scheduled?
|
631
680
|
@records = exec_queries(&block)
|
632
681
|
@loaded = true
|
633
682
|
end
|
@@ -642,11 +691,13 @@ module ActiveRecord
|
|
642
691
|
end
|
643
692
|
|
644
693
|
def reset
|
694
|
+
@future_result&.cancel
|
695
|
+
@future_result = nil
|
645
696
|
@delegate_to_klass = false
|
646
697
|
@to_sql = @arel = @loaded = @should_eager_load = nil
|
647
698
|
@offsets = @take = nil
|
648
699
|
@cache_keys = nil
|
649
|
-
@records =
|
700
|
+
@records = nil
|
650
701
|
self
|
651
702
|
end
|
652
703
|
|
@@ -655,16 +706,14 @@ module ActiveRecord
|
|
655
706
|
# User.where(name: 'Oscar').to_sql
|
656
707
|
# # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
|
657
708
|
def to_sql
|
658
|
-
@to_sql ||=
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
relation.to_sql
|
663
|
-
end
|
664
|
-
else
|
665
|
-
conn = klass.connection
|
666
|
-
conn.unprepared_statement { conn.to_sql(arel) }
|
709
|
+
@to_sql ||= if eager_loading?
|
710
|
+
apply_join_dependency do |relation, join_dependency|
|
711
|
+
relation = join_dependency.apply_column_aliases(relation)
|
712
|
+
relation.to_sql
|
667
713
|
end
|
714
|
+
else
|
715
|
+
conn = klass.connection
|
716
|
+
conn.unprepared_statement { conn.to_sql(arel) }
|
668
717
|
end
|
669
718
|
end
|
670
719
|
|
@@ -722,6 +771,10 @@ module ActiveRecord
|
|
722
771
|
@values.dup
|
723
772
|
end
|
724
773
|
|
774
|
+
def values_for_queries # :nodoc:
|
775
|
+
@values.except(:extending, :skip_query_cache, :strict_loading)
|
776
|
+
end
|
777
|
+
|
725
778
|
def inspect
|
726
779
|
subject = loaded? ? records : annotate("loading for inspect")
|
727
780
|
entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
|
@@ -756,11 +809,9 @@ module ActiveRecord
|
|
756
809
|
def preload_associations(records) # :nodoc:
|
757
810
|
preload = preload_values
|
758
811
|
preload += includes_values unless eager_loading?
|
759
|
-
preloader = nil
|
760
812
|
scope = strict_loading_value ? StrictLoadingScope : nil
|
761
813
|
preload.each do |associations|
|
762
|
-
|
763
|
-
preloader.preload records, associations, scope
|
814
|
+
ActiveRecord::Associations::Preloader.new(records: records, associations: associations, scope: scope).call
|
764
815
|
end
|
765
816
|
end
|
766
817
|
|
@@ -775,8 +826,12 @@ module ActiveRecord
|
|
775
826
|
end
|
776
827
|
|
777
828
|
private
|
778
|
-
def already_in_scope?
|
779
|
-
@delegate_to_klass &&
|
829
|
+
def already_in_scope?(registry)
|
830
|
+
@delegate_to_klass && registry.current_scope(klass, true)
|
831
|
+
end
|
832
|
+
|
833
|
+
def global_scope?(registry)
|
834
|
+
registry.global_current_scope(klass, true)
|
780
835
|
end
|
781
836
|
|
782
837
|
def current_scope_restoring_block(&block)
|
@@ -799,11 +854,20 @@ module ActiveRecord
|
|
799
854
|
klass.create!(attributes, &block)
|
800
855
|
end
|
801
856
|
|
802
|
-
def _scoping(scope)
|
803
|
-
previous
|
857
|
+
def _scoping(scope, registry, all_queries = false)
|
858
|
+
previous = registry.current_scope(klass, true)
|
859
|
+
registry.set_current_scope(klass, scope)
|
860
|
+
|
861
|
+
if all_queries
|
862
|
+
previous_global = registry.global_current_scope(klass, true)
|
863
|
+
registry.set_global_current_scope(klass, scope)
|
864
|
+
end
|
804
865
|
yield
|
805
866
|
ensure
|
806
|
-
klass
|
867
|
+
registry.set_current_scope(klass, previous)
|
868
|
+
if all_queries
|
869
|
+
registry.set_global_current_scope(klass, previous_global)
|
870
|
+
end
|
807
871
|
end
|
808
872
|
|
809
873
|
def _substitute_values(values)
|
@@ -826,23 +890,15 @@ module ActiveRecord
|
|
826
890
|
|
827
891
|
def exec_queries(&block)
|
828
892
|
skip_query_cache_if_necessary do
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
else
|
837
|
-
relation = join_dependency.apply_column_aliases(relation)
|
838
|
-
rows = connection.select_all(relation.arel, "SQL")
|
839
|
-
join_dependency.instantiate(rows, strict_loading_value, &block)
|
840
|
-
end.freeze
|
841
|
-
end
|
842
|
-
else
|
843
|
-
klass.find_by_sql(arel, &block).freeze
|
844
|
-
end
|
893
|
+
rows = if scheduled?
|
894
|
+
future = @future_result
|
895
|
+
@future_result = nil
|
896
|
+
future.result
|
897
|
+
else
|
898
|
+
exec_main_query
|
899
|
+
end
|
845
900
|
|
901
|
+
records = instantiate_records(rows, &block)
|
846
902
|
preload_associations(records) unless skip_preloading_value
|
847
903
|
|
848
904
|
records.each(&:readonly!) if readonly_value
|
@@ -852,18 +908,43 @@ module ActiveRecord
|
|
852
908
|
end
|
853
909
|
end
|
854
910
|
|
855
|
-
def
|
856
|
-
|
857
|
-
|
858
|
-
|
911
|
+
def exec_main_query(async: false)
|
912
|
+
skip_query_cache_if_necessary do
|
913
|
+
if where_clause.contradiction?
|
914
|
+
[].freeze
|
915
|
+
elsif eager_loading?
|
916
|
+
apply_join_dependency do |relation, join_dependency|
|
917
|
+
if relation.null_relation?
|
918
|
+
[].freeze
|
919
|
+
else
|
920
|
+
relation = join_dependency.apply_column_aliases(relation)
|
921
|
+
@_join_dependency = join_dependency
|
922
|
+
connection.select_all(relation.arel, "SQL", async: async)
|
923
|
+
end
|
924
|
+
end
|
925
|
+
else
|
926
|
+
klass._query_by_sql(arel, async: async)
|
859
927
|
end
|
928
|
+
end
|
929
|
+
end
|
930
|
+
|
931
|
+
def instantiate_records(rows, &block)
|
932
|
+
return [].freeze if rows.empty?
|
933
|
+
if eager_loading?
|
934
|
+
records = @_join_dependency.instantiate(rows, strict_loading_value, &block).freeze
|
935
|
+
@_join_dependency = nil
|
936
|
+
records
|
860
937
|
else
|
861
|
-
|
938
|
+
klass._load_from_sql(rows, &block).freeze
|
862
939
|
end
|
863
940
|
end
|
864
941
|
|
865
|
-
def
|
866
|
-
|
942
|
+
def skip_query_cache_if_necessary(&block)
|
943
|
+
if skip_query_cache_value
|
944
|
+
uncached(&block)
|
945
|
+
else
|
946
|
+
yield
|
947
|
+
end
|
867
948
|
end
|
868
949
|
|
869
950
|
def references_eager_loaded_tables?
|
@@ -889,5 +970,9 @@ module ActiveRecord
|
|
889
970
|
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
|
890
971
|
string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
|
891
972
|
end
|
973
|
+
|
974
|
+
def limited_count
|
975
|
+
limit_value ? count : limit(2).count
|
976
|
+
end
|
892
977
|
end
|
893
978
|
end
|
data/lib/active_record/result.rb
CHANGED
@@ -36,6 +36,10 @@ module ActiveRecord
|
|
36
36
|
|
37
37
|
attr_reader :columns, :rows, :column_types
|
38
38
|
|
39
|
+
def self.empty # :nodoc:
|
40
|
+
EMPTY
|
41
|
+
end
|
42
|
+
|
39
43
|
def initialize(columns, rows, column_types = {})
|
40
44
|
@columns = columns
|
41
45
|
@rows = rows
|
@@ -43,6 +47,9 @@ module ActiveRecord
|
|
43
47
|
@column_types = column_types
|
44
48
|
end
|
45
49
|
|
50
|
+
EMPTY = new([].freeze, [].freeze, {}.freeze)
|
51
|
+
private_constant :EMPTY
|
52
|
+
|
46
53
|
# Returns true if this result set includes the column named +name+
|
47
54
|
def includes_column?(name)
|
48
55
|
@columns.include? name
|
@@ -57,19 +64,14 @@ module ActiveRecord
|
|
57
64
|
# row as parameter.
|
58
65
|
#
|
59
66
|
# Returns an +Enumerator+ if no block is given.
|
60
|
-
def each
|
67
|
+
def each(&block)
|
61
68
|
if block_given?
|
62
|
-
hash_rows.each
|
69
|
+
hash_rows.each(&block)
|
63
70
|
else
|
64
71
|
hash_rows.to_enum { @rows.size }
|
65
72
|
end
|
66
73
|
end
|
67
74
|
|
68
|
-
alias :map! :map
|
69
|
-
alias :collect! :map
|
70
|
-
deprecate "map!": :map
|
71
|
-
deprecate "collect!": :map
|
72
|
-
|
73
75
|
# Returns true if there are no records, otherwise false.
|
74
76
|
def empty?
|
75
77
|
rows.empty?
|
@@ -91,6 +93,14 @@ module ActiveRecord
|
|
91
93
|
n ? hash_rows.last(n) : hash_rows.last
|
92
94
|
end
|
93
95
|
|
96
|
+
def result # :nodoc:
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
def cancel # :nodoc:
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
94
104
|
def cast_values(type_overrides = {}) # :nodoc:
|
95
105
|
if columns.one?
|
96
106
|
# Separated to avoid allocating an array per row
|
@@ -1,24 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/per_thread_registry"
|
4
|
-
|
5
3
|
module ActiveRecord
|
6
4
|
# This is a thread locals registry for Active Record. For example:
|
7
5
|
#
|
8
|
-
# ActiveRecord::RuntimeRegistry.
|
9
|
-
#
|
10
|
-
# returns the connection handler local to the current thread.
|
6
|
+
# ActiveRecord::RuntimeRegistry.sql_runtime
|
11
7
|
#
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
extend ActiveSupport::PerThreadRegistry
|
8
|
+
# returns the connection handler local to the current unit of execution (either thread of fiber).
|
9
|
+
module RuntimeRegistry # :nodoc:
|
10
|
+
extend self
|
16
11
|
|
17
|
-
|
12
|
+
def sql_runtime
|
13
|
+
ActiveSupport::IsolatedExecutionState[:active_record_sql_runtime]
|
14
|
+
end
|
18
15
|
|
19
|
-
|
20
|
-
|
21
|
-
class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
|
16
|
+
def sql_runtime=(runtime)
|
17
|
+
ActiveSupport::IsolatedExecutionState[:active_record_sql_runtime] = runtime
|
22
18
|
end
|
23
19
|
end
|
24
20
|
end
|