appstats 0.13.4 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- appstats (0.13.4)
4
+ appstats (0.14.0)
5
5
  daemons
6
6
  net-scp
7
7
  rails (>= 2.3.0)
@@ -0,0 +1,9 @@
1
+ class AddAppstatsResultsGroupQueryToSql < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :appstats_results, :group_query_to_sql, :text
4
+ end
5
+
6
+ def self.down
7
+ remove_column :appstats_results, :group_query_to_sql, :text
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ class CreateAppstatsSubResults < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :appstats_sub_results do |t|
4
+ t.integer :appstats_result_id
5
+ t.string :context_filter
6
+ t.integer :count
7
+ t.float :ratio_of_total
8
+ t.timestamps
9
+ end
10
+
11
+ add_index :appstats_sub_results, :context_filter
12
+ end
13
+
14
+ def self.down
15
+ remove_index :appstats_sub_results, :context_filter
16
+
17
+ drop_table :appstats_sub_results
18
+ end
19
+ end
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # It's strongly recommended to check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(:version => 20110225192624) do
13
+ ActiveRecord::Schema.define(:version => 20110301170947) do
14
14
 
15
15
  create_table "appstats_actions", :force => true do |t|
16
16
  t.string "name"
@@ -118,6 +118,7 @@ ActiveRecord::Schema.define(:version => 20110225192624) do
118
118
  t.datetime "created_at"
119
119
  t.datetime "updated_at"
120
120
  t.text "contexts"
121
+ t.text "group_query_to_sql"
121
122
  end
122
123
 
123
124
  add_index "appstats_results", ["action"], :name => "index_appstats_results_on_action"
@@ -125,6 +126,17 @@ ActiveRecord::Schema.define(:version => 20110225192624) do
125
126
  add_index "appstats_results", ["name"], :name => "index_appstats_results_on_name"
126
127
  add_index "appstats_results", ["page"], :name => "index_appstats_results_on_page"
127
128
 
129
+ create_table "appstats_sub_results", :force => true do |t|
130
+ t.integer "appstats_result_id"
131
+ t.string "context_filter"
132
+ t.integer "count"
133
+ t.float "ratio_of_total"
134
+ t.datetime "created_at"
135
+ t.datetime "updated_at"
136
+ end
137
+
138
+ add_index "appstats_sub_results", ["context_filter"], :name => "index_appstats_sub_results_on_context_filter"
139
+
128
140
  create_table "appstats_test_objects", :force => true do |t|
129
141
  t.string "name"
130
142
  t.datetime "created_at"
@@ -13,6 +13,7 @@ require "#{File.dirname(__FILE__)}/appstats/log_collector"
13
13
  require "#{File.dirname(__FILE__)}/appstats/parser"
14
14
  require "#{File.dirname(__FILE__)}/appstats/query"
15
15
  require "#{File.dirname(__FILE__)}/appstats/result"
16
+ require "#{File.dirname(__FILE__)}/appstats/sub_result"
16
17
  require "#{File.dirname(__FILE__)}/appstats/result_job"
17
18
  require "#{File.dirname(__FILE__)}/appstats/host"
18
19
  require "#{File.dirname(__FILE__)}/appstats/context_key"
@@ -2,12 +2,13 @@
2
2
  module Appstats
3
3
  class Query
4
4
 
5
- @@parser_template = Appstats::Parser.new(:rules => ":operation :action :date on :host where :contexts")
5
+ @@parser_template = Appstats::Parser.new(:rules => ":operation :action :date on :host where :contexts group by :groups")
6
6
  @@contexts_parser_template = Appstats::Parser.new(:rules => ":context", :repeating => true, :tokenize => "and or || && = <= >= <> != ( ) like")
7
+ @@groups_parser_template = Appstats::Parser.new(:rules => ":filter", :repeating => true, :tokenize => ",")
7
8
 
8
9
  @@nill_query = "select 0 from appstats_entries LIMIT 1"
9
10
  @@default = "1=1"
10
- attr_accessor :name, :query, :action, :host, :date_range, :query_to_sql, :contexts
11
+ attr_accessor :name, :query, :action, :host, :date_range, :query_to_sql, :contexts, :groups, :group_query_to_sql
11
12
 
12
13
  def initialize(data = {})
13
14
  @name = data[:name]
@@ -24,6 +25,17 @@ module Appstats
24
25
  result = Appstats::Result.new(:name => @name, :result_type => @result_type, :query => @query, :query_as_sql => @query_to_sql, :action => @action, :host => @host, :from_date => @date_range.from_date, :to_date => @date_range.to_date, :contexts => @contexts)
25
26
  result.count = ActiveRecord::Base.connection.select_one(@query_to_sql)["count(*)"].to_i
26
27
  result.save
