mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Refactor pluck with multiple columns
Ensure it works with mix of symbols and strings, and with a select clause possibly containing more than one column. Also remove support for pluck with an array of columns, in favor of passing the list of attributes: Model.pluck(:a, :b) See comments: https://github.com/rails/rails/pull/6500#issuecomment-6030292
This commit is contained in:
parent
2e379c1e63
commit
6aae17e856
2 changed files with 29 additions and 36 deletions
|
@ -107,7 +107,6 @@ module ActiveRecord
|
||||||
relation = with_default_scope
|
relation = with_default_scope
|
||||||
|
|
||||||
if relation.equal?(self)
|
if relation.equal?(self)
|
||||||
|
|
||||||
if has_include?(column_name)
|
if has_include?(column_name)
|
||||||
construct_relation_for_association_calculations.calculate(operation, column_name, options)
|
construct_relation_for_association_calculations.calculate(operation, column_name, options)
|
||||||
else
|
else
|
||||||
|
@ -139,9 +138,6 @@ module ActiveRecord
|
||||||
# # SELECT people.id FROM people
|
# # SELECT people.id FROM people
|
||||||
# # => [1, 2, 3]
|
# # => [1, 2, 3]
|
||||||
#
|
#
|
||||||
# Person.pluck([:id, :name])
|
|
||||||
# # SELECT people.id, people.name FROM people
|
|
||||||
#
|
|
||||||
# Person.pluck(:id, :name)
|
# Person.pluck(:id, :name)
|
||||||
# # SELECT people.id, people.name FROM people
|
# # SELECT people.id, people.name FROM people
|
||||||
#
|
#
|
||||||
|
@ -158,23 +154,19 @@ module ActiveRecord
|
||||||
# # => ['0', '27761', '173']
|
# # => ['0', '27761', '173']
|
||||||
#
|
#
|
||||||
def pluck(*column_names)
|
def pluck(*column_names)
|
||||||
column_names = column_names.flatten
|
column_names.map! do |column_name|
|
||||||
|
if column_name.is_a?(Symbol) && self.column_names.include?(column_name.to_s)
|
||||||
if column_names.first.is_a?(Symbol) && self.column_names.include?(column_names.first.to_s)
|
"#{table_name}.#{column_name}"
|
||||||
if column_names.one?
|
|
||||||
column_names = "#{table_name}.#{column_names.first}"
|
|
||||||
else
|
else
|
||||||
column_names = column_names.collect{|column_name| "#{table_name}.#{column_name}"}
|
column_name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if has_include?(column_names)
|
if has_include?(column_names.first)
|
||||||
construct_relation_for_association_calculations.pluck(column_names)
|
construct_relation_for_association_calculations.pluck(*column_names)
|
||||||
else
|
else
|
||||||
result = klass.connection.select_all(select(column_names).arel, nil, bind_values)
|
result = klass.connection.select_all(select(column_names).arel, nil, bind_values)
|
||||||
|
columns = result.columns.map do |key|
|
||||||
keys = column_names.is_a?(Array) && !column_names.one? ? result.columns : [result.columns.first]
|
|
||||||
columns = keys.map do |key|
|
|
||||||
klass.column_types.fetch(key) {
|
klass.column_types.fetch(key) {
|
||||||
result.column_types.fetch(key) {
|
result.column_types.fetch(key) {
|
||||||
Class.new { def type_cast(v); v; end }.new
|
Class.new { def type_cast(v); v; end }.new
|
||||||
|
@ -182,19 +174,14 @@ module ActiveRecord
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
result.map do |attributes|
|
result = result.map do |attributes|
|
||||||
if attributes.one?
|
values = klass.initialize_attributes(attributes).values
|
||||||
value = klass.initialize_attributes(attributes).values.first
|
|
||||||
|
|
||||||
columns.first.type_cast(value)
|
columns.zip(values).map do |column, value|
|
||||||
else
|
column.type_cast(value)
|
||||||
values = klass.initialize_attributes(attributes).values
|
|
||||||
|
|
||||||
values.each_with_index.map do |value, i|
|
|
||||||
columns[i].type_cast(value)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
columns.one? ? result.map!(&:first) : result
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -532,10 +532,6 @@ class CalculationsTest < ActiveRecord::TestCase
|
||||||
assert_equal [50 + 53 + 55 + 60], Account.pluck('SUM(DISTINCT(credit_limit)) as credit_limit')
|
assert_equal [50 + 53 + 55 + 60], Account.pluck('SUM(DISTINCT(credit_limit)) as credit_limit')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_pluck_expects_a_multiple_selection_as_array
|
|
||||||
assert_raise(ArgumentError) { Account.pluck 'id, credit_limit' }
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_plucks_with_ids
|
def test_plucks_with_ids
|
||||||
assert_equal Company.all.map(&:id).sort, Company.ids.sort
|
assert_equal Company.all.map(&:id).sort, Company.ids.sort
|
||||||
end
|
end
|
||||||
|
@ -551,14 +547,24 @@ class CalculationsTest < ActiveRecord::TestCase
|
||||||
assert_equal [
|
assert_equal [
|
||||||
[1, "The First Topic"], [2, "The Second Topic of the day"],
|
[1, "The First Topic"], [2, "The Second Topic of the day"],
|
||||||
[3, "The Third Topic of the day"], [4, "The Fourth Topic of the day"]
|
[3, "The Third Topic of the day"], [4, "The Fourth Topic of the day"]
|
||||||
], Topic.order(:id).pluck([:id, :title])
|
], Topic.order(:id).pluck(:id, :title)
|
||||||
assert_equal [
|
assert_equal [
|
||||||
[1, "The First Topic", "David"], [2, "The Second Topic of the day", "Mary"],
|
[1, "The First Topic", "David"], [2, "The Second Topic of the day", "Mary"],
|
||||||
[3, "The Third Topic of the day", "Carl"], [4, "The Fourth Topic of the day", "Carl"]
|
[3, "The Third Topic of the day", "Carl"], [4, "The Fourth Topic of the day", "Carl"]
|
||||||
], Topic.order(:id).pluck([:id, :title, :author_name])
|
], Topic.order(:id).pluck(:id, :title, :author_name)
|
||||||
assert_equal [
|
end
|
||||||
[1, "The First Topic"], [2, "The Second Topic of the day"],
|
|
||||||
[3, "The Third Topic of the day"], [4, "The Fourth Topic of the day"]
|
def test_pluck_with_multiple_columns_and_selection_clause
|
||||||
], Topic.order(:id).pluck(:id, :title)
|
assert_equal [[1, 50], [2, 50], [3, 50], [4, 60], [5, 55], [6, 53]],
|
||||||
|
Account.pluck('id, credit_limit')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_pluck_with_multiple_columns_and_includes
|
||||||
|
Company.create!(:name => "test", :contracts => [Contract.new(:developer_id => 7)])
|
||||||
|
companies_and_developers = Company.order('companies.id').includes(:contracts).pluck(:name, :developer_id)
|
||||||
|
|
||||||
|
assert_equal Company.count, companies_and_developers.length
|
||||||
|
assert_equal ["37signals", nil], companies_and_developers.first
|
||||||
|
assert_equal ["test", 7], companies_and_developers.last
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue