Module: WeightedAverage::ArelSelectManagerInstanceMethods

Defined in:
lib/weighted_average/arel_select_manager_instance_methods.rb

Instance Method Summary collapse

Instance Method Details

#weighted_average(data_column_names, options = {}) ⇒ Float?

Calculate the weighted average of column(s).

Examples:

Weighted average of load factor in flight stage data

Arel::Table.new(:flight_segments).weighted_average(:load_factor, :weighted_by => :passengers)

Parameters:

  • data_column_names (Symbol, Array<Symbol>)

    One or more column names whose average should be calculated. Added together before being multiplied by the weighting if more than one.

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :weighted_by (Symbol)

    The name of the weighting column if it’s not :weighting (the default)

  • :disaggregate_by (Symbol)

    The name of a column to disaggregate by. Usually not necessary.

Returns:

  • (Float, nil)

See Also:



17
18
19
20
# File 'lib/weighted_average/arel_select_manager_instance_methods.rb', line 17

def weighted_average(data_column_names, options = {})
  weighted_average = @engine.connection.select_value(weighted_average_relation(data_column_names, options).to_sql)
  weighted_average.nil? ? nil : weighted_average.to_f
end

#weighted_average_relation(data_column_names, options = {}) ⇒ Arel::SelectManager

In case you want to get the relation and/or the SQL of the calculation query before actually runnnig it.

Examples:

Get the SQL

Arel::Table.new(:flight_segments).weighted_average_relation(:load_factor, :weighted_by => :passengers).to_sql

Returns:

  • (Arel::SelectManager)

    A relation you can play around with.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/weighted_average/arel_select_manager_instance_methods.rb', line 28

def weighted_average_relation(data_column_names, options = {})
  unless options[:safe] == true
    return clone.weighted_average_relation(data_column_names, options.merge(:safe => true))
  end

  data_column_names = Array.wrap data_column_names
  left = self.source.left

  weighted_by_column = case options[:weighted_by]
  when Arel::Attribute
    options[:weighted_by]
  when Symbol, String
    left[options[:weighted_by]]
  when NilClass
    left[DEFAULT_WEIGHTED_BY_COLUMN_NAME]
  else
    raise ArgumentError, ":weighted_by => #{options[:weighted_by].inspect} must be a column on #{left.inspect}"
  end
  
  disaggregate_by_column = if options[:disaggregate_by]
    left[options[:disaggregate_by]]
  end

  data_columns = data_column_names.map do |data_column_name|
    left[data_column_name]
  end

  data_columns_added_together = data_columns.inject(nil) do |memo, data_column|
    if memo
      Arel::Nodes::Addition.new(memo, data_column)
    else
      data_column
    end
  end

  if data_column_names.many?
    data_columns_added_together = Arel::Nodes::Grouping.new(data_columns_added_together)
  end

  if disaggregate_by_column
    self.projections = [Arel::Nodes::Division.new(Arel::Nodes::Sum.new(weighted_by_column * data_columns_added_together / disaggregate_by_column * 1.0), Arel::Nodes::Sum.new([weighted_by_column]))]
  else
    self.projections = [Arel::Nodes::Division.new(Arel::Nodes::Sum.new(weighted_by_column * data_columns_added_together * 1.0), Arel::Nodes::Sum.new([weighted_by_column]))]
  end

  data_columns_not_eq_nil = data_columns.inject(nil) do |memo, data_column|
    if memo
      memo.and(data_column.not_eq(nil))
    else
      data_column.not_eq(nil)
    end
  end

  if disaggregate_by_column
    where data_columns_not_eq_nil.and(weighted_by_column.gt(0)).and(disaggregate_by_column.gt(0))
  else
    where data_columns_not_eq_nil.and(weighted_by_column.gt(0))
  end
end