28
+
29
+ unless @groups.empty?
30
+ all_sub_results = ActiveRecord::Base.connection.select_all(@group_query_to_sql)
31
+ all_sub_results.each do |data|
32
+ ratio_of_total = data["num"].to_f / result.count
33
+ sub_result = Appstats::SubResult.new(:context_filter => data["context_filter"], :count => data["num"], :ratio_of_total => ratio_of_total)
34
+ sub_result.result = result
35
+ sub_result.save
36
+ end
37
+ end
38
+ result.reload
27
39
  result
28
40
  end
29
41
 
@@ -101,6 +113,15 @@ module Appstats
101
113
  action.nil? ? action_name : action.name
102
114
  end
103
115
 
116
+ def parse_groups(raw_input)
117
+ group_parser = @@groups_parser_template.dup
118
+ return if (raw_input.blank? || !group_parser.parse(raw_input))
119
+ group_parser.raw_results.each do |entry|
120
+ next if entry.kind_of?(String)
121
+ @groups<< entry[:filter]
122
+ end
123
+ end
124
+
104
125
  def parse_query
105
126
  reset_query
106
127
  return nil_query if @query.nil?
@@ -114,6 +135,7 @@ module Appstats
114
135
  @date_range = DateRange.parse(parser.results[:date])
115
136
  @host = parser.results[:host]
116
137
  @contexts = parser.results[:contexts]
138
+ parse_groups(parser.results[:groups])
117
139
 
118
140
  if @operation == "#"
119
141
  @query_to_sql = "select count(*) from appstats_entries"
@@ -123,6 +145,12 @@ module Appstats
123
145
  @query_to_sql += " and #{Query.contexts_filter_to_sql(@contexts)}" unless @contexts.nil?
124
146
  end
125
147
 
148
+ unless @groups.empty?
149
+ query_to_sql_with_id = @query_to_sql.sub("count(*)","id")
150
+ group_as_sql = @groups.collect { |g| "'#{Query.sqlclean(g)}'" }.join(',')
151
+ @group_query_to_sql = "select context_filter, count(*) num from (select group_concat(appstats_contexts.context_value separator ', ') as context_filter, appstats_entry_id from appstats_contexts where context_key in (#{group_as_sql}) and appstats_entry_id in ( #{query_to_sql_with_id} ) group by appstats_entry_id) results group by context_filter;"
152
+ end
153
+
126
154
  @query_to_sql
127
155
  end
128
156
 
@@ -138,6 +166,7 @@ module Appstats
138
166
  def nil_query
139
167
  @query_to_sql = @@nill_query
140
168
  @query_to_sql
169
+ @group_query_to_sql = nil
141
170
  end
142
171
 
143
172
  def reset_query
@@ -145,6 +174,7 @@ module Appstats
145
174
  @host = nil
146
175
  nil_query
147
176
  @date_range = DateRange.new
177
+ @groups = []
148
178
  end
149
179
 
150
180
  end
@@ -3,6 +3,7 @@ module Appstats
3
3
  set_table_name "appstats_results"
4
4
 
5
5
  attr_accessible :name, :result_type, :query, :query_as_sql, :count, :action, :host, :from_date, :to_date, :contexts
6
+ has_many :sub_results, :table_name => 'appstats_subresults', :foreign_key => 'appstats_result_id', :order => 'count DESC'
6
7
 
7
8
  def date_to_s
8
9
  return "" if from_date.nil? && to_date.nil?
@@ -0,0 +1,26 @@
1
+ module Appstats
2
+ class SubResult < ActiveRecord::Base
3
+ set_table_name "appstats_sub_results"
4
+
5
+ attr_accessible :context_filter, :count, :ratio_of_total
6
+ belongs_to :result, :foreign_key => "appstats_result_id"
7
+
8
+ def total_count
9
+ return 0 if result.nil?
10
+ result.count
11
+ end
12
+
13
+ def ==(o)
14
+ o.class == self.class && o.send(:state) == state
15
+ end
16
+ alias_method :eql?, :==
17
+
18
+ private
19
+
20
+ def state
21
+ [context_filter, count, ratio_of_total]
22
+ end
23
+
24
+
25
+ end
26
+ end
@@ -1,3 +1,3 @@
1
1
  module Appstats
2
- VERSION = "0.13.4"
2
+ VERSION = "0.14.0"
3
3
  end
@@ -193,18 +193,18 @@ module Appstats
193
193
  end
194
194
 
195
195
  it "should understand an entry without contexts" do
