activerecord 7.2.3.1 → 8.0.5.1
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 +475 -946
- data/README.rdoc +1 -1
- data/lib/active_record/association_relation.rb +1 -0
- data/lib/active_record/associations/association.rb +34 -10
- data/lib/active_record/associations/builder/association.rb +7 -6
- data/lib/active_record/associations/collection_association.rb +1 -1
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +2 -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/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_methods/primary_key.rb +4 -8
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -12
- data/lib/active_record/autosave_association.rb +69 -27
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +34 -25
- 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 +8 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +91 -44
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -2
- 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 +37 -10
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +67 -74
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +21 -40
- 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 +50 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +84 -94
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -8
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +72 -43
- data/lib/active_record/connection_adapters/postgresql/oid/array.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 +1 -11
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +6 -12
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +59 -16
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +53 -96
- data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +80 -100
- 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 +9 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +53 -12
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- 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 +23 -1
- data/lib/active_record/core.rb +29 -14
- data/lib/active_record/database_configurations/database_config.rb +4 -0
- data/lib/active_record/database_configurations/hash_config.rb +16 -2
- 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 +16 -8
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +8 -1
- data/lib/active_record/enum.rb +9 -22
- data/lib/active_record/errors.rb +13 -5
- data/lib/active_record/fixtures.rb +0 -2
- data/lib/active_record/future_result.rb +15 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/insert_all.rb +3 -3
- data/lib/active_record/locking/optimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +5 -11
- data/lib/active_record/migration/command_recorder.rb +32 -12
- data/lib/active_record/migration/compatibility.rb +5 -2
- data/lib/active_record/migration.rb +38 -42
- data/lib/active_record/model_schema.rb +3 -4
- data/lib/active_record/nested_attributes.rb +4 -6
- data/lib/active_record/persistence.rb +128 -130
- 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 +2 -26
- data/lib/active_record/railties/databases.rake +11 -35
- data/lib/active_record/reflection.rb +18 -21
- 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 +40 -39
- 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/array_handler.rb +3 -1
- 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 +13 -0
- data/lib/active_record/relation/query_methods.rb +105 -61
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +1 -1
- data/lib/active_record/relation.rb +80 -62
- 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 +14 -14
- 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 +69 -60
- data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
- data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +12 -0
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transactions.rb +5 -6
- data/lib/active_record/type/serialized.rb +5 -0
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +21 -48
- 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/nodes/binary.rb +1 -1
- data/lib/arel/nodes/node.rb +1 -1
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/predications.rb +1 -3
- data/lib/arel/table.rb +3 -7
- metadata +10 -11
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
|
@@ -233,7 +233,7 @@ module ActiveRecord
|
|
|
233
233
|
if operation == "count"
|
|
234
234
|
unless distinct_value || distinct_select?(column_name || select_for_count)
|
|
235
235
|
relation.distinct!
|
|
236
|
-
relation.select_values = Array(
|
|
236
|
+
relation.select_values = Array(model.primary_key || table[Arel.star])
|
|
237
237
|
end
|
|
238
238
|
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
|
239
239
|
relation.order_values = [] if group_values.empty?
|
|
@@ -274,10 +274,14 @@ module ActiveRecord
|
|
|
274
274
|
# # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
|
|
275
275
|
# # => [2, 3]
|
|
276
276
|
#
|
|
277
|
-
# Comment.joins(:person).pluck(:id, person:
|
|
278
|
-
# # SELECT comments.id,
|
|
277
|
+
# Comment.joins(:person).pluck(:id, person: :id)
|
|
278
|
+
# # SELECT comments.id, person.id FROM comments INNER JOIN people person ON person.id = comments.person_id
|
|
279
279
|
# # => [[1, 2], [2, 2]]
|
|
280
280
|
#
|
|
281
|
+
# Comment.joins(:person).pluck(:id, person: [:id, :name])
|
|
282
|
+
# # SELECT comments.id, person.id, person.name FROM comments INNER JOIN people person ON person.id = comments.person_id
|
|
283
|
+
# # => [[1, 2, 'David'], [2, 2, 'David']]
|
|
284
|
+
#
|
|
281
285
|
# Person.pluck(Arel.sql('DATEDIFF(updated_at, created_at)'))
|
|
282
286
|
# # SELECT DATEDIFF(updated_at, created_at) FROM people
|
|
283
287
|
# # => ['0', '27761', '173']
|
|
@@ -305,7 +309,7 @@ module ActiveRecord
|
|
|
305
309
|
relation = apply_join_dependency
|
|
306
310
|
relation.pluck(*column_names)
|
|
307
311
|
else
|
|
308
|
-
|
|
312
|
+
model.disallow_raw_sql!(flattened_args(column_names))
|
|
309
313
|
relation = spawn
|
|
310
314
|
columns = relation.arel_columns(column_names)
|
|
311
315
|
relation.select_values = columns
|
|
@@ -313,8 +317,8 @@ module ActiveRecord
|
|
|
313
317
|
if where_clause.contradiction?
|
|
314
318
|
ActiveRecord::Result.empty(async: @async)
|
|
315
319
|
else
|
|
316
|
-
|
|
317
|
-
c.select_all(relation.arel, "#{
|
|
320
|
+
model.with_connection do |c|
|
|
321
|
+
c.select_all(relation.arel, "#{model.name} Pluck", async: @async)
|
|
318
322
|
end
|
|
319
323
|
end
|
|
320
324
|
end
|
|
@@ -390,8 +394,8 @@ module ActiveRecord
|
|
|
390
394
|
ActiveRecord::Result.empty
|
|
391
395
|
else
|
|
392
396
|
skip_query_cache_if_necessary do
|
|
393
|
-
|
|
394
|
-
c.select_all(relation, "#{
|
|
397
|
+
model.with_connection do |c|
|
|
398
|
+
c.select_all(relation, "#{model.name} Ids", async: @async)
|
|
395
399
|
end
|
|
396
400
|
end
|
|
397
401
|
end
|
|
@@ -407,16 +411,19 @@ module ActiveRecord
|
|
|
407
411
|
|
|
408
412
|
protected
|
|
409
413
|
def aggregate_column(column_name)
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
+
case column_name
|
|
415
|
+
when Arel::Expressions
|
|
416
|
+
column_name
|
|
417
|
+
when :all
|
|
418
|
+
Arel.star
|
|
419
|
+
else
|
|
420
|
+
arel_column(column_name)
|
|
414
421
|
end
|
|
415
422
|
end
|
|
416
423
|
|
|
417
424
|
private
|
|
418
425
|
def all_attributes?(column_names)
|
|
419
|
-
(column_names.map(&:to_s) -
|
|
426
|
+
(column_names.map(&:to_s) - model.attribute_names - model.attribute_aliases.keys).empty?
|
|
420
427
|
end
|
|
421
428
|
|
|
422
429
|
def has_include?(column_name)
|
|
@@ -486,8 +493,8 @@ module ActiveRecord
|
|
|
486
493
|
end
|
|
487
494
|
else
|
|
488
495
|
skip_query_cache_if_necessary do
|
|
489
|
-
|
|
490
|
-
c.select_all(query_builder, "#{
|
|
496
|
+
model.with_connection do |c|
|
|
497
|
+
c.select_all(query_builder, "#{model.name} #{operation.capitalize}", async: @async)
|
|
491
498
|
end
|
|
492
499
|
end
|
|
493
500
|
end
|
|
@@ -508,7 +515,7 @@ module ActiveRecord
|
|
|
508
515
|
group_fields = group_fields.uniq if group_fields.size > 1
|
|
509
516
|
|
|
510
517
|
if group_fields.size == 1 && group_fields.first.respond_to?(:to_sym)
|
|
511
|
-
association =
|
|
518
|
+
association = model._reflect_on_association(group_fields.first)
|
|
512
519
|
associated = association && association.belongs_to? # only count belongs_to associations
|
|
513
520
|
group_fields = Array(association.foreign_key) if associated
|
|
514
521
|
end
|
|
@@ -516,7 +523,7 @@ module ActiveRecord
|
|
|
516
523
|
relation = except(:group).distinct!(false)
|
|
517
524
|
group_fields = relation.arel_columns(group_fields)
|
|
518
525
|
|
|
519
|
-
|
|
526
|
+
model.with_connection do |connection|
|
|
520
527
|
column_alias_tracker = ColumnAliasTracker.new(connection)
|
|
521
528
|
|
|
522
529
|
group_aliases = group_fields.map { |field|
|
|
@@ -528,13 +535,13 @@ module ActiveRecord
|
|
|
528
535
|
column = relation.aggregate_column(column_name)
|
|
529
536
|
column_alias = column_alias_tracker.alias_for("#{operation} #{column_name.to_s.downcase}")
|
|
530
537
|
select_value = operation_over_aggregate_column(column, operation, distinct)
|
|
531
|
-
select_value.as(adapter_class.quote_column_name(column_alias))
|
|
538
|
+
select_value.as(model.adapter_class.quote_column_name(column_alias))
|
|
532
539
|
|
|
533
540
|
select_values = [select_value]
|
|
534
541
|
select_values += self.select_values unless having_clause.empty?
|
|
535
542
|
|
|
536
543
|
select_values.concat group_columns.map { |aliaz, field|
|
|
537
|
-
aliaz = adapter_class.quote_column_name(aliaz)
|
|
544
|
+
aliaz = model.adapter_class.quote_column_name(aliaz)
|
|
538
545
|
if field.respond_to?(:as)
|
|
539
546
|
field.as(aliaz)
|
|
540
547
|
else
|
|
@@ -546,7 +553,7 @@ module ActiveRecord
|
|
|
546
553
|
relation.select_values = select_values
|
|
547
554
|
|
|
548
555
|
result = skip_query_cache_if_necessary do
|
|
549
|
-
connection.select_all(relation.arel, "#{
|
|
556
|
+
connection.select_all(relation.arel, "#{model.name} #{operation.capitalize}", async: @async)
|
|
550
557
|
end
|
|
551
558
|
|
|
552
559
|
result.then do |calculated_data|
|
|
@@ -588,7 +595,7 @@ module ActiveRecord
|
|
|
588
595
|
|
|
589
596
|
def type_for(field, &block)
|
|
590
597
|
field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split(".").last
|
|
591
|
-
|
|
598
|
+
model.type_for_attribute(field_name, &block)
|
|
592
599
|
end
|
|
593
600
|
|
|
594
601
|
def lookup_cast_type_from_join_dependencies(name, join_dependencies = build_join_dependencies)
|
|
@@ -601,12 +608,12 @@ module ActiveRecord
|
|
|
601
608
|
|
|
602
609
|
def type_cast_pluck_values(result, columns)
|
|
603
610
|
cast_types = if result.columns.size != columns.size
|
|
604
|
-
|
|
611
|
+
model.attribute_types
|
|
605
612
|
else
|
|
606
613
|
join_dependencies = nil
|
|
607
614
|
columns.map.with_index do |column, i|
|
|
608
615
|
column.try(:type_caster) ||
|
|
609
|
-
|
|
616
|
+
model.attribute_types.fetch(name = result.columns[i]) do
|
|
610
617
|
join_dependencies ||= build_join_dependencies
|
|
611
618
|
lookup_cast_type_from_join_dependencies(name, join_dependencies) ||
|
|
612
619
|
result.column_types[i] || Type.default_value
|
|
@@ -635,22 +642,12 @@ module ActiveRecord
|
|
|
635
642
|
end
|
|
636
643
|
|
|
637
644
|
def select_for_count
|
|
638
|
-
if select_values.
|
|
639
|
-
return select_values.first if select_values.one?
|
|
640
|
-
|
|
641
|
-
select_values.map do |field|
|
|
642
|
-
column = arel_column(field.to_s) do |attr_name|
|
|
643
|
-
Arel.sql(attr_name)
|
|
644
|
-
end
|
|
645
|
-
|
|
646
|
-
if column.is_a?(Arel::Nodes::SqlLiteral)
|
|
647
|
-
column
|
|
648
|
-
else
|
|
649
|
-
"#{adapter_class.quote_table_name(column.relation.name)}.#{adapter_class.quote_column_name(column.name)}"
|
|
650
|
-
end
|
|
651
|
-
end.join(", ")
|
|
652
|
-
else
|
|
645
|
+
if select_values.empty?
|
|
653
646
|
:all
|
|
647
|
+
else
|
|
648
|
+
with_connection do |conn|
|
|
649
|
+
arel_columns(select_values).map { |column| conn.visitor.compile(column) }.join(", ")
|
|
650
|
+
end
|
|
654
651
|
end
|
|
655
652
|
end
|
|
656
653
|
|
|
@@ -673,7 +670,11 @@ module ActiveRecord
|
|
|
673
670
|
subquery_alias = Arel.sql("subquery_for_count", retryable: true)
|
|
674
671
|
select_value = operation_over_aggregate_column(column_alias, "count", false)
|
|
675
672
|
|
|
676
|
-
|
|
673
|
+
if column_name == :all
|
|
674
|
+
relation.unscope(:order).build_subquery(subquery_alias, select_value)
|
|
675
|
+
else
|
|
676
|
+
relation.build_subquery(subquery_alias, select_value)
|
|
677
|
+
end
|
|
677
678
|
end
|
|
678
679
|
end
|
|
679
680
|
end
|
|
@@ -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(self)
|
|
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}"
|
|
@@ -472,7 +472,7 @@ module ActiveRecord
|
|
|
472
472
|
)
|
|
473
473
|
)
|
|
474
474
|
relation = skip_query_cache_if_necessary do
|
|
475
|
-
|
|
475
|
+
model.with_connection do |c|
|
|
476
476
|
c.distinct_relation_for_primary_key(relation)
|
|
477
477
|
end
|
|
478
478
|
end
|
|
@@ -490,9 +490,9 @@ module ActiveRecord
|
|
|
490
490
|
end
|
|
491
491
|
|
|
492
492
|
def find_with_ids(*ids)
|
|
493
|
-
raise UnknownPrimaryKey.new(
|
|
493
|
+
raise UnknownPrimaryKey.new(model) if primary_key.nil?
|
|
494
494
|
|
|
495
|
-
expects_array = if
|
|
495
|
+
expects_array = if model.composite_primary_key?
|
|
496
496
|
ids.first.first.is_a?(Array)
|
|
497
497
|
else
|
|
498
498
|
ids.first.is_a?(Array)
|
|
@@ -504,7 +504,7 @@ module ActiveRecord
|
|
|
504
504
|
|
|
505
505
|
ids = ids.compact.uniq
|
|
506
506
|
|
|
507
|
-
model_name =
|
|
507
|
+
model_name = model.name
|
|
508
508
|
|
|
509
509
|
case ids.size
|
|
510
510
|
when 0
|
|
@@ -526,7 +526,7 @@ module ActiveRecord
|
|
|
526
526
|
MSG
|
|
527
527
|
end
|
|
528
528
|
|
|
529
|
-
relation = if
|
|
529
|
+
relation = if model.composite_primary_key?
|
|
530
530
|
where(primary_key.zip(id).to_h)
|
|
531
531
|
else
|
|
532
532
|
where(primary_key => id)
|
|
@@ -574,7 +574,7 @@ module ActiveRecord
|
|
|
574
574
|
result = relation.records
|
|
575
575
|
|
|
576
576
|
if result.size == ids.size
|
|
577
|
-
result.in_order_of(:id, ids.map { |id|
|
|
577
|
+
result.in_order_of(:id, ids.map { |id| model.type_for_attribute(primary_key).cast(id) })
|
|
578
578
|
else
|
|
579
579
|
raise_record_not_found_exception!(ids, result.size, ids.size)
|
|
580
580
|
end
|
|
@@ -639,7 +639,7 @@ module ActiveRecord
|
|
|
639
639
|
end
|
|
640
640
|
|
|
641
641
|
def ordered_relation
|
|
642
|
-
if order_values.empty? && (implicit_order_column || !query_constraints_list.nil? || primary_key)
|
|
642
|
+
if order_values.empty? && (model.implicit_order_column || !model.query_constraints_list.nil? || primary_key)
|
|
643
643
|
order(_order_columns.map { |column| table[column].asc })
|
|
644
644
|
else
|
|
645
645
|
self
|
|
@@ -649,11 +649,11 @@ module ActiveRecord
|
|
|
649
649
|
def _order_columns
|
|
650
650
|
oc = []
|
|
651
651
|
|
|
652
|
-
oc << implicit_order_column if implicit_order_column
|
|
653
|
-
oc << query_constraints_list if query_constraints_list
|
|
652
|
+
oc << model.implicit_order_column if model.implicit_order_column
|
|
653
|
+
oc << model.query_constraints_list if model.query_constraints_list
|
|
654
654
|
|
|
655
|
-
if primary_key && query_constraints_list.nil?
|
|
656
|
-
oc << primary_key
|
|
655
|
+
if model.primary_key && model.query_constraints_list.nil?
|
|
656
|
+
oc << model.primary_key
|
|
657
657
|
end
|
|
658
658
|
|
|
659
659
|
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
|
|
@@ -31,7 +31,9 @@ module ActiveRecord
|
|
|
31
31
|
values_predicate
|
|
32
32
|
else
|
|
33
33
|
array_predicates = ranges.map! { |range| predicate_builder.build(attribute, range) }
|
|
34
|
-
|
|
34
|
+
values_predicate.or(
|
|
35
|
+
Arel::Nodes::Grouping.new Arel::Nodes::Or.new(array_predicates)
|
|
36
|
+
)
|
|
35
37
|
end
|
|
36
38
|
end
|
|
37
39
|
|
|
@@ -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)
|