activerecord 7.0.0.alpha1 → 7.0.0.rc3
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 +516 -10
- data/lib/active_record/associations/association.rb +2 -8
- data/lib/active_record/associations/builder/collection_association.rb +9 -2
- data/lib/active_record/associations/collection_association.rb +10 -2
- data/lib/active_record/associations/preloader/association.rb +68 -48
- data/lib/active_record/associations/preloader/batch.rb +3 -6
- data/lib/active_record/associations/preloader/through_association.rb +19 -9
- data/lib/active_record/associations/preloader.rb +14 -24
- data/lib/active_record/associations/through_association.rb +2 -2
- data/lib/active_record/associations.rb +16 -3
- data/lib/active_record/asynchronous_queries_tracker.rb +3 -0
- data/lib/active_record/attribute_methods/dirty.rb +9 -1
- data/lib/active_record/attribute_methods.rb +7 -5
- data/lib/active_record/autosave_association.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +6 -26
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +18 -5
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +33 -70
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +9 -2
- data/lib/active_record/connection_adapters/abstract/transaction.rb +12 -19
- data/lib/active_record/connection_adapters/abstract_adapter.rb +37 -8
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +2 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +23 -24
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/pool_config.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -44
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +18 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -4
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +48 -5
- data/lib/active_record/connection_adapters/schema_cache.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +15 -16
- data/lib/active_record/connection_handling.rb +31 -19
- data/lib/active_record/core.rb +13 -24
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +0 -9
- data/lib/active_record/database_configurations/hash_config.rb +40 -8
- data/lib/active_record/database_configurations.rb +2 -27
- data/lib/active_record/delegated_type.rb +19 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +1 -1
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +1 -2
- data/lib/active_record/encryption/message_serializer.rb +11 -1
- data/lib/active_record/encryption/scheme.rb +1 -1
- data/lib/active_record/enum.rb +8 -1
- data/lib/active_record/errors.rb +1 -1
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/fixture_set/table_row.rb +1 -1
- data/lib/active_record/fixtures.rb +1 -9
- data/lib/active_record/future_result.rb +2 -2
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/insert_all.rb +52 -15
- data/lib/active_record/integration.rb +3 -2
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/pessimistic.rb +9 -3
- data/lib/active_record/log_subscriber.rb +8 -1
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/model_schema.rb +1 -28
- data/lib/active_record/nested_attributes.rb +11 -10
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +99 -21
- data/lib/active_record/query_logs.rb +18 -83
- data/lib/active_record/railtie.rb +11 -1
- data/lib/active_record/railties/databases.rake +4 -91
- data/lib/active_record/reflection.rb +22 -6
- data/lib/active_record/relation/calculations.rb +1 -10
- data/lib/active_record/relation/finder_methods.rb +0 -13
- data/lib/active_record/relation/query_methods.rb +5 -14
- data/lib/active_record/relation/record_fetch_warning.rb +5 -7
- data/lib/active_record/relation/where_clause.rb +2 -15
- data/lib/active_record/relation.rb +11 -13
- data/lib/active_record/result.rb +0 -5
- data/lib/active_record/runtime_registry.rb +10 -12
- data/lib/active_record/schema_dumper.rb +7 -0
- data/lib/active_record/scoping.rb +34 -22
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/tasks/database_tasks.rb +18 -44
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -1
- data/lib/active_record/validations/uniqueness.rb +1 -1
- data/lib/active_record.rb +41 -33
- data/lib/arel/crud.rb +12 -2
- data/lib/arel/delete_manager.rb +16 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/nodes/delete_statement.rb +5 -1
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/update_statement.rb +5 -1
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +10 -2
- data/lib/arel/update_manager.rb +16 -0
- data/lib/arel/visitors/mysql.rb +2 -1
- data/lib/arel/visitors/to_sql.rb +15 -0
- data/lib/arel.rb +1 -0
- metadata +17 -13
@@ -571,7 +571,6 @@ module ActiveRecord
|
|
571
571
|
@columns_hash.each do |name, column|
|
572
572
|
type = connection.lookup_cast_type_from_column(column)
|
573
573
|
type = _convert_type_from_options(type)
|
574
|
-
warn_if_deprecated_type(column)
|
575
574
|
define_attribute(
|
576
575
|
name,
|
577
576
|
type,
|
@@ -595,7 +594,7 @@ module ActiveRecord
|
|
595
594
|
@schema_loaded = false
|
596
595
|
@attribute_names = nil
|
597
596
|
@yaml_encoder = nil
|
598
|
-
|
597
|
+
subclasses.each do |descendant|
|
599
598
|
descendant.send(:reload_schema_from_cache)
|
600
599
|
end
|
601
600
|
end
|
@@ -630,32 +629,6 @@ module ActiveRecord
|
|
630
629
|
type
|
631
630
|
end
|
632
631
|
end
|
633
|
-
|
634
|
-
def warn_if_deprecated_type(column)
|
635
|
-
return if attributes_to_define_after_schema_loads.key?(column.name)
|
636
|
-
return unless column.respond_to?(:array?)
|
637
|
-
|
638
|
-
if column.array?
|
639
|
-
array_arguments = ", array: true"
|
640
|
-
else
|
641
|
-
array_arguments = ""
|
642
|
-
end
|
643
|
-
|
644
|
-
if column.sql_type.start_with?("interval")
|
645
|
-
precision_arguments = column.precision.presence && ", precision: #{column.precision}"
|
646
|
-
ActiveSupport::Deprecation.warn(<<~WARNING)
|
647
|
-
The behavior of the `:interval` type will be changing in Rails 7.0
|
648
|
-
to return an `ActiveSupport::Duration` object. If you'd like to keep
|
649
|
-
the old behavior, you can add this line to #{self.name} model:
|
650
|
-
|
651
|
-
attribute :#{column.name}, :string#{precision_arguments}#{array_arguments}
|
652
|
-
|
653
|
-
If you'd like the new behavior today, you can add this line:
|
654
|
-
|
655
|
-
attribute :#{column.name}, :interval#{precision_arguments}#{array_arguments}
|
656
|
-
WARNING
|
657
|
-
end
|
658
|
-
end
|
659
632
|
end
|
660
633
|
end
|
661
634
|
end
|
@@ -245,18 +245,19 @@ module ActiveRecord
|
|
245
245
|
#
|
246
246
|
# === Validating the presence of a parent model
|
247
247
|
#
|
248
|
-
#
|
249
|
-
#
|
250
|
-
#
|
251
|
-
#
|
252
|
-
#
|
253
|
-
#
|
254
|
-
#
|
248
|
+
# The +belongs_to+ association validates the presence of the parent model
|
249
|
+
# by default. You can disable this behavior by specifying <code>optional: true</code>.
|
250
|
+
# This can be used, for example, when conditionally validating the presence
|
251
|
+
# of the parent model:
|
252
|
+
#
|
253
|
+
# class Veterinarian < ActiveRecord::Base
|
254
|
+
# has_many :patients, inverse_of: :veterinarian
|
255
|
+
# accepts_nested_attributes_for :patients
|
255
256
|
# end
|
256
257
|
#
|
257
|
-
# class
|
258
|
-
# belongs_to :
|
259
|
-
#
|
258
|
+
# class Patient < ActiveRecord::Base
|
259
|
+
# belongs_to :veterinarian, inverse_of: :patients, optional: true
|
260
|
+
# validates :veterinarian, presence: true, unless: -> { awaiting_intake }
|
260
261
|
# end
|
261
262
|
#
|
262
263
|
# Note that if you do not specify the +:inverse_of+ option, then
|
@@ -63,8 +63,8 @@ module ActiveRecord
|
|
63
63
|
# go through Active Record's type casting and serialization.
|
64
64
|
#
|
65
65
|
# See <tt>ActiveRecord::Persistence#insert_all</tt> for documentation.
|
66
|
-
def insert(attributes, returning: nil, unique_by: nil)
|
67
|
-
insert_all([ attributes ], returning: returning, unique_by: unique_by)
|
66
|
+
def insert(attributes, returning: nil, unique_by: nil, record_timestamps: nil)
|
67
|
+
insert_all([ attributes ], returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
|
68
68
|
end
|
69
69
|
|
70
70
|
# Inserts multiple records into the database in a single SQL INSERT
|
@@ -110,6 +110,17 @@ module ActiveRecord
|
|
110
110
|
# unique_by: %i[ author_id name ]
|
111
111
|
# unique_by: :index_books_on_isbn
|
112
112
|
#
|
113
|
+
# [:record_timestamps]
|
114
|
+
# By default, automatic setting of timestamp columns is controlled by
|
115
|
+
# the model's <tt>record_timestamps</tt> config, matching typical
|
116
|
+
# behavior.
|
117
|
+
#
|
118
|
+
# To override this and force automatic setting of timestamp columns one
|
119
|
+
# way or the other, pass <tt>:record_timestamps</tt>:
|
120
|
+
#
|
121
|
+
# record_timestamps: true # Always set timestamps automatically
|
122
|
+
# record_timestamps: false # Never set timestamps automatically
|
123
|
+
#
|
113
124
|
# Because it relies on the index information from the database
|
114
125
|
# <tt>:unique_by</tt> is recommended to be paired with
|
115
126
|
# Active Record's schema_cache.
|
@@ -131,8 +142,8 @@ module ActiveRecord
|
|
131
142
|
# { id: 1, title: "Rework" },
|
132
143
|
# { id: 2, title: "Eloquent Ruby" }
|
133
144
|
# ])
|
134
|
-
def insert_all(attributes, returning: nil, unique_by: nil)
|
135
|
-
InsertAll.new(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by).execute
|
145
|
+
def insert_all(attributes, returning: nil, unique_by: nil, record_timestamps: nil)
|
146
|
+
InsertAll.new(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps).execute
|
136
147
|
end
|
137
148
|
|
138
149
|
# Inserts a single record into the database in a single SQL INSERT
|
@@ -141,8 +152,8 @@ module ActiveRecord
|
|
141
152
|
# go through Active Record's type casting and serialization.
|
142
153
|
#
|
143
154
|
# See <tt>ActiveRecord::Persistence#insert_all!</tt> for more.
|
144
|
-
def insert!(attributes, returning: nil)
|
145
|
-
insert_all!([ attributes ], returning: returning)
|
155
|
+
def insert!(attributes, returning: nil, record_timestamps: nil)
|
156
|
+
insert_all!([ attributes ], returning: returning, record_timestamps: record_timestamps)
|
146
157
|
end
|
147
158
|
|
148
159
|
# Inserts multiple records into the database in a single SQL INSERT
|
@@ -174,6 +185,17 @@ module ActiveRecord
|
|
174
185
|
# You can also pass an SQL string if you need more control on the return values
|
175
186
|
# (for example, <tt>returning: "id, name as new_name"</tt>).
|
176
187
|
#
|
188
|
+
# [:record_timestamps]
|
189
|
+
# By default, automatic setting of timestamp columns is controlled by
|
190
|
+
# the model's <tt>record_timestamps</tt> config, matching typical
|
191
|
+
# behavior.
|
192
|
+
#
|
193
|
+
# To override this and force automatic setting of timestamp columns one
|
194
|
+
# way or the other, pass <tt>:record_timestamps</tt>:
|
195
|
+
#
|
196
|
+
# record_timestamps: true # Always set timestamps automatically
|
197
|
+
# record_timestamps: false # Never set timestamps automatically
|
198
|
+
#
|
177
199
|
# ==== Examples
|
178
200
|
#
|
179
201
|
# # Insert multiple records
|
@@ -188,8 +210,8 @@ module ActiveRecord
|
|
188
210
|
# { id: 1, title: "Rework", author: "David" },
|
189
211
|
# { id: 1, title: "Eloquent Ruby", author: "Russ" }
|
190
212
|
# ])
|
191
|
-
def insert_all!(attributes, returning: nil)
|
192
|
-
InsertAll.new(self, attributes, on_duplicate: :raise, returning: returning).execute
|
213
|
+
def insert_all!(attributes, returning: nil, record_timestamps: nil)
|
214
|
+
InsertAll.new(self, attributes, on_duplicate: :raise, returning: returning, record_timestamps: record_timestamps).execute
|
193
215
|
end
|
194
216
|
|
195
217
|
# Updates or inserts (upserts) a single record into the database in a
|
@@ -198,8 +220,8 @@ module ActiveRecord
|
|
198
220
|
# go through Active Record's type casting and serialization.
|
199
221
|
#
|
200
222
|
# See <tt>ActiveRecord::Persistence#upsert_all</tt> for documentation.
|
201
|
-
def upsert(attributes, on_duplicate: :update, returning: nil, unique_by: nil)
|
202
|
-
upsert_all([ attributes ], on_duplicate: on_duplicate, returning: returning, unique_by: unique_by)
|
223
|
+
def upsert(attributes, on_duplicate: :update, returning: nil, unique_by: nil, record_timestamps: nil)
|
224
|
+
upsert_all([ attributes ], on_duplicate: on_duplicate, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
|
203
225
|
end
|
204
226
|
|
205
227
|
# Updates or inserts (upserts) multiple records into the database in a
|
@@ -213,6 +235,10 @@ module ActiveRecord
|
|
213
235
|
# Returns an <tt>ActiveRecord::Result</tt> with its contents based on
|
214
236
|
# <tt>:returning</tt> (see below).
|
215
237
|
#
|
238
|
+
# By default, +upsert_all+ will update all the columns that can be updated when
|
239
|
+
# there is a conflict. These are all the columns except primary keys, read-only
|
240
|
+
# columns, and columns covered by the optional +unique_by+.
|
241
|
+
#
|
216
242
|
# ==== Options
|
217
243
|
#
|
218
244
|
# [:returning]
|
@@ -246,9 +272,52 @@ module ActiveRecord
|
|
246
272
|
# Active Record's schema_cache.
|
247
273
|
#
|
248
274
|
# [:on_duplicate]
|
249
|
-
#
|
275
|
+
# Configure the SQL update sentence that will be used in case of conflict.
|
276
|
+
#
|
277
|
+
# NOTE: If you use this option you must provide all the columns you want to update
|
278
|
+
# by yourself.
|
279
|
+
#
|
280
|
+
# Example:
|
281
|
+
#
|
282
|
+
# Commodity.upsert_all(
|
283
|
+
# [
|
284
|
+
# { id: 2, name: "Copper", price: 4.84 },
|
285
|
+
# { id: 4, name: "Gold", price: 1380.87 },
|
286
|
+
# { id: 6, name: "Aluminium", price: 0.35 }
|
287
|
+
# ],
|
288
|
+
# on_duplicate: Arel.sql("price = GREATEST(commodities.price, EXCLUDED.price)")
|
289
|
+
# )
|
290
|
+
#
|
291
|
+
# See the related +:update_only+ option. Both options can't be used at the same time.
|
250
292
|
#
|
251
|
-
#
|
293
|
+
# [:update_only]
|
294
|
+
# Provide a list of column names that will be updated in case of conflict. If not provided,
|
295
|
+
# +upsert_all+ will update all the columns that can be updated. These are all the columns
|
296
|
+
# except primary keys, read-only columns, and columns covered by the optional +unique_by+
|
297
|
+
#
|
298
|
+
# Example:
|
299
|
+
#
|
300
|
+
# Commodity.upsert_all(
|
301
|
+
# [
|
302
|
+
# { id: 2, name: "Copper", price: 4.84 },
|
303
|
+
# { id: 4, name: "Gold", price: 1380.87 },
|
304
|
+
# { id: 6, name: "Aluminium", price: 0.35 }
|
305
|
+
# ],
|
306
|
+
# update_only: [:price] # Only prices will be updated
|
307
|
+
# )
|
308
|
+
#
|
309
|
+
# See the related +:on_duplicate+ option. Both options can't be used at the same time.
|
310
|
+
#
|
311
|
+
# [:record_timestamps]
|
312
|
+
# By default, automatic setting of timestamp columns is controlled by
|
313
|
+
# the model's <tt>record_timestamps</tt> config, matching typical
|
314
|
+
# behavior.
|
315
|
+
#
|
316
|
+
# To override this and force automatic setting of timestamp columns one
|
317
|
+
# way or the other, pass <tt>:record_timestamps</tt>:
|
318
|
+
#
|
319
|
+
# record_timestamps: true # Always set timestamps automatically
|
320
|
+
# record_timestamps: false # Never set timestamps automatically
|
252
321
|
#
|
253
322
|
# ==== Examples
|
254
323
|
#
|
@@ -261,8 +330,8 @@ module ActiveRecord
|
|
261
330
|
# ], unique_by: :isbn)
|
262
331
|
#
|
263
332
|
# Book.find_by(isbn: "1").title # => "Eloquent Ruby"
|
264
|
-
def upsert_all(attributes, on_duplicate: :update, returning: nil, unique_by: nil)
|
265
|
-
InsertAll.new(self, attributes, on_duplicate: on_duplicate, returning: returning, unique_by: unique_by).execute
|
333
|
+
def upsert_all(attributes, on_duplicate: :update, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
|
334
|
+
InsertAll.new(self, attributes, on_duplicate: on_duplicate, update_only: update_only, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps).execute
|
266
335
|
end
|
267
336
|
|
268
337
|
# Given an attributes hash, +instantiate+ returns a new instance of
|
@@ -431,9 +500,8 @@ module ActiveRecord
|
|
431
500
|
def _update_record(values, constraints) # :nodoc:
|
432
501
|
constraints = constraints.map { |name, value| predicate_builder[name, value] }
|
433
502
|
|
434
|
-
|
435
|
-
|
436
|
-
end
|
503
|
+
default_constraint = build_default_constraint
|
504
|
+
constraints << default_constraint if default_constraint
|
437
505
|
|
438
506
|
if current_scope = self.global_current_scope
|
439
507
|
constraints << current_scope.where_clause.ast
|
@@ -449,9 +517,8 @@ module ActiveRecord
|
|
449
517
|
def _delete_record(constraints) # :nodoc:
|
450
518
|
constraints = constraints.map { |name, value| predicate_builder[name, value] }
|
451
519
|
|
452
|
-
|
453
|
-
|
454
|
-
end
|
520
|
+
default_constraint = build_default_constraint
|
521
|
+
constraints << default_constraint if default_constraint
|
455
522
|
|
456
523
|
if current_scope = self.global_current_scope
|
457
524
|
constraints << current_scope.where_clause.ast
|
@@ -479,6 +546,16 @@ module ActiveRecord
|
|
479
546
|
def discriminate_class_for_record(record)
|
480
547
|
self
|
481
548
|
end
|
549
|
+
|
550
|
+
# Called by +_update_record+ and +_delete_record+
|
551
|
+
# to build `where` clause from default scopes.
|
552
|
+
# Skips empty scopes.
|
553
|
+
def build_default_constraint
|
554
|
+
return unless default_scopes?(all_queries: true)
|
555
|
+
|
556
|
+
default_where_clause = default_scoped(all_queries: true).where_clause
|
557
|
+
default_where_clause.ast unless default_where_clause.empty?
|
558
|
+
end
|
482
559
|
end
|
483
560
|
|
484
561
|
# Returns true if this object hasn't been saved yet -- that is, a record
|
@@ -1035,7 +1112,8 @@ module ActiveRecord
|
|
1035
1112
|
|
1036
1113
|
def _raise_record_not_destroyed
|
1037
1114
|
@_association_destroy_exception ||= nil
|
1038
|
-
|
1115
|
+
key = self.class.primary_key
|
1116
|
+
raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{send(key)}", self)
|
1039
1117
|
ensure
|
1040
1118
|
@_association_destroy_exception = nil
|
1041
1119
|
end
|
@@ -38,24 +38,24 @@ module ActiveRecord
|
|
38
38
|
# tags = [
|
39
39
|
# :application,
|
40
40
|
# {
|
41
|
-
# custom_tag: ->(context) { context[:controller]
|
41
|
+
# custom_tag: ->(context) { context[:controller]&.controller_name },
|
42
42
|
# custom_value: -> { Custom.value },
|
43
43
|
# }
|
44
44
|
# ]
|
45
45
|
# ActiveRecord::QueryLogs.tags = tags
|
46
46
|
#
|
47
|
-
# The QueryLogs +context+ can be manipulated via
|
48
|
-
#
|
49
|
-
# Direct updates to a context value:
|
50
|
-
#
|
51
|
-
# ActiveRecord::QueryLogs.update_context(foo: Bar.new)
|
47
|
+
# The QueryLogs +context+ can be manipulated via the +ActiveSupport::ExecutionContext.set+ method.
|
52
48
|
#
|
53
49
|
# Temporary updates limited to the execution of a block:
|
54
50
|
#
|
55
|
-
#
|
51
|
+
# ActiveSupport::ExecutionContext.set(foo: Bar.new) do
|
56
52
|
# posts = Post.all
|
57
53
|
# end
|
58
54
|
#
|
55
|
+
# Direct updates to a context value:
|
56
|
+
#
|
57
|
+
# ActiveSupport::ExecutionContext[:foo] = Bar.new
|
58
|
+
#
|
59
59
|
# Tag comments can be prepended to the query:
|
60
60
|
#
|
61
61
|
# ActiveRecord::QueryLogs.prepend_comment = true
|
@@ -75,66 +75,22 @@ module ActiveRecord
|
|
75
75
|
mattr_accessor :cache_query_log_tags, instance_accessor: false, default: false
|
76
76
|
thread_mattr_accessor :cached_comment, instance_accessor: false
|
77
77
|
|
78
|
-
class NullObject # :nodoc:
|
79
|
-
def method_missing(method, *args, &block)
|
80
|
-
NullObject.new
|
81
|
-
end
|
82
|
-
|
83
|
-
def nil?
|
84
|
-
true
|
85
|
-
end
|
86
|
-
|
87
|
-
private
|
88
|
-
def respond_to_missing?(method, include_private = false)
|
89
|
-
true
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
78
|
class << self
|
94
|
-
# Updates the context used to construct tags in the SQL comment.
|
95
|
-
# Resets the cached comment if <tt>cache_query_log_tags</tt> is +true+.
|
96
|
-
def update_context(**options)
|
97
|
-
context.merge!(**options.symbolize_keys)
|
98
|
-
self.cached_comment = nil
|
99
|
-
end
|
100
|
-
|
101
|
-
# Updates the context used to construct tags in the SQL comment during
|
102
|
-
# execution of the provided block. Resets the provided keys to their
|
103
|
-
# previous value once the block exits.
|
104
|
-
def set_context(**options)
|
105
|
-
keys = options.keys
|
106
|
-
previous_context = keys.zip(context.values_at(*keys)).to_h
|
107
|
-
update_context(**options)
|
108
|
-
yield if block_given?
|
109
|
-
ensure
|
110
|
-
update_context(**previous_context)
|
111
|
-
end
|
112
|
-
|
113
|
-
# Temporarily tag any query executed within `&block`. Can be nested.
|
114
|
-
def with_tag(tag, &block)
|
115
|
-
inline_tags.push(tag)
|
116
|
-
yield if block_given?
|
117
|
-
ensure
|
118
|
-
inline_tags.pop
|
119
|
-
end
|
120
|
-
|
121
79
|
def call(sql) # :nodoc:
|
122
|
-
parts = self.comments
|
123
80
|
if prepend_comment
|
124
|
-
|
81
|
+
"#{self.comment} #{sql}"
|
125
82
|
else
|
126
|
-
|
127
|
-
end
|
128
|
-
parts.join(" ")
|
83
|
+
"#{sql} #{self.comment}"
|
84
|
+
end.strip
|
129
85
|
end
|
130
86
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
end
|
87
|
+
def clear_cache # :nodoc:
|
88
|
+
self.cached_comment = nil
|
89
|
+
end
|
90
|
+
|
91
|
+
ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
|
137
92
|
|
93
|
+
private
|
138
94
|
# Returns an SQL comment +String+ containing the query log tags.
|
139
95
|
# Sets and returns a cached comment if <tt>cache_query_log_tags</tt> is +true+.
|
140
96
|
def comment
|
@@ -152,30 +108,13 @@ module ActiveRecord
|
|
152
108
|
end
|
153
109
|
end
|
154
110
|
|
155
|
-
# Returns a +String+ containing any inline comments from +with_tag+.
|
156
|
-
def inline_comment
|
157
|
-
return nil unless inline_tags.present?
|
158
|
-
"/*#{escape_sql_comment(inline_tag_content)}*/"
|
159
|
-
end
|
160
|
-
|
161
|
-
# Return the set of active inline tags from +with_tag+.
|
162
|
-
def inline_tags
|
163
|
-
if context[:inline_tags].nil?
|
164
|
-
context[:inline_tags] = []
|
165
|
-
else
|
166
|
-
context[:inline_tags]
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
def context
|
171
|
-
Thread.current[:active_record_query_log_tags_context] ||= Hash.new { NullObject.new }
|
172
|
-
end
|
173
|
-
|
174
111
|
def escape_sql_comment(content)
|
175
112
|
content.to_s.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "")
|
176
113
|
end
|
177
114
|
|
178
115
|
def tag_content
|
116
|
+
context = ActiveSupport::ExecutionContext.to_h
|
117
|
+
|
179
118
|
tags.flat_map { |i| [*i] }.filter_map do |tag|
|
180
119
|
key, handler = tag
|
181
120
|
handler ||= taggings[key]
|
@@ -194,10 +133,6 @@ module ActiveRecord
|
|
194
133
|
"#{key}:#{val}" unless val.nil?
|
195
134
|
end.join(",")
|
196
135
|
end
|
197
|
-
|
198
|
-
def inline_tag_content
|
199
|
-
inline_tags.join
|
200
|
-
end
|
201
136
|
end
|
202
137
|
end
|
203
138
|
end
|
@@ -102,6 +102,14 @@ module ActiveRecord
|
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
+
initializer "active_record.shard_selector" do
|
106
|
+
if resolver = config.active_record.shard_resolver
|
107
|
+
options = config.active_record.shard_selector || {}
|
108
|
+
|
109
|
+
config.app_middleware.use ActiveRecord::Middleware::ShardSelector, resolver, options
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
105
113
|
initializer "Check for cache versioning support" do
|
106
114
|
config.after_initialize do |app|
|
107
115
|
ActiveSupport.on_load(:active_record) do
|
@@ -130,7 +138,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
130
138
|
initializer "active_record.check_schema_cache_dump" do
|
131
139
|
check_schema_cache_dump_version = config.active_record.check_schema_cache_dump_version
|
132
140
|
|
133
|
-
if config.active_record.use_schema_cache_dump
|
141
|
+
if config.active_record.use_schema_cache_dump && !config.active_record.lazily_load_schema_cache
|
134
142
|
config.after_initialize do |app|
|
135
143
|
ActiveSupport.on_load(:active_record) do
|
136
144
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first
|
@@ -232,6 +240,8 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
232
240
|
:database_selector,
|
233
241
|
:database_resolver,
|
234
242
|
:database_resolver_context,
|
243
|
+
:shard_selector,
|
244
|
+
:shard_resolver,
|
235
245
|
:query_log_tags_enabled,
|
236
246
|
:query_log_tags,
|
237
247
|
:cache_query_log_tags,
|
@@ -332,7 +332,7 @@ db_namespace = namespace :db do
|
|
332
332
|
|
333
333
|
desc "Retrieves the current schema version number"
|
334
334
|
task version: :load_config do
|
335
|
-
puts "Current version: #{ActiveRecord::Base.connection.
|
335
|
+
puts "Current version: #{ActiveRecord::Base.connection.schema_version}"
|
336
336
|
end
|
337
337
|
|
338
338
|
# desc "Raises an error if there are pending migrations"
|
@@ -469,14 +469,6 @@ db_namespace = namespace :db do
|
|
469
469
|
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(ActiveRecord.schema_format, ENV["SCHEMA"])
|
470
470
|
end
|
471
471
|
|
472
|
-
task load_if_ruby: ["db:create", :environment] do
|
473
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
474
|
-
Using `bin/rails db:schema:load_if_ruby` is deprecated and will be removed in Rails 7.0.
|
475
|
-
Configure the format using `config.active_record.schema_format = :ruby` to use `schema.rb` and run `bin/rails db:schema:load` instead.
|
476
|
-
MSG
|
477
|
-
db_namespace["schema:load"].invoke if ActiveRecord.schema_format == :ruby
|
478
|
-
end
|
479
|
-
|
480
472
|
namespace :dump do
|
481
473
|
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
|
482
474
|
desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) for #{name} database"
|
@@ -495,7 +487,7 @@ db_namespace = namespace :db do
|
|
495
487
|
task name => :load_config do
|
496
488
|
original_db_config = ActiveRecord::Base.connection_db_config
|
497
489
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env, name: name)
|
498
|
-
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config
|
490
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config)
|
499
491
|
ensure
|
500
492
|
ActiveRecord::Base.establish_connection(original_db_config) if original_db_config
|
501
493
|
end
|
@@ -533,63 +525,6 @@ db_namespace = namespace :db do
|
|
533
525
|
end
|
534
526
|
end
|
535
527
|
|
536
|
-
namespace :structure do
|
537
|
-
desc "Dumps the database structure to db/structure.sql. Specify another file with SCHEMA=db/my_structure.sql"
|
538
|
-
task dump: :load_config do
|
539
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
540
|
-
Using `bin/rails db:structure:dump` is deprecated and will be removed in Rails 7.0.
|
541
|
-
Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:schema:dump` instead.
|
542
|
-
MSG
|
543
|
-
|
544
|
-
db_namespace["schema:dump"].invoke
|
545
|
-
db_namespace["structure:dump"].reenable
|
546
|
-
end
|
547
|
-
|
548
|
-
desc "Recreates the databases from the structure.sql file"
|
549
|
-
task load: [:load_config, :check_protected_environments] do
|
550
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
551
|
-
Using `bin/rails db:structure:load` is deprecated and will be removed in Rails 7.0.
|
552
|
-
Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:schema:load` instead.
|
553
|
-
MSG
|
554
|
-
db_namespace["schema:load"].invoke
|
555
|
-
end
|
556
|
-
|
557
|
-
task load_if_sql: ["db:create", :environment] do
|
558
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
559
|
-
Using `bin/rails db:structure:load_if_sql` is deprecated and will be removed in Rails 7.0.
|
560
|
-
Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:schema:load` instead.
|
561
|
-
MSG
|
562
|
-
db_namespace["schema:load"].invoke if ActiveRecord.schema_format == :sql
|
563
|
-
end
|
564
|
-
|
565
|
-
namespace :dump do
|
566
|
-
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
|
567
|
-
desc "Dumps the #{name} database structure to db/structure.sql. Specify another file with SCHEMA=db/my_structure.sql"
|
568
|
-
task name => :load_config do
|
569
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
570
|
-
Using `bin/rails db:structure:dump:#{name}` is deprecated and will be removed in Rails 7.0.
|
571
|
-
Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:schema:dump:#{name}` instead.
|
572
|
-
MSG
|
573
|
-
db_namespace["schema:dump:#{name}"].invoke
|
574
|
-
db_namespace["structure:dump:#{name}"].reenable
|
575
|
-
end
|
576
|
-
end
|
577
|
-
end
|
578
|
-
|
579
|
-
namespace :load do
|
580
|
-
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
|
581
|
-
desc "Recreates the #{name} database from the structure.sql file"
|
582
|
-
task name => :load_config do
|
583
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
584
|
-
Using `bin/rails db:structure:load:#{name}` is deprecated and will be removed in Rails 7.0.
|
585
|
-
Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:schema:load:#{name}` instead.
|
586
|
-
MSG
|
587
|
-
db_namespace["schema:load:#{name}"].invoke
|
588
|
-
end
|
589
|
-
end
|
590
|
-
end
|
591
|
-
end
|
592
|
-
|
593
528
|
namespace :encryption do
|
594
529
|
desc "Generate a set of keys for configuring Active Record encryption in a given environment"
|
595
530
|
task :init do
|
@@ -615,8 +550,7 @@ db_namespace = namespace :db do
|
|
615
550
|
should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
|
616
551
|
ActiveRecord::Schema.verbose = false
|
617
552
|
ActiveRecord::Base.configurations.configs_for(env_name: "test").each do |db_config|
|
618
|
-
|
619
|
-
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ActiveRecord.schema_format, filename)
|
553
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config)
|
620
554
|
end
|
621
555
|
ensure
|
622
556
|
if should_reconnect
|
@@ -624,15 +558,6 @@ db_namespace = namespace :db do
|
|
624
558
|
end
|
625
559
|
end
|
626
560
|
|
627
|
-
# desc "Recreate the test database from an existent structure.sql file"
|
628
|
-
task load_structure: %w(db:test:purge) do
|
629
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
630
|
-
Using `bin/rails db:test:load_structure` is deprecated and will be removed in Rails 7.0.
|
631
|
-
Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:test:load_schema` instead.
|
632
|
-
MSG
|
633
|
-
db_namespace["test:load_schema"].invoke
|
634
|
-
end
|
635
|
-
|
636
561
|
# desc "Empty the test database"
|
637
562
|
task purge: %w(load_config check_protected_environments) do
|
638
563
|
ActiveRecord::Base.configurations.configs_for(env_name: "test").each do |db_config|
|
@@ -660,9 +585,8 @@ db_namespace = namespace :db do
|
|
660
585
|
task name => "db:test:purge:#{name}" do
|
661
586
|
should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
|
662
587
|
ActiveRecord::Schema.verbose = false
|
663
|
-
filename = ActiveRecord::Tasks::DatabaseTasks.dump_filename(name)
|
664
588
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "test", name: name)
|
665
|
-
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config
|
589
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config)
|
666
590
|
ensure
|
667
591
|
if should_reconnect
|
668
592
|
ActiveRecord::Base.establish_connection(ActiveRecord::Tasks::DatabaseTasks.env.to_sym)
|
@@ -670,17 +594,6 @@ db_namespace = namespace :db do
|
|
670
594
|
end
|
671
595
|
end
|
672
596
|
|
673
|
-
# desc "Recreate the #{name} test database from an existent structure.sql file"
|
674
|
-
namespace :load_structure do
|
675
|
-
task name => "db:test:purge:#{name}" do
|
676
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
677
|
-
Using `bin/rails db:test:load_structure:#{name}` is deprecated and will be removed in Rails 7.0.
|
678
|
-
Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:test:load_structure:#{name}` instead.
|
679
|
-
MSG
|
680
|
-
db_namespace["test:load_schema:#{name}"].invoke
|
681
|
-
end
|
682
|
-
end
|
683
|
-
|
684
597
|
# desc "Empty the #{name} test database"
|
685
598
|
namespace :purge do
|
686
599
|
task name => %w(load_config check_protected_environments) do
|