activerecord 7.2.1.1 → 8.0.0.rc1
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 +220 -756
- data/README.rdoc +1 -1
- data/lib/active_record/associations/association.rb +25 -5
- data/lib/active_record/associations/builder/association.rb +7 -6
- data/lib/active_record/associations/collection_association.rb +10 -8
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +4 -4
- data/lib/active_record/associations/preloader/association.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +34 -4
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_assignment.rb +9 -1
- data/lib/active_record/attribute_methods/primary_key.rb +2 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -12
- data/lib/active_record/attributes.rb +1 -2
- data/lib/active_record/autosave_association.rb +69 -27
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +16 -10
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +26 -9
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +12 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +34 -7
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +24 -26
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +28 -42
- data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +42 -98
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -8
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -42
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -11
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +54 -14
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +45 -97
- data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +76 -100
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +8 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +53 -12
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +0 -17
- data/lib/active_record/connection_adapters.rb +0 -56
- data/lib/active_record/connection_handling.rb +22 -0
- data/lib/active_record/core.rb +28 -18
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +4 -4
- data/lib/active_record/encryption/encrypted_attribute_type.rb +10 -1
- data/lib/active_record/encryption/encryptor.rb +15 -8
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/scheme.rb +8 -1
- data/lib/active_record/encryption.rb +2 -0
- data/lib/active_record/enum.rb +54 -75
- data/lib/active_record/errors.rb +13 -5
- data/lib/active_record/fixtures.rb +0 -2
- data/lib/active_record/future_result.rb +14 -10
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/insert_all.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +5 -11
- data/lib/active_record/marshalling.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +22 -5
- data/lib/active_record/migration/compatibility.rb +5 -2
- data/lib/active_record/migration.rb +35 -38
- data/lib/active_record/model_schema.rb +4 -6
- data/lib/active_record/nested_attributes.rb +11 -2
- data/lib/active_record/persistence.rb +128 -130
- data/lib/active_record/query_cache.rb +0 -4
- data/lib/active_record/query_logs.rb +102 -50
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +8 -8
- data/lib/active_record/railtie.rb +9 -38
- data/lib/active_record/railties/databases.rake +1 -1
- data/lib/active_record/reflection.rb +23 -23
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +132 -72
- data/lib/active_record/relation/calculations.rb +41 -40
- data/lib/active_record/relation/delegation.rb +25 -14
- data/lib/active_record/relation/finder_methods.rb +18 -18
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +14 -1
- data/lib/active_record/relation/query_methods.rb +122 -71
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation.rb +79 -61
- data/lib/active_record/result.rb +66 -4
- data/lib/active_record/sanitization.rb +7 -6
- data/lib/active_record/schema_dumper.rb +5 -0
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/statement_cache.rb +12 -12
- data/lib/active_record/store.rb +7 -3
- data/lib/active_record/table_metadata.rb +1 -3
- data/lib/active_record/tasks/database_tasks.rb +40 -47
- data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
- data/lib/active_record/test_fixtures.rb +12 -0
- data/lib/active_record/testing/query_assertions.rb +2 -2
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +9 -8
- data/lib/active_record.rb +15 -45
- data/lib/arel/collectors/bind.rb +1 -1
- data/lib/arel/table.rb +3 -7
- data/lib/arel/visitors/sqlite.rb +25 -0
- metadata +10 -11
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
@@ -22,6 +22,9 @@ module ActiveRecord
|
|
22
22
|
end
|
23
23
|
|
24
24
|
module DelegateCache # :nodoc:
|
25
|
+
@delegate_base_methods = true
|
26
|
+
singleton_class.attr_accessor :delegate_base_methods
|
27
|
+
|
25
28
|
def relation_delegate_class(klass)
|
26
29
|
@relation_delegate_cache[klass]
|
27
30
|
end
|
@@ -75,12 +78,12 @@ module ActiveRecord
|
|
75
78
|
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method) && !::ActiveSupport::Delegation::RESERVED_METHOD_NAMES.include?(method.to_s)
|
76
79
|
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
77
80
|
def #{method}(...)
|
78
|
-
scoping {
|
81
|
+
scoping { model.#{method}(...) }
|
79
82
|
end
|
80
83
|
RUBY
|
81
84
|
else
|
82
85
|
define_method(method) do |*args, **kwargs, &block|
|
83
|
-
scoping {
|
86
|
+
scoping { model.public_send(method, *args, **kwargs, &block) }
|
84
87
|
end
|
85
88
|
end
|
86
89
|
end
|
@@ -92,15 +95,15 @@ module ActiveRecord
|
|
92
95
|
|
93
96
|
# This module creates compiled delegation methods dynamically at runtime, which makes
|
94
97
|
# subsequent calls to that method faster by avoiding method_missing. The delegations
|
95
|
-
# may vary depending on the
|
96
|
-
# for each different
|
98
|
+
# may vary depending on the model of a relation, so we create a subclass of Relation
|
99
|
+
# for each different model, and the delegations are compiled into that subclass only.
|
97
100
|
|
98
101
|
delegate :to_xml, :encode_with, :length, :each, :join, :intersect?,
|
99
102
|
:[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
|
100
103
|
:to_sentence, :to_fs, :to_formatted_s, :as_json,
|
101
104
|
:shuffle, :split, :slice, :index, :rindex, to: :records
|
102
105
|
|
103
|
-
delegate :primary_key, :
|
106
|
+
delegate :primary_key, :with_connection, :connection, :table_name, :transaction, :sanitize_sql_like, :unscoped, :name, to: :model
|
104
107
|
|
105
108
|
module ClassSpecificRelation # :nodoc:
|
106
109
|
extend ActiveSupport::Concern
|
@@ -113,11 +116,19 @@ module ActiveRecord
|
|
113
116
|
|
114
117
|
private
|
115
118
|
def method_missing(method, ...)
|
116
|
-
if
|
117
|
-
|
118
|
-
|
119
|
+
if model.respond_to?(method)
|
120
|
+
if !DelegateCache.delegate_base_methods && Base.respond_to?(method)
|
121
|
+
# A common mistake in Active Record's own code is to call `ActiveRecord::Base`
|
122
|
+
# class methods on Association. It works because it's automatically delegated, but
|
123
|
+
# can introduce subtle bugs because it sets the global scope.
|
124
|
+
# We can't deprecate this behavior because gems might depend on it, however we
|
125
|
+
# can ban it from Active Record's own test suite to avoid regressions.
|
126
|
+
raise NotImplementedError, "Active Record code shouldn't rely on association delegation into ActiveRecord::Base methods"
|
127
|
+
elsif !Delegation.uncacheable_methods.include?(method)
|
128
|
+
model.generate_relation_method(method)
|
119
129
|
end
|
120
|
-
|
130
|
+
|
131
|
+
scoping { model.public_send(method, ...) }
|
121
132
|
else
|
122
133
|
super
|
123
134
|
end
|
@@ -125,19 +136,19 @@ module ActiveRecord
|
|
125
136
|
end
|
126
137
|
|
127
138
|
module ClassMethods # :nodoc:
|
128
|
-
def create(
|
129
|
-
relation_class_for(
|
139
|
+
def create(model, ...)
|
140
|
+
relation_class_for(model).new(model, ...)
|
130
141
|
end
|
131
142
|
|
132
143
|
private
|
133
|
-
def relation_class_for(
|
134
|
-
|
144
|
+
def relation_class_for(model)
|
145
|
+
model.relation_delegate_class(self)
|
135
146
|
end
|
136
147
|
end
|
137
148
|
|
138
149
|
private
|
139
150
|
def respond_to_missing?(method, _)
|
140
|
-
super ||
|
151
|
+
super || model.respond_to?(method)
|
141
152
|
end
|
142
153
|
end
|
143
154
|
end
|
@@ -145,10 +145,10 @@ module ActiveRecord
|
|
145
145
|
|
146
146
|
if found.nil?
|
147
147
|
raise_record_not_found_exception!
|
148
|
-
elsif undesired.
|
149
|
-
raise ActiveRecord::SoleRecordExceeded.new(self)
|
150
|
-
else
|
148
|
+
elsif undesired.nil?
|
151
149
|
found
|
150
|
+
else
|
151
|
+
raise ActiveRecord::SoleRecordExceeded.new(model)
|
152
152
|
end
|
153
153
|
end
|
154
154
|
|
@@ -376,7 +376,7 @@ module ActiveRecord
|
|
376
376
|
|
377
377
|
skip_query_cache_if_necessary do
|
378
378
|
with_connection do |c|
|
379
|
-
c.select_rows(relation.arel, "#{name} Exists?").size == 1
|
379
|
+
c.select_rows(relation.arel, "#{model.name} Exists?").size == 1
|
380
380
|
end
|
381
381
|
end
|
382
382
|
end
|
@@ -389,7 +389,7 @@ module ActiveRecord
|
|
389
389
|
def include?(record)
|
390
390
|
# The existing implementation relies on receiving an Active Record instance as the input parameter named record.
|
391
391
|
# Any non-Active Record object passed to this implementation is guaranteed to return `false`.
|
392
|
-
return false unless record.is_a?(
|
392
|
+
return false unless record.is_a?(model)
|
393
393
|
|
394
394
|
if loaded? || offset_value || limit_value || having_clause.any?
|
395
395
|
records.include?(record)
|
@@ -415,9 +415,9 @@ module ActiveRecord
|
|
415
415
|
# the expected number of results should be provided in the +expected_size+
|
416
416
|
# argument.
|
417
417
|
def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key, not_found_ids = nil) # :nodoc:
|
418
|
-
conditions = " [#{arel.where_sql(
|
418
|
+
conditions = " [#{arel.where_sql(model)}]" unless where_clause.empty?
|
419
419
|
|
420
|
-
name =
|
420
|
+
name = model.name
|
421
421
|
|
422
422
|
if ids.nil?
|
423
423
|
error = +"Couldn't find #{name}"
|
@@ -471,7 +471,7 @@ module ActiveRecord
|
|
471
471
|
)
|
472
472
|
)
|
473
473
|
relation = skip_query_cache_if_necessary do
|
474
|
-
|
474
|
+
model.with_connection do |c|
|
475
475
|
c.distinct_relation_for_primary_key(relation)
|
476
476
|
end
|
477
477
|
end
|
@@ -489,9 +489,9 @@ module ActiveRecord
|
|
489
489
|
end
|
490
490
|
|
491
491
|
def find_with_ids(*ids)
|
492
|
-
raise UnknownPrimaryKey.new(
|
492
|
+
raise UnknownPrimaryKey.new(model) if primary_key.nil?
|
493
493
|
|
494
|
-
expects_array = if
|
494
|
+
expects_array = if model.composite_primary_key?
|
495
495
|
ids.first.first.is_a?(Array)
|
496
496
|
else
|
497
497
|
ids.first.is_a?(Array)
|
@@ -503,7 +503,7 @@ module ActiveRecord
|
|
503
503
|
|
504
504
|
ids = ids.compact.uniq
|
505
505
|
|
506
|
-
model_name =
|
506
|
+
model_name = model.name
|
507
507
|
|
508
508
|
case ids.size
|
509
509
|
when 0
|
@@ -525,7 +525,7 @@ module ActiveRecord
|
|
525
525
|
MSG
|
526
526
|
end
|
527
527
|
|
528
|
-
relation = if
|
528
|
+
relation = if model.composite_primary_key?
|
529
529
|
where(primary_key.zip(id).to_h)
|
530
530
|
else
|
531
531
|
where(primary_key => id)
|
@@ -573,7 +573,7 @@ module ActiveRecord
|
|
573
573
|
result = relation.records
|
574
574
|
|
575
575
|
if result.size == ids.size
|
576
|
-
result.in_order_of(:id, ids.map { |id|
|
576
|
+
result.in_order_of(:id, ids.map { |id| model.type_for_attribute(primary_key).cast(id) })
|
577
577
|
else
|
578
578
|
raise_record_not_found_exception!(ids, result.size, ids.size)
|
579
579
|
end
|
@@ -638,7 +638,7 @@ module ActiveRecord
|
|
638
638
|
end
|
639
639
|
|
640
640
|
def ordered_relation
|
641
|
-
if order_values.empty? && (implicit_order_column || !query_constraints_list.nil? || primary_key)
|
641
|
+
if order_values.empty? && (model.implicit_order_column || !model.query_constraints_list.nil? || primary_key)
|
642
642
|
order(_order_columns.map { |column| table[column].asc })
|
643
643
|
else
|
644
644
|
self
|
@@ -648,11 +648,11 @@ module ActiveRecord
|
|
648
648
|
def _order_columns
|
649
649
|
oc = []
|
650
650
|
|
651
|
-
oc << implicit_order_column if implicit_order_column
|
652
|
-
oc << query_constraints_list if query_constraints_list
|
651
|
+
oc << model.implicit_order_column if model.implicit_order_column
|
652
|
+
oc << model.query_constraints_list if model.query_constraints_list
|
653
653
|
|
654
|
-
if primary_key && query_constraints_list.nil?
|
655
|
-
oc << primary_key
|
654
|
+
if model.primary_key && model.query_constraints_list.nil?
|
655
|
+
oc << model.primary_key
|
656
656
|
end
|
657
657
|
|
658
658
|
oc.flatten.uniq.compact
|
@@ -24,7 +24,7 @@ module ActiveRecord
|
|
24
24
|
# the values.
|
25
25
|
def other
|
26
26
|
other = Relation.create(
|
27
|
-
relation.
|
27
|
+
relation.model,
|
28
28
|
table: relation.table,
|
29
29
|
predicate_builder: relation.predicate_builder
|
30
30
|
)
|
@@ -84,7 +84,7 @@ module ActiveRecord
|
|
84
84
|
def merge_select_values
|
85
85
|
return if other.select_values.empty?
|
86
86
|
|
87
|
-
if other.
|
87
|
+
if other.model == relation.model
|
88
88
|
relation.select_values |= other.select_values
|
89
89
|
else
|
90
90
|
relation.select_values |= other.instance_eval do
|
@@ -96,12 +96,12 @@ module ActiveRecord
|
|
96
96
|
def merge_preloads
|
97
97
|
return if other.preload_values.empty? && other.includes_values.empty?
|
98
98
|
|
99
|
-
if other.
|
99
|
+
if other.model == relation.model
|
100
100
|
relation.preload_values |= other.preload_values unless other.preload_values.empty?
|
101
101
|
relation.includes_values |= other.includes_values unless other.includes_values.empty?
|
102
102
|
else
|
103
|
-
reflection = relation.
|
104
|
-
r.class_name == other.
|
103
|
+
reflection = relation.model.reflect_on_all_associations.find do |r|
|
104
|
+
r.class_name == other.model.name
|
105
105
|
end || return
|
106
106
|
|
107
107
|
unless other.preload_values.empty?
|
@@ -117,7 +117,7 @@ module ActiveRecord
|
|
117
117
|
def merge_joins
|
118
118
|
return if other.joins_values.empty?
|
119
119
|
|
120
|
-
if other.
|
120
|
+
if other.model == relation.model
|
121
121
|
relation.joins_values |= other.joins_values
|
122
122
|
else
|
123
123
|
associations, others = other.joins_values.partition do |join|
|
@@ -136,7 +136,7 @@ module ActiveRecord
|
|
136
136
|
def merge_outer_joins
|
137
137
|
return if other.left_outer_joins_values.empty?
|
138
138
|
|
139
|
-
if other.
|
139
|
+
if other.model == relation.model
|
140
140
|
relation.left_outer_joins_values |= other.left_outer_joins_values
|
141
141
|
else
|
142
142
|
associations, others = other.left_outer_joins_values.partition do |join|
|
@@ -185,7 +185,7 @@ module ActiveRecord
|
|
185
185
|
|
186
186
|
def replace_from_clause?
|
187
187
|
relation.from_clause.empty? && !other.from_clause.empty? &&
|
188
|
-
relation.
|
188
|
+
relation.model.base_class == other.model.base_class
|
189
189
|
end
|
190
190
|
end
|
191
191
|
end
|
@@ -9,10 +9,11 @@ module ActiveRecord
|
|
9
9
|
end
|
10
10
|
|
11
11
|
if value.select_values.empty?
|
12
|
-
|
13
|
-
|
12
|
+
model = value.model
|
13
|
+
if model.composite_primary_key?
|
14
|
+
raise ArgumentError, "Cannot map composite primary key #{model.primary_key} to #{attribute.name}"
|
14
15
|
else
|
15
|
-
value = value.select(value.table[
|
16
|
+
value = value.select(value.table[model.primary_key])
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
@@ -72,11 +72,24 @@ module ActiveRecord
|
|
72
72
|
table.associated_table(table_name, &block).arel_table[column_name]
|
73
73
|
end
|
74
74
|
|
75
|
+
def with(table)
|
76
|
+
other = dup
|
77
|
+
other.table = table
|
78
|
+
other
|
79
|
+
end
|
80
|
+
|
75
81
|
protected
|
82
|
+
attr_writer :table
|
83
|
+
|
76
84
|
def expand_from_hash(attributes, &block)
|
77
85
|
return ["1=0"] if attributes.empty?
|
78
86
|
|
79
87
|
attributes.flat_map do |key, value|
|
88
|
+
if key.is_a?(Array) && key.size == 1
|
89
|
+
key = key.first
|
90
|
+
value = value.flatten
|
91
|
+
end
|
92
|
+
|
80
93
|
if key.is_a?(Array)
|
81
94
|
queries = Array(value).map do |ids_set|
|
82
95
|
raise ArgumentError, "Expected corresponding value for #{key} to be an Array" unless ids_set.is_a?(Array)
|
@@ -142,7 +155,7 @@ module ActiveRecord
|
|
142
155
|
queries.first
|
143
156
|
else
|
144
157
|
queries.map! { |query| query.reduce(&:and) }
|
145
|
-
queries =
|
158
|
+
queries = Arel::Nodes::Or.new(queries)
|
146
159
|
Arel::Nodes::Grouping.new(queries)
|
147
160
|
end
|
148
161
|
end
|