appstats 0.20.2 → 0.20.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- appstats (0.20.2)
4
+ appstats (0.20.6)
5
5
  daemons
6
6
  net-scp
7
7
  rails (>= 2.3.0)
@@ -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
@@ -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
- current_token = token.upcase
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
- @tokenize_no_spaces<< current_token
203
- current_token = "\\s+#{current_token}(\\s|$)" unless current_token.match(/.*[a-z].*/i).nil?
204
- @tokenize<< current_token
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("|")
@@ -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 || && = <= >= <> < > != ( ) like")
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 = '#{Query.sqlclean(entry[:context])}'"
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} '#{Query.sqlclean(entry[:context])}')"
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| "'#{Query.sqlclean(g)}'" }.join(',')
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
 
@@ -1,3 +1,3 @@
1
1
  module Appstats
2
- VERSION = "0.20.2"
2
+ VERSION = "0.20.6"
3
3
  end
@@ -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
@@ -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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
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.2 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.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.2 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : action=save_ovcen : app_name=cdb"
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.2 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.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.2 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : app_name=market : app_name=cdb"
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"
@@ -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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=5 : blah=6"]
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=search : provider=one : provider=two"]
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=appstats-exception : error=blah : on=login"]
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : action=blah : app_name=Market : server=Live")
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Sin : app_name=Market : server=Live")
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.2 setup[:,=,-n] 2010-09-21 23:15:20 app_name=Market : server=Live")
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.2 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n")
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.2 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n")
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.2 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n")
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=1 : note=2.2"
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : app_name=market"
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
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.2 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n"
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.2 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n"
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.2 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n"
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address search"
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_-nsearch"
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.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : blah=some-nlong-nstatement"
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.2 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=--nsearch-n"
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
@@ -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 )")
@@ -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: 75
4
+ hash: 67
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 20
9
- - 2
10
- version: 0.20.2
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-03-30 00:00:00 -04:00
18
+ date: 2011-04-06 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency