Module: DataMapper::Aggregates::Functions

Includes:
DataMapper::Assertions
Included in:
Collection, Model
Defined in:
lib/dm-aggregates/functions.rb

Instance Method Summary collapse

Instance Method Details

#aggregate(*args) ⇒ Array, ...

Perform aggregate queries

Examples:

the count of friends

Friend.aggregate(:all.count)

the minimum age, the maximum age and the total age of friends

Friend.aggregate(:age.min, :age.max, :age.sum)

the average age, grouped by gender

Friend.aggregate(:age.avg, :fields => [ :gender ])

Parameters:

  • aggregates (Symbol, ...)

    operators to aggregate with

  • query (Hash)

    the conditions

Returns:

  • (Array, Numeric, DateTime, Date, Time)

    the results of the aggregate query

Raises:

  • (ArgumentError)


153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/dm-aggregates/functions.rb', line 153

def aggregate(*args)
  query = args.last.kind_of?(Hash) ? args.pop : {}

  query[:fields] ||= []
  query[:fields]  |= args
  query[:fields].map! { |f| normalize_field(f) }

  raise ArgumentError, 'query[:fields] must not be empty' if query[:fields].empty?

  unless query.key?(:order)
    # the current collection/model is already sorted by attributes
    # and since we are projecting away some of the attributes,
    # and then performing aggregate functions on the remainder,
    # we need to honor the existing order, as if it were already
    # materialized, and we are looping over the rows in order.

    directions = direction_map

    query[:order] = []

    # use the current query order for each property if available
    query[:fields].each do |property|
      next unless property.kind_of?(Property)
      query[:order] << directions.fetch(property, property)
    end
  end

  query = scoped_query(query)

  if query.fields.any? { |p| p.kind_of?(Property) }
    query.repository.aggregate(query.update(:unique => true))
  else
    query.repository.aggregate(query).first  # only return one row
  end
end

#avg(*args) ⇒ Integer

Get the average value of a property

Examples:

the average age of all friends

Friend.avg(:age)

the average age of all female friends

Friend.avg(:age, :conditions => [ 'gender = ?', 'female' ])

Parameters:

  • property (Symbol)

    the property you wish to get the average value of

  • opts (Hash, Symbol)

    the conditions

Returns:

  • (Integer)

    return the average value of a property given the conditions



103
104
105
106
107
108
109
110
# File 'lib/dm-aggregates/functions.rb', line 103

def avg(*args)
  query         = args.last.kind_of?(Hash) ? args.pop : {}
  property_name = args.first

  assert_property_type property_name, ::Integer, ::Float, ::BigDecimal

  aggregate(query.merge(:fields => [ property_name.avg ]))
end

#count(*args) ⇒ Integer

Count results (given the conditions)

Examples:

the count of all friends

Friend.count

the count of all friends older then 18

Friend.count(:age.gt => 18)

the count of all your female friends

Friend.count(:conditions => [ 'gender = ?', 'female' ])

the count of all friends with an address (NULL values are not included)

Friend.count(:address)

the count of all friends with an address that are older then 18

Friend.count(:address, :age.gt => 18)

the count of all your female friends with an address

Friend.count(:address, :conditions => [ 'gender = ?', 'female' ])

Parameters:

  • property (Symbol)

    of the property you with to count (optional)

  • opts (Hash, Symbol)

    the conditions

Returns:

  • (Integer)

    return the count given the conditions



32
33
34
35
36
37
38
39
40
41
# File 'lib/dm-aggregates/functions.rb', line 32

def count(*args)
  query         = args.last.kind_of?(Hash) ? args.pop : {}
  property_name = args.first

  if property_name
    assert_kind_of 'property', property_by_name(property_name), Property
  end

  aggregate(query.merge(:fields => [ property_name ? property_name.count : :all.count ])).to_i
end

#max(*args) ⇒ Integer

Get the highest value of a property

Examples:

the age of the oldest friend

Friend.max(:age)

the age of the oldest female friend

Friend.max(:age, :conditions => [ 'gender = ?', 'female' ])

Parameters:

  • property (Symbol)

    the property you wish to get the highest value of

  • opts (Hash, Symbol)

    the conditions

Returns:

  • (Integer)

    return the highest value of a property given the conditions



80
81
82
83
84
85
86
87
# File 'lib/dm-aggregates/functions.rb', line 80

def max(*args)
  query         = args.last.kind_of?(Hash) ? args.pop : {}
  property_name = args.first

  assert_property_type property_name, ::Integer, ::Float, ::BigDecimal, ::DateTime, ::Date, ::Time

  aggregate(query.merge(:fields => [ property_name.max ]))
end

#min(*args) ⇒ Integer

Get the lowest value of a property

Examples:

the age of the youngest friend

Friend.min(:age)

the age of the youngest female friend

Friend.min(:age, :conditions => [ 'gender = ?', 'female' ])

Parameters:

  • property (Symbol)

    the property you wish to get the lowest value of

  • opts (Hash, Symbol)

    the conditions

Returns:

  • (Integer)

    return the lowest value of a property given the conditions



57
58
59
60
61
62
63
64
# File 'lib/dm-aggregates/functions.rb', line 57

def min(*args)
  query         = args.last.kind_of?(Hash) ? args.pop : {}
  property_name = args.first

  assert_property_type property_name, ::Integer, ::Float, ::BigDecimal, ::DateTime, ::Date, ::Time

  aggregate(query.merge(:fields => [ property_name.min ]))
end

#sum(*args) ⇒ Integer

Get the total value of a property

Examples:

the total age of all friends

Friend.sum(:age)

the total age of all female friends

Friend.max(:age, :conditions => [ 'gender = ?', 'female' ])

Parameters:

  • property (Symbol)

    the property you wish to get the total value of

  • opts (Hash, Symbol)

    the conditions

Returns:

  • (Integer)

    return the total value of a property given the conditions



126
127
128
129
130
131
132
133
# File 'lib/dm-aggregates/functions.rb', line 126

def sum(*args)
  query         = args.last.kind_of?(::Hash) ? args.pop : {}
  property_name = args.first

  assert_property_type property_name, ::Integer, ::Float, ::BigDecimal

  aggregate(query.merge(:fields => [ property_name.sum ]))
end