activerecord 5.2.0.beta2 → 5.2.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +231 -2
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_record.rb +1 -1
- data/lib/active_record/aggregations.rb +4 -5
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations.rb +18 -12
- data/lib/active_record/associations/alias_tracker.rb +2 -10
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/belongs_to_association.rb +9 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -6
- data/lib/active_record/associations/builder/association.rb +2 -2
- data/lib/active_record/associations/builder/belongs_to.rb +7 -3
- data/lib/active_record/associations/collection_association.rb +2 -2
- data/lib/active_record/associations/collection_proxy.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +4 -17
- data/lib/active_record/associations/has_one_through_association.rb +5 -6
- data/lib/active_record/associations/preloader.rb +1 -1
- data/lib/active_record/associations/preloader/association.rb +2 -2
- data/lib/active_record/associations/through_association.rb +22 -9
- data/lib/active_record/attribute_methods.rb +1 -5
- data/lib/active_record/attribute_methods/dirty.rb +2 -4
- data/lib/active_record/attributes.rb +1 -1
- data/lib/active_record/autosave_association.rb +3 -0
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/collection_cache_key.rb +5 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +57 -21
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +20 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +55 -15
- data/lib/active_record/connection_adapters/abstract_adapter.rb +19 -6
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +55 -64
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +8 -1
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +0 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +21 -6
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +9 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +13 -4
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +170 -48
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +15 -5
- data/lib/active_record/connection_adapters/schema_cache.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +63 -18
- data/lib/active_record/core.rb +12 -3
- data/lib/active_record/enum.rb +2 -0
- data/lib/active_record/fixtures.rb +28 -37
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +3 -4
- data/lib/active_record/log_subscriber.rb +41 -0
- data/lib/active_record/migration.rb +138 -120
- data/lib/active_record/migration/compatibility.rb +20 -0
- data/lib/active_record/model_schema.rb +19 -16
- data/lib/active_record/persistence.rb +8 -11
- data/lib/active_record/railtie.rb +7 -2
- data/lib/active_record/railties/databases.rake +8 -11
- data/lib/active_record/reflection.rb +10 -13
- data/lib/active_record/relation.rb +27 -17
- data/lib/active_record/relation/calculations.rb +17 -12
- data/lib/active_record/relation/finder_methods.rb +30 -37
- data/lib/active_record/relation/merger.rb +30 -2
- data/lib/active_record/relation/predicate_builder.rb +12 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -1
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +14 -24
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +16 -2
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/sanitization.rb +130 -128
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +12 -3
- data/lib/active_record/scoping/named.rb +6 -0
- data/lib/active_record/store.rb +1 -1
- data/lib/active_record/table_metadata.rb +10 -3
- data/lib/active_record/tasks/database_tasks.rb +4 -4
- data/lib/active_record/type_caster/map.rb +1 -1
- metadata +9 -9
@@ -99,7 +99,9 @@ module ActiveRecord
|
|
99
99
|
# for updating all records in a single query.
|
100
100
|
def update(id = :all, attributes)
|
101
101
|
if id.is_a?(Array)
|
102
|
-
id.map
|
102
|
+
id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
|
103
|
+
object.update(attributes[idx])
|
104
|
+
}
|
103
105
|
elsif id == :all
|
104
106
|
all.each { |record| record.update(attributes) }
|
105
107
|
else
|
@@ -112,7 +114,6 @@ module ActiveRecord
|
|
112
114
|
object.update(attributes)
|
113
115
|
object
|
114
116
|
end
|
115
|
-
rescue RecordNotFound
|
116
117
|
end
|
117
118
|
|
118
119
|
# Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
|
@@ -136,11 +137,10 @@ module ActiveRecord
|
|
136
137
|
# Todo.destroy(todos)
|
137
138
|
def destroy(id)
|
138
139
|
if id.is_a?(Array)
|
139
|
-
id.
|
140
|
+
find(id).each(&:destroy)
|
140
141
|
else
|
141
142
|
find(id).destroy
|
142
143
|
end
|
143
|
-
rescue RecordNotFound
|
144
144
|
end
|
145
145
|
|
146
146
|
# Deletes the row with a primary key matching the +id+ argument, using a
|
@@ -359,10 +359,10 @@ module ActiveRecord
|
|
359
359
|
# Any change to the attributes on either instance will affect both instances.
|
360
360
|
# If you want to change the sti column as well, use #becomes! instead.
|
361
361
|
def becomes(klass)
|
362
|
-
became = klass.
|
362
|
+
became = klass.allocate
|
363
|
+
became.send(:initialize)
|
363
364
|
became.instance_variable_set("@attributes", @attributes)
|
364
365
|
became.instance_variable_set("@mutations_from_database", @mutations_from_database) if defined?(@mutations_from_database)
|
365
|
-
became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
|
366
366
|
became.instance_variable_set("@new_record", new_record?)
|
367
367
|
became.instance_variable_set("@destroyed", destroyed?)
|
368
368
|
became.errors.copy!(errors)
|
@@ -402,11 +402,7 @@ module ActiveRecord
|
|
402
402
|
verify_readonly_attribute(name)
|
403
403
|
public_send("#{name}=", value)
|
404
404
|
|
405
|
-
|
406
|
-
save(validate: false)
|
407
|
-
else
|
408
|
-
true
|
409
|
-
end
|
405
|
+
save(validate: false)
|
410
406
|
end
|
411
407
|
|
412
408
|
# Updates the attributes of the model from the passed-in hash and saves the
|
@@ -698,6 +694,7 @@ module ActiveRecord
|
|
698
694
|
|
699
695
|
def create_or_update(*args, &block)
|
700
696
|
_raise_readonly_record_error if readonly?
|
697
|
+
return false if destroyed?
|
701
698
|
result = new_record? ? _create_record(&block) : _update_record(*args, &block)
|
702
699
|
result != false
|
703
700
|
end
|
@@ -59,6 +59,7 @@ module ActiveRecord
|
|
59
59
|
console = ActiveSupport::Logger.new(STDERR)
|
60
60
|
Rails.logger.extend ActiveSupport::Logger.broadcast console
|
61
61
|
end
|
62
|
+
ActiveRecord::Base.verbose_query_logs = false
|
62
63
|
end
|
63
64
|
|
64
65
|
runner do
|
@@ -90,12 +91,16 @@ module ActiveRecord
|
|
90
91
|
filename = File.join(app.config.paths["db"].first, "schema_cache.yml")
|
91
92
|
|
92
93
|
if File.file?(filename)
|
94
|
+
current_version = ActiveRecord::Migrator.current_version
|
95
|
+
|
96
|
+
next if current_version.nil?
|
97
|
+
|
93
98
|
cache = YAML.load(File.read(filename))
|
94
|
-
if cache.version ==
|
99
|
+
if cache.version == current_version
|
95
100
|
connection.schema_cache = cache
|
96
101
|
connection_pool.schema_cache = cache.dup
|
97
102
|
else
|
98
|
-
warn "Ignoring db/schema_cache.yml because it has expired. The current schema version is #{
|
103
|
+
warn "Ignoring db/schema_cache.yml because it has expired. The current schema version is #{current_version}, but the one in the cache is #{cache.version}."
|
99
104
|
end
|
100
105
|
end
|
101
106
|
end
|
@@ -6,7 +6,7 @@ db_namespace = namespace :db do
|
|
6
6
|
desc "Set the environment value for the database"
|
7
7
|
task "environment:set" => :load_config do
|
8
8
|
ActiveRecord::InternalMetadata.create_table
|
9
|
-
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::
|
9
|
+
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
|
10
10
|
end
|
11
11
|
|
12
12
|
task check_protected_environments: :load_config do
|
@@ -99,9 +99,8 @@ db_namespace = namespace :db do
|
|
99
99
|
|
100
100
|
ActiveRecord::Tasks::DatabaseTasks.check_target_version
|
101
101
|
|
102
|
-
ActiveRecord::
|
102
|
+
ActiveRecord::Base.connection.migration_context.run(
|
103
103
|
:up,
|
104
|
-
ActiveRecord::Tasks::DatabaseTasks.migrations_paths,
|
105
104
|
ActiveRecord::Tasks::DatabaseTasks.target_version
|
106
105
|
)
|
107
106
|
db_namespace["_dump"].invoke
|
@@ -113,9 +112,8 @@ db_namespace = namespace :db do
|
|
113
112
|
|
114
113
|
ActiveRecord::Tasks::DatabaseTasks.check_target_version
|
115
114
|
|
116
|
-
ActiveRecord::
|
115
|
+
ActiveRecord::Base.connection.migration_context.run(
|
117
116
|
:down,
|
118
|
-
ActiveRecord::Tasks::DatabaseTasks.migrations_paths,
|
119
117
|
ActiveRecord::Tasks::DatabaseTasks.target_version
|
120
118
|
)
|
121
119
|
db_namespace["_dump"].invoke
|
@@ -131,8 +129,7 @@ db_namespace = namespace :db do
|
|
131
129
|
puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
|
132
130
|
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
|
133
131
|
puts "-" * 50
|
134
|
-
|
135
|
-
ActiveRecord::Migrator.migrations_status(paths).each do |status, version, name|
|
132
|
+
ActiveRecord::Base.connection.migration_context.migrations_status.each do |status, version, name|
|
136
133
|
puts "#{status.center(8)} #{version.ljust(14)} #{name}"
|
137
134
|
end
|
138
135
|
puts
|
@@ -142,14 +139,14 @@ db_namespace = namespace :db do
|
|
142
139
|
desc "Rolls the schema back to the previous version (specify steps w/ STEP=n)."
|
143
140
|
task rollback: :load_config do
|
144
141
|
step = ENV["STEP"] ? ENV["STEP"].to_i : 1
|
145
|
-
ActiveRecord::
|
142
|
+
ActiveRecord::Base.connection.migration_context.rollback(step)
|
146
143
|
db_namespace["_dump"].invoke
|
147
144
|
end
|
148
145
|
|
149
146
|
# desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
|
150
147
|
task forward: :load_config do
|
151
148
|
step = ENV["STEP"] ? ENV["STEP"].to_i : 1
|
152
|
-
ActiveRecord::
|
149
|
+
ActiveRecord::Base.connection.migration_context.forward(step)
|
153
150
|
db_namespace["_dump"].invoke
|
154
151
|
end
|
155
152
|
|
@@ -172,12 +169,12 @@ db_namespace = namespace :db do
|
|
172
169
|
|
173
170
|
desc "Retrieves the current schema version number"
|
174
171
|
task version: :load_config do
|
175
|
-
puts "Current version: #{ActiveRecord::
|
172
|
+
puts "Current version: #{ActiveRecord::Base.connection.migration_context.current_version}"
|
176
173
|
end
|
177
174
|
|
178
175
|
# desc "Raises an error if there are pending migrations"
|
179
176
|
task abort_if_pending_migrations: :load_config do
|
180
|
-
pending_migrations = ActiveRecord::
|
177
|
+
pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
|
181
178
|
|
182
179
|
if pending_migrations.any?
|
183
180
|
puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
|
@@ -34,7 +34,8 @@ module ActiveRecord
|
|
34
34
|
|
35
35
|
def self.add_reflection(ar, name, reflection)
|
36
36
|
ar.clear_reflections_cache
|
37
|
-
|
37
|
+
name = name.to_s
|
38
|
+
ar._reflections = ar._reflections.except(name).merge!(name => reflection)
|
38
39
|
end
|
39
40
|
|
40
41
|
def self.add_aggregate_reflection(ar, name, reflection)
|
@@ -290,10 +291,14 @@ module ActiveRecord
|
|
290
291
|
end
|
291
292
|
|
292
293
|
def build_scope(table, predicate_builder = predicate_builder(table))
|
293
|
-
Relation.create(
|
294
|
+
Relation.create(
|
295
|
+
klass,
|
296
|
+
table: table,
|
297
|
+
predicate_builder: predicate_builder
|
298
|
+
)
|
294
299
|
end
|
295
300
|
|
296
|
-
def join_primary_key(
|
301
|
+
def join_primary_key(*)
|
297
302
|
foreign_key
|
298
303
|
end
|
299
304
|
|
@@ -458,10 +463,6 @@ module ActiveRecord
|
|
458
463
|
options[:primary_key] || primary_key(klass || self.klass)
|
459
464
|
end
|
460
465
|
|
461
|
-
def association_primary_key_type
|
462
|
-
klass.type_for_attribute(association_primary_key.to_s)
|
463
|
-
end
|
464
|
-
|
465
466
|
def active_record_primary_key
|
466
467
|
@active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
|
467
468
|
end
|
@@ -567,7 +568,7 @@ module ActiveRecord
|
|
567
568
|
end
|
568
569
|
|
569
570
|
VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
|
570
|
-
INVALID_AUTOMATIC_INVERSE_OPTIONS = [:
|
571
|
+
INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
|
571
572
|
|
572
573
|
def add_as_source(seed)
|
573
574
|
seed
|
@@ -722,7 +723,7 @@ module ActiveRecord
|
|
722
723
|
end
|
723
724
|
end
|
724
725
|
|
725
|
-
def join_primary_key(klass)
|
726
|
+
def join_primary_key(klass = nil)
|
726
727
|
polymorphic? ? association_primary_key(klass) : association_primary_key
|
727
728
|
end
|
728
729
|
|
@@ -859,10 +860,6 @@ module ActiveRecord
|
|
859
860
|
actual_source_reflection.options[:primary_key] || primary_key(klass || self.klass)
|
860
861
|
end
|
861
862
|
|
862
|
-
def association_primary_key_type
|
863
|
-
klass.type_for_attribute(association_primary_key.to_s)
|
864
|
-
end
|
865
|
-
|
866
863
|
# Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
|
867
864
|
#
|
868
865
|
# class Post < ActiveRecord::Base
|
@@ -10,7 +10,7 @@ module ActiveRecord
|
|
10
10
|
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
|
11
11
|
:reverse_order, :distinct, :create_with, :skip_query_cache]
|
12
12
|
CLAUSE_METHODS = [:where, :having, :from]
|
13
|
-
INVALID_METHODS_FOR_DELETE_ALL = [:
|
13
|
+
INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :group, :having]
|
14
14
|
|
15
15
|
VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
|
16
16
|
|
@@ -22,7 +22,7 @@ module ActiveRecord
|
|
22
22
|
alias :loaded? :loaded
|
23
23
|
alias :locked? :lock_value
|
24
24
|
|
25
|
-
def initialize(klass, table, predicate_builder, values
|
25
|
+
def initialize(klass, table: klass.arel_table, predicate_builder: klass.predicate_builder, values: {})
|
26
26
|
@klass = klass
|
27
27
|
@table = table
|
28
28
|
@values = values
|
@@ -52,8 +52,8 @@ module ActiveRecord
|
|
52
52
|
#
|
53
53
|
# user = users.new { |user| user.name = 'Oscar' }
|
54
54
|
# user.name # => Oscar
|
55
|
-
def new(
|
56
|
-
scoping {
|
55
|
+
def new(attributes = nil, &block)
|
56
|
+
scoping { klass.new(scope_for_create(attributes), &block) }
|
57
57
|
end
|
58
58
|
|
59
59
|
alias build new
|
@@ -77,8 +77,12 @@ module ActiveRecord
|
|
77
77
|
#
|
78
78
|
# users.create(name: nil) # validation on name
|
79
79
|
# # => #<User id: nil, name: nil, ...>
|
80
|
-
def create(
|
81
|
-
|
80
|
+
def create(attributes = nil, &block)
|
81
|
+
if attributes.is_a?(Array)
|
82
|
+
attributes.collect { |attr| create(attr, &block) }
|
83
|
+
else
|
84
|
+
scoping { klass.create(scope_for_create(attributes), &block) }
|
85
|
+
end
|
82
86
|
end
|
83
87
|
|
84
88
|
# Similar to #create, but calls
|
@@ -87,8 +91,12 @@ module ActiveRecord
|
|
87
91
|
#
|
88
92
|
# Expects arguments in the same format as
|
89
93
|
# {ActiveRecord::Base.create!}[rdoc-ref:Persistence::ClassMethods#create!].
|
90
|
-
def create!(
|
91
|
-
|
94
|
+
def create!(attributes = nil, &block)
|
95
|
+
if attributes.is_a?(Array)
|
96
|
+
attributes.collect { |attr| create!(attr, &block) }
|
97
|
+
else
|
98
|
+
scoping { klass.create!(scope_for_create(attributes), &block) }
|
99
|
+
end
|
92
100
|
end
|
93
101
|
|
94
102
|
def first_or_create(attributes = nil, &block) # :nodoc:
|
@@ -306,10 +314,10 @@ module ActiveRecord
|
|
306
314
|
|
307
315
|
stmt = Arel::UpdateManager.new
|
308
316
|
|
309
|
-
stmt.set Arel.sql(@klass.
|
317
|
+
stmt.set Arel.sql(@klass.sanitize_sql_for_assignment(updates))
|
310
318
|
stmt.table(table)
|
311
319
|
|
312
|
-
if has_join_values?
|
320
|
+
if has_join_values? || offset_value
|
313
321
|
@klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
|
314
322
|
else
|
315
323
|
stmt.key = arel_attribute(primary_key)
|
@@ -357,8 +365,8 @@ module ActiveRecord
|
|
357
365
|
#
|
358
366
|
# If an invalid method is supplied, #delete_all raises an ActiveRecordError:
|
359
367
|
#
|
360
|
-
# Post.
|
361
|
-
# # => ActiveRecord::ActiveRecordError: delete_all doesn't support
|
368
|
+
# Post.distinct.delete_all
|
369
|
+
# # => ActiveRecord::ActiveRecordError: delete_all doesn't support distinct
|
362
370
|
def delete_all
|
363
371
|
invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
|
364
372
|
value = get_value(method)
|
@@ -376,7 +384,7 @@ module ActiveRecord
|
|
376
384
|
stmt = Arel::DeleteManager.new
|
377
385
|
stmt.from(table)
|
378
386
|
|
379
|
-
if has_join_values?
|
387
|
+
if has_join_values? || has_limit_or_offset?
|
380
388
|
@klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
|
381
389
|
else
|
382
390
|
stmt.wheres = arel.constraints
|
@@ -422,7 +430,7 @@ module ActiveRecord
|
|
422
430
|
relation = self
|
423
431
|
|
424
432
|
if eager_loading?
|
425
|
-
|
433
|
+
apply_join_dependency { |rel, _| relation = rel }
|
426
434
|
end
|
427
435
|
|
428
436
|
conn = klass.connection
|
@@ -440,8 +448,10 @@ module ActiveRecord
|
|
440
448
|
where_clause.to_h(relation_table_name)
|
441
449
|
end
|
442
450
|
|
443
|
-
def scope_for_create
|
444
|
-
where_values_hash.merge!(create_with_value.stringify_keys)
|
451
|
+
def scope_for_create(attributes = nil)
|
452
|
+
scope = where_values_hash.merge!(create_with_value.stringify_keys)
|
453
|
+
scope.merge!(attributes) if attributes
|
454
|
+
scope
|
445
455
|
end
|
446
456
|
|
447
457
|
# Returns true if relation needs eager loading.
|
@@ -523,7 +533,7 @@ module ActiveRecord
|
|
523
533
|
skip_query_cache_if_necessary do
|
524
534
|
@records =
|
525
535
|
if eager_loading?
|
526
|
-
|
536
|
+
apply_join_dependency do |relation, join_dependency|
|
527
537
|
if ActiveRecord::NullRelation === relation
|
528
538
|
[]
|
529
539
|
else
|
@@ -131,7 +131,14 @@ module ActiveRecord
|
|
131
131
|
def calculate(operation, column_name)
|
132
132
|
if has_include?(column_name)
|
133
133
|
relation = apply_join_dependency
|
134
|
-
|
134
|
+
|
135
|
+
if operation.to_s.downcase == "count" && !distinct_value
|
136
|
+
relation.distinct!
|
137
|
+
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
138
|
+
if (column_name == :all || column_name.nil?) && select_values.empty?
|
139
|
+
relation.order_values = []
|
140
|
+
end
|
141
|
+
end
|
135
142
|
|
136
143
|
relation.calculate(operation, column_name)
|
137
144
|
else
|
@@ -217,7 +224,7 @@ module ActiveRecord
|
|
217
224
|
if operation == "count"
|
218
225
|
column_name ||= select_for_count
|
219
226
|
if column_name == :all
|
220
|
-
if distinct && (group_values.any? ||
|
227
|
+
if distinct && (group_values.any? || select_values.empty? && order_values.empty?)
|
221
228
|
column_name = primary_key
|
222
229
|
end
|
223
230
|
elsif column_name =~ /\s*DISTINCT[\s(]+/i
|
@@ -235,7 +242,7 @@ module ActiveRecord
|
|
235
242
|
def aggregate_column(column_name)
|
236
243
|
return column_name if Arel::Expressions === column_name
|
237
244
|
|
238
|
-
if @klass.has_attribute?(column_name
|
245
|
+
if @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
|
239
246
|
@klass.arel_attribute(column_name)
|
240
247
|
else
|
241
248
|
Arel.sql(column_name == :all ? "*" : column_name.to_s)
|
@@ -249,7 +256,7 @@ module ActiveRecord
|
|
249
256
|
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
|
250
257
|
column_alias = column_name
|
251
258
|
|
252
|
-
if operation == "count" && has_limit_or_offset?
|
259
|
+
if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
|
253
260
|
# Shortcut when limit is zero.
|
254
261
|
return 0 if limit_value == 0
|
255
262
|
|
@@ -391,14 +398,12 @@ module ActiveRecord
|
|
391
398
|
end
|
392
399
|
|
393
400
|
def build_count_subquery(relation, column_name, distinct)
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
end
|
401
|
-
]
|
401
|
+
if column_name == :all
|
402
|
+
relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
|
403
|
+
else
|
404
|
+
column_alias = Arel.sql("count_column")
|
405
|
+
relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
|
406
|
+
end
|
402
407
|
|
403
408
|
subquery = relation.arel.as(Arel.sql("subquery_for_count"))
|
404
409
|
select_value = operation_over_aggregate_column(column_alias || Arel.star, "count", false)
|
@@ -18,9 +18,10 @@ module ActiveRecord
|
|
18
18
|
# Person.find([1]) # returns an array for the object with ID = 1
|
19
19
|
# Person.where("administrator = 1").order("created_on DESC").find(1)
|
20
20
|
#
|
21
|
-
# NOTE: The returned records
|
22
|
-
#
|
23
|
-
#
|
21
|
+
# NOTE: The returned records are in the same order as the ids you provide.
|
22
|
+
# If you want the results to be sorted by database, you can use ActiveRecord::QueryMethods#where
|
23
|
+
# method and provide an explicit ActiveRecord::QueryMethods#order option.
|
24
|
+
# But ActiveRecord::QueryMethods#where method doesn't raise ActiveRecord::RecordNotFound.
|
24
25
|
#
|
25
26
|
# ==== Find with lock
|
26
27
|
#
|
@@ -147,7 +148,7 @@ module ActiveRecord
|
|
147
148
|
#
|
148
149
|
# [#<Person id:4>, #<Person id:3>, #<Person id:2>]
|
149
150
|
def last(limit = nil)
|
150
|
-
return find_last(limit) if loaded? ||
|
151
|
+
return find_last(limit) if loaded? || has_limit_or_offset?
|
151
152
|
|
152
153
|
result = ordered_relation.limit(limit)
|
153
154
|
result = result.reverse_order!
|
@@ -312,7 +313,7 @@ module ActiveRecord
|
|
312
313
|
return false if !conditions || limit_value == 0
|
313
314
|
|
314
315
|
if eager_loading?
|
315
|
-
relation = apply_join_dependency(
|
316
|
+
relation = apply_join_dependency(eager_loading: false)
|
316
317
|
return relation.exists?(conditions)
|
317
318
|
end
|
318
319
|
|
@@ -357,24 +358,6 @@ module ActiveRecord
|
|
357
358
|
offset_value || 0
|
358
359
|
end
|
359
360
|
|
360
|
-
def find_with_associations
|
361
|
-
# NOTE: the JoinDependency constructed here needs to know about
|
362
|
-
# any joins already present in `self`, so pass them in
|
363
|
-
#
|
364
|
-
# failing to do so means that in cases like activerecord/test/cases/associations/inner_join_association_test.rb:136
|
365
|
-
# incorrect SQL is generated. In that case, the join dependency for
|
366
|
-
# SpecialCategorizations is constructed without knowledge of the
|
367
|
-
# preexisting join in joins_values to categorizations (by way of
|
368
|
-
# the `has_many :through` for categories).
|
369
|
-
#
|
370
|
-
join_dependency = construct_join_dependency
|
371
|
-
|
372
|
-
relation = apply_join_dependency(join_dependency)
|
373
|
-
relation._select!(join_dependency.aliases.columns)
|
374
|
-
|
375
|
-
yield relation, join_dependency
|
376
|
-
end
|
377
|
-
|
378
361
|
def construct_relation_for_exists(conditions)
|
379
362
|
relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
|
380
363
|
|
@@ -390,22 +373,29 @@ module ActiveRecord
|
|
390
373
|
|
391
374
|
def construct_join_dependency(eager_loading: true)
|
392
375
|
including = eager_load_values + includes_values
|
376
|
+
joins = joins_values.select { |join| join.is_a?(Arel::Nodes::Join) }
|
393
377
|
ActiveRecord::Associations::JoinDependency.new(
|
394
|
-
klass, table, including, alias_tracker(
|
378
|
+
klass, table, including, alias_tracker(joins), eager_loading: eager_loading
|
395
379
|
)
|
396
380
|
end
|
397
381
|
|
398
|
-
def apply_join_dependency(
|
382
|
+
def apply_join_dependency(eager_loading: true)
|
383
|
+
join_dependency = construct_join_dependency(eager_loading: eager_loading)
|
399
384
|
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
400
385
|
|
401
|
-
if using_limitable_reflections?(join_dependency.reflections)
|
402
|
-
|
403
|
-
else
|
404
|
-
if relation.limit_value
|
386
|
+
if eager_loading && !using_limitable_reflections?(join_dependency.reflections)
|
387
|
+
if has_limit_or_offset?
|
405
388
|
limited_ids = limited_ids_for(relation)
|
406
389
|
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
407
390
|
end
|
408
|
-
relation.
|
391
|
+
relation.limit_value = relation.offset_value = nil
|
392
|
+
end
|
393
|
+
|
394
|
+
if block_given?
|
395
|
+
relation._select!(join_dependency.aliases.columns)
|
396
|
+
yield relation, join_dependency
|
397
|
+
else
|
398
|
+
relation
|
409
399
|
end
|
410
400
|
end
|
411
401
|
|
@@ -531,7 +521,11 @@ module ActiveRecord
|
|
531
521
|
else
|
532
522
|
relation = ordered_relation
|
533
523
|
|
534
|
-
if limit_value
|
524
|
+
if limit_value
|
525
|
+
limit = [limit_value - index, limit].min
|
526
|
+
end
|
527
|
+
|
528
|
+
if limit > 0
|
535
529
|
relation = relation.offset(offset_index + index) unless index.zero?
|
536
530
|
relation.limit(limit).to_a
|
537
531
|
else
|
@@ -546,12 +540,11 @@ module ActiveRecord
|
|
546
540
|
else
|
547
541
|
relation = ordered_relation
|
548
542
|
|
549
|
-
relation
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
# e.g., reverse_order.offset(index-1).first
|
543
|
+
if equal?(relation) || has_limit_or_offset?
|
544
|
+
relation.records[-index]
|
545
|
+
else
|
546
|
+
relation.last(index)[-index]
|
547
|
+
end
|
555
548
|
end
|
556
549
|
end
|
557
550
|
|