196
- entry = Entry.create_from_logger_string("0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
196
+ entry = Entry.create_from_logger_string("0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
197
197
  Entry.count.should == @before_count + 1
198
198
  entry.action.should == "address_search"
199
- entry.raw_entry.should == "0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
199
+ entry.raw_entry.should == "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
200
200
  entry.occurred_at.should == Time.parse("2010-09-21 23:15:20")
201
201
  end
202
202
 
203
203
  it "should understand contexts" do
204
- entry = Entry.create_from_logger_string("0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
204
+ entry = Entry.create_from_logger_string("0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
205
205
  Entry.count.should == @before_count + 1
206
206
  entry.action.should == "address_filter"
207
- entry.raw_entry.should == "0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
207
+ entry.raw_entry.should == "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
208
208
  entry.occurred_at.should == Time.parse("2010-09-21 23:15:20")
209
209
  entry.contexts.size.should == 2
210
210
  entry.contexts[0].context_key = "app_name"
@@ -214,10 +214,10 @@ module Appstats
214
214
  end
215
215
 
216
216
  it "should handle 'action' as a context" do
217
- entry = Entry.create_from_logger_string('0.13.4 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : action=save_ovcen : app_name=cdb')
217
+ entry = Entry.create_from_logger_string('0.14.0 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : action=save_ovcen : app_name=cdb')
218
218
  Entry.count.should == @before_count + 1
219
219
  entry.action.should == "page-view"
220
- entry.raw_entry.should == "0.13.4 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : action=save_ovcen : app_name=cdb"
220
+ entry.raw_entry.should == "0.14.0 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : action=save_ovcen : app_name=cdb"
221
221
  entry.occurred_at.should == Time.parse("2011-02-24 12:59:57")
222
222
  entry.contexts.size.should == 2
223
223
  entry.contexts[0].context_key = "action"
@@ -228,10 +228,10 @@ module Appstats
228
228
  end
229
229
 
230
230
  it "should handle multiple of the same 'context'" do
231
- entry = Entry.create_from_logger_string('0.13.4 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : app_name=market : app_name=cdb')
231
+ entry = Entry.create_from_logger_string('0.14.0 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : app_name=market : app_name=cdb')
232
232
  Entry.count.should == @before_count + 1
233
233
  entry.action.should == "page-view"
234
- entry.raw_entry.should == "0.13.4 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : app_name=market : app_name=cdb"
234
+ entry.raw_entry.should == "0.14.0 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : app_name=market : app_name=cdb"
235
235
  entry.occurred_at.should == Time.parse("2011-02-24 12:59:57")
236
236
  entry.contexts.size.should == 2
237
237
  entry.contexts[0].context_key = "app_name"
@@ -115,12 +115,12 @@ module Appstats
115
115
 
116
116
  it "should accept numbers" do
117
117
  Appstats::Logger.entry(5, :blah => 6)
118
- Appstats::Logger.raw_read.should == ["0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=5 : blah=6"]
118
+ Appstats::Logger.raw_read.should == ["0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=5 : blah=6"]
119
119
  end
120
120
 
121
121
  it "should accept arrays" do
122
122
  Appstats::Logger.entry('search', :provider => [ 'one', 'two' ])
123
- Appstats::Logger.raw_read.should == ["0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=search : provider=one : provider=two"]
123
+ Appstats::Logger.raw_read.should == ["0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=search : provider=one : provider=two"]
124
124
  end
125
125
 
126
126
 
@@ -130,7 +130,7 @@ module Appstats
130
130
 
131
131
  it "should look similar to regular entry" do
132
132
  Appstats::Logger.exception_entry(RuntimeError.new("blah"),:on => "login")
133
- Appstats::Logger.raw_read.should == ["0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=appstats-exception : error=blah : on=login"]
133
+ Appstats::Logger.raw_read.should == ["0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=appstats-exception : error=blah : on=login"]
134
134
  end
135
135
 
136
136
  end
@@ -147,47 +147,47 @@ module Appstats
147
147
 
148
148
  it "should handle a statistics entry" do
149
149
  expected = { :action => "address_search", :timestamp => "2010-09-21 23:15:20" }
150
- actual = Appstats::Logger.entry_to_hash("0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
150
+ actual = Appstats::Logger.entry_to_hash("0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
151
151
  actual.should == expected
152
152
  end
153
153
 
154
154
  it "should handle contexts" do
155
155
  expected = { :action => "address_filter", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
156
- actual = Appstats::Logger.entry_to_hash("0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
156
+ actual = Appstats::Logger.entry_to_hash("0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
157
157
  actual.should == expected
158
158
  end
159
159
 
160
160
  it "should handle multiple actions" do
161
161
  expected = { :action => ["address_filter", "blah"], :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
162
- actual = Appstats::Logger.entry_to_hash("0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : action=blah : app_name=Market : server=Live")
162
+ actual = Appstats::Logger.entry_to_hash("0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : action=blah : app_name=Market : server=Live")
163
163
  actual.should == expected
164
164
  end
165
165
 
166
166
  it "should handle multiple of same context" do
167
167
  expected = { :action => "address_filter", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => ['Sin','Market'] }
168
- actual = Appstats::Logger.entry_to_hash("0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Sin : app_name=Market : server=Live")
168
+ actual = Appstats::Logger.entry_to_hash("0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Sin : app_name=Market : server=Live")
169
169
  actual.should == expected
170
170
  end
171
171
 
172
172
  it "should handle no actions" do
173
173
  expected = { :action => "UNKNOWN_ACTION", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
174
- actual = Appstats::Logger.entry_to_hash("0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 app_name=Market : server=Live")
174
+ actual = Appstats::Logger.entry_to_hash("0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 app_name=Market : server=Live")
175
175
  actual.should == expected
176
176
  end
177
177
 
178
178
  it "should handle actions with the delimiter (and change the delimiter)" do
179
179
  expected = { :action => "address:=search-n", :timestamp => "2010-09-21 23:15:20" }
180
- actual = Appstats::Logger.entry_to_hash("0.13.4 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n")
180
+ actual = Appstats::Logger.entry_to_hash("0.14.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n")
181
181
  actual.should == expected
182
182
 
183
183
  expected = { :action => "address::search==--n", :timestamp => "2010-09-21 23:15:20" }
184
- actual = Appstats::Logger.entry_to_hash("0.13.4 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n")
184
+ actual = Appstats::Logger.entry_to_hash("0.14.0 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n")
185
185
  actual.should == expected
186
186
  end
187
187
 
188
188
  it "should handle contexts with the delimiter (and change the delimiter)" do
189
189
  expected = { :action => "address", :timestamp => "2010-09-21 23:15:20", :server => "market:eval=-n" }
190
- actual = Appstats::Logger.entry_to_hash("0.13.4 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n")
190
+ actual = Appstats::Logger.entry_to_hash("0.14.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n")
191
191
  actual.should == expected
192
192
  end
193
193
 
@@ -196,66 +196,66 @@ module Appstats
196
196
  describe "#entry_to_s" do
197
197
 
198
198
  it "should handle a statistics entry" do
199
- expected = "0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
199
+ expected = "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
200
200
  actual = Appstats::Logger.entry_to_s("address_search")
201
201
  actual.should == expected
202
202
  end
203
203
 
204
204
  it "should handle numbers" do
205
- expected = "0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=1 : note=2.2"
205
+ expected = "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=1 : note=2.2"
206
206
  actual = Appstats::Logger.entry_to_s(1,:note => 2.2)
207
207
  actual.should == expected
208
208
  end
209
209
 
210
210
  it "should handle default contexts" do
211
211
  Appstats::Logger.default_contexts[:app_name] = "market"
212
- expected = "0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : app_name=market"
212
+ expected = "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : app_name=market"
213
213
  actual = Appstats::Logger.entry_to_s("address_search")
214
214
  actual.should == expected
215
215
  end
216
216
 
217
217
  it "should handle contexts (and sort them by symbol)" do
218
- expected = "0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
218
+ expected = "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
219
219
  actual = Appstats::Logger.entry_to_s("address_filter", { :server => "Live", :app_name => 'Market' })
220
220
  actual.should == expected
221
221
  end
222
222
 
223
223
  it "should handle actions with the delimiter (and change the delimiter)" do
224
- expected = "0.13.4 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n"
224
+ expected = "0.14.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n"
225
225
  actual = Appstats::Logger.entry_to_s("address:=search-n")
226
226
  actual.should == expected
227
227
 
228
- expected = "0.13.4 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n"
228
+ expected = "0.14.0 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n"
229
229
  actual = Appstats::Logger.entry_to_s("address::search==--n")
230
230
  actual.should == expected
231
231
  end
232
232
 
233
233
  it "should handle contexts with the delimiter (and change the delimiter)" do
234
- expected = "0.13.4 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n"
234
+ expected = "0.14.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n"
235
235
  actual = Appstats::Logger.entry_to_s("address", :server => 'market:eval=-n')
236
236
  actual.should == expected
237
237
  end
238
238
 
239
239
  it "should ignore spaces" do
240
- expected = "0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=address search"
240
+ expected = "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address search"
241
241
  actual = Appstats::Logger.entry_to_s("address search")
242
242
  actual.should == expected
243
243
  end
244
244
 
245
245
  it "should convert newlines in action" do
246
- expected = "0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=address_-nsearch"
246
+ expected = "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_-nsearch"
247
247
  actual = Appstats::Logger.entry_to_s("address_\nsearch")
248
248
  actual.should == expected
249
249
  end
250
250
 
251
251
  it "should convert newlines in context" do
252
- expected = "0.13.4 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : blah=some-nlong-nstatement"
252
+ expected = "0.14.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : blah=some-nlong-nstatement"
253
253
  actual = Appstats::Logger.entry_to_s("address_search",:blah => "some\nlong\nstatement")
254
254
  actual.should == expected
255
255
  end
256
256
 
257
257
  it "should convert newlines based on the delimiter" do
258
- expected = "0.13.4 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=--nsearch-n"
258
+ expected = "0.14.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=--nsearch-n"
259
259
  actual = Appstats::Logger.entry_to_s("address:=\nsearch-n")
260
260
  actual.should == expected
261
261
  end
@@ -32,7 +32,8 @@ module Appstats
32
32
  query.action.should == nil
33
33
  query.host.should == nil
34
34
  query.date_range.should == DateRange.new
35
-
35
+ query.groups.should == []
36
+ query.group_query_to_sql.should == nil
36
37
  end
37
38
 
38
39
  it "should set the action and host" do
@@ -40,6 +41,8 @@ module Appstats
40
41
  query.action.should == "myblahs"
41
42
  query.host.should == "xyz.localnet"
42
43
  query.date_range.should == DateRange.parse("today")
44
+ query.groups.should == []
45
+ query.group_query_to_sql.should == nil
43
46
  end
44
47
 
45
48
  it "should understand the short hand 'on' instead of 'on server'" do
@@ -47,6 +50,8 @@ module Appstats
47
50
  query.action.should == "myblahs"
48
51
  query.host.should == "xyz.localnet"
49
52
  query.date_range.should == DateRange.new
53
+ query.groups.should == []
54
+ query.group_query_to_sql.should == nil
50
55
  end
51
56
 
52
57
  it "should understand the old 'on server' instead of new 'on'" do
@@ -54,7 +59,24 @@ module Appstats
54
59
  query.action.should == "myblahs"
55
60
  query.host.should == "xyz.localnet"
56
61
  query.date_range.should == DateRange.new
62
+ query.groups.should == []
63
+ query.group_query_to_sql.should == nil
64
+ end
65
+
66
+ describe "group by" do
67
+
68
+ it "should handle single entry" do
69
+ query = Appstats::Query.new(:query => "# myblahs group by aa")
70
+ query.groups.should == ["aa"]
71
+ end
72
+
73
+ it "should handle multi-entry" do
74
+ query = Appstats::Query.new(:query => "# myblahs group by aa,bbbb")
75
+ query.groups.should == ["aa","bbbb"]
76
+ end
77
+
57
78
  end
79
+
58
80
 
59
81
  end
60
82
 
@@ -64,102 +86,130 @@ module Appstats
64
86
  Appstats::Entry.delete_all
65
87
  end
66
88
 
67
- it "should return 0 if no results" do
68
- query = Appstats::Query.new(:query => "# blahs")
69
- result = query.run
70
- result.new_record?.should == false
71
- result.should == Appstats::Result.new(:result_type => "on_demand", :query => "# blahs", :query_as_sql => query.query_to_sql, :count => 0, :action => "blahs")
72
- end
89
+ describe "core search" do
90
+ it "should return 0 if no results" do
91
+ query = Appstats::Query.new(:query => "# blahs")
92
+ result = query.run
93
+ result.new_record?.should == false
94
+ result.should == Appstats::Result.new(:result_type => "on_demand", :query => "# blahs", :query_as_sql => query.query_to_sql, :count => 0, :action => "blahs")
95
+ end
73
96
 
74
- it "should set name and result_type if provided" do
75
- query = Appstats::Query.new(:name => "x", :result_type => "some_reason", :query => "# blahs")
76
- result = query.run
77
- result.new_record?.should == false
78
- result.should == Appstats::Result.new(:name => "x", :result_type => "some_reason", :query => "# blahs", :query_as_sql => query.query_to_sql, :count => 0, :action => "blahs")
79
- end
80
-
81
- it "should track contexts" do
82
- query = Appstats::Query.new(:query => "# blahs where (a=b and c=4) or (aaa=5)")
83
- result = query.run
84
- result.new_record?.should == false
85
- result.contexts.should == "(a=b and c=4) or (aaa=5)"
86
- end
87
-
88
-
89
- it "should track the count if available" do
90
- Appstats::Entry.create(:action => "myblahs")
91
- query = Appstats::Query.new(:query => "# myblahs")
92
- query.run.count.should == 1
93
- Appstats::Entry.create(:action => "myblahs")
94
- query.run.count.should == 2
95
- end
97
+ it "should set name and result_type if provided" do
98
+ query = Appstats::Query.new(:name => "x", :result_type => "some_reason", :query => "# blahs")
99
+ result = query.run
100
+ result.new_record?.should == false
101
+ result.should == Appstats::Result.new(:name => "x", :result_type => "some_reason", :query => "# blahs", :query_as_sql => query.query_to_sql, :count => 0, :action => "blahs")
102
+ end
96
103
 
97
- it "should not double count an entry with multiple contexts" do
98
- Appstats::Entry.create_from_logger("myblahs",:app_name => ["a","b"])
99
- query = Appstats::Query.new(:query => "# myblahs where app_name='a' or app_name = 'b'")
100
- query.run.count.should == 1
104
+ it "should track contexts" do
105
+ query = Appstats::Query.new(:query => "# blahs where (a=b and c=4) or (aaa=5)")
106
+ result = query.run
107
+ result.new_record?.should == false
108
+ result.contexts.should == "(a=b and c=4) or (aaa=5)"
109
+ end
101
110
 
102
- Appstats::Entry.create_from_logger("myblahs",:app_name => ["a","c"])
103
- Appstats::Entry.create_from_logger("myblahs",:app_name => ["b","d"])
104
- Appstats::Entry.create_from_logger("myblahs",:app_name => ["c","d"])
105
- query = Appstats::Query.new(:query => "# myblahs where app_name='a' or app_name = 'b'")
106
- query.run.count.should == 3
107
111
 
108
- end
112
+ it "should track the count if available" do
113
+ Appstats::Entry.create(:action => "myblahs")
114
+ query = Appstats::Query.new(:query => "# myblahs")
115
+ query.run.count.should == 1
116
+ Appstats::Entry.create(:action => "myblahs")
117
+ query.run.count.should == 2
118
+ end
109
119
 
110
-
111
- it "should perform the action search" do
112
- Appstats::Entry.create_from_logger("myblahs", :one => "11", :two => "222")
113
- Appstats::Entry.create_from_logger("myblahs", :one => "111", :two => "22")
114
-
115
- query = Appstats::Query.new(:query => "# myblahs where one=11")
116
- result = query.run
117
- result.count.should == 1
118
-
119
- query = Appstats::Query.new(:query => "# myblahs where one=anything")
120
- query.run.count.should == 0
121
-
122
- query = Appstats::Query.new(:query => "# myblahs where one=11 && two=22")
123
- query.run.count.should == 0
124
-
125
- query = Appstats::Query.new(:query => "# myblahs where one=11 || two=22")
126
- query.run.count.should == 2
127
- end
128
-
129
- describe "fixed_points searches" do
120
+ it "should not double count an entry with multiple contexts" do
121
+ Appstats::Entry.create_from_logger("myblahs",:app_name => ["a","b"])
122
+ query = Appstats::Query.new(:query => "# myblahs where app_name='a' or app_name = 'b'")
123
+ query.run.count.should == 1
130
124
 
131
- it "should handle year" do
132
- query = Appstats::Query.new(:query => "# myblahs last year")
133
- result = query.run
134
- result.date_to_s.should == "2009-01-01 to 2009-12-31"
135
- end
125
+ Appstats::Entry.create_from_logger("myblahs",:app_name => ["a","c"])
126
+ Appstats::Entry.create_from_logger("myblahs",:app_name => ["b","d"])
127
+ Appstats::Entry.create_from_logger("myblahs",:app_name => ["c","d"])
128
+ query = Appstats::Query.new(:query => "# myblahs where app_name='a' or app_name = 'b'")
129
+ query.run.count.should == 3
136
130
 
137
- it "should handle quarter" do
138
- query = Appstats::Query.new(:query => "# myblahs last quarter")
139
- result = query.run
140
- result.date_to_s.should == "2010-04-01 to 2010-06-30"
141
131
  end
142
132
 
143
- it "should handle month" do
144
- query = Appstats::Query.new(:query => "# myblahs last month")
133
+
134
+ it "should perform the action search" do
135
+ Appstats::Entry.create_from_logger("myblahs", :one => "11", :two => "222")
136
+ Appstats::Entry.create_from_logger("myblahs", :one => "111", :two => "22")
137
+
138
+ query = Appstats::Query.new(:query => "# myblahs where one=11")
145
139
  result = query.run
146
- result.date_to_s.should == "2010-08-01 to 2010-08-31"
140
+ result.count.should == 1
141
+
142
+ query = Appstats::Query.new(:query => "# myblahs where one=anything")
143
+ query.run.count.should == 0
144
+
145
+ query = Appstats::Query.new(:query => "# myblahs where one=11 && two=22")
146
+ query.run.count.should == 0
147
+
148
+ query = Appstats::Query.new(:query => "# myblahs where one=11 || two=22")
149
+ query.run.count.should == 2
147
150
  end
148
151
 
149
- it "should handle week" do
150
- query = Appstats::Query.new(:query => "# myblahs last week")
152
+ describe "fixed_points searches" do
153
+
154
+ it "should handle year" do
155
+ query = Appstats::Query.new(:query => "# myblahs last year")
156
+ result = query.run
157
+ result.date_to_s.should == "2009-01-01 to 2009-12-31"
158
+ end
159
+
160
+ it "should handle quarter" do
161
+ query = Appstats::Query.new(:query => "# myblahs last quarter")
162
+ result = query.run
163
+ result.date_to_s.should == "2010-04-01 to 2010-06-30"
164
+ end
165
+
166
+ it "should handle month" do
167
+ query = Appstats::Query.new(:query => "# myblahs last month")
168
+ result = query.run
169
+ result.date_to_s.should == "2010-08-01 to 2010-08-31"
170
+ end
171
+
172
+ it "should handle week" do
173
+ query = Appstats::Query.new(:query => "# myblahs last week")
174
+ result = query.run
175
+ result.date_to_s.should == "2010-09-13 to 2010-09-19"
176
+ end
177
+
178
+ it "should handle day" do
179
+ query = Appstats::Query.new(:query => "# myblahs last day")
180
+ result = query.run
181
+ result.date_to_s.should == "2010-09-20"
182
+ end
183
+ end
184
+ end
185
+
186
+ describe "group sub results" do
187
+
188
+ it "should not create sub results if no groups" do
189
+ query = Appstats::Query.new(:query => "# myblahs last day")
151
190
  result = query.run
152
- result.date_to_s.should == "2010-09-13 to 2010-09-19"
191
+ result.sub_results.should == []
153
192
  end
154
193
 
155
- it "should handle day" do
156
- query = Appstats::Query.new(:query => "# myblahs last day")
194
+ it "should track sub results as required" do
195
+ Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :ignore => "1")
196
+ Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :ignore => "1")
197
+ Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :ignore => "2")
198
+ Appstats::Entry.create_from_logger("myblahs",:service_provider => "b", :ignore => "1")
199
+
200
+ query = Appstats::Query.new(:query => "# myblahs group by service_provider")
157
201
  result = query.run
158
- result.date_to_s.should == "2010-09-20"
202
+ result.count.should == 4
203
+ result.sub_results.size.should == 2
204
+
205
+ result.sub_results[0].should == SubResult.new(:context_filter => "a", :count => 3, :ratio_of_total => 0.75)
206
+ result.sub_results[1].should == SubResult.new(:context_filter => "b", :count => 1, :ratio_of_total => 0.25)
207
+
208
+
159
209
  end
160
210
 
211
+
161
212
  end
162
-
163
213
 
164
214
  end
165
215
 
@@ -252,6 +302,45 @@ module Appstats
252
302
 
253
303
  end
254
304
 
305
+ describe "#group_query_to_sql" do
306
+
307
+ before(:each) do
308
+ @template = "select id from appstats_entries where action = 'myblahs'"
309
+ end
310
+
311
+ it "should support no filters" do
312
+ query = Appstats::Query.new(:query => "# myblahs")
313
+ query.group_query_to_sql.should == nil
314
+ end
315
+
316
+ it "should support 1 filter" do
317
+ query = Appstats::Query.new(:query => "# myblahs group by aa")
318
+ expected = "select context_filter, count(*) num from (select group_concat(appstats_contexts.context_value separator ', ') as context_filter, appstats_entry_id from appstats_contexts where context_key in ('aa') and appstats_entry_id in ( #{@template} ) group by appstats_entry_id) results group by context_filter;"
319
+ query.group_query_to_sql.should == expected
320
+ end
321
+
322
+ it "should support surrounding quotes" do
323
+ query = Appstats::Query.new(:query => "# myblahs group by 'aa'")
324
+ expected = "select context_filter, count(*) num from (select group_concat(appstats_contexts.context_value separator ', ') as context_filter, appstats_entry_id from appstats_contexts where context_key in ('aa') and appstats_entry_id in ( #{@template} ) group by appstats_entry_id) results group by context_filter;"
325
+ query.group_query_to_sql.should == expected
326
+ end
327
+
328
+ it "should support inner quotes" do
329
+ query = Appstats::Query.new(:query => "# myblahs group by a's")
330
+ expected = "select context_filter, count(*) num from (select group_concat(appstats_contexts.context_value separator ', ') as context_filter, appstats_entry_id from appstats_contexts where context_key in ('a''s') and appstats_entry_id in ( #{@template} ) group by appstats_entry_id) results group by context_filter;"
331
+ query.group_query_to_sql.should == expected
332
+ end
333
+
334
+
335
+ it "should support many filters" do
336
+ query = Appstats::Query.new(:query => "# myblahs group by aa, bbb")
337
+ expected = "select context_filter, count(*) num from (select group_concat(appstats_contexts.context_value separator ', ') as context_filter, appstats_entry_id from appstats_contexts where context_key in ('aa','bbb') and appstats_entry_id in ( #{@template} ) group by appstats_entry_id) results group by context_filter;"
338
+ query.group_query_to_sql.should == expected
339
+ end
340
+
341
+
342
+ end
343
+
255
344
  describe "#contexts_filter_to_sql" do
256
345
 
257
346
  before(:each) do
@@ -126,6 +126,30 @@ module Appstats
126
126
  end
127
127
 
128
128
  end
129
+
130
+ describe "#sub_results" do
131
+
132
+ it "should be empty be default" do
133
+ @result.sub_results.should == []
134
+ end
135
+
136
+ it "should order by count" do
137
+ @result = Result.create
138
+ sub1 = SubResult.create(:count => 10)
139
+ sub2 = SubResult.create(:count => 20)
140
+ sub3 = SubResult.create(:count => 30)
141
+
142
+ @result.sub_results<< sub1
143
+ @result.sub_results<< sub3
144
+ @result.sub_results<< sub2
145
+
146
+ @result.save.should == true
147
+ @result.reload
148
+
149
+ @result.sub_results.should == [sub3,sub2,sub1]
150
+ end
151
+
152
+ end
129
153
 
130
154
  end
131
155
  end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ module Appstats
4
+ describe SubResult do
5
+
6
+ before(:each) do
7
+ @sub_result = Appstats::SubResult.new
8
+ Time.stub!(:now).and_return(Time.parse('2010-09-21 23:15:20'))
9
+ end
10
+
11
+ describe "#initialize" do
12
+
13
+ it "should set attributes to nil" do
14
+ @sub_result.context_filter.should == nil
15
+ @sub_result.count.should == nil
16
+ @sub_result.ratio_of_total.should == nil
17
+ end
18
+
19
+ it "should set on constructor" do
20
+ sub_result = Appstats::SubResult.new(:context_filter => 'a', :count => 1, :ratio_of_total => 0.2)
21
+ sub_result.context_filter.should == 'a'
22
+ sub_result.count.should == 1
23
+ sub_result.ratio_of_total.should == 0.2
24
+ end
25
+
26
+ end
27
+
28
+ describe "#result" do
29
+
30
+ it "should be nil be default" do
31
+ @sub_result.result.should == nil
32
+ end
33
+
34
+ it "should be settable" do
35
+ @result = Result.create
36
+ @sub_result.result = @result
37
+ @sub_result.save.should == true
38
+
39
+ @sub_result.reload
40
+ @result.reload
41
+
42
+ @sub_result.result.should == @result
43
+ @result.sub_results.should == [@sub_result]
44
+ end
45
+
46
+ end
47
+
48
+ describe "#==" do
49
+
50
+ it "should be equal on all attributes" do
51
+ sub_result = Appstats::SubResult.new(:context_filter => 'a', :count => 1, :ratio_of_total => 0.2)
52
+ same_sub_result = Appstats::SubResult.new(:context_filter => 'a', :count => 1, :ratio_of_total => 0.2)
53
+ (sub_result == same_sub_result).should == true
54
+ end
55
+
56
+ it "should be not equal if diferent attributes" do
57
+ sub_result = Appstats::SubResult.new(:context_filter => 'a', :count => 1, :ratio_of_total => 0.2)
58
+
59
+ [:context_filter,:count,:ratio_of_total].each do |attr|
60
+ different_sub_result = Appstats::SubResult.new(:context_filter => 'a', :count => 1, :ratio_of_total => 0.2)
61
+ different_sub_result.context_filter = "XXX" if attr == :context_filter
62
+ different_sub_result.count = 11 if attr == :count
63
+ different_sub_result.ratio_of_total = 0.22 if attr == :ratio_of_total
64
+
65
+ different_sub_result.should_not == sub_result
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ describe "#total_count" do
72
+
73
+ it "should be zero if no result" do
74
+ @sub_result.total_count.should == 0
75
+ end
76
+
77
+ it "should be based on result.count" do
78
+ @sub_result.result = Result.create(:count => 10)
79
+ @sub_result.total_count.should == 10
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appstats
3
3
  version: !ruby/object:Gem::Version
4
- hash: 35
4
+ hash: 39
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 13
9
- - 4
10
- version: 0.13.4
8
+ - 14
9
+ - 0
10
+ version: 0.14.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Andrew Forward
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-02-28 00:00:00 -05:00
18
+ date: 2011-03-01 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -159,6 +159,8 @@ files:
159
159
  - db/migrations/20110222215437_create_appstats_jobs.rb
160
160
  - db/migrations/20110223212232_add_appstats_entries_week_and_quarter.rb
161
161
  - db/migrations/20110225192624_add_appstats_log_collector_local_filename.rb
162
+ - db/migrations/20110301170733_add_appstats_results_group_query_to_sql.rb
163
+ - db/migrations/20110301170947_create_appstats_sub_results.rb
162
164
  - db/schema.rb
163
165
  - lib/appstats.rb
164
166
  - lib/appstats/action.rb
@@ -177,6 +179,7 @@ files:
177
179
  - lib/appstats/query.rb
178
180
  - lib/appstats/result.rb
179
181
  - lib/appstats/result_job.rb
182
+ - lib/appstats/sub_result.rb
180
183
  - lib/appstats/tasks.rb
181
184
  - lib/appstats/test_object.rb
182
185
  - lib/appstats/version.rb
@@ -217,6 +220,7 @@ files:
217
220
  - spec/result_job_spec.rb
218
221
  - spec/result_spec.rb
219
222
  - spec/spec_helper.rb
223
+ - spec/sub_result_spec.rb
220
224
  - spec/test_object_spec.rb
221
225
  has_rdoc: true
222
226
  homepage: http://github.com/aforward/appstats
@@ -270,4 +274,5 @@ test_files:
270
274
  - spec/result_job_spec.rb
271
275
  - spec/result_spec.rb
272
276
  - spec/spec_helper.rb
277
+ - spec/sub_result_spec.rb
273
278
  - spec/test_object_spec.rb