Module: ActiveOLAP::ClassMethods

Defined in:
lib/active_olap.rb

Instance Method Summary collapse

Instance Method Details

#olap_query(*args) ⇒ Object

Performs an OLAP query that counts how many records do occur in given categories. It can be used for multiple dimensions It expects a list of category definitions



25
26
27
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
# File 'lib/active_olap.rb', line 25

def olap_query(*args)

  # set aggregates apart if they are given
  aggregates_given = (args.last.kind_of?(Hash) && args.last.has_key?(:aggregate)) ? args.pop[:aggregate] : nil
  
  # parse the dimensions
  raise "You have to provide at least one dimension for an OLAP query" if args.length == 0    
  dimensions = args.collect { |d| Dimension.create(self, d) }
  
  raise "Overlapping categories only supported in the last dimension" if dimensions[0..-2].any? { |d| d.has_overlap? }
  raise "Only counting is supported with overlapping categories" if dimensions.last.has_overlap? && aggregates_given

  if !aggregates_given
    if dimensions.last.has_overlap?
      aggregates = []
    else
      aggregates = [Aggregate.create(self, :the_olap_count_field, :count_distinct)]
    end
  else 
    aggregates = Aggregate.all_from_olap_query_call(self, aggregates_given)        
  end

  conditions = self.send(:merge_conditions, *dimensions.map(&:conditions))
  joins = (dimensions.map(&:joins) + aggregates.map(&:joins)).flatten.uniq
  joins_clause = joins.empty? ? nil : self.send(:merge_joins, *joins)

  selects = aggregates.map { |agg| agg.to_sanitized_sql }
  groups  = []

  if aggregates.length > 0
    dimensions_to_group = dimensions.clone
  else 
    selects << dimensions.last.to_count_with_overlap_sql
    dimensions_to_group = dimensions[0, dimensions.length - 1]
  end
  
  dimensions_to_group.each_with_index do |d, index|
    var_name = "dimension_#{index}"
    groups  << self.connection.quote_column_name(var_name)
    selects << d.to_case_expression(var_name)
  end

  group_clause = groups.length > 0 ? groups.join(', ') : nil
  # TODO: having
  
  olap_temporarily_set_join_type if joins_clause
  
  query_result = self.scoped(:conditions => conditions).find(:all, :select => selects.join(', '), 
      :joins => joins_clause, :group => group_clause, :order => group_clause)  
  
  olap_temporarily_reset_join_type if joins_clause
  
  return Cube.new(self, dimensions, aggregates, query_result)
end