Class: Appstats::Query

Inherits:
Object
  • Object
show all
Defined in:
lib/appstats/query.rb

Constant Summary collapse

@@parser_template =
Appstats::Parser.new(:rules => ":operation :action :date on :host where :contexts group by :group_by")
@@contexts_parser_template =
Appstats::Parser.new(:rules => ":context", :repeating => true, :tokenize => "and or || && = <= >= <> < > != ( ) like")
@@group_by_parser_template =
Appstats::Parser.new(:rules => ":filter", :repeating => true, :tokenize => ",")
@@nill_query =
"select 0 from appstats_entries LIMIT 1"
@@default =
"1=1"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data = {}) ⇒ Query

Returns a new instance of Query.



13
14
15
16
17
18
# File 'lib/appstats/query.rb', line 13

def initialize(data = {})
  @name = data[:name]
  @query_type = data[:query_type]
  @result_type = data[:result_type] || "on_demand"
  self.query=(data[:query])
end

Instance Attribute Details

#actionObject

Returns the value of attribute action.



11
12
13
# File 'lib/appstats/query.rb', line 11

def action
  @action
end

#contextsObject

Returns the value of attribute contexts.



11
12
13
# File 'lib/appstats/query.rb', line 11

def contexts
  @contexts
end

#date_rangeObject

Returns the value of attribute date_range.



11
12
13
# File 'lib/appstats/query.rb', line 11

def date_range
  @date_range
end

#group_byObject

Returns the value of attribute group_by.



11
12
13
# File 'lib/appstats/query.rb', line 11

def group_by
  @group_by
end

#group_query_to_sqlObject

Returns the value of attribute group_query_to_sql.



11
12
13
# File 'lib/appstats/query.rb', line 11

def group_query_to_sql
  @group_query_to_sql
end

#hostObject

Returns the value of attribute host.



11
12
13
# File 'lib/appstats/query.rb', line 11

def host
  @host
end

#nameObject

Returns the value of attribute name.



11
12
13
# File 'lib/appstats/query.rb', line 11

def name
  @name
end

#parsed_contextsObject

Returns the value of attribute parsed_contexts.



11
12
13
# File 'lib/appstats/query.rb', line 11

def parsed_contexts
  @parsed_contexts
end

#queryObject

Returns the value of attribute query.



11
12
13
# File 'lib/appstats/query.rb', line 11

def query
  @query
end

#query_to_sqlObject

Returns the value of attribute query_to_sql.



11
12
13
# File 'lib/appstats/query.rb', line 11

def query_to_sql
  @query_to_sql
end

#query_typeObject

Returns the value of attribute query_type.



11
12
13
# File 'lib/appstats/query.rb', line 11

def query_type
  @query_type
end

Class Method Details

.comparator?(raw_input) ⇒ Boolean

Returns:

  • (Boolean)


140
141
142
143
# File 'lib/appstats/query.rb', line 140

def self.comparator?(raw_input)
  return false if raw_input.nil?
  comparators.include?(raw_input)
end

.comparatorsObject



145
146
147
# File 'lib/appstats/query.rb', line 145

def self.comparators
  ["=","!=","<>",">","<",">=","<=","like"]
end

.host_filter_to_sql(raw_input) ⇒ Object



78
79
80
81
82
83
84
85
86
# File 'lib/appstats/query.rb', line 78

def self.host_filter_to_sql(raw_input)
  return @@default if raw_input.nil?
  input = raw_input.strip
  m = raw_input.strip.match(/(^[^\s']*$)/)
  return @@default if m.nil?
  host = m[1]
  return @@default if host == '' or host.nil?
  "EXISTS (select * from appstats_log_collectors where appstats_entries.appstats_log_collector_id = appstats_log_collectors.id and host = '#{host}' )"
end

.sqlclean(raw_input) ⇒ Object



132
133
134
135
136
137
138
# File 'lib/appstats/query.rb', line 132

def self.sqlclean(raw_input)
  return raw_input if raw_input.blank?
  m = raw_input.match(/^['"](.*)['"]$/)
  input = m.nil? ? raw_input : m[1]
  input = input.gsub(/\\/, '\&\&').gsub(/'/, "''")
  input
end

.sqlize(input) ⇒ Object



125
126
127
128
129
130
# File 'lib/appstats/query.rb', line 125

def self.sqlize(input)
  return "and" if input == "&&"
  return "or" if input == "||"
  return "<>" if input == "!="
  input
end

Instance Method Details

#contexts_filter_to_sqlObject



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/appstats/query.rb', line 88

def contexts_filter_to_sql
  context_parser = @@contexts_parser_template.dup
  return @@default if @contexts.blank? || !context_parser.parse(@contexts)
  sql = "EXISTS (select * from appstats_contexts where appstats_entries.id = appstats_contexts.appstats_entry_id and ("
  
  status = :next
  comparator = "="
  context_parser.raw_results.each do |entry|
    if entry.kind_of?(String)
      sqlentry = Query.sqlize(entry)
      if Query.comparator?(entry) && status == :waiting_comparator
        comparator = Query.sqlize(entry)
        status = :waiting_operand
      else
        sql += ")" if status == :waiting_comparator
        sql += " #{sqlentry}"
        @parsed_contexts<< sqlentry
        status = :next
      end
      next
    end
    if status == :next
      status = :waiting_comparator
      @parsed_contexts<< { :context_key => entry[:context] }
      sql += " (context_key = '#{Query.sqlclean(entry[:context])}'"
    else
      status = :next
      @parsed_contexts.last[:context_value] = entry[:context]
      @parsed_contexts.last[:comparator] = comparator
      sql += " and context_value #{comparator} '#{Query.sqlclean(entry[:context])}')"
    end
  end
  sql += ")" if status == :waiting_comparator
  sql += "))"
  sql
end

#runObject



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
# File 'lib/appstats/query.rb', line 38

def run
  result = Appstats::Result.new(:name => @name, :result_type => @result_type, :query => @query, :query_to_sql => @query_to_sql, :action => @action, :host => @host, :from_date => @date_range.from_date, :to_date => @date_range.to_date, :contexts => @contexts, :query_type => @query_type)
  unless @group_by.empty?
    result.group_by = @group_by.join(", ")
    result.group_query_to_sql = @group_query_to_sql
  end

  result.group_by = @group_by.join(", ") unless @group_by.empty?
  
  data = run_query { |conn| conn.select_one(@query_to_sql)["num"].to_i }
  unless data.nil?
    result.count = data[:results]
    result.db_username = data[:db_config][:username]
    result.db_name = data[:db_config][:database]
    result.db_host = data[:db_config][:host]
  end
  result.save

  unless @group_by.empty?
    data = run_query { |conn| conn.select_all(@group_query_to_sql) }
    all_sub_results = data.nil? ? [] : data[:results]
    all_sub_results.each do |data|
      if data["context_key_filter"].nil? || data["context_value_filter"].nil? || data["num"].nil?
        Appstats.log(:error,"Missing context_key_filter, context_value_filter, or num in #{data.inspect}")
        next 
      end
      
      keys = data["context_key_filter"].split(",")
      values = data["context_value_filter"].split(",")
      key_values = {} and keys.each_with_index { |k,i| key_values[k] = values[i] }
      ratio_of_total = data["num"].to_f / result.count
      sub_result = Appstats::SubResult.new(:context_filter => @group_by.collect { |k| key_values[k] }.join(", "), :count => data["num"], :ratio_of_total => ratio_of_total)
      sub_result.result = result
      sub_result.save
    end
  end
  result.reload
  result
end