module Pluckeroid
module ActiveRecord
module Relation
# Performs select by column names as direct SQL query.
# Returns Array of hashes each element of which contains
# specified column names as keys and the values of the column names as values.
# The values has same data type as column.
#
# Examples:
#
# Person.pluck(:id) # SELECT people.id FROM people
# # => [{ 'id' => 1 }, { 'id' => 2 }]
#
# Person.pluck_attributes(:id, :name) # SELECT people.id, people.name FROM people
# # => [{ 'id' => 1, 'name' => 'Obi-Wan' }, { 'id' => 2, 'name' => 'Luke' }]
#
#
def pluck_attributes(*column_names)
pluck_columns(column_names) do |attributes|
attributes.each do |key, _|
attributes[key] = klass.type_cast_attribute(key, attributes)
end
end
end
# Same as +pluck_attributes+ but returns Array with values
# of the specified column name.
#
# Examples:
#
# Person.pluck(:id) # SELECT people.id FROM people
# # => [1, 2]
#
# Person.pluck(:id, :name) # SELECT people.id, people.name FROM people
# # => [[1, 'Obi-Wan'], [2, 'Luke']]
#
def pluck(*column_names)
flatten = column_names.size == 1
pluck_columns(column_names) do |attributes|
values = attributes.map do |key, _|
klass.type_cast_attribute(key, attributes)
end
if flatten
values.first
else
values
end
end
end
alias :value_of :pluck
alias :values_of :pluck
protected
def pluck_columns(columns)
if columns.size.zero?
raise ArgumentError, 'wrong number of arguments (0 for 1)'
end
columns = columns.map do |column_name|
if Symbol === column_name && column_names.include?(column_name.to_s)
"#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}"
else
column_name.to_s
end
end
relation = clone
relation.select_values = columns
klass.connection.select_all(relation.arel).map! do |attributes|
yield klass.initialize_attributes(attributes)
end
end
end
end
end
class ActiveRecord::Relation
include Pluckeroid::ActiveRecord::Relation
end