activerecord 7.2.2.1 → 8.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +564 -753
- data/README.rdoc +2 -2
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/association.rb +35 -11
- data/lib/active_record/associations/belongs_to_association.rb +18 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +17 -4
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +1 -1
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +10 -8
- data/lib/active_record/associations/collection_proxy.rb +22 -4
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +3 -0
- data/lib/active_record/associations/has_many_through_association.rb +3 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/associations/join_dependency.rb +4 -2
- data/lib/active_record/associations/preloader/association.rb +2 -2
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +1 -0
- data/lib/active_record/associations/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +192 -24
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/primary_key.rb +4 -8
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +17 -4
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
- data/lib/active_record/attribute_methods.rb +24 -19
- data/lib/active_record/attributes.rb +40 -26
- data/lib/active_record/autosave_association.rb +91 -39
- data/lib/active_record/base.rb +3 -4
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +458 -117
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +136 -74
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +44 -11
- data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -29
- data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
- data/lib/active_record/connection_adapters/abstract_adapter.rb +175 -87
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +77 -58
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -9
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +73 -46
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -11
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -45
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +28 -45
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +140 -64
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +13 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +112 -42
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +38 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +2 -19
- data/lib/active_record/connection_adapters.rb +1 -56
- data/lib/active_record/connection_handling.rb +37 -10
- data/lib/active_record/core.rb +61 -25
- data/lib/active_record/counter_cache.rb +34 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- data/lib/active_record/database_configurations/database_config.rb +9 -1
- data/lib/active_record/database_configurations/hash_config.rb +67 -9
- data/lib/active_record/database_configurations/url_config.rb +13 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +19 -19
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +9 -9
- data/lib/active_record/encryption/encrypted_attribute_type.rb +12 -3
- data/lib/active_record/encryption/encryptor.rb +49 -28
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +9 -2
- data/lib/active_record/enum.rb +46 -42
- data/lib/active_record/errors.rb +36 -12
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +73 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +2 -4
- data/lib/active_record/future_result.rb +13 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +1 -1
- data/lib/active_record/insert_all.rb +12 -7
- data/lib/active_record/locking/optimistic.rb +8 -1
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +3 -13
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +44 -11
- data/lib/active_record/migration/compatibility.rb +37 -24
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration.rb +50 -43
- data/lib/active_record/model_schema.rb +38 -13
- data/lib/active_record/nested_attributes.rb +6 -6
- data/lib/active_record/persistence.rb +162 -133
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +104 -52
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +12 -12
- data/lib/active_record/railtie.rb +37 -32
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +26 -37
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +53 -21
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +147 -73
- data/lib/active_record/relation/calculations.rb +80 -63
- data/lib/active_record/relation/delegation.rb +25 -15
- data/lib/active_record/relation/finder_methods.rb +54 -37
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +22 -7
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +156 -95
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +10 -11
- data/lib/active_record/relation.rb +122 -80
- data/lib/active_record/result.rb +109 -24
- data/lib/active_record/runtime_registry.rb +42 -58
- data/lib/active_record/sanitization.rb +9 -6
- data/lib/active_record/schema_dumper.rb +47 -22
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +47 -18
- data/lib/active_record/statement_cache.rb +24 -20
- data/lib/active_record/store.rb +51 -22
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +6 -23
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +85 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
- data/lib/active_record/test_databases.rb +14 -4
- data/lib/active_record/test_fixtures.rb +39 -2
- data/lib/active_record/testing/query_assertions.rb +8 -2
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transaction.rb +2 -5
- data/lib/active_record/transactions.rb +39 -16
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +15 -2
- data/lib/active_record/type/serialized.rb +11 -4
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +2 -1
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +85 -50
- data/lib/arel/alias_predication.rb +2 -0
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/node.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/select_manager.rb +13 -4
- data/lib/arel/table.rb +3 -7
- data/lib/arel/update_manager.rb +5 -0
- data/lib/arel/visitors/dot.rb +2 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +6 -22
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +17 -17
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -163
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
|
@@ -60,7 +60,7 @@ module ActiveRecord
|
|
|
60
60
|
:reverse_order, :distinct, :create_with, :skip_query_cache]
|
|
61
61
|
|
|
62
62
|
CLAUSE_METHODS = [:where, :having, :from]
|
|
63
|
-
|
|
63
|
+
INVALID_METHODS_FOR_UPDATE_AND_DELETE_ALL = [:distinct, :with, :with_recursive]
|
|
64
64
|
|
|
65
65
|
VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
|
|
66
66
|
|
|
@@ -68,19 +68,26 @@ module ActiveRecord
|
|
|
68
68
|
include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
|
|
69
69
|
include SignedId::RelationMethods, TokenFor::RelationMethods
|
|
70
70
|
|
|
71
|
-
attr_reader :table, :
|
|
71
|
+
attr_reader :table, :model, :loaded, :predicate_builder
|
|
72
72
|
attr_accessor :skip_preloading_value
|
|
73
|
-
alias :
|
|
73
|
+
alias :klass :model
|
|
74
74
|
alias :loaded? :loaded
|
|
75
75
|
alias :locked? :lock_value
|
|
76
76
|
|
|
77
|
-
def initialize(
|
|
78
|
-
|
|
77
|
+
def initialize(model, table: nil, predicate_builder: nil, values: {})
|
|
78
|
+
if table
|
|
79
|
+
predicate_builder ||= model.predicate_builder.with(TableMetadata.new(model, table))
|
|
80
|
+
else
|
|
81
|
+
table = model.arel_table
|
|
82
|
+
predicate_builder ||= model.predicate_builder
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
@model = model
|
|
79
86
|
@table = table
|
|
80
87
|
@values = values
|
|
81
88
|
@loaded = false
|
|
82
89
|
@predicate_builder = predicate_builder
|
|
83
|
-
@
|
|
90
|
+
@delegate_to_model = false
|
|
84
91
|
@future_result = nil
|
|
85
92
|
@records = nil
|
|
86
93
|
@async = false
|
|
@@ -93,7 +100,7 @@ module ActiveRecord
|
|
|
93
100
|
end
|
|
94
101
|
|
|
95
102
|
def bind_attribute(name, value) # :nodoc:
|
|
96
|
-
if reflection =
|
|
103
|
+
if reflection = model._reflect_on_association(name)
|
|
97
104
|
name = reflection.foreign_key
|
|
98
105
|
value = value.read_attribute(reflection.association_primary_key) unless value.nil?
|
|
99
106
|
end
|
|
@@ -265,7 +272,12 @@ module ActiveRecord
|
|
|
265
272
|
# such situation.
|
|
266
273
|
def create_or_find_by(attributes, &block)
|
|
267
274
|
with_connection do |connection|
|
|
268
|
-
|
|
275
|
+
record = nil
|
|
276
|
+
transaction(requires_new: true) do
|
|
277
|
+
record = create(attributes, &block)
|
|
278
|
+
record._last_transaction_return_status || raise(ActiveRecord::Rollback)
|
|
279
|
+
end
|
|
280
|
+
record
|
|
269
281
|
rescue ActiveRecord::RecordNotUnique
|
|
270
282
|
if connection.transaction_open?
|
|
271
283
|
where(attributes).lock.find_by!(attributes)
|
|
@@ -280,7 +292,12 @@ module ActiveRecord
|
|
|
280
292
|
# is raised if the created record is invalid.
|
|
281
293
|
def create_or_find_by!(attributes, &block)
|
|
282
294
|
with_connection do |connection|
|
|
283
|
-
|
|
295
|
+
record = nil
|
|
296
|
+
transaction(requires_new: true) do
|
|
297
|
+
record = create!(attributes, &block)
|
|
298
|
+
record._last_transaction_return_status || raise(ActiveRecord::Rollback)
|
|
299
|
+
end
|
|
300
|
+
record
|
|
284
301
|
rescue ActiveRecord::RecordNotUnique
|
|
285
302
|
if connection.transaction_open?
|
|
286
303
|
where(attributes).lock.find_by!(attributes)
|
|
@@ -290,7 +307,7 @@ module ActiveRecord
|
|
|
290
307
|
end
|
|
291
308
|
end
|
|
292
309
|
|
|
293
|
-
# Like #find_or_create_by, but calls {new}[rdoc-ref:Core
|
|
310
|
+
# Like #find_or_create_by, but calls {new}[rdoc-ref:Core.new]
|
|
294
311
|
# instead of {create}[rdoc-ref:Persistence::ClassMethods#create].
|
|
295
312
|
def find_or_initialize_by(attributes, &block)
|
|
296
313
|
find_by(attributes) || new(attributes, &block)
|
|
@@ -430,14 +447,14 @@ module ActiveRecord
|
|
|
430
447
|
# Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
|
|
431
448
|
def cache_key(timestamp_column = "updated_at")
|
|
432
449
|
@cache_keys ||= {}
|
|
433
|
-
@cache_keys[timestamp_column] ||=
|
|
450
|
+
@cache_keys[timestamp_column] ||= model.collection_cache_key(self, timestamp_column)
|
|
434
451
|
end
|
|
435
452
|
|
|
436
453
|
def compute_cache_key(timestamp_column = :updated_at) # :nodoc:
|
|
437
454
|
query_signature = ActiveSupport::Digest.hexdigest(to_sql)
|
|
438
|
-
key = "#{
|
|
455
|
+
key = "#{model.model_name.cache_key}/query-#{query_signature}"
|
|
439
456
|
|
|
440
|
-
if collection_cache_versioning
|
|
457
|
+
if model.collection_cache_versioning
|
|
441
458
|
key
|
|
442
459
|
else
|
|
443
460
|
"#{key}-#{compute_cache_version(timestamp_column)}"
|
|
@@ -456,7 +473,7 @@ module ActiveRecord
|
|
|
456
473
|
#
|
|
457
474
|
# SELECT COUNT(*), MAX("products"."updated_at") FROM "products" WHERE (name like '%Cosmic Encounter%')
|
|
458
475
|
def cache_version(timestamp_column = :updated_at)
|
|
459
|
-
if collection_cache_versioning
|
|
476
|
+
if model.collection_cache_versioning
|
|
460
477
|
@cache_versions ||= {}
|
|
461
478
|
@cache_versions[timestamp_column] ||= compute_cache_version(timestamp_column)
|
|
462
479
|
end
|
|
@@ -475,7 +492,7 @@ module ActiveRecord
|
|
|
475
492
|
|
|
476
493
|
with_connection do |c|
|
|
477
494
|
column = c.visitor.compile(table[timestamp_column])
|
|
478
|
-
select_values = "COUNT(*) AS #{adapter_class.quote_column_name("size")}, MAX(%s) AS timestamp"
|
|
495
|
+
select_values = "COUNT(*) AS #{model.adapter_class.quote_column_name("size")}, MAX(%s) AS timestamp"
|
|
479
496
|
|
|
480
497
|
if collection.has_limit_or_offset?
|
|
481
498
|
query = collection.select("#{column} AS collection_cache_key_timestamp")
|
|
@@ -492,7 +509,7 @@ module ActiveRecord
|
|
|
492
509
|
size, timestamp = c.select_rows(arel, nil).first
|
|
493
510
|
|
|
494
511
|
if size
|
|
495
|
-
column_type =
|
|
512
|
+
column_type = model.type_for_attribute(timestamp_column)
|
|
496
513
|
timestamp = column_type.deserialize(timestamp)
|
|
497
514
|
else
|
|
498
515
|
size = 0
|
|
@@ -501,7 +518,7 @@ module ActiveRecord
|
|
|
501
518
|
end
|
|
502
519
|
|
|
503
520
|
if timestamp
|
|
504
|
-
"#{size}-#{timestamp.utc.to_fs(cache_timestamp_format)}"
|
|
521
|
+
"#{size}-#{timestamp.utc.to_fs(model.cache_timestamp_format)}"
|
|
505
522
|
else
|
|
506
523
|
"#{size}"
|
|
507
524
|
end
|
|
@@ -532,7 +549,7 @@ module ActiveRecord
|
|
|
532
549
|
# Please check unscoped if you want to remove all previous scopes (including
|
|
533
550
|
# the default_scope) during the execution of a block.
|
|
534
551
|
def scoping(all_queries: nil, &block)
|
|
535
|
-
registry =
|
|
552
|
+
registry = model.scope_registry
|
|
536
553
|
if global_scope?(registry) && all_queries == false
|
|
537
554
|
raise ArgumentError, "Scoping is set to apply to all queries and cannot be unset in a nested block."
|
|
538
555
|
elsif already_in_scope?(registry)
|
|
@@ -543,11 +560,11 @@ module ActiveRecord
|
|
|
543
560
|
end
|
|
544
561
|
|
|
545
562
|
def _exec_scope(...) # :nodoc:
|
|
546
|
-
@
|
|
547
|
-
registry =
|
|
563
|
+
@delegate_to_model = true
|
|
564
|
+
registry = model.scope_registry
|
|
548
565
|
_scoping(nil, registry) { instance_exec(...) || self }
|
|
549
566
|
ensure
|
|
550
|
-
@
|
|
567
|
+
@delegate_to_model = false
|
|
551
568
|
end
|
|
552
569
|
|
|
553
570
|
# Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
|
|
@@ -583,31 +600,41 @@ module ActiveRecord
|
|
|
583
600
|
|
|
584
601
|
return 0 if @none
|
|
585
602
|
|
|
603
|
+
invalid_methods = INVALID_METHODS_FOR_UPDATE_AND_DELETE_ALL.select do |method|
|
|
604
|
+
value = @values[method]
|
|
605
|
+
method == :distinct ? value : value&.any?
|
|
606
|
+
end
|
|
607
|
+
if invalid_methods.any?
|
|
608
|
+
ActiveRecord.deprecator.warn <<~MESSAGE
|
|
609
|
+
`#{invalid_methods.join(', ')}` is not supported by `update_all` and was never included in the generated query.
|
|
610
|
+
|
|
611
|
+
Calling `#{invalid_methods.join(', ')}` with `update_all` will raise an error in Rails 8.2.
|
|
612
|
+
MESSAGE
|
|
613
|
+
end
|
|
614
|
+
|
|
586
615
|
if updates.is_a?(Hash)
|
|
587
|
-
if
|
|
588
|
-
!updates.key?(
|
|
589
|
-
!updates.key?(
|
|
590
|
-
attr = table[
|
|
616
|
+
if model.locking_enabled? &&
|
|
617
|
+
!updates.key?(model.locking_column) &&
|
|
618
|
+
!updates.key?(model.locking_column.to_sym)
|
|
619
|
+
attr = table[model.locking_column]
|
|
591
620
|
updates[attr.name] = _increment_attribute(attr)
|
|
592
621
|
end
|
|
593
622
|
values = _substitute_values(updates)
|
|
594
623
|
else
|
|
595
|
-
values = Arel.sql(
|
|
624
|
+
values = Arel.sql(model.sanitize_sql_for_assignment(updates, table.name))
|
|
596
625
|
end
|
|
597
626
|
|
|
598
|
-
|
|
599
|
-
arel = eager_loading? ? apply_join_dependency.arel :
|
|
627
|
+
model.with_connection do |c|
|
|
628
|
+
arel = eager_loading? ? apply_join_dependency.arel : arel()
|
|
600
629
|
arel.source.left = table
|
|
601
630
|
|
|
602
|
-
|
|
603
|
-
having_clause_ast = having_clause.ast unless having_clause.empty?
|
|
604
|
-
key = if klass.composite_primary_key?
|
|
631
|
+
key = if model.composite_primary_key?
|
|
605
632
|
primary_key.map { |pk| table[pk] }
|
|
606
633
|
else
|
|
607
634
|
table[primary_key]
|
|
608
635
|
end
|
|
609
|
-
stmt = arel.compile_update(values, key
|
|
610
|
-
c.update(stmt, "#{
|
|
636
|
+
stmt = arel.compile_update(values, key)
|
|
637
|
+
c.update(stmt, "#{model} Update All").tap { reset }
|
|
611
638
|
end
|
|
612
639
|
end
|
|
613
640
|
|
|
@@ -615,7 +642,7 @@ module ActiveRecord
|
|
|
615
642
|
if id == :all
|
|
616
643
|
each { |record| record.update(attributes) }
|
|
617
644
|
else
|
|
618
|
-
|
|
645
|
+
model.update(id, attributes)
|
|
619
646
|
end
|
|
620
647
|
end
|
|
621
648
|
|
|
@@ -623,7 +650,7 @@ module ActiveRecord
|
|
|
623
650
|
if id == :all
|
|
624
651
|
each { |record| record.update!(attributes) }
|
|
625
652
|
else
|
|
626
|
-
|
|
653
|
+
model.update!(id, attributes)
|
|
627
654
|
end
|
|
628
655
|
end
|
|
629
656
|
|
|
@@ -813,7 +840,7 @@ module ActiveRecord
|
|
|
813
840
|
#
|
|
814
841
|
# [:returning]
|
|
815
842
|
# (PostgreSQL, SQLite3, and MariaDB only) An array of attributes to return for all successfully
|
|
816
|
-
#
|
|
843
|
+
# upserted records, which by default is the primary key.
|
|
817
844
|
# Pass <tt>returning: %w[ id name ]</tt> for both id and name
|
|
818
845
|
# or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
|
|
819
846
|
# clause entirely.
|
|
@@ -842,7 +869,9 @@ module ActiveRecord
|
|
|
842
869
|
# Active Record's schema_cache.
|
|
843
870
|
#
|
|
844
871
|
# [:on_duplicate]
|
|
845
|
-
# Configure the
|
|
872
|
+
# Configure the behavior that will be used in case of conflict. Use `:skip`
|
|
873
|
+
# to ignore any conflicts or provide a safe SQL fragment wrapped with
|
|
874
|
+
# `Arel.sql`.
|
|
846
875
|
#
|
|
847
876
|
# NOTE: If you use this option you must provide all the columns you want to update
|
|
848
877
|
# by yourself.
|
|
@@ -929,7 +958,7 @@ module ActiveRecord
|
|
|
929
958
|
names = touch if touch != true
|
|
930
959
|
names = Array.wrap(names)
|
|
931
960
|
options = names.extract_options!
|
|
932
|
-
touch_updates =
|
|
961
|
+
touch_updates = model.touch_attributes_with_time(*names, **options)
|
|
933
962
|
updates.merge!(touch_updates) unless touch_updates.empty?
|
|
934
963
|
end
|
|
935
964
|
|
|
@@ -942,7 +971,7 @@ module ActiveRecord
|
|
|
942
971
|
# If attribute names are passed, they are updated along with +updated_at+/+updated_on+ attributes.
|
|
943
972
|
# If no time argument is passed, the current time is used as default.
|
|
944
973
|
#
|
|
945
|
-
#
|
|
974
|
+
# ==== Examples
|
|
946
975
|
#
|
|
947
976
|
# # Touch all records
|
|
948
977
|
# Person.all.touch_all
|
|
@@ -960,7 +989,7 @@ module ActiveRecord
|
|
|
960
989
|
# Person.where(name: 'David').touch_all
|
|
961
990
|
# # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670' WHERE \"people\".\"name\" = 'David'"
|
|
962
991
|
def touch_all(*names, time: nil)
|
|
963
|
-
update_all
|
|
992
|
+
update_all model.touch_attributes_with_time(*names, time: time)
|
|
964
993
|
end
|
|
965
994
|
|
|
966
995
|
# Destroys the records by instantiating each
|
|
@@ -993,7 +1022,7 @@ module ActiveRecord
|
|
|
993
1022
|
#
|
|
994
1023
|
# Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
|
|
995
1024
|
#
|
|
996
|
-
#
|
|
1025
|
+
# This call deletes the affected posts all at once with a single DELETE statement.
|
|
997
1026
|
# If you need to destroy dependent associations or call your <tt>before_*</tt> or
|
|
998
1027
|
# +after_destroy+ callbacks, use the #destroy_all method instead.
|
|
999
1028
|
#
|
|
@@ -1004,7 +1033,7 @@ module ActiveRecord
|
|
|
1004
1033
|
def delete_all
|
|
1005
1034
|
return 0 if @none
|
|
1006
1035
|
|
|
1007
|
-
invalid_methods =
|
|
1036
|
+
invalid_methods = INVALID_METHODS_FOR_UPDATE_AND_DELETE_ALL.select do |method|
|
|
1008
1037
|
value = @values[method]
|
|
1009
1038
|
method == :distinct ? value : value&.any?
|
|
1010
1039
|
end
|
|
@@ -1012,20 +1041,18 @@ module ActiveRecord
|
|
|
1012
1041
|
raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
|
|
1013
1042
|
end
|
|
1014
1043
|
|
|
1015
|
-
|
|
1016
|
-
arel = eager_loading? ? apply_join_dependency.arel :
|
|
1044
|
+
model.with_connection do |c|
|
|
1045
|
+
arel = eager_loading? ? apply_join_dependency.arel : arel()
|
|
1017
1046
|
arel.source.left = table
|
|
1018
1047
|
|
|
1019
|
-
|
|
1020
|
-
having_clause_ast = having_clause.ast unless having_clause.empty?
|
|
1021
|
-
key = if klass.composite_primary_key?
|
|
1048
|
+
key = if model.composite_primary_key?
|
|
1022
1049
|
primary_key.map { |pk| table[pk] }
|
|
1023
1050
|
else
|
|
1024
1051
|
table[primary_key]
|
|
1025
1052
|
end
|
|
1026
|
-
stmt = arel.compile_delete(key
|
|
1053
|
+
stmt = arel.compile_delete(key)
|
|
1027
1054
|
|
|
1028
|
-
c.delete(stmt, "#{
|
|
1055
|
+
c.delete(stmt, "#{model} Delete All").tap { reset }
|
|
1029
1056
|
end
|
|
1030
1057
|
end
|
|
1031
1058
|
|
|
@@ -1124,9 +1151,6 @@ module ActiveRecord
|
|
|
1124
1151
|
# for queries to actually be executed concurrently. Otherwise it defaults to
|
|
1125
1152
|
# executing them in the foreground.
|
|
1126
1153
|
#
|
|
1127
|
-
# +load_async+ will also fall back to executing in the foreground in the test environment when transactional
|
|
1128
|
-
# fixtures are enabled.
|
|
1129
|
-
#
|
|
1130
1154
|
# If the query was actually executed in the background, the Active Record logs will show
|
|
1131
1155
|
# it by prefixing the log line with <tt>ASYNC</tt>:
|
|
1132
1156
|
#
|
|
@@ -1136,7 +1160,7 @@ module ActiveRecord
|
|
|
1136
1160
|
return load if !c.async_enabled?
|
|
1137
1161
|
|
|
1138
1162
|
unless loaded?
|
|
1139
|
-
result = exec_main_query(async: c.current_transaction.
|
|
1163
|
+
result = exec_main_query(async: !c.current_transaction.joinable?)
|
|
1140
1164
|
|
|
1141
1165
|
if result.is_a?(Array)
|
|
1142
1166
|
@records = result
|
|
@@ -1150,6 +1174,16 @@ module ActiveRecord
|
|
|
1150
1174
|
self
|
|
1151
1175
|
end
|
|
1152
1176
|
|
|
1177
|
+
def then(&block) # :nodoc:
|
|
1178
|
+
if @future_result
|
|
1179
|
+
@future_result.then do
|
|
1180
|
+
yield self
|
|
1181
|
+
end
|
|
1182
|
+
else
|
|
1183
|
+
super
|
|
1184
|
+
end
|
|
1185
|
+
end
|
|
1186
|
+
|
|
1153
1187
|
# Returns <tt>true</tt> if the relation was scheduled on the background
|
|
1154
1188
|
# thread pool.
|
|
1155
1189
|
def scheduled?
|
|
@@ -1180,7 +1214,7 @@ module ActiveRecord
|
|
|
1180
1214
|
def reset
|
|
1181
1215
|
@future_result&.cancel
|
|
1182
1216
|
@future_result = nil
|
|
1183
|
-
@
|
|
1217
|
+
@delegate_to_model = false
|
|
1184
1218
|
@to_sql = @arel = @loaded = @should_eager_load = nil
|
|
1185
1219
|
@offsets = @take = nil
|
|
1186
1220
|
@cache_keys = nil
|
|
@@ -1200,7 +1234,7 @@ module ActiveRecord
|
|
|
1200
1234
|
relation.to_sql
|
|
1201
1235
|
end
|
|
1202
1236
|
else
|
|
1203
|
-
|
|
1237
|
+
model.with_connection do |conn|
|
|
1204
1238
|
conn.unprepared_statement { conn.to_sql(arel) }
|
|
1205
1239
|
end
|
|
1206
1240
|
end
|
|
@@ -1210,12 +1244,12 @@ module ActiveRecord
|
|
|
1210
1244
|
#
|
|
1211
1245
|
# User.where(name: 'Oscar').where_values_hash
|
|
1212
1246
|
# # => {name: "Oscar"}
|
|
1213
|
-
def where_values_hash(relation_table_name =
|
|
1247
|
+
def where_values_hash(relation_table_name = model.table_name) # :nodoc:
|
|
1214
1248
|
where_clause.to_h(relation_table_name)
|
|
1215
1249
|
end
|
|
1216
1250
|
|
|
1217
1251
|
def scope_for_create
|
|
1218
|
-
hash = where_clause.to_h(
|
|
1252
|
+
hash = where_clause.to_h(model.table_name, equality_only: true)
|
|
1219
1253
|
create_with_value.each { |k, v| hash[k.to_s] = v } unless create_with_value.empty?
|
|
1220
1254
|
hash
|
|
1221
1255
|
end
|
|
@@ -1261,6 +1295,10 @@ module ActiveRecord
|
|
|
1261
1295
|
records.blank?
|
|
1262
1296
|
end
|
|
1263
1297
|
|
|
1298
|
+
def readonly?
|
|
1299
|
+
readonly_value
|
|
1300
|
+
end
|
|
1301
|
+
|
|
1264
1302
|
def values
|
|
1265
1303
|
@values.dup
|
|
1266
1304
|
end
|
|
@@ -1279,7 +1317,7 @@ module ActiveRecord
|
|
|
1279
1317
|
end
|
|
1280
1318
|
|
|
1281
1319
|
def empty_scope? # :nodoc:
|
|
1282
|
-
@values ==
|
|
1320
|
+
@values == model.unscoped.values
|
|
1283
1321
|
end
|
|
1284
1322
|
|
|
1285
1323
|
def has_limit_or_offset? # :nodoc:
|
|
@@ -1287,7 +1325,7 @@ module ActiveRecord
|
|
|
1287
1325
|
end
|
|
1288
1326
|
|
|
1289
1327
|
def alias_tracker(joins = [], aliases = nil) # :nodoc:
|
|
1290
|
-
ActiveRecord::Associations::AliasTracker.create(connection_pool, table.name, joins, aliases)
|
|
1328
|
+
ActiveRecord::Associations::AliasTracker.create(model.connection_pool, table.name, joins, aliases)
|
|
1291
1329
|
end
|
|
1292
1330
|
|
|
1293
1331
|
class StrictLoadingScope # :nodoc:
|
|
@@ -1317,46 +1355,46 @@ module ActiveRecord
|
|
|
1317
1355
|
|
|
1318
1356
|
private
|
|
1319
1357
|
def already_in_scope?(registry)
|
|
1320
|
-
@
|
|
1358
|
+
@delegate_to_model && registry.current_scope(model, true)
|
|
1321
1359
|
end
|
|
1322
1360
|
|
|
1323
1361
|
def global_scope?(registry)
|
|
1324
|
-
registry.global_current_scope(
|
|
1362
|
+
registry.global_current_scope(model, true)
|
|
1325
1363
|
end
|
|
1326
1364
|
|
|
1327
1365
|
def current_scope_restoring_block(&block)
|
|
1328
|
-
current_scope =
|
|
1366
|
+
current_scope = model.current_scope(true)
|
|
1329
1367
|
-> record do
|
|
1330
|
-
|
|
1368
|
+
model.current_scope = current_scope
|
|
1331
1369
|
yield record if block_given?
|
|
1332
1370
|
end
|
|
1333
1371
|
end
|
|
1334
1372
|
|
|
1335
1373
|
def _new(attributes, &block)
|
|
1336
|
-
|
|
1374
|
+
model.new(attributes, &block)
|
|
1337
1375
|
end
|
|
1338
1376
|
|
|
1339
1377
|
def _create(attributes, &block)
|
|
1340
|
-
|
|
1378
|
+
model.create(attributes, &block)
|
|
1341
1379
|
end
|
|
1342
1380
|
|
|
1343
1381
|
def _create!(attributes, &block)
|
|
1344
|
-
|
|
1382
|
+
model.create!(attributes, &block)
|
|
1345
1383
|
end
|
|
1346
1384
|
|
|
1347
1385
|
def _scoping(scope, registry, all_queries = false)
|
|
1348
|
-
previous = registry.current_scope(
|
|
1349
|
-
registry.set_current_scope(
|
|
1386
|
+
previous = registry.current_scope(model, true)
|
|
1387
|
+
registry.set_current_scope(model, scope)
|
|
1350
1388
|
|
|
1351
1389
|
if all_queries
|
|
1352
|
-
previous_global = registry.global_current_scope(
|
|
1353
|
-
registry.set_global_current_scope(
|
|
1390
|
+
previous_global = registry.global_current_scope(model, true)
|
|
1391
|
+
registry.set_global_current_scope(model, scope)
|
|
1354
1392
|
end
|
|
1355
1393
|
yield
|
|
1356
1394
|
ensure
|
|
1357
|
-
registry.set_current_scope(
|
|
1395
|
+
registry.set_current_scope(model, previous)
|
|
1358
1396
|
if all_queries
|
|
1359
|
-
registry.set_global_current_scope(
|
|
1397
|
+
registry.set_global_current_scope(model, previous_global)
|
|
1360
1398
|
end
|
|
1361
1399
|
end
|
|
1362
1400
|
|
|
@@ -1368,7 +1406,7 @@ module ActiveRecord
|
|
|
1368
1406
|
value = Arel::Nodes::Grouping.new(value)
|
|
1369
1407
|
end
|
|
1370
1408
|
else
|
|
1371
|
-
type =
|
|
1409
|
+
type = model.type_for_attribute(attr.name)
|
|
1372
1410
|
value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
|
|
1373
1411
|
end
|
|
1374
1412
|
[attr, value]
|
|
@@ -1377,12 +1415,16 @@ module ActiveRecord
|
|
|
1377
1415
|
|
|
1378
1416
|
def _increment_attribute(attribute, value = 1)
|
|
1379
1417
|
bind = predicate_builder.build_bind_attribute(attribute.name, value.abs)
|
|
1380
|
-
expr = table.coalesce(
|
|
1418
|
+
expr = table.coalesce(attribute, 0)
|
|
1381
1419
|
expr = value < 0 ? expr - bind : expr + bind
|
|
1382
1420
|
expr.expr
|
|
1383
1421
|
end
|
|
1384
1422
|
|
|
1385
1423
|
def exec_queries(&block)
|
|
1424
|
+
if lock_value && model.current_preventing_writes
|
|
1425
|
+
raise ActiveRecord::ReadOnlyError, "Lock query attempted while in readonly mode"
|
|
1426
|
+
end
|
|
1427
|
+
|
|
1386
1428
|
skip_query_cache_if_necessary do
|
|
1387
1429
|
rows = if scheduled?
|
|
1388
1430
|
future = @future_result
|
|
@@ -1415,20 +1457,20 @@ module ActiveRecord
|
|
|
1415
1457
|
if where_clause.contradiction?
|
|
1416
1458
|
[].freeze
|
|
1417
1459
|
elsif eager_loading?
|
|
1418
|
-
|
|
1460
|
+
model.with_connection do |c|
|
|
1419
1461
|
apply_join_dependency do |relation, join_dependency|
|
|
1420
1462
|
if relation.null_relation?
|
|
1421
1463
|
[].freeze
|
|
1422
1464
|
else
|
|
1423
1465
|
relation = join_dependency.apply_column_aliases(relation)
|
|
1424
1466
|
@_join_dependency = join_dependency
|
|
1425
|
-
c.select_all(relation.arel, "
|
|
1467
|
+
c.select_all(relation.arel, "#{model.name} Eager Load", async: async)
|
|
1426
1468
|
end
|
|
1427
1469
|
end
|
|
1428
1470
|
end
|
|
1429
1471
|
else
|
|
1430
|
-
|
|
1431
|
-
|
|
1472
|
+
model.with_connection do |c|
|
|
1473
|
+
model._query_by_sql(c, arel, async: async)
|
|
1432
1474
|
end
|
|
1433
1475
|
end
|
|
1434
1476
|
end
|
|
@@ -1441,13 +1483,13 @@ module ActiveRecord
|
|
|
1441
1483
|
@_join_dependency = nil
|
|
1442
1484
|
records
|
|
1443
1485
|
else
|
|
1444
|
-
|
|
1486
|
+
model._load_from_sql(rows, &block).freeze
|
|
1445
1487
|
end
|
|
1446
1488
|
end
|
|
1447
1489
|
|
|
1448
1490
|
def skip_query_cache_if_necessary(&block)
|
|
1449
1491
|
if skip_query_cache_value
|
|
1450
|
-
uncached(&block)
|
|
1492
|
+
model.uncached(&block)
|
|
1451
1493
|
else
|
|
1452
1494
|
yield
|
|
1453
1495
|
end
|