Module: ActiveEnumerable::Queries

Included in:
ActiveEnumerable
Defined in:
lib/active_enumerable/queries.rb

Instance Method Summary collapse

Instance Method Details

#average(key) ⇒ Object

Calculates the average value on a given attribute. Returns nil if there’s no row.

<#ActiveEnumerable>.average(:age) # => 35.8


89
90
91
92
93
94
# File 'lib/active_enumerable/queries.rb', line 89

def average(key)
  values = values_by_key(key)
  total  = values.inject { |sum, n| sum + n }
  return unless total
  BigDecimal.new(total) / BigDecimal.new(values.count)
end

#count(name = nil) ⇒ Object

Count the records.

<#ActiveEnumerable>.count
# => the total count of all people

<#ActiveEnumerable>.count(:age)
# => returns the total count of all people whose age is not nil


62
63
64
65
# File 'lib/active_enumerable/queries.rb', line 62

def count(name = nil)
  return to_a.size if name.nil?
  to_a.reject { |record| Finder.new(record).is_of(name: nil) }.size
end

#find(*args) ⇒ ActiveEnumerable, Object

Find by id - Depends on either having an Object#id or HashInteger This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). If no record can be found for all of the listed ids, then RecordNotFound will be raised. If the primary key is an integer, find by id coerces its arguments using to_i.

<#ActiveEnumerable>.find(1)          # returns the object for ID = 1
<#ActiveEnumerable>.find(1, 2, 6)    # returns an array for objects with IDs in (1, 2, 6)
<#ActiveEnumerable>.find([7, 17])    # returns an array for objects with IDs in (7, 17)
<#ActiveEnumerable>.find([1])        # returns an array for the object with ID = 1

ActiveEnumerable::RecordNotFound will be raised if one or more ids are not found.

Raises:



19
20
21
22
23
24
25
26
27
28
# File 'lib/active_enumerable/queries.rb', line 19

def find(*args)
  raise RecordNotFound.new("Couldn't find #{self.respond_to?(:name) ? self.name : self.class.name} without an ID") if args.compact.empty?
  if args.count > 1 || args.first.is_a?(Array)
    __new_relation__(args.flatten.lazy.map do |id|
      find_by!(id: id.to_i)
    end)
  else
    find_by!(id: args.first.to_i)
  end
end

#find_by(conditions = {}) ⇒ Object

Finds the first record matching the specified conditions. There is no implied ordering so if order matters, you should specify it yourself.

If no record is found, returns nil.

<#ActiveEnumerable>.find_by name: 'Spartacus', rating: 4

# @see ActiveEnumerable::Finder#is_of for all usages of conditions.



39
40
41
42
43
# File 'lib/active_enumerable/queries.rb', line 39

def find_by(conditions = {})
  to_a.detect do |record|
    Finder.new(record).is_of(conditions)
  end
end

#find_by!(conditions = {}) ⇒ Object

Like find_by, except that if no record is found, raises an ActiveEnumerable::RecordNotFound error.



47
48
49
50
51
52
53
# File 'lib/active_enumerable/queries.rb', line 47

def find_by!(conditions={})
  result = find_by(conditions)
  if result.nil?
    raise RecordNotFound.new("Couldn't find #{self.name} with '#{conditions.keys.first}'=#{conditions.values.first}")
  end
  result
end

#limit(num) ⇒ Object

Specifies a limit for the number of records to retrieve.

<#ActiveEnumerable>.limit(10)


70
71
72
# File 'lib/active_enumerable/queries.rb', line 70

def limit(num)
  __new_relation__(all.take(num))
end

#maximum(key) ⇒ Object

Calculates the maximum value on a given attribute. The value is returned with the same data type of the attribute, or nil if there’s no row.

<#ActiveEnumerable>.maximum(:age) # => 93


108
109
110
# File 'lib/active_enumerable/queries.rb', line 108

def maximum(key)
  values_by_key(key).max_by { |i| i }
end

#minimum(key) ⇒ Object

Calculates the minimum value on a given attribute. Returns nil if there’s no row.

<#ActiveEnumerable>.minimum(:age) # => 7


100
101
102
# File 'lib/active_enumerable/queries.rb', line 100

def minimum(key)
  values_by_key(key).min_by { |i| i }
end

#noneObject

Returns a chainable relation with zero records.

Any subsequent condition chained to the returned relation will continue generating an empty relation.

Used in cases where a method or scope could return zero records but the result needs to be chainable.

For example:

@posts = current_user.visible_posts.where(name: params[:name])
# => the visible_posts method is expected to return a chainable Relation

def visible_posts
  case role
  when 'Country Manager'
    <#ActiveEnumerable>.where(country: country)
  when 'Reviewer'
    <#ActiveEnumerable>.published
  when 'Bad User'
    <#ActiveEnumerable>.none # It can't be chained if [] is returned.
  end
end


157
158
159
# File 'lib/active_enumerable/queries.rb', line 157

def none
  __new_relation__([])
end

#order(*args) ⇒ Object

Allows to specify an order attribute:

<#ActiveEnumerable>.order('name')

<#ActiveEnumerable>.order(:name)

<#ActiveEnumerable>.order(email: :desc)

<#ActiveEnumerable>.order(:name, email: :desc)


121
122
123
# File 'lib/active_enumerable/queries.rb', line 121

def order(*args)
  __new_relation__(Order.call(args, all))
end

#reverse_orderObject

Reverse the existing order clause on the relation.

<#ActiveEnumerable>.order('name').reverse_order


129
130
131
# File 'lib/active_enumerable/queries.rb', line 129

def reverse_order
  __new_relation__(to_a.reverse)
end

#sum(key) ⇒ Object

Calculates the sum of values on a given attribute. The value is returned with the same data type of the attribute, 0 if there’s no row.

<#ActiveEnumerable>.sum(:age) # => 4562


78
79
80
81
82
83
# File 'lib/active_enumerable/queries.rb', line 78

def sum(key)
  values = values_by_key(key)
  values.inject(0) do |sum, n|
    sum + (n || 0)
  end
end