Module: ActiveHll::Utils

Defined in:
lib/active_hll/utils.rb

Class Method Summary collapse

Class Method Details

.hll_calculate(relation, operation, column, default_value:) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/active_hll/utils.rb', line 20

def hll_calculate(relation, operation, column, default_value:)
  sql, relation, group_values = hll_calculate_sql(relation, operation, column)
  result = relation.connection.select_all(sql)

  # typecast
  rows = []
  columns = result.columns
  result.rows.each do |untyped_row|
    rows << (result.column_types.empty? ? untyped_row : columns.each_with_index.map { |c, i| untyped_row[i] && result.column_types[c] ? result.column_types[c].deserialize(untyped_row[i]) : untyped_row[i] })
  end

  result =
    if group_values.any?
      Hash[rows.map { |r| [r.size == 2 ? r[0] : r[0..-2], r[-1]] }]
    else
      rows[0] && rows[0][0]
    end

  result = Groupdate.process_result(relation, result, default_value: default_value) if defined?(Groupdate.process_result)

  result
end

.hll_calculate_sql(relation, operation, column) ⇒ Object



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
# File 'lib/active_hll/utils.rb', line 43

def hll_calculate_sql(relation, operation, column)
  # basic version of Active Record disallow_raw_sql!
  # symbol = column (safe), Arel node = SQL (safe), other = untrusted
  # matches table.column and column
  unless column.is_a?(Symbol) || column.is_a?(Arel::Nodes::SqlLiteral)
    column = column.to_s
    unless /\A\w+(\.\w+)?\z/i.match?(column)
      raise ActiveRecord::UnknownAttributeReference, "Query method called with non-attribute argument(s): #{column.inspect}. Use Arel.sql() for known-safe values."
    end
  end

  # column resolution
  node = relation.all.send(:arel_columns, [column]).first
  node = Arel::Nodes::SqlLiteral.new(node) if node.is_a?(String)
  column = relation.connection.visitor.accept(node, Arel::Collectors::SQLString.new).value

  group_values = relation.all.group_values

  relation = relation.unscope(:select).select(*group_values, operation % [column])

  # same as average
  relation = relation.unscope(:order).distinct!(false) if group_values.empty?

  [relation.to_sql, relation, group_values]
end

.hll_hash_sql(klass, value) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/active_hll/utils.rb', line 4

def hll_hash_sql(klass, value)
  hash_function =
    case value
    when true, false
      "hll_hash_boolean"
    when Integer
      "hll_hash_bigint"
    when String
      "hll_hash_text"
    else
      raise ArgumentError, "Unexpected type: #{value.class.name}"
    end
  quoted_value = klass.connection.quote(value)
  "#{hash_function}(#{quoted_value})"
end