activerecord 6.1.3.2 → 7.0.0.alpha2
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 +734 -1058
- 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 +35 -7
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +16 -6
- 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 +1 -1
- 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 +24 -25
- 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/preloader/association.rb +161 -49
- data/lib/active_record/associations/preloader/batch.rb +51 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +37 -11
- data/lib/active_record/associations/preloader.rb +46 -110
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +76 -81
- data/lib/active_record/asynchronous_queries_tracker.rb +57 -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 +41 -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 +6 -9
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +3 -18
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/yaml_column.rb +11 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -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 +31 -558
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -7
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -18
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -9
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
- data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
- data/lib/active_record/connection_adapters/abstract_adapter.rb +115 -69
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +6 -2
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -21
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +1 -3
- data/lib/active_record/connection_adapters/pool_manager.rb +5 -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 +6 -6
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +157 -100
- data/lib/active_record/connection_adapters/schema_cache.rb +35 -4
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +0 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -17
- 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 +8 -5
- data/lib/active_record/connection_handling.rb +20 -38
- data/lib/active_record/core.rb +129 -117
- data/lib/active_record/database_configurations/database_config.rb +12 -0
- data/lib/active_record/database_configurations/hash_config.rb +27 -1
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +18 -9
- data/lib/active_record/delegated_type.rb +33 -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 +29 -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 +80 -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 +44 -46
- data/lib/active_record/errors.rb +66 -3
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +40 -5
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +16 -11
- 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 +39 -6
- data/lib/active_record/integration.rb +1 -1
- data/lib/active_record/internal_metadata.rb +3 -5
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/log_subscriber.rb +6 -2
- 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/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +83 -1
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +109 -79
- data/lib/active_record/model_schema.rb +46 -32
- data/lib/active_record/nested_attributes.rb +3 -3
- data/lib/active_record/no_touching.rb +2 -2
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +134 -45
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +203 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +117 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +83 -58
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +45 -44
- 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 +42 -25
- data/lib/active_record/relation/delegation.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +32 -23
- 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 +233 -50
- data/lib/active_record/relation/record_fetch_warning.rb +2 -2
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +22 -15
- data/lib/active_record/relation.rb +170 -87
- data/lib/active_record/result.rb +17 -2
- data/lib/active_record/runtime_registry.rb +2 -4
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +3 -3
- data/lib/active_record/schema_migration.rb +0 -4
- data/lib/active_record/scoping/default.rb +62 -15
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +40 -22
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/tasks/database_tasks.rb +107 -23
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +45 -4
- 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/numericality.rb +1 -1
- data/lib/active_record.rb +170 -2
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/composite.rb +3 -3
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +18 -22
- data/lib/arel/delete_manager.rb +2 -4
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +8 -13
- data/lib/arel/nodes/homogeneous_in.rb +4 -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 +3 -2
- data/lib/arel/predications.rb +3 -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 +2 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +6 -1
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +44 -3
- data/lib/arel.rb +1 -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
- metadata +55 -16
@@ -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
|
@@ -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
|
@@ -103,28 +108,31 @@ module ActiveRecord
|
|
103
108
|
end
|
104
109
|
|
105
110
|
def extract_attributes
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
110
|
-
attrs << attr if attr
|
111
|
-
end
|
111
|
+
attrs = []
|
112
|
+
each_attributes { |attr, _| attrs << attr }
|
113
|
+
attrs
|
112
114
|
end
|
113
115
|
|
114
116
|
protected
|
115
117
|
attr_reader :predicates
|
116
118
|
|
117
119
|
def referenced_columns
|
118
|
-
|
120
|
+
hash = {}
|
121
|
+
each_attributes { |attr, node| hash[attr] = node }
|
122
|
+
hash
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
def each_attributes
|
127
|
+
predicates.each do |node|
|
119
128
|
attr = extract_attribute(node) || begin
|
120
129
|
node.left if equality_node?(node) && node.left.is_a?(Arel::Predications)
|
121
130
|
end
|
122
131
|
|
123
|
-
|
132
|
+
yield attr, node if attr
|
124
133
|
end
|
125
134
|
end
|
126
135
|
|
127
|
-
private
|
128
136
|
def extract_attribute(node)
|
129
137
|
attr_node = nil
|
130
138
|
Arel.fetch_attribute(node) do |attr|
|
@@ -165,8 +173,8 @@ module ActiveRecord
|
|
165
173
|
else
|
166
174
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
167
175
|
Merging (#{node.to_sql}) and (#{ref.to_sql}) no longer maintain
|
168
|
-
both conditions, and will be replaced by the latter in Rails
|
169
|
-
To migrate to Rails
|
176
|
+
both conditions, and will be replaced by the latter in Rails 7.0.
|
177
|
+
To migrate to Rails 7.0's behavior, use `relation.merge(other, rewhere: true)`.
|
170
178
|
MSG
|
171
179
|
false
|
172
180
|
end
|
@@ -224,11 +232,10 @@ module ActiveRecord
|
|
224
232
|
end
|
225
233
|
|
226
234
|
def extract_node_value(node)
|
227
|
-
|
228
|
-
when Array
|
229
|
-
node.map { |v| extract_node_value(v) }
|
230
|
-
when Arel::Nodes::BindParam, Arel::Nodes::Casted, Arel::Nodes::Quoted
|
235
|
+
if node.respond_to?(:value_before_type_cast)
|
231
236
|
node.value_before_type_cast
|
237
|
+
elsif Array === node
|
238
|
+
node.map { |v| extract_node_value(v) }
|
232
239
|
end
|
233
240
|
end
|
234
241
|
end
|
@@ -31,6 +31,9 @@ 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
|
36
|
+
@limited_count = nil
|
34
37
|
end
|
35
38
|
|
36
39
|
def initialize_copy(other)
|
@@ -67,8 +70,12 @@ module ActiveRecord
|
|
67
70
|
# user = users.new { |user| user.name = 'Oscar' }
|
68
71
|
# user.name # => Oscar
|
69
72
|
def new(attributes = nil, &block)
|
70
|
-
|
71
|
-
|
73
|
+
if attributes.is_a?(Array)
|
74
|
+
attributes.collect { |attr| new(attr, &block) }
|
75
|
+
else
|
76
|
+
block = current_scope_restoring_block(&block)
|
77
|
+
scoping { _new(attributes, &block) }
|
78
|
+
end
|
72
79
|
end
|
73
80
|
alias build new
|
74
81
|
|
@@ -148,7 +155,7 @@ module ActiveRecord
|
|
148
155
|
# above can be alternatively written this way:
|
149
156
|
#
|
150
157
|
# # Find the first user named "Scarlett" or create a new one with a
|
151
|
-
# #
|
158
|
+
# # particular last name.
|
152
159
|
# User.find_or_create_by(first_name: 'Scarlett') do |user|
|
153
160
|
# user.last_name = 'Johansson'
|
154
161
|
# end
|
@@ -175,7 +182,7 @@ module ActiveRecord
|
|
175
182
|
find_by(attributes) || create!(attributes, &block)
|
176
183
|
end
|
177
184
|
|
178
|
-
# Attempts to create a record with the given attributes in a table that has a unique constraint
|
185
|
+
# Attempts to create a record with the given attributes in a table that has a unique database constraint
|
179
186
|
# on one or several of its columns. If a row already exists with one or several of these
|
180
187
|
# unique constraints, the exception such an insertion would normally raise is caught,
|
181
188
|
# and the existing record with those attributes is found using #find_by!.
|
@@ -186,7 +193,7 @@ module ActiveRecord
|
|
186
193
|
#
|
187
194
|
# There are several drawbacks to #create_or_find_by, though:
|
188
195
|
#
|
189
|
-
# * The underlying table must have the relevant columns defined with unique constraints.
|
196
|
+
# * The underlying table must have the relevant columns defined with unique database constraints.
|
190
197
|
# * A unique constraint violation may be triggered by only one, or at least less than all,
|
191
198
|
# of the given attributes. This means that the subsequent #find_by! may fail to find a
|
192
199
|
# matching record, which will then raise an <tt>ActiveRecord::RecordNotFound</tt> exception,
|
@@ -257,13 +264,20 @@ module ActiveRecord
|
|
257
264
|
|
258
265
|
# Returns size of the records.
|
259
266
|
def size
|
260
|
-
loaded?
|
267
|
+
if loaded?
|
268
|
+
records.length
|
269
|
+
else
|
270
|
+
count(:all)
|
271
|
+
end
|
261
272
|
end
|
262
273
|
|
263
274
|
# Returns true if there are no records.
|
264
275
|
def empty?
|
265
|
-
|
266
|
-
|
276
|
+
if loaded?
|
277
|
+
records.empty?
|
278
|
+
else
|
279
|
+
!exists?
|
280
|
+
end
|
267
281
|
end
|
268
282
|
|
269
283
|
# Returns true if there are no records.
|
@@ -281,13 +295,15 @@ module ActiveRecord
|
|
281
295
|
# Returns true if there is exactly one record.
|
282
296
|
def one?
|
283
297
|
return super if block_given?
|
284
|
-
|
298
|
+
return records.one? if limit_value || loaded?
|
299
|
+
limited_count == 1
|
285
300
|
end
|
286
301
|
|
287
302
|
# Returns true if there is more than one record.
|
288
303
|
def many?
|
289
304
|
return super if block_given?
|
290
|
-
|
305
|
+
return records.many? if limit_value || loaded?
|
306
|
+
limited_count > 1
|
291
307
|
end
|
292
308
|
|
293
309
|
# Returns a stable cache key that can be used to identify this query.
|
@@ -344,7 +360,7 @@ module ActiveRecord
|
|
344
360
|
def compute_cache_version(timestamp_column) # :nodoc:
|
345
361
|
timestamp_column = timestamp_column.to_s
|
346
362
|
|
347
|
-
if loaded?
|
363
|
+
if loaded?
|
348
364
|
size = records.size
|
349
365
|
if size > 0
|
350
366
|
timestamp = records.map { |record| record.read_attribute(timestamp_column) }.max
|
@@ -357,6 +373,7 @@ module ActiveRecord
|
|
357
373
|
|
358
374
|
if collection.has_limit_or_offset?
|
359
375
|
query = collection.select("#{column} AS collection_cache_key_timestamp")
|
376
|
+
query._select!(table[Arel.star]) if distinct_value && collection.select_values.empty?
|
360
377
|
subquery_alias = "subquery_for_cache_key"
|
361
378
|
subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
|
362
379
|
arel = query.build_subquery(subquery_alias, select_values % subquery_column)
|
@@ -400,15 +417,28 @@ module ActiveRecord
|
|
400
417
|
# end
|
401
418
|
# # => SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1
|
402
419
|
#
|
420
|
+
# If <tt>all_queries: true</tt> is passed, scoping will apply to all queries
|
421
|
+
# for the relation including +update+ and +delete+ on instances.
|
422
|
+
# Once +all_queries+ is set to true it cannot be set to false in a
|
423
|
+
# nested block.
|
424
|
+
#
|
403
425
|
# Please check unscoped if you want to remove all previous scopes (including
|
404
426
|
# the default_scope) during the execution of a block.
|
405
|
-
def scoping
|
406
|
-
|
427
|
+
def scoping(all_queries: nil, &block)
|
428
|
+
registry = klass.scope_registry
|
429
|
+
if global_scope?(registry) && all_queries == false
|
430
|
+
raise ArgumentError, "Scoping is set to apply to all queries and cannot be unset in a nested block."
|
431
|
+
elsif already_in_scope?(registry)
|
432
|
+
yield
|
433
|
+
else
|
434
|
+
_scoping(self, registry, all_queries, &block)
|
435
|
+
end
|
407
436
|
end
|
408
437
|
|
409
438
|
def _exec_scope(*args, &block) # :nodoc:
|
410
439
|
@delegate_to_klass = true
|
411
|
-
|
440
|
+
registry = klass.scope_registry
|
441
|
+
_scoping(nil, registry) { instance_exec(*args, &block) || self }
|
412
442
|
ensure
|
413
443
|
@delegate_to_klass = false
|
414
444
|
end
|
@@ -440,19 +470,6 @@ module ActiveRecord
|
|
440
470
|
def update_all(updates)
|
441
471
|
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
|
442
472
|
|
443
|
-
if eager_loading?
|
444
|
-
relation = apply_join_dependency
|
445
|
-
return relation.update_all(updates)
|
446
|
-
end
|
447
|
-
|
448
|
-
stmt = Arel::UpdateManager.new
|
449
|
-
stmt.table(arel.join_sources.empty? ? table : arel.source)
|
450
|
-
stmt.key = table[primary_key]
|
451
|
-
stmt.take(arel.limit)
|
452
|
-
stmt.offset(arel.offset)
|
453
|
-
stmt.order(*arel.orders)
|
454
|
-
stmt.wheres = arel.constraints
|
455
|
-
|
456
473
|
if updates.is_a?(Hash)
|
457
474
|
if klass.locking_enabled? &&
|
458
475
|
!updates.key?(klass.locking_column) &&
|
@@ -460,12 +477,17 @@ module ActiveRecord
|
|
460
477
|
attr = table[klass.locking_column]
|
461
478
|
updates[attr.name] = _increment_attribute(attr)
|
462
479
|
end
|
463
|
-
|
480
|
+
values = _substitute_values(updates)
|
464
481
|
else
|
465
|
-
|
482
|
+
values = Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
|
466
483
|
end
|
467
484
|
|
468
|
-
|
485
|
+
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
486
|
+
arel.source.left = table
|
487
|
+
|
488
|
+
stmt = arel.compile_update(values, table[primary_key])
|
489
|
+
|
490
|
+
klass.connection.update(stmt, "#{klass} Update All").tap { reset }
|
469
491
|
end
|
470
492
|
|
471
493
|
def update(id = :all, attributes) # :nodoc:
|
@@ -476,6 +498,14 @@ module ActiveRecord
|
|
476
498
|
end
|
477
499
|
end
|
478
500
|
|
501
|
+
def update!(id = :all, attributes) # :nodoc:
|
502
|
+
if id == :all
|
503
|
+
each { |record| record.update!(attributes) }
|
504
|
+
else
|
505
|
+
klass.update!(id, attributes)
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
479
509
|
# Updates the counters of the records in the current relation.
|
480
510
|
#
|
481
511
|
# ==== Parameters
|
@@ -582,23 +612,12 @@ module ActiveRecord
|
|
582
612
|
raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
|
583
613
|
end
|
584
614
|
|
585
|
-
|
586
|
-
|
587
|
-
return relation.delete_all
|
588
|
-
end
|
615
|
+
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
616
|
+
arel.source.left = table
|
589
617
|
|
590
|
-
stmt =
|
591
|
-
stmt.from(arel.join_sources.empty? ? table : arel.source)
|
592
|
-
stmt.key = table[primary_key]
|
593
|
-
stmt.take(arel.limit)
|
594
|
-
stmt.offset(arel.offset)
|
595
|
-
stmt.order(*arel.orders)
|
596
|
-
stmt.wheres = arel.constraints
|
618
|
+
stmt = arel.compile_delete(table[primary_key])
|
597
619
|
|
598
|
-
|
599
|
-
|
600
|
-
reset
|
601
|
-
affected
|
620
|
+
klass.connection.delete(stmt, "#{klass} Delete All").tap { reset }
|
602
621
|
end
|
603
622
|
|
604
623
|
# Finds and destroys all records matching the specified conditions.
|
@@ -627,6 +646,32 @@ module ActiveRecord
|
|
627
646
|
where(*args).delete_all
|
628
647
|
end
|
629
648
|
|
649
|
+
# Schedule the query to be performed from a background thread pool.
|
650
|
+
#
|
651
|
+
# Post.where(published: true).load_async # => #<ActiveRecord::Relation>
|
652
|
+
def load_async
|
653
|
+
return load if !connection.async_enabled?
|
654
|
+
|
655
|
+
unless loaded?
|
656
|
+
result = exec_main_query(async: connection.current_transaction.closed?)
|
657
|
+
|
658
|
+
if result.is_a?(Array)
|
659
|
+
@records = result
|
660
|
+
else
|
661
|
+
@future_result = result
|
662
|
+
end
|
663
|
+
@loaded = true
|
664
|
+
end
|
665
|
+
|
666
|
+
self
|
667
|
+
end
|
668
|
+
|
669
|
+
# Returns <tt>true</tt> if the relation was scheduled on the background
|
670
|
+
# thread pool.
|
671
|
+
def scheduled?
|
672
|
+
!!@future_result
|
673
|
+
end
|
674
|
+
|
630
675
|
# Causes the records to be loaded from the database if they have not
|
631
676
|
# been loaded already. You can use this if for some reason you need
|
632
677
|
# to explicitly load some records before actually using them. The
|
@@ -634,7 +679,7 @@ module ActiveRecord
|
|
634
679
|
#
|
635
680
|
# Post.where(published: true).load # => #<ActiveRecord::Relation>
|
636
681
|
def load(&block)
|
637
|
-
|
682
|
+
if !loaded? || scheduled?
|
638
683
|
@records = exec_queries(&block)
|
639
684
|
@loaded = true
|
640
685
|
end
|
@@ -649,10 +694,14 @@ module ActiveRecord
|
|
649
694
|
end
|
650
695
|
|
651
696
|
def reset
|
697
|
+
@future_result&.cancel
|
698
|
+
@future_result = nil
|
652
699
|
@delegate_to_klass = false
|
653
700
|
@to_sql = @arel = @loaded = @should_eager_load = nil
|
654
701
|
@offsets = @take = nil
|
655
|
-
@
|
702
|
+
@cache_keys = nil
|
703
|
+
@records = nil
|
704
|
+
@limited_count = nil
|
656
705
|
self
|
657
706
|
end
|
658
707
|
|
@@ -661,16 +710,14 @@ module ActiveRecord
|
|
661
710
|
# User.where(name: 'Oscar').to_sql
|
662
711
|
# # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
|
663
712
|
def to_sql
|
664
|
-
@to_sql ||=
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
relation.to_sql
|
669
|
-
end
|
670
|
-
else
|
671
|
-
conn = klass.connection
|
672
|
-
conn.unprepared_statement { conn.to_sql(arel) }
|
713
|
+
@to_sql ||= if eager_loading?
|
714
|
+
apply_join_dependency do |relation, join_dependency|
|
715
|
+
relation = join_dependency.apply_column_aliases(relation)
|
716
|
+
relation.to_sql
|
673
717
|
end
|
718
|
+
else
|
719
|
+
conn = klass.connection
|
720
|
+
conn.unprepared_statement { conn.to_sql(arel) }
|
674
721
|
end
|
675
722
|
end
|
676
723
|
|
@@ -728,6 +775,10 @@ module ActiveRecord
|
|
728
775
|
@values.dup
|
729
776
|
end
|
730
777
|
|
778
|
+
def values_for_queries # :nodoc:
|
779
|
+
@values.except(:extending, :skip_query_cache, :strict_loading)
|
780
|
+
end
|
781
|
+
|
731
782
|
def inspect
|
732
783
|
subject = loaded? ? records : annotate("loading for inspect")
|
733
784
|
entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
|
@@ -762,11 +813,9 @@ module ActiveRecord
|
|
762
813
|
def preload_associations(records) # :nodoc:
|
763
814
|
preload = preload_values
|
764
815
|
preload += includes_values unless eager_loading?
|
765
|
-
preloader = nil
|
766
816
|
scope = strict_loading_value ? StrictLoadingScope : nil
|
767
817
|
preload.each do |associations|
|
768
|
-
|
769
|
-
preloader.preload records, associations, scope
|
818
|
+
ActiveRecord::Associations::Preloader.new(records: records, associations: associations, scope: scope).call
|
770
819
|
end
|
771
820
|
end
|
772
821
|
|
@@ -781,8 +830,12 @@ module ActiveRecord
|
|
781
830
|
end
|
782
831
|
|
783
832
|
private
|
784
|
-
def already_in_scope?
|
785
|
-
@delegate_to_klass &&
|
833
|
+
def already_in_scope?(registry)
|
834
|
+
@delegate_to_klass && registry.current_scope(klass, true)
|
835
|
+
end
|
836
|
+
|
837
|
+
def global_scope?(registry)
|
838
|
+
registry.global_current_scope(klass, true)
|
786
839
|
end
|
787
840
|
|
788
841
|
def current_scope_restoring_block(&block)
|
@@ -805,11 +858,20 @@ module ActiveRecord
|
|
805
858
|
klass.create!(attributes, &block)
|
806
859
|
end
|
807
860
|
|
808
|
-
def _scoping(scope)
|
809
|
-
previous
|
861
|
+
def _scoping(scope, registry, all_queries = false)
|
862
|
+
previous = registry.current_scope(klass, true)
|
863
|
+
registry.set_current_scope(klass, scope)
|
864
|
+
|
865
|
+
if all_queries
|
866
|
+
previous_global = registry.global_current_scope(klass, true)
|
867
|
+
registry.set_global_current_scope(klass, scope)
|
868
|
+
end
|
810
869
|
yield
|
811
870
|
ensure
|
812
|
-
klass
|
871
|
+
registry.set_current_scope(klass, previous)
|
872
|
+
if all_queries
|
873
|
+
registry.set_global_current_scope(klass, previous_global)
|
874
|
+
end
|
813
875
|
end
|
814
876
|
|
815
877
|
def _substitute_values(values)
|
@@ -832,23 +894,15 @@ module ActiveRecord
|
|
832
894
|
|
833
895
|
def exec_queries(&block)
|
834
896
|
skip_query_cache_if_necessary do
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
else
|
843
|
-
relation = join_dependency.apply_column_aliases(relation)
|
844
|
-
rows = connection.select_all(relation.arel, "SQL")
|
845
|
-
join_dependency.instantiate(rows, strict_loading_value, &block)
|
846
|
-
end.freeze
|
847
|
-
end
|
848
|
-
else
|
849
|
-
klass.find_by_sql(arel, &block).freeze
|
850
|
-
end
|
897
|
+
rows = if scheduled?
|
898
|
+
future = @future_result
|
899
|
+
@future_result = nil
|
900
|
+
future.result
|
901
|
+
else
|
902
|
+
exec_main_query
|
903
|
+
end
|
851
904
|
|
905
|
+
records = instantiate_records(rows, &block)
|
852
906
|
preload_associations(records) unless skip_preloading_value
|
853
907
|
|
854
908
|
records.each(&:readonly!) if readonly_value
|
@@ -858,18 +912,43 @@ module ActiveRecord
|
|
858
912
|
end
|
859
913
|
end
|
860
914
|
|
861
|
-
def
|
862
|
-
|
863
|
-
|
864
|
-
|
915
|
+
def exec_main_query(async: false)
|
916
|
+
skip_query_cache_if_necessary do
|
917
|
+
if where_clause.contradiction?
|
918
|
+
[].freeze
|
919
|
+
elsif eager_loading?
|
920
|
+
apply_join_dependency do |relation, join_dependency|
|
921
|
+
if relation.null_relation?
|
922
|
+
[].freeze
|
923
|
+
else
|
924
|
+
relation = join_dependency.apply_column_aliases(relation)
|
925
|
+
@_join_dependency = join_dependency
|
926
|
+
connection.select_all(relation.arel, "SQL", async: async)
|
927
|
+
end
|
928
|
+
end
|
929
|
+
else
|
930
|
+
klass._query_by_sql(arel, async: async)
|
865
931
|
end
|
932
|
+
end
|
933
|
+
end
|
934
|
+
|
935
|
+
def instantiate_records(rows, &block)
|
936
|
+
return [].freeze if rows.empty?
|
937
|
+
if eager_loading?
|
938
|
+
records = @_join_dependency.instantiate(rows, strict_loading_value, &block).freeze
|
939
|
+
@_join_dependency = nil
|
940
|
+
records
|
866
941
|
else
|
867
|
-
|
942
|
+
klass._load_from_sql(rows, &block).freeze
|
868
943
|
end
|
869
944
|
end
|
870
945
|
|
871
|
-
def
|
872
|
-
|
946
|
+
def skip_query_cache_if_necessary(&block)
|
947
|
+
if skip_query_cache_value
|
948
|
+
uncached(&block)
|
949
|
+
else
|
950
|
+
yield
|
951
|
+
end
|
873
952
|
end
|
874
953
|
|
875
954
|
def references_eager_loaded_tables?
|
@@ -895,5 +974,9 @@ module ActiveRecord
|
|
895
974
|
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
|
896
975
|
string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
|
897
976
|
end
|
977
|
+
|
978
|
+
def limited_count
|
979
|
+
@limited_count ||= limit(2).count
|
980
|
+
end
|
898
981
|
end
|
899
982
|
end
|