appstats 0.20.2 → 0.20.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/lib/appstats/context_key.rb +12 -0
- data/lib/appstats/parser.rb +30 -4
- data/lib/appstats/query.rb +27 -5
- data/lib/appstats/version.rb +1 -1
- data/spec/context_key_spec.rb +33 -0
- data/spec/entry_spec.rb +8 -8
- data/spec/logger_spec.rb +22 -22
- data/spec/parser_spec.rb +22 -3
- data/spec/query_spec.rb +120 -1
- metadata +4 -4
data/Gemfile.lock
CHANGED
data/lib/appstats/context_key.rb
CHANGED
@@ -4,6 +4,18 @@ module Appstats
|
|
4
4
|
|
5
5
|
attr_accessible :name, :status
|
6
6
|
|
7
|
+
def self.rename(old_key,new_key)
|
8
|
+
sql = ["update appstats_context_keys set name = ?, updated_at = ? where name = ?",new_key,Time.now,old_key]
|
9
|
+
ActiveRecord::Base.connection.update(ActiveRecord::Base.send(:sanitize_sql_array, sql))
|
10
|
+
|
11
|
+
sql = ["update appstats_contexts set context_key = ?, updated_at = ? where context_key = ?",new_key,Time.now,old_key]
|
12
|
+
ActiveRecord::Base.connection.update(ActiveRecord::Base.send(:sanitize_sql_array, sql))
|
13
|
+
|
14
|
+
sql = ["update appstats_action_context_keys set context_key = ?, updated_at = ? where context_key = ?",new_key,Time.now,old_key]
|
15
|
+
ActiveRecord::Base.connection.update(ActiveRecord::Base.send(:sanitize_sql_array, sql))
|
16
|
+
|
17
|
+
end
|
18
|
+
|
7
19
|
def self.update_context_keys
|
8
20
|
sql = "select distinct(context_key) from appstats_contexts where context_key not in (select name from appstats_context_keys)"
|
9
21
|
count = 0
|
data/lib/appstats/parser.rb
CHANGED
@@ -194,14 +194,40 @@ module Appstats
|
|
194
194
|
@tokenize_regex = nil
|
195
195
|
@tokenize_regex_no_spaces = nil
|
196
196
|
return if @raw_tokenize.blank?
|
197
|
+
is_multi_work_token = false
|
198
|
+
current_token = nil
|
197
199
|
@raw_tokenize.split(" ").each do |token|
|
198
|
-
|
200
|
+
|
201
|
+
start_token = token.starts_with?("'")
|
202
|
+
end_token = is_multi_work_token and token.ends_with?("'")
|
203
|
+
mid_token = !start_token && !end_token && is_multi_work_token
|
204
|
+
add_token = false
|
205
|
+
|
206
|
+
if start_token
|
207
|
+
current_token = token.upcase[1..-1]
|
208
|
+
is_multi_work_token = true
|
209
|
+
elsif mid_token
|
210
|
+
current_token = "#{current_token}#{token.upcase}"
|
211
|
+
elsif end_token
|
212
|
+
current_token = "#{current_token}#{token.upcase.chop}"
|
213
|
+
is_multi_work_token = false
|
214
|
+
add_token = true
|
215
|
+
else
|
216
|
+
current_token = token.upcase
|
217
|
+
add_token = true
|
218
|
+
end
|
219
|
+
|
199
220
|
current_token.gsub!("(",'\(')
|
200
221
|
current_token.gsub!(")",'\)')
|
201
222
|
current_token.gsub!("|",'\|')
|
202
|
-
|
203
|
-
|
204
|
-
|
223
|
+
|
224
|
+
if add_token
|
225
|
+
@tokenize_no_spaces<< current_token
|
226
|
+
current_token = "\\s+#{current_token}(\\s|$)" unless current_token.match(/.*[a-z].*/i).nil?
|
227
|
+
@tokenize<< current_token
|
228
|
+
else is_multi_work_token
|
229
|
+
current_token = "#{current_token}\\s+"
|
230
|
+
end
|
205
231
|
end
|
206
232
|
@tokenize_regex_no_spaces = @tokenize_no_spaces.join("|")
|
207
233
|
@tokenize_regex = @tokenize.join("|")
|
data/lib/appstats/query.rb
CHANGED
@@ -3,7 +3,7 @@ module Appstats
|
|
3
3
|
class Query
|
4
4
|
|
5
5
|
@@parser_template = Appstats::Parser.new(:rules => ":operation :action :date on :host where :contexts group by :group_by")
|
6
|
-
@@contexts_parser_template = Appstats::Parser.new(:rules => ":context", :repeating => true, :tokenize => "and or || && = <= >= <> < > !=
|
6
|
+
@@contexts_parser_template = Appstats::Parser.new(:rules => ":context", :repeating => true, :tokenize => "( ) and or || && = <= >= <> < > != like 'not like' in")
|
7
7
|
@@group_by_parser_template = Appstats::Parser.new(:rules => ":filter", :repeating => true, :tokenize => ",")
|
8
8
|
|
9
9
|
@@nill_query = "select 0 from appstats_entries LIMIT 1"
|
@@ -35,6 +35,19 @@ module Appstats
|
|
35
35
|
|
36
36
|
end
|
37
37
|
|
38
|
+
def find(job_frequency_if_not_available = 'once')
|
39
|
+
result = Appstats::Result.where("query = ? and is_latest = 1",@query).first
|
40
|
+
if result.nil?
|
41
|
+
if job_frequency_if_not_available.nil?
|
42
|
+
result = run
|
43
|
+
else
|
44
|
+
job_frequency_if_not_available = "once" if job_frequency_if_not_available == true
|
45
|
+
Appstats::ResultJob.create(:name => "Missing Query#find requested", :frequency => job_frequency_if_not_available, :query => @query, :query_type => @query_type)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
result
|
49
|
+
end
|
50
|
+
|
38
51
|
def run
|
39
52
|
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)
|
40
53
|
unless @group_by.empty?
|
@@ -130,12 +143,12 @@ module Appstats
|
|
130
143
|
if status == :next
|
131
144
|
status = :waiting_comparator
|
132
145
|
@parsed_contexts<< { :context_key => entry[:context] }
|
133
|
-
sql += " (context_key =
|
146
|
+
sql += " (context_key = #{Query.sqlquote(entry[:context])}"
|
134
147
|
else
|
135
148
|
status = :next
|
136
149
|
@parsed_contexts.last[:context_value] = entry[:context]
|
137
150
|
@parsed_contexts.last[:comparator] = comparator
|
138
|
-
sql += " and context_value #{comparator}
|
151
|
+
sql += " and context_value #{comparator} #{Query.sqlquote(entry[:context],comparator)})"
|
139
152
|
end
|
140
153
|
end
|
141
154
|
sql += ")" if status == :waiting_comparator
|
@@ -150,6 +163,15 @@ module Appstats
|
|
150
163
|
input
|
151
164
|
end
|
152
165
|
|
166
|
+
def self.sqlquote(raw_input,comparator = '=')
|
167
|
+
return "NULL" if raw_input.nil?
|
168
|
+
if ["in"].include?(comparator)
|
169
|
+
return "(" + raw_input.split(",").collect { |x| sqlquote(x) }.join (",") + ")"
|
170
|
+
else
|
171
|
+
return "'#{sqlclean(raw_input)}'"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
153
175
|
def self.sqlclean(raw_input)
|
154
176
|
return raw_input if raw_input.blank?
|
155
177
|
m = raw_input.match(/^['"](.*)['"]$/)
|
@@ -164,7 +186,7 @@ module Appstats
|
|
164
186
|
end
|
165
187
|
|
166
188
|
def self.comparators
|
167
|
-
["=","!=","<>",">","<",">=","<=","like"]
|
189
|
+
["=","!=","<>",">","<",">=","<=","like","not like","in"]
|
168
190
|
end
|
169
191
|
|
170
192
|
private
|
@@ -243,7 +265,7 @@ module Appstats
|
|
243
265
|
|
244
266
|
unless @group_by.empty?
|
245
267
|
query_to_sql_with_id = @query_to_sql.sub("count(*) as num","id")
|
246
|
-
group_as_sql = @group_by.collect { |g| "
|
268
|
+
group_as_sql = @group_by.collect { |g| "#{Query.sqlquote(g)}" }.join(',')
|
247
269
|
@group_query_to_sql = "select context_key_filter, context_value_filter, count(*) as num from (select group_concat(appstats_contexts.context_key) as context_key_filter, group_concat(appstats_contexts.context_value) as context_value_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_value_filter"
|
248
270
|
end
|
249
271
|
|
data/lib/appstats/version.rb
CHANGED
data/spec/context_key_spec.rb
CHANGED
@@ -46,6 +46,39 @@ module Appstats
|
|
46
46
|
|
47
47
|
end
|
48
48
|
|
49
|
+
describe "#rename" do
|
50
|
+
|
51
|
+
it "should update the ContextKey" do
|
52
|
+
context_key = Appstats::ContextKey.create(:name => 'a', :status => 'c')
|
53
|
+
Appstats::ContextKey.rename('a','aaa')
|
54
|
+
context_key.reload
|
55
|
+
context_key.name.should == 'aaa'
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should update all Contexts" do
|
59
|
+
context = Appstats::Context.create(:context_key => 'b')
|
60
|
+
context2 = Appstats::Context.create(:context_key => 'notb')
|
61
|
+
Appstats::ContextKey.rename('b','bbb')
|
62
|
+
context.reload and context2.reload
|
63
|
+
|
64
|
+
context.context_key.should == 'bbb'
|
65
|
+
context2.context_key.should == 'notb'
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should update ActionContextKeys" do
|
69
|
+
action = Appstats::ActionContextKey.create(:action_name => 'a', :context_key => 'b', :status => 'c')
|
70
|
+
action2 = Appstats::ActionContextKey.create(:action_name => 'a', :context_key => 'notb', :status => 'c')
|
71
|
+
|
72
|
+
Appstats::ContextKey.rename('b','bbb')
|
73
|
+
action.reload and action2.reload
|
74
|
+
|
75
|
+
action.context_key.should == 'bbb'
|
76
|
+
action2.context_key.should == 'notb'
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
end
|
81
|
+
|
49
82
|
|
50
83
|
end
|
51
84
|
end
|
data/spec/entry_spec.rb
CHANGED
@@ -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.20.
|
196
|
+
entry = Entry.create_from_logger_string("0.20.6 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.20.
|
199
|
+
entry.raw_entry.should == "0.20.6 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.20.
|
204
|
+
entry = Entry.create_from_logger_string("0.20.6 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.20.
|
207
|
+
entry.raw_entry.should == "0.20.6 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.20.
|
217
|
+
entry = Entry.create_from_logger_string('0.20.6 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.20.
|
220
|
+
entry.raw_entry.should == "0.20.6 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.20.
|
231
|
+
entry = Entry.create_from_logger_string('0.20.6 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.20.
|
234
|
+
entry.raw_entry.should == "0.20.6 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"
|
data/spec/logger_spec.rb
CHANGED
@@ -122,12 +122,12 @@ module Appstats
|
|
122
122
|
|
123
123
|
it "should accept numbers" do
|
124
124
|
Appstats::Logger.entry(5, :blah => 6)
|
125
|
-
Appstats::Logger.raw_read.should == ["0.20.
|
125
|
+
Appstats::Logger.raw_read.should == ["0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 action=5 : blah=6"]
|
126
126
|
end
|
127
127
|
|
128
128
|
it "should accept arrays" do
|
129
129
|
Appstats::Logger.entry('search', :provider => [ 'one', 'two' ])
|
130
|
-
Appstats::Logger.raw_read.should == ["0.20.
|
130
|
+
Appstats::Logger.raw_read.should == ["0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 action=search : provider=one : provider=two"]
|
131
131
|
end
|
132
132
|
|
133
133
|
|
@@ -137,7 +137,7 @@ module Appstats
|
|
137
137
|
|
138
138
|
it "should look similar to regular entry" do
|
139
139
|
Appstats::Logger.exception_entry(RuntimeError.new("blah"),:on => "login")
|
140
|
-
Appstats::Logger.raw_read.should == ["0.20.
|
140
|
+
Appstats::Logger.raw_read.should == ["0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 action=appstats-exception : error=blah : on=login"]
|
141
141
|
end
|
142
142
|
|
143
143
|
end
|
@@ -154,47 +154,47 @@ module Appstats
|
|
154
154
|
|
155
155
|
it "should handle a statistics entry" do
|
156
156
|
expected = { :action => "address_search", :timestamp => "2010-09-21 23:15:20" }
|
157
|
-
actual = Appstats::Logger.entry_to_hash("0.20.
|
157
|
+
actual = Appstats::Logger.entry_to_hash("0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
|
158
158
|
actual.should == expected
|
159
159
|
end
|
160
160
|
|
161
161
|
it "should handle contexts" do
|
162
162
|
expected = { :action => "address_filter", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
|
163
|
-
actual = Appstats::Logger.entry_to_hash("0.20.
|
163
|
+
actual = Appstats::Logger.entry_to_hash("0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
|
164
164
|
actual.should == expected
|
165
165
|
end
|
166
166
|
|
167
167
|
it "should handle multiple actions" do
|
168
168
|
expected = { :action => ["address_filter", "blah"], :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
|
169
|
-
actual = Appstats::Logger.entry_to_hash("0.20.
|
169
|
+
actual = Appstats::Logger.entry_to_hash("0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : action=blah : app_name=Market : server=Live")
|
170
170
|
actual.should == expected
|
171
171
|
end
|
172
172
|
|
173
173
|
it "should handle multiple of same context" do
|
174
174
|
expected = { :action => "address_filter", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => ['Sin','Market'] }
|
175
|
-
actual = Appstats::Logger.entry_to_hash("0.20.
|
175
|
+
actual = Appstats::Logger.entry_to_hash("0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Sin : app_name=Market : server=Live")
|
176
176
|
actual.should == expected
|
177
177
|
end
|
178
178
|
|
179
179
|
it "should handle no actions" do
|
180
180
|
expected = { :action => "UNKNOWN_ACTION", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
|
181
|
-
actual = Appstats::Logger.entry_to_hash("0.20.
|
181
|
+
actual = Appstats::Logger.entry_to_hash("0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 app_name=Market : server=Live")
|
182
182
|
actual.should == expected
|
183
183
|
end
|
184
184
|
|
185
185
|
it "should handle actions with the delimiter (and change the delimiter)" do
|
186
186
|
expected = { :action => "address:=search-n", :timestamp => "2010-09-21 23:15:20" }
|
187
|
-
actual = Appstats::Logger.entry_to_hash("0.20.
|
187
|
+
actual = Appstats::Logger.entry_to_hash("0.20.6 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n")
|
188
188
|
actual.should == expected
|
189
189
|
|
190
190
|
expected = { :action => "address::search==--n", :timestamp => "2010-09-21 23:15:20" }
|
191
|
-
actual = Appstats::Logger.entry_to_hash("0.20.
|
191
|
+
actual = Appstats::Logger.entry_to_hash("0.20.6 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n")
|
192
192
|
actual.should == expected
|
193
193
|
end
|
194
194
|
|
195
195
|
it "should handle contexts with the delimiter (and change the delimiter)" do
|
196
196
|
expected = { :action => "address", :timestamp => "2010-09-21 23:15:20", :server => "market:eval=-n" }
|
197
|
-
actual = Appstats::Logger.entry_to_hash("0.20.
|
197
|
+
actual = Appstats::Logger.entry_to_hash("0.20.6 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n")
|
198
198
|
actual.should == expected
|
199
199
|
end
|
200
200
|
|
@@ -203,66 +203,66 @@ module Appstats
|
|
203
203
|
describe "#entry_to_s" do
|
204
204
|
|
205
205
|
it "should handle a statistics entry" do
|
206
|
-
expected = "0.20.
|
206
|
+
expected = "0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
|
207
207
|
actual = Appstats::Logger.entry_to_s("address_search")
|
208
208
|
actual.should == expected
|
209
209
|
end
|
210
210
|
|
211
211
|
it "should handle numbers" do
|
212
|
-
expected = "0.20.
|
212
|
+
expected = "0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 action=1 : note=2.2"
|
213
213
|
actual = Appstats::Logger.entry_to_s(1,:note => 2.2)
|
214
214
|
actual.should == expected
|
215
215
|
end
|
216
216
|
|
217
217
|
it "should handle default contexts" do
|
218
218
|
Appstats::Logger.default_contexts[:app_name] = "market"
|
219
|
-
expected = "0.20.
|
219
|
+
expected = "0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : app_name=market"
|
220
220
|
actual = Appstats::Logger.entry_to_s("address_search")
|
221
221
|
actual.should == expected
|
222
222
|
end
|
223
223
|
|
224
224
|
it "should handle contexts (and sort them by symbol)" do
|
225
|
-
expected = "0.20.
|
225
|
+
expected = "0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
|
226
226
|
actual = Appstats::Logger.entry_to_s("address_filter", { :server => "Live", :app_name => 'Market' })
|
227
227
|
actual.should == expected
|
228
228
|
end
|
229
229
|
|
230
230
|
it "should handle actions with the delimiter (and change the delimiter)" do
|
231
|
-
expected = "0.20.
|
231
|
+
expected = "0.20.6 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n"
|
232
232
|
actual = Appstats::Logger.entry_to_s("address:=search-n")
|
233
233
|
actual.should == expected
|
234
234
|
|
235
|
-
expected = "0.20.
|
235
|
+
expected = "0.20.6 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n"
|
236
236
|
actual = Appstats::Logger.entry_to_s("address::search==--n")
|
237
237
|
actual.should == expected
|
238
238
|
end
|
239
239
|
|
240
240
|
it "should handle contexts with the delimiter (and change the delimiter)" do
|
241
|
-
expected = "0.20.
|
241
|
+
expected = "0.20.6 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n"
|
242
242
|
actual = Appstats::Logger.entry_to_s("address", :server => 'market:eval=-n')
|
243
243
|
actual.should == expected
|
244
244
|
end
|
245
245
|
|
246
246
|
it "should ignore spaces" do
|
247
|
-
expected = "0.20.
|
247
|
+
expected = "0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 action=address search"
|
248
248
|
actual = Appstats::Logger.entry_to_s("address search")
|
249
249
|
actual.should == expected
|
250
250
|
end
|
251
251
|
|
252
252
|
it "should convert newlines in action" do
|
253
|
-
expected = "0.20.
|
253
|
+
expected = "0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 action=address_-nsearch"
|
254
254
|
actual = Appstats::Logger.entry_to_s("address_\nsearch")
|
255
255
|
actual.should == expected
|
256
256
|
end
|
257
257
|
|
258
258
|
it "should convert newlines in context" do
|
259
|
-
expected = "0.20.
|
259
|
+
expected = "0.20.6 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : blah=some-nlong-nstatement"
|
260
260
|
actual = Appstats::Logger.entry_to_s("address_search",:blah => "some\nlong\nstatement")
|
261
261
|
actual.should == expected
|
262
262
|
end
|
263
263
|
|
264
264
|
it "should convert newlines based on the delimiter" do
|
265
|
-
expected = "0.20.
|
265
|
+
expected = "0.20.6 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=--nsearch-n"
|
266
266
|
actual = Appstats::Logger.entry_to_s("address:=\nsearch-n")
|
267
267
|
actual.should == expected
|
268
268
|
end
|
data/spec/parser_spec.rb
CHANGED
@@ -19,7 +19,7 @@ module Appstats
|
|
19
19
|
@parser.constants.should == []
|
20
20
|
@parser.constants_no_spaces.should == []
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
it "should set rules from constructor" do
|
24
24
|
parser = Parser.new(:rules => ":name or :bust", :tokenize => "a bb c", :repeating => true)
|
25
25
|
parser.raw_rules.should == ":name or :bust"
|
@@ -31,6 +31,13 @@ module Appstats
|
|
31
31
|
parser.constants.should == ["\\s+OR(\\s|$)"]
|
32
32
|
parser.constants_no_spaces.should == ["OR"]
|
33
33
|
end
|
34
|
+
|
35
|
+
it "should tokenize multi words" do
|
36
|
+
parser = Parser.new(:rules => ":name or :bust", :tokenize => "a 'not a'", :repeating => true)
|
37
|
+
parser.tokenize.should == ["\\s+A(\\s|$)","\\s+NOT\\s+A(\\s|$)"]
|
38
|
+
parser.tokenize_no_spaces.should == ["A","NOT\\s+A"]
|
39
|
+
end
|
40
|
+
|
34
41
|
|
35
42
|
it "should espace tokens as required" do
|
36
43
|
parser = Parser.new(:tokenize => "( ) abc |")
|
@@ -48,8 +55,7 @@ module Appstats
|
|
48
55
|
it "should end on constant if tokens present" do
|
49
56
|
Parser.new(:rules => ":name", :tokenize => ")").rules.should == [ { :rule => :name, :stop => :end } ]
|
50
57
|
end
|
51
|
-
|
52
|
-
|
58
|
+
|
53
59
|
it "should handle one variable" do
|
54
60
|
Parser.new(:rules => ":name").rules.should == [ { :rule => :name, :stop => :end } ]
|
55
61
|
end
|
@@ -355,6 +361,19 @@ module Appstats
|
|
355
361
|
parser.parse("( ( a = b ) )").should == true
|
356
362
|
parser.raw_results.should == [ "(", "(", { :context_key => "a"}, "=", { :context_value => "b"}, ")", ")" ]
|
357
363
|
end
|
364
|
+
|
365
|
+
it "should handle tokens with spaces" do
|
366
|
+
parser = Parser.new(:rules => ":context", :repeating => true, :tokenize => "like 'not like'")
|
367
|
+
parser.parse("a not like b").should == true
|
368
|
+
parser.raw_results.should == [ { :context => "a"}, "not like", { :context => "b"} ]
|
369
|
+
end
|
370
|
+
|
371
|
+
it "should handle tokens with many spaces" do
|
372
|
+
parser = Parser.new(:rules => ":context", :repeating => true, :tokenize => "like 'not like'")
|
373
|
+
parser.parse("a not like b").should == true
|
374
|
+
parser.raw_results.should == [ { :context => "a"}, "not like", { :context => "b"} ]
|
375
|
+
end
|
376
|
+
|
358
377
|
|
359
378
|
it "should tokenize letters only if spaces between them" do
|
360
379
|
parser = Appstats::Parser.new(:rules => ":one :two", :tokenize => "( aa a1 )")
|
data/spec/query_spec.rb
CHANGED
@@ -120,13 +120,105 @@ module Appstats
|
|
120
120
|
|
121
121
|
end
|
122
122
|
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "#find" do
|
126
|
+
|
127
|
+
before(:each) do
|
128
|
+
Appstats::Entry.delete_all
|
129
|
+
Appstats::Result.delete_all
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "run right away" do
|
133
|
+
|
134
|
+
it "should run the query if it has not been run yet" do
|
135
|
+
Appstats::Entry.create(:action => "myblahs")
|
136
|
+
|
137
|
+
Time.stub!(:now).and_return(Time.parse("2010-09-20"))
|
138
|
+
query = Appstats::Query.new(:query => "# myblahs")
|
139
|
+
query.find(nil).count.should == 1
|
140
|
+
|
141
|
+
Appstats::Entry.create(:action => "myblahs")
|
142
|
+
query.find(nil).count.should == 1
|
143
|
+
|
144
|
+
Time.stub!(:now).and_return(Time.parse("2010-09-21"))
|
145
|
+
query = Appstats::Query.new(:query => "# myblahs")
|
146
|
+
query.run.count.should == 2
|
147
|
+
|
148
|
+
query = Appstats::Query.new(:query => "# myblahs")
|
149
|
+
query.find(nil).count.should == 2
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "do not run right away" do
|
155
|
+
|
156
|
+
it "should return nil no result available" do
|
157
|
+
Appstats::Entry.create(:action => "myblahs")
|
158
|
+
|
159
|
+
query = Appstats::Query.new(:query => "# myblahs")
|
160
|
+
query.find.should == nil
|
161
|
+
|
162
|
+
query = Appstats::Query.new(:query => "# myblahs")
|
163
|
+
query.run.count.should == 1
|
164
|
+
|
165
|
+
query = Appstats::Query.new(:query => "# myblahs")
|
166
|
+
query.find.count.should == 1
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should schedule the query to be run" do
|
170
|
+
|
171
|
+
query = Query.new(:query => "# x", :query_type => "Appstats::TestQuery")
|
172
|
+
query.find.should == nil
|
173
|
+
|
174
|
+
job = Appstats::ResultJob.last
|
175
|
+
job.name.should == "Missing Query#find requested"
|
176
|
+
job.frequency.should == 'once'
|
177
|
+
job.query.should == "# x"
|
178
|
+
job.query_type.should == "Appstats::TestQuery"
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should allow scheduling to be set" do
|
182
|
+
|
183
|
+
query = Query.new(:query => "# myblahs")
|
184
|
+
query.find('daily').should == nil
|
185
|
+
|
186
|
+
job = Appstats::ResultJob.last
|
187
|
+
job.name.should == "Missing Query#find requested"
|
188
|
+
job.frequency.should == 'daily'
|
189
|
+
job.query.should == "# myblahs"
|
190
|
+
job.query_type.should == nil
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
|
123
197
|
end
|
124
198
|
|
125
199
|
describe "#run" do
|
126
200
|
|
127
201
|
before(:each) do
|
128
202
|
Appstats::Entry.delete_all
|
203
|
+
Appstats::Result.delete_all
|
129
204
|
end
|
205
|
+
|
206
|
+
it "should update is_latest accordingly" do
|
207
|
+
Appstats::Entry.create(:action => "myblahs")
|
208
|
+
|
209
|
+
Time.stub!(:now).and_return(Time.parse("2010-09-20"))
|
210
|
+
query = Appstats::Query.new(:query => "# myblahs")
|
211
|
+
result = query.run
|
212
|
+
result.is_latest.should == true
|
213
|
+
|
214
|
+
Time.stub!(:now).and_return(Time.parse("2010-09-21"))
|
215
|
+
query = Appstats::Query.new(:query => "# myblahs")
|
216
|
+
result2 = query.run
|
217
|
+
result.reload
|
218
|
+
result.is_latest.should == false
|
219
|
+
result2.is_latest.should == true
|
220
|
+
end
|
221
|
+
|
130
222
|
|
131
223
|
describe "core search" do
|
132
224
|
it "should return 0 if no results" do
|
@@ -267,6 +359,8 @@ module Appstats
|
|
267
359
|
before(:each) do
|
268
360
|
Appstats::Entry.delete_all
|
269
361
|
Appstats::Context.delete_all
|
362
|
+
Appstats::Result.delete_all
|
363
|
+
Appstats::SubResult.delete_all
|
270
364
|
end
|
271
365
|
|
272
366
|
it "should not create sub results if no group_by" do
|
@@ -600,6 +694,14 @@ module Appstats
|
|
600
694
|
it "should support like" do
|
601
695
|
Appstats::Query.new(:query => "# logins where user like '%andrew%'").contexts_filter_to_sql.should == "#{@template} (context_key = 'user' and context_value like '%andrew%')))"
|
602
696
|
end
|
697
|
+
|
698
|
+
it "should support not like" do
|
699
|
+
Appstats::Query.new(:query => "# logins where user not like '%andrew%'").contexts_filter_to_sql.should == "#{@template} (context_key = 'user' and context_value not like '%andrew%')))"
|
700
|
+
end
|
701
|
+
|
702
|
+
it "should support in" do
|
703
|
+
Appstats::Query.new(:query => "# logins where user_id in 1,2,3").contexts_filter_to_sql.should == "#{@template} (context_key = 'user_id' and context_value in ('1','2','3'))))"
|
704
|
+
end
|
603
705
|
|
604
706
|
it "should support and" do
|
605
707
|
Appstats::Query.new(:query => "# logins where user='andrew' and user='aforward'").contexts_filter_to_sql.should == "#{@template} (context_key = 'user' and context_value = 'andrew') and (context_key = 'user' and context_value = 'aforward')))"
|
@@ -613,6 +715,23 @@ module Appstats
|
|
613
715
|
|
614
716
|
end
|
615
717
|
|
718
|
+
describe "#sqlquote" do
|
719
|
+
|
720
|
+
it "should handle nil" do
|
721
|
+
Appstats::Query.sqlquote(nil).should == "NULL"
|
722
|
+
Appstats::Query.sqlquote('').should == "''"
|
723
|
+
end
|
724
|
+
|
725
|
+
it "should handle simple data" do
|
726
|
+
Appstats::Query.sqlquote("blah").should == "'blah'"
|
727
|
+
end
|
728
|
+
|
729
|
+
it "should handle IN comparator" do
|
730
|
+
Appstats::Query.sqlquote("1,2,3","in").should == "('1','2','3')"
|
731
|
+
end
|
732
|
+
|
733
|
+
end
|
734
|
+
|
616
735
|
describe "#sqlize" do
|
617
736
|
|
618
737
|
it "should handle nil" do
|
@@ -669,7 +788,7 @@ module Appstats
|
|
669
788
|
describe "#comparators" do
|
670
789
|
|
671
790
|
it "should be a list " do
|
672
|
-
Appstats::Query.comparators.should == ["=","!=","<>",">","<",">=","<=","like"]
|
791
|
+
Appstats::Query.comparators.should == ["=","!=","<>",">","<",">=","<=","like","not like","in"]
|
673
792
|
end
|
674
793
|
|
675
794
|
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:
|
4
|
+
hash: 67
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 20
|
9
|
-
-
|
10
|
-
version: 0.20.
|
9
|
+
- 6
|
10
|
+
version: 0.20.6
|
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-
|
18
|
+
date: 2011-04-06 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|