activerecord 7.2.3 → 8.1.3
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 +612 -1055
- data/README.rdoc +1 -1
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/association.rb +35 -11
- 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 +1 -1
- 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.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 +16 -3
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
- data/lib/active_record/attributes.rb +3 -0
- data/lib/active_record/autosave_association.rb +69 -27
- data/lib/active_record/base.rb +1 -2
- 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 +412 -88
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +137 -75
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +27 -5
- 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 +32 -35
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -32
- data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
- data/lib/active_record/connection_adapters/abstract_adapter.rb +150 -91
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +63 -52
- 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 +0 -8
- 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 +2 -10
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +8 -2
- 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 +14 -33
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +71 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +139 -63
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +78 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
- data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -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 -14
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +102 -37
- 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 +1 -18
- data/lib/active_record/connection_adapters.rb +1 -56
- data/lib/active_record/connection_handling.rb +25 -2
- data/lib/active_record/core.rb +33 -17
- data/lib/active_record/counter_cache.rb +33 -8
- 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 +1 -1
- 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 +8 -8
- data/lib/active_record/encryption/encrypted_attribute_type.rb +11 -2
- data/lib/active_record/encryption/encryptor.rb +28 -8
- 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 +33 -30
- data/lib/active_record/errors.rb +33 -9
- 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/fixtures.rb +2 -4
- data/lib/active_record/future_result.rb +15 -9
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +1 -1
- data/lib/active_record/insert_all.rb +14 -9
- 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 +45 -12
- 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 +48 -42
- 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 +100 -52
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +8 -8
- data/lib/active_record/railtie.rb +35 -30
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +26 -38
- 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 +52 -40
- data/lib/active_record/relation/delegation.rb +25 -15
- data/lib/active_record/relation/finder_methods.rb +40 -24
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -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 +3 -1
- data/lib/active_record/relation/query_methods.rb +140 -86
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +2 -9
- data/lib/active_record/relation.rb +107 -75
- 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 +18 -11
- 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/signed_id.rb +43 -15
- 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 +7 -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 +37 -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 +13 -2
- data/lib/active_record/type/serialized.rb +16 -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 +84 -49
- 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 +6 -11
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/count.rb +2 -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.rb +0 -2
- data/lib/arel/predications.rb +1 -3
- data/lib/arel/select_manager.rb +7 -2
- data/lib/arel/table.rb +3 -7
- data/lib/arel/visitors/dot.rb +0 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +3 -21
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +16 -13
- 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
|
|
@@ -440,14 +447,14 @@ module ActiveRecord
|
|
|
440
447
|
# Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
|
|
441
448
|
def cache_key(timestamp_column = "updated_at")
|
|
442
449
|
@cache_keys ||= {}
|
|
443
|
-
@cache_keys[timestamp_column] ||=
|
|
450
|
+
@cache_keys[timestamp_column] ||= model.collection_cache_key(self, timestamp_column)
|
|
444
451
|
end
|
|
445
452
|
|
|
446
453
|
def compute_cache_key(timestamp_column = :updated_at) # :nodoc:
|
|
447
454
|
query_signature = ActiveSupport::Digest.hexdigest(to_sql)
|
|
448
|
-
key = "#{
|
|
455
|
+
key = "#{model.model_name.cache_key}/query-#{query_signature}"
|
|
449
456
|
|
|
450
|
-
if collection_cache_versioning
|
|
457
|
+
if model.collection_cache_versioning
|
|
451
458
|
key
|
|
452
459
|
else
|
|
453
460
|
"#{key}-#{compute_cache_version(timestamp_column)}"
|
|
@@ -466,7 +473,7 @@ module ActiveRecord
|
|
|
466
473
|
#
|
|
467
474
|
# SELECT COUNT(*), MAX("products"."updated_at") FROM "products" WHERE (name like '%Cosmic Encounter%')
|
|
468
475
|
def cache_version(timestamp_column = :updated_at)
|
|
469
|
-
if collection_cache_versioning
|
|
476
|
+
if model.collection_cache_versioning
|
|
470
477
|
@cache_versions ||= {}
|
|
471
478
|
@cache_versions[timestamp_column] ||= compute_cache_version(timestamp_column)
|
|
472
479
|
end
|
|
@@ -485,7 +492,7 @@ module ActiveRecord
|
|
|
485
492
|
|
|
486
493
|
with_connection do |c|
|
|
487
494
|
column = c.visitor.compile(table[timestamp_column])
|
|
488
|
-
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"
|
|
489
496
|
|
|
490
497
|
if collection.has_limit_or_offset?
|
|
491
498
|
query = collection.select("#{column} AS collection_cache_key_timestamp")
|
|
@@ -502,7 +509,7 @@ module ActiveRecord
|
|
|
502
509
|
size, timestamp = c.select_rows(arel, nil).first
|
|
503
510
|
|
|
504
511
|
if size
|
|
505
|
-
column_type =
|
|
512
|
+
column_type = model.type_for_attribute(timestamp_column)
|
|
506
513
|
timestamp = column_type.deserialize(timestamp)
|
|
507
514
|
else
|
|
508
515
|
size = 0
|
|
@@ -511,7 +518,7 @@ module ActiveRecord
|
|
|
511
518
|
end
|
|
512
519
|
|
|
513
520
|
if timestamp
|
|
514
|
-
"#{size}-#{timestamp.utc.to_fs(cache_timestamp_format)}"
|
|
521
|
+
"#{size}-#{timestamp.utc.to_fs(model.cache_timestamp_format)}"
|
|
515
522
|
else
|
|
516
523
|
"#{size}"
|
|
517
524
|
end
|
|
@@ -542,7 +549,7 @@ module ActiveRecord
|
|
|
542
549
|
# Please check unscoped if you want to remove all previous scopes (including
|
|
543
550
|
# the default_scope) during the execution of a block.
|
|
544
551
|
def scoping(all_queries: nil, &block)
|
|
545
|
-
registry =
|
|
552
|
+
registry = model.scope_registry
|
|
546
553
|
if global_scope?(registry) && all_queries == false
|
|
547
554
|
raise ArgumentError, "Scoping is set to apply to all queries and cannot be unset in a nested block."
|
|
548
555
|
elsif already_in_scope?(registry)
|
|
@@ -553,11 +560,11 @@ module ActiveRecord
|
|
|
553
560
|
end
|
|
554
561
|
|
|
555
562
|
def _exec_scope(...) # :nodoc:
|
|
556
|
-
@
|
|
557
|
-
registry =
|
|
563
|
+
@delegate_to_model = true
|
|
564
|
+
registry = model.scope_registry
|
|
558
565
|
_scoping(nil, registry) { instance_exec(...) || self }
|
|
559
566
|
ensure
|
|
560
|
-
@
|
|
567
|
+
@delegate_to_model = false
|
|
561
568
|
end
|
|
562
569
|
|
|
563
570
|
# Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
|
|
@@ -593,31 +600,41 @@ module ActiveRecord
|
|
|
593
600
|
|
|
594
601
|
return 0 if @none
|
|
595
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
|
+
|
|
596
615
|
if updates.is_a?(Hash)
|
|
597
|
-
if
|
|
598
|
-
!updates.key?(
|
|
599
|
-
!updates.key?(
|
|
600
|
-
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]
|
|
601
620
|
updates[attr.name] = _increment_attribute(attr)
|
|
602
621
|
end
|
|
603
622
|
values = _substitute_values(updates)
|
|
604
623
|
else
|
|
605
|
-
values = Arel.sql(
|
|
624
|
+
values = Arel.sql(model.sanitize_sql_for_assignment(updates, table.name))
|
|
606
625
|
end
|
|
607
626
|
|
|
608
|
-
|
|
609
|
-
arel = eager_loading? ? apply_join_dependency.arel :
|
|
627
|
+
model.with_connection do |c|
|
|
628
|
+
arel = eager_loading? ? apply_join_dependency.arel : arel()
|
|
610
629
|
arel.source.left = table
|
|
611
630
|
|
|
612
|
-
|
|
613
|
-
having_clause_ast = having_clause.ast unless having_clause.empty?
|
|
614
|
-
key = if klass.composite_primary_key?
|
|
631
|
+
key = if model.composite_primary_key?
|
|
615
632
|
primary_key.map { |pk| table[pk] }
|
|
616
633
|
else
|
|
617
634
|
table[primary_key]
|
|
618
635
|
end
|
|
619
|
-
stmt = arel.compile_update(values, key
|
|
620
|
-
c.update(stmt, "#{
|
|
636
|
+
stmt = arel.compile_update(values, key)
|
|
637
|
+
c.update(stmt, "#{model} Update All").tap { reset }
|
|
621
638
|
end
|
|
622
639
|
end
|
|
623
640
|
|
|
@@ -625,7 +642,7 @@ module ActiveRecord
|
|
|
625
642
|
if id == :all
|
|
626
643
|
each { |record| record.update(attributes) }
|
|
627
644
|
else
|
|
628
|
-
|
|
645
|
+
model.update(id, attributes)
|
|
629
646
|
end
|
|
630
647
|
end
|
|
631
648
|
|
|
@@ -633,7 +650,7 @@ module ActiveRecord
|
|
|
633
650
|
if id == :all
|
|
634
651
|
each { |record| record.update!(attributes) }
|
|
635
652
|
else
|
|
636
|
-
|
|
653
|
+
model.update!(id, attributes)
|
|
637
654
|
end
|
|
638
655
|
end
|
|
639
656
|
|
|
@@ -852,7 +869,9 @@ module ActiveRecord
|
|
|
852
869
|
# Active Record's schema_cache.
|
|
853
870
|
#
|
|
854
871
|
# [:on_duplicate]
|
|
855
|
-
# 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`.
|
|
856
875
|
#
|
|
857
876
|
# NOTE: If you use this option you must provide all the columns you want to update
|
|
858
877
|
# by yourself.
|
|
@@ -939,7 +958,7 @@ module ActiveRecord
|
|
|
939
958
|
names = touch if touch != true
|
|
940
959
|
names = Array.wrap(names)
|
|
941
960
|
options = names.extract_options!
|
|
942
|
-
touch_updates =
|
|
961
|
+
touch_updates = model.touch_attributes_with_time(*names, **options)
|
|
943
962
|
updates.merge!(touch_updates) unless touch_updates.empty?
|
|
944
963
|
end
|
|
945
964
|
|
|
@@ -970,7 +989,7 @@ module ActiveRecord
|
|
|
970
989
|
# Person.where(name: 'David').touch_all
|
|
971
990
|
# # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670' WHERE \"people\".\"name\" = 'David'"
|
|
972
991
|
def touch_all(*names, time: nil)
|
|
973
|
-
update_all
|
|
992
|
+
update_all model.touch_attributes_with_time(*names, time: time)
|
|
974
993
|
end
|
|
975
994
|
|
|
976
995
|
# Destroys the records by instantiating each
|
|
@@ -1003,7 +1022,7 @@ module ActiveRecord
|
|
|
1003
1022
|
#
|
|
1004
1023
|
# Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
|
|
1005
1024
|
#
|
|
1006
|
-
#
|
|
1025
|
+
# This call deletes the affected posts all at once with a single DELETE statement.
|
|
1007
1026
|
# If you need to destroy dependent associations or call your <tt>before_*</tt> or
|
|
1008
1027
|
# +after_destroy+ callbacks, use the #destroy_all method instead.
|
|
1009
1028
|
#
|
|
@@ -1014,7 +1033,7 @@ module ActiveRecord
|
|
|
1014
1033
|
def delete_all
|
|
1015
1034
|
return 0 if @none
|
|
1016
1035
|
|
|
1017
|
-
invalid_methods =
|
|
1036
|
+
invalid_methods = INVALID_METHODS_FOR_UPDATE_AND_DELETE_ALL.select do |method|
|
|
1018
1037
|
value = @values[method]
|
|
1019
1038
|
method == :distinct ? value : value&.any?
|
|
1020
1039
|
end
|
|
@@ -1022,20 +1041,18 @@ module ActiveRecord
|
|
|
1022
1041
|
raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
|
|
1023
1042
|
end
|
|
1024
1043
|
|
|
1025
|
-
|
|
1026
|
-
arel = eager_loading? ? apply_join_dependency.arel :
|
|
1044
|
+
model.with_connection do |c|
|
|
1045
|
+
arel = eager_loading? ? apply_join_dependency.arel : arel()
|
|
1027
1046
|
arel.source.left = table
|
|
1028
1047
|
|
|
1029
|
-
|
|
1030
|
-
having_clause_ast = having_clause.ast unless having_clause.empty?
|
|
1031
|
-
key = if klass.composite_primary_key?
|
|
1048
|
+
key = if model.composite_primary_key?
|
|
1032
1049
|
primary_key.map { |pk| table[pk] }
|
|
1033
1050
|
else
|
|
1034
1051
|
table[primary_key]
|
|
1035
1052
|
end
|
|
1036
|
-
stmt = arel.compile_delete(key
|
|
1053
|
+
stmt = arel.compile_delete(key)
|
|
1037
1054
|
|
|
1038
|
-
c.delete(stmt, "#{
|
|
1055
|
+
c.delete(stmt, "#{model} Delete All").tap { reset }
|
|
1039
1056
|
end
|
|
1040
1057
|
end
|
|
1041
1058
|
|
|
@@ -1134,9 +1151,6 @@ module ActiveRecord
|
|
|
1134
1151
|
# for queries to actually be executed concurrently. Otherwise it defaults to
|
|
1135
1152
|
# executing them in the foreground.
|
|
1136
1153
|
#
|
|
1137
|
-
# +load_async+ will also fall back to executing in the foreground in the test environment when transactional
|
|
1138
|
-
# fixtures are enabled.
|
|
1139
|
-
#
|
|
1140
1154
|
# If the query was actually executed in the background, the Active Record logs will show
|
|
1141
1155
|
# it by prefixing the log line with <tt>ASYNC</tt>:
|
|
1142
1156
|
#
|
|
@@ -1146,7 +1160,7 @@ module ActiveRecord
|
|
|
1146
1160
|
return load if !c.async_enabled?
|
|
1147
1161
|
|
|
1148
1162
|
unless loaded?
|
|
1149
|
-
result = exec_main_query(async: c.current_transaction.
|
|
1163
|
+
result = exec_main_query(async: !c.current_transaction.joinable?)
|
|
1150
1164
|
|
|
1151
1165
|
if result.is_a?(Array)
|
|
1152
1166
|
@records = result
|
|
@@ -1160,6 +1174,16 @@ module ActiveRecord
|
|
|
1160
1174
|
self
|
|
1161
1175
|
end
|
|
1162
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
|
+
|
|
1163
1187
|
# Returns <tt>true</tt> if the relation was scheduled on the background
|
|
1164
1188
|
# thread pool.
|
|
1165
1189
|
def scheduled?
|
|
@@ -1190,7 +1214,7 @@ module ActiveRecord
|
|
|
1190
1214
|
def reset
|
|
1191
1215
|
@future_result&.cancel
|
|
1192
1216
|
@future_result = nil
|
|
1193
|
-
@
|
|
1217
|
+
@delegate_to_model = false
|
|
1194
1218
|
@to_sql = @arel = @loaded = @should_eager_load = nil
|
|
1195
1219
|
@offsets = @take = nil
|
|
1196
1220
|
@cache_keys = nil
|
|
@@ -1210,7 +1234,7 @@ module ActiveRecord
|
|
|
1210
1234
|
relation.to_sql
|
|
1211
1235
|
end
|
|
1212
1236
|
else
|
|
1213
|
-
|
|
1237
|
+
model.with_connection do |conn|
|
|
1214
1238
|
conn.unprepared_statement { conn.to_sql(arel) }
|
|
1215
1239
|
end
|
|
1216
1240
|
end
|
|
@@ -1220,12 +1244,12 @@ module ActiveRecord
|
|
|
1220
1244
|
#
|
|
1221
1245
|
# User.where(name: 'Oscar').where_values_hash
|
|
1222
1246
|
# # => {name: "Oscar"}
|
|
1223
|
-
def where_values_hash(relation_table_name =
|
|
1247
|
+
def where_values_hash(relation_table_name = model.table_name) # :nodoc:
|
|
1224
1248
|
where_clause.to_h(relation_table_name)
|
|
1225
1249
|
end
|
|
1226
1250
|
|
|
1227
1251
|
def scope_for_create
|
|
1228
|
-
hash = where_clause.to_h(
|
|
1252
|
+
hash = where_clause.to_h(model.table_name, equality_only: true)
|
|
1229
1253
|
create_with_value.each { |k, v| hash[k.to_s] = v } unless create_with_value.empty?
|
|
1230
1254
|
hash
|
|
1231
1255
|
end
|
|
@@ -1271,6 +1295,10 @@ module ActiveRecord
|
|
|
1271
1295
|
records.blank?
|
|
1272
1296
|
end
|
|
1273
1297
|
|
|
1298
|
+
def readonly?
|
|
1299
|
+
readonly_value
|
|
1300
|
+
end
|
|
1301
|
+
|
|
1274
1302
|
def values
|
|
1275
1303
|
@values.dup
|
|
1276
1304
|
end
|
|
@@ -1289,7 +1317,7 @@ module ActiveRecord
|
|
|
1289
1317
|
end
|
|
1290
1318
|
|
|
1291
1319
|
def empty_scope? # :nodoc:
|
|
1292
|
-
@values ==
|
|
1320
|
+
@values == model.unscoped.values
|
|
1293
1321
|
end
|
|
1294
1322
|
|
|
1295
1323
|
def has_limit_or_offset? # :nodoc:
|
|
@@ -1297,7 +1325,7 @@ module ActiveRecord
|
|
|
1297
1325
|
end
|
|
1298
1326
|
|
|
1299
1327
|
def alias_tracker(joins = [], aliases = nil) # :nodoc:
|
|
1300
|
-
ActiveRecord::Associations::AliasTracker.create(connection_pool, table.name, joins, aliases)
|
|
1328
|
+
ActiveRecord::Associations::AliasTracker.create(model.connection_pool, table.name, joins, aliases)
|
|
1301
1329
|
end
|
|
1302
1330
|
|
|
1303
1331
|
class StrictLoadingScope # :nodoc:
|
|
@@ -1327,46 +1355,46 @@ module ActiveRecord
|
|
|
1327
1355
|
|
|
1328
1356
|
private
|
|
1329
1357
|
def already_in_scope?(registry)
|
|
1330
|
-
@
|
|
1358
|
+
@delegate_to_model && registry.current_scope(model, true)
|
|
1331
1359
|
end
|
|
1332
1360
|
|
|
1333
1361
|
def global_scope?(registry)
|
|
1334
|
-
registry.global_current_scope(
|
|
1362
|
+
registry.global_current_scope(model, true)
|
|
1335
1363
|
end
|
|
1336
1364
|
|
|
1337
1365
|
def current_scope_restoring_block(&block)
|
|
1338
|
-
current_scope =
|
|
1366
|
+
current_scope = model.current_scope(true)
|
|
1339
1367
|
-> record do
|
|
1340
|
-
|
|
1368
|
+
model.current_scope = current_scope
|
|
1341
1369
|
yield record if block_given?
|
|
1342
1370
|
end
|
|
1343
1371
|
end
|
|
1344
1372
|
|
|
1345
1373
|
def _new(attributes, &block)
|
|
1346
|
-
|
|
1374
|
+
model.new(attributes, &block)
|
|
1347
1375
|
end
|
|
1348
1376
|
|
|
1349
1377
|
def _create(attributes, &block)
|
|
1350
|
-
|
|
1378
|
+
model.create(attributes, &block)
|
|
1351
1379
|
end
|
|
1352
1380
|
|
|
1353
1381
|
def _create!(attributes, &block)
|
|
1354
|
-
|
|
1382
|
+
model.create!(attributes, &block)
|
|
1355
1383
|
end
|
|
1356
1384
|
|
|
1357
1385
|
def _scoping(scope, registry, all_queries = false)
|
|
1358
|
-
previous = registry.current_scope(
|
|
1359
|
-
registry.set_current_scope(
|
|
1386
|
+
previous = registry.current_scope(model, true)
|
|
1387
|
+
registry.set_current_scope(model, scope)
|
|
1360
1388
|
|
|
1361
1389
|
if all_queries
|
|
1362
|
-
previous_global = registry.global_current_scope(
|
|
1363
|
-
registry.set_global_current_scope(
|
|
1390
|
+
previous_global = registry.global_current_scope(model, true)
|
|
1391
|
+
registry.set_global_current_scope(model, scope)
|
|
1364
1392
|
end
|
|
1365
1393
|
yield
|
|
1366
1394
|
ensure
|
|
1367
|
-
registry.set_current_scope(
|
|
1395
|
+
registry.set_current_scope(model, previous)
|
|
1368
1396
|
if all_queries
|
|
1369
|
-
registry.set_global_current_scope(
|
|
1397
|
+
registry.set_global_current_scope(model, previous_global)
|
|
1370
1398
|
end
|
|
1371
1399
|
end
|
|
1372
1400
|
|
|
@@ -1378,7 +1406,7 @@ module ActiveRecord
|
|
|
1378
1406
|
value = Arel::Nodes::Grouping.new(value)
|
|
1379
1407
|
end
|
|
1380
1408
|
else
|
|
1381
|
-
type =
|
|
1409
|
+
type = model.type_for_attribute(attr.name)
|
|
1382
1410
|
value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
|
|
1383
1411
|
end
|
|
1384
1412
|
[attr, value]
|
|
@@ -1387,12 +1415,16 @@ module ActiveRecord
|
|
|
1387
1415
|
|
|
1388
1416
|
def _increment_attribute(attribute, value = 1)
|
|
1389
1417
|
bind = predicate_builder.build_bind_attribute(attribute.name, value.abs)
|
|
1390
|
-
expr = table.coalesce(
|
|
1418
|
+
expr = table.coalesce(attribute, 0)
|
|
1391
1419
|
expr = value < 0 ? expr - bind : expr + bind
|
|
1392
1420
|
expr.expr
|
|
1393
1421
|
end
|
|
1394
1422
|
|
|
1395
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
|
+
|
|
1396
1428
|
skip_query_cache_if_necessary do
|
|
1397
1429
|
rows = if scheduled?
|
|
1398
1430
|
future = @future_result
|
|
@@ -1425,20 +1457,20 @@ module ActiveRecord
|
|
|
1425
1457
|
if where_clause.contradiction?
|
|
1426
1458
|
[].freeze
|
|
1427
1459
|
elsif eager_loading?
|
|
1428
|
-
|
|
1460
|
+
model.with_connection do |c|
|
|
1429
1461
|
apply_join_dependency do |relation, join_dependency|
|
|
1430
1462
|
if relation.null_relation?
|
|
1431
1463
|
[].freeze
|
|
1432
1464
|
else
|
|
1433
1465
|
relation = join_dependency.apply_column_aliases(relation)
|
|
1434
1466
|
@_join_dependency = join_dependency
|
|
1435
|
-
c.select_all(relation.arel, "
|
|
1467
|
+
c.select_all(relation.arel, "#{model.name} Eager Load", async: async)
|
|
1436
1468
|
end
|
|
1437
1469
|
end
|
|
1438
1470
|
end
|
|
1439
1471
|
else
|
|
1440
|
-
|
|
1441
|
-
|
|
1472
|
+
model.with_connection do |c|
|
|
1473
|
+
model._query_by_sql(c, arel, async: async)
|
|
1442
1474
|
end
|
|
1443
1475
|
end
|
|
1444
1476
|
end
|
|
@@ -1451,13 +1483,13 @@ module ActiveRecord
|
|
|
1451
1483
|
@_join_dependency = nil
|
|
1452
1484
|
records
|
|
1453
1485
|
else
|
|
1454
|
-
|
|
1486
|
+
model._load_from_sql(rows, &block).freeze
|
|
1455
1487
|
end
|
|
1456
1488
|
end
|
|
1457
1489
|
|
|
1458
1490
|
def skip_query_cache_if_necessary(&block)
|
|
1459
1491
|
if skip_query_cache_value
|
|
1460
|
-
uncached(&block)
|
|
1492
|
+
model.uncached(&block)
|
|
1461
1493
|
else
|
|
1462
1494
|
yield
|
|
1463
1495
|
end
|