user_query 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/ChangeLog +4 -0
  2. data/README +45 -0
  3. data/Rakefile +359 -0
  4. data/Releases +6 -0
  5. data/TODO +0 -0
  6. data/examples/userqueryex/HOWTO.txt +5 -0
  7. data/examples/userqueryex/README +183 -0
  8. data/examples/userqueryex/Rakefile +10 -0
  9. data/examples/userqueryex/WHAT.txt +16 -0
  10. data/examples/userqueryex/app/controllers/application.rb +4 -0
  11. data/examples/userqueryex/app/controllers/entries_controller.rb +68 -0
  12. data/examples/userqueryex/app/helpers/application_helper.rb +3 -0
  13. data/examples/userqueryex/app/helpers/entries_helper.rb +2 -0
  14. data/examples/userqueryex/app/models/entry.rb +8 -0
  15. data/examples/userqueryex/app/views/entries/_form.rhtml +20 -0
  16. data/examples/userqueryex/app/views/entries/edit.rhtml +9 -0
  17. data/examples/userqueryex/app/views/entries/list.rhtml +75 -0
  18. data/examples/userqueryex/app/views/entries/new.rhtml +8 -0
  19. data/examples/userqueryex/app/views/entries/show.rhtml +8 -0
  20. data/examples/userqueryex/app/views/layouts/entries.rhtml +13 -0
  21. data/examples/userqueryex/config/boot.rb +44 -0
  22. data/examples/userqueryex/config/database.yml +36 -0
  23. data/examples/userqueryex/config/environment.rb +54 -0
  24. data/examples/userqueryex/config/environments/development.rb +21 -0
  25. data/examples/userqueryex/config/environments/production.rb +18 -0
  26. data/examples/userqueryex/config/environments/test.rb +19 -0
  27. data/examples/userqueryex/config/routes.rb +22 -0
  28. data/examples/userqueryex/db/migrate/001_entry_migration.rb +16 -0
  29. data/examples/userqueryex/db/schema.rb +15 -0
  30. data/examples/userqueryex/doc/README_FOR_APP +2 -0
  31. data/examples/userqueryex/public/404.html +8 -0
  32. data/examples/userqueryex/public/500.html +8 -0
  33. data/examples/userqueryex/public/dispatch.cgi +10 -0
  34. data/examples/userqueryex/public/dispatch.fcgi +24 -0
  35. data/examples/userqueryex/public/dispatch.rb +10 -0
  36. data/examples/userqueryex/public/favicon.ico +0 -0
  37. data/examples/userqueryex/public/images/rails.png +0 -0
  38. data/examples/userqueryex/public/javascripts/application.js +2 -0
  39. data/examples/userqueryex/public/javascripts/controls.js +815 -0
  40. data/examples/userqueryex/public/javascripts/dragdrop.js +913 -0
  41. data/examples/userqueryex/public/javascripts/effects.js +958 -0
  42. data/examples/userqueryex/public/javascripts/prototype.js +2006 -0
  43. data/examples/userqueryex/public/robots.txt +1 -0
  44. data/examples/userqueryex/public/stylesheets/scaffold.css +74 -0
  45. data/examples/userqueryex/script/about +3 -0
  46. data/examples/userqueryex/script/breakpointer +3 -0
  47. data/examples/userqueryex/script/console +3 -0
  48. data/examples/userqueryex/script/destroy +3 -0
  49. data/examples/userqueryex/script/generate +3 -0
  50. data/examples/userqueryex/script/performance/benchmarker +3 -0
  51. data/examples/userqueryex/script/performance/profiler +3 -0
  52. data/examples/userqueryex/script/plugin +3 -0
  53. data/examples/userqueryex/script/process/reaper +3 -0
  54. data/examples/userqueryex/script/process/spawner +3 -0
  55. data/examples/userqueryex/script/runner +3 -0
  56. data/examples/userqueryex/script/server +3 -0
  57. data/examples/userqueryex/test/fixtures/entries.yml +5 -0
  58. data/examples/userqueryex/test/functional/entries_controller_test.rb +88 -0
  59. data/examples/userqueryex/test/test_helper.rb +28 -0
  60. data/examples/userqueryex/test/unit/entry_test.rb +10 -0
  61. data/lib/user_query.rb +10 -0
  62. data/lib/user_query/generator.rb +219 -0
  63. data/lib/user_query/parameters.rb +93 -0
  64. data/lib/user_query/parser.rb +762 -0
  65. data/lib/user_query/schema.rb +159 -0
  66. data/lib/user_query/user_query_version.rb +6 -0
  67. data/test/parser_test.rb +539 -0
  68. data/test/schema_test.rb +142 -0
  69. metadata +148 -0
@@ -0,0 +1,159 @@
1
+ # This class defined how query parameters are to be interpreted.
2
+ #
3
+ module UserQuery
4
+
5
+ class Schema
6
+ @active_record_base = false
7
+ begin
8
+ # Kernel.require 'active_record'
9
+ @@active_record_base = ActiveRecord::Base
10
+ rescue Object => err
11
+ @@active_record_base = false
12
+ end
13
+
14
+ @@empty_hash = { }
15
+ @@empty_hash.freeze
16
+
17
+ attr_accessor :verbose
18
+
19
+ def initialize(*opts)
20
+ @opt = Hash[*opts]
21
+
22
+ @verbose = @opt[:verbose]
23
+
24
+ @field_by_name = { }
25
+ @field = [ ]
26
+
27
+ field = @opt[:field]
28
+ field = [ field ] unless field.kind_of?(Array)
29
+ field.each{|x| add_field(x)}
30
+
31
+ # Interpret ActiveRecord::Base subclass
32
+ cls = @opt[:table]
33
+ if is_active_record?(cls)
34
+ columns = cls.columns
35
+ table_name = cls.table_name;
36
+ columns.each do |col|
37
+ field = {
38
+ :table => table_name,
39
+ :name => col.name,
40
+ :type => col.type,
41
+ }
42
+ field = add_field(field)
43
+ # $stderr.puts "AR::Base column #{col.inspect} =>\n #{field.inspect}"
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+ def is_active_record?(cls)
50
+ return false unless cls.kind_of?(Class)
51
+ while cls
52
+ if cls == @@active_record_base
53
+ return true;
54
+ end
55
+ cls = cls.superclass
56
+ end
57
+ false
58
+ end
59
+
60
+ private
61
+
62
+ def add_field(field)
63
+ field = { :name => field } unless field.kind_of?(Array) || field.kind_of?(Hash)
64
+ field = { :name => field[0], :type => field[1], :table => field[2] } if field.kind_of?(Array)
65
+
66
+ # Normalize name.
67
+ field[:name] = field[:name].intern if field[:name].respond_to?(:intern);
68
+
69
+ # Normalize table.
70
+ field[:table] ||= @opt[:table]
71
+ field[:table] = sql_table_name(field[:table])
72
+
73
+ return nil if (@field_by_name[field[:table]] ||= {})[field[:name]]
74
+
75
+ # Normalize type
76
+ field[:type] ||= :string
77
+ field[:type] = :string if field[:type] == :text
78
+ field[:type] = :number if field[:type] == :integer
79
+ field[:type] = :datetime if field[:type] == :date
80
+
81
+ # Keep track of by table.column name.
82
+ (@field_by_name[field[:table]] ||= {})[field[:name]] = field;
83
+ @field << field
84
+
85
+ field
86
+ end
87
+
88
+ def sql_table_name(x)
89
+ x && (x.kind_of?(String) ? x : x.table_name)
90
+ end
91
+
92
+ def sql_field_table_name(field)
93
+ sql_table_name(field[:table] || @opt[:table])
94
+ end
95
+
96
+ def sql_expr(field)
97
+ field[:sql_expr] || sql_table_column(sql_field_table_name(field), field[:name].to_s)
98
+ end
99
+
100
+ def sql_table_column(table, column)
101
+ table ? table + '.' + column : column
102
+ end
103
+
104
+ public
105
+
106
+ def sql(parameters, record = nil)
107
+ record ||= parameters if parameters.respond_to?(:errors)
108
+
109
+
110
+ sql = @field.map do |field|
111
+ f_sql = nil
112
+ begin
113
+ name = field[:name]
114
+ type = field[:type]
115
+
116
+ verbose = field[:verbose] || @verbose
117
+
118
+ target = sql_expr(field)
119
+
120
+ parameter = parameters.kind_of?(Hash) ?
121
+ parameters[name] :
122
+ parameters.send(name)
123
+
124
+ query_expr = UserQuery::Parser.
125
+ new(:type => type,
126
+ :verbose => verbose).
127
+ parse(parameter)
128
+
129
+ f_sql = UserQuery::Generator.
130
+ new(:type => type,
131
+ :target => target,
132
+ :verbose => verbose).
133
+ sql(query_expr)
134
+
135
+ if verbose
136
+ $stderr.puts "name = #{name.inspect}"
137
+ $stderr.puts "target = #{target.inspect}"
138
+ $stderr.puts "type = #{type.inspect}"
139
+ $stderr.puts "query = #{parameter.inspect}"
140
+ $stderr.puts "sql = #{f_sql.inspect}"
141
+ end
142
+
143
+ rescue UserQuery::Parser::SyntaxError => err
144
+ record.errors.add(name, err.to_s) if record
145
+ $stderr.puts "\n#{self.class.name}: Error: #{err}" if verbose
146
+ f_sql = nil
147
+ end
148
+
149
+ f_sql
150
+ end.compact.join(' AND ')
151
+
152
+ sql = nil if sql.empty?
153
+
154
+ sql
155
+ end
156
+
157
+ end
158
+
159
+ end # module
@@ -0,0 +1,6 @@
1
+ # DO NOT EDIT
2
+ # This file is auto-generated by build scripts.
3
+ # See: rake update_version
4
+ module UserQuery
5
+ UserQueryVersion = '0.1.0'
6
+ end
@@ -0,0 +1,539 @@
1
+ # $Id$
2
+ # REAL
3
+ #require File.dirname(__FILE__) + '/../test_helper'
4
+
5
+ require 'test/unit'
6
+ require 'user_query'
7
+ #require 'currency' # OPTIONAL
8
+
9
+ module UserQuery
10
+
11
+ class ParserTest < Test::Unit::TestCase
12
+
13
+ @@has_currency = false
14
+ begin
15
+ Kernel.require 'currency' # For :type => :money
16
+ @@has_currency = true
17
+ rescue Object => err
18
+ $stderr.puts "Error loading currency: skipping Currency tests\n#{err}"
19
+ @@has_currency = false
20
+ end
21
+
22
+
23
+ def setup
24
+ super
25
+ end
26
+
27
+ ############################################
28
+ # Simple stuff.
29
+ #
30
+
31
+ def test_create
32
+ assert_not_nil qp = UserQuery::Parser.
33
+ new()
34
+
35
+ qp
36
+ end
37
+
38
+ def test_empty
39
+ qp = test_create
40
+ assert_equal qp << ' ', nil
41
+ end
42
+
43
+ def test_bad_syntax
44
+ qp = test_create
45
+
46
+ assert_raises(UserQuery::Parser::SyntaxError) {qp << '##@!@'}
47
+ end
48
+
49
+ def test_trailing_tokens
50
+ qp = test_create
51
+
52
+ assert_raises(UserQuery::Parser::SyntaxError) {qp << '=Foo bar'}
53
+ end
54
+
55
+ def test_word
56
+ qp = test_create
57
+ assert_equal [:like, [:word, 'hello', 'hello']], qp << 'hello'
58
+
59
+ assert_equal [:like, [:word, 'NOTfoo', 'NOTfoo']], qp << 'NOTfoo'
60
+
61
+ assert_equal [:like, [:word, 'true', 'true']], qp << 'true'
62
+
63
+ assert_equal [:like, [:word, 'FALSE', 'FALSE']], qp << 'FALSE'
64
+ end
65
+
66
+ def test_word_trailing_whitespace
67
+ qp = test_create
68
+ assert_equal [:like, [:word, 'hello', 'hello']], qp << 'hello '
69
+ end
70
+
71
+ def test_string
72
+ qp = test_create
73
+ assert_equal [:like, [:string, "", ""]], qp << ' "" '
74
+ assert_equal [:like, [:string, " ", " "]], qp << ' " " '
75
+ assert_equal [:like, [:string, 'hello world!', 'hello world!']], qp << '"hello world!"'
76
+ end
77
+
78
+ def test_string_escape
79
+ qp = test_create
80
+ # qp.verbose = 1
81
+ assert_equal [:like, [:string, "\\", "\\"]], qp << '"\\\\"'
82
+ assert_equal [:like, [:string, "\"", "\""]], qp << '"\\""'
83
+ assert_equal [:like, [:string, "\"foo\"", "\"foo\""]], qp << '"\\"foo\\""'
84
+ assert_equal [:like, [:string, "he\\llo \"world!", "he\\llo \"world!"]], qp << '"he\\\\llo \"world!"'
85
+ end
86
+
87
+ def test_integer
88
+ qp = test_create
89
+ assert_equal [:eq, [:number, '123', 123]], qp << 123
90
+ assert_equal [:eq, [:number, '123', 123]], qp << '123'
91
+ assert_equal [:eq, [:number, '-123', -123]], qp << '-123'
92
+ assert_equal [:eq, [:number, '-123', -123]], qp << ' -123'
93
+ assert_equal [:eq, [:number, '+1234', 1234]], qp << '+1234'
94
+ end
95
+
96
+ def test_integer_like
97
+ qp = test_create
98
+ assert_equal [:like, [:string, '123', '123']], qp << 'LIKE 123'
99
+ end
100
+
101
+ def test_float
102
+ qp = test_create
103
+ assert_equal [:eq, [:number, '1.23', 1.23]], qp << 1.23
104
+ assert_equal [:eq, [:number, '1.23', 1.23]], qp << '1.23'
105
+ assert_equal [:eq, [:number, '-12.34', -12.34]], qp << '-12.34'
106
+ assert_equal [:eq, [:number, '-0.3', -0.3]], qp << '-0.3'
107
+ assert_equal [:eq, [:number, '+1.2e10', 1.2e10]], qp << '+1.2e10'
108
+ assert_equal [:eq, [:number, '0.25e-8', 0.25e-8]], qp << '0.25e-8'
109
+ end
110
+
111
+ def test_boolean
112
+ qp = test_create
113
+
114
+ qp.type = :boolean
115
+ # qp.verbose = true
116
+ assert_equal [:eq, [:boolean, 'true', true ]], qp << 'true'
117
+ assert_equal [:eq, [:boolean, 'false', false ]], qp << 'false'
118
+ end
119
+
120
+ def test_money
121
+ return true unless @@has_currency
122
+
123
+ qp = test_create
124
+
125
+ qp.type = :money
126
+ # qp.verbose = true
127
+ assert_equal [:eq, [:money, '123', Currency::Money.new('123')]], qp << '123'
128
+ assert_equal [:eq, [:money, '123.00', Currency::Money.new('123')]], qp << '123.00'
129
+ assert_equal [:eq, [:money, '-123.00', Currency::Money.new('-123')]], qp << '-123.00'
130
+ assert_equal [:eq, [:money, '123.45', Currency::Money.new('123.45')]], qp << '123.45'
131
+ assert_equal [:gt, [:money, '1,234.56', Currency::Money.new('1234.56')]], qp << '>1,234.56'
132
+ assert_equal [:eq, [:money, '$123', Currency::Money.new('123')]], qp << '$123'
133
+ assert_equal [:eq, [:money, '$123.00', Currency::Money.new('123')]], qp << '$123.00'
134
+ assert_equal [:eq, [:money, '$-123.00', Currency::Money.new('-123')]], qp << '$-123.00'
135
+ assert_equal [:eq, [:money, '$123.45', Currency::Money.new('123.45')]], qp << '$123.45'
136
+ assert_equal [:gt, [:money, '$1,234.56', Currency::Money.new('1234.56')]], qp << '>$1,234.56'
137
+ end
138
+
139
+ def test_sequence
140
+ qp = test_create
141
+ # qp.verbose = true
142
+ assert_equal [:and, [:like, [:word, 'hello', 'hello']], [:like, [:word, 'world', 'world']]], qp << 'hello world'
143
+ end
144
+
145
+ def test_between
146
+ qp = test_create
147
+ assert_equal [:between, [:number, '1', 1], [:number, '5', 5]], qp << 'BETWEEN 1 AND 5'
148
+ assert_equal [:between, [:number, '2', 2], [:number, '199', 199]], qp << 'BETWEEN 2 ... 199'
149
+
150
+ assert_equal [:between, [:word, 'abraxas', 'abraxas'], [:word, 'zebra', 'zebra']], qp << 'BETWEEN abraxas...zebra'
151
+ end
152
+
153
+ def test_elipsis
154
+ qp = test_create
155
+ assert_equal [:between, [:number, '1', 1], [:number, '19', 19]], qp << '1 ... 19'
156
+ end
157
+
158
+ def test_and
159
+ qp = test_create
160
+ assert_equal [:and,
161
+ [:like, [:word, 'foo', 'foo']],
162
+ [:and,
163
+ [:like, [:word, 'bar', 'bar']],
164
+ [:like, [:word, 'baz', 'baz']]]],
165
+ qp << 'foo AND bar AND baz'
166
+
167
+ qp = test_create
168
+ assert_equal [:and,
169
+ [:like, [:word, 'foo', 'foo']],
170
+ [:and,
171
+ [:like, [:word, 'bar', 'bar']],
172
+ [:not, [:like, [:word, 'baz', 'baz']]]]],
173
+ qp << 'foo AND bar AND !baz'
174
+ end
175
+
176
+ def test_and_or
177
+ qp = test_create
178
+ assert_equal [:or,
179
+ [:and,
180
+ [:like, [:word, 'foo', 'foo']],
181
+ [:like, [:word, 'bar', 'bar']]],
182
+ [:like, [:word, 'baz', 'baz']]],
183
+ qp << 'foo AND bar OR baz'
184
+ end
185
+
186
+ def test_not
187
+ qp = test_create
188
+
189
+ assert_equal [:not,
190
+ [:like, [:word, 'foo', 'foo']]
191
+ ],
192
+ qp << 'NOT foo'
193
+
194
+ #qp.verbose = true
195
+
196
+ assert_equal [:not,
197
+ [:and,
198
+ [:like, [:word, 'foo', 'foo']],
199
+ [:like, [:word, 'bar', 'bar']]
200
+ ]
201
+ ],
202
+ qp << 'NOT (foo AND bar)'
203
+
204
+
205
+ assert_equal [:not,
206
+ [:and,
207
+ [:like, [:word, 'foo', 'foo']],
208
+ [:like, [:word, 'bar', 'bar']]
209
+ ]
210
+ ],
211
+ qp << 'NOT foo bar'
212
+
213
+ end
214
+
215
+ def test_grouping
216
+ qp = test_create
217
+ #qp.verbose = true
218
+
219
+ assert_equal [:or,
220
+ [:and,
221
+ [:like,
222
+ [:word, 'foo', 'foo']
223
+ ],
224
+ [:like,
225
+ [:word, 'bar', 'bar']
226
+ ]],
227
+ [:like,
228
+ [:word, 'baz', 'baz']
229
+ ]],
230
+ qp << '(foo AND bar) OR baz'
231
+
232
+ qp = test_create
233
+ assert_equal [:and,
234
+ [:like,
235
+ [:word, 'foo', 'foo']
236
+ ],
237
+ [:or,
238
+ [:like,
239
+ [:word, 'bar', 'bar']
240
+ ],
241
+ [:like,
242
+ [:word, 'baz', 'baz']
243
+ ]]],
244
+ qp << 'foo AND (bar OR baz)'
245
+ end
246
+
247
+ def test_year
248
+ qp = test_create
249
+ qp.type = :datetime
250
+
251
+ assert_equal [:range, [:year, '2006', 2006], [:year, '2006', 2007]], qp << '2006'
252
+ end
253
+
254
+ def test_month
255
+ qp = test_create
256
+ qp.type = :datetime
257
+
258
+ assert_equal [:range,
259
+ [:month, '4/2006', 2006, 4],
260
+ [:month, '4/2006', 2006, 5]],
261
+ qp << '4/2006'
262
+
263
+ assert_equal [:range,
264
+ [:month, '04/2006', 2006, 4],
265
+ [:month, '04/2006', 2006, 5]],
266
+ qp << '04/2006'
267
+
268
+ assert_equal [:range,
269
+ [:month, '12/2006', 2006, 12],
270
+ [:month, '12/2006', 2007, 1]],
271
+ qp << '12/2006'
272
+ end
273
+
274
+ def test_day
275
+ qp = test_create
276
+ qp.type = :datetime
277
+
278
+ assert_equal [:range,
279
+ [:day, '2/4/2006', 2006, 2, 4],
280
+ [:day, '2/4/2006', 2006, 2, 5]],
281
+ qp << '2/4/2006'
282
+
283
+ assert_equal [:range,
284
+ [:day, '2/04/2006', 2006, 2, 4],
285
+ [:day, '2/04/2006', 2006, 2, 5]],
286
+ qp << '2/04/2006'
287
+
288
+ assert_equal [:range,
289
+ [:day, '02/04/2006', 2006, 2, 4],
290
+ [:day, '02/04/2006', 2006, 2, 5]],
291
+ qp << '02/04/2006'
292
+
293
+ assert_equal [:range,
294
+ [:day, '02/4/2006', 2006, 2, 4],
295
+ [:day, '02/4/2006', 2006, 2, 5]],
296
+ qp << '02/4/2006'
297
+
298
+ assert_equal [:range,
299
+ [:day, '12/4/2006', 2006, 12, 4],
300
+ [:day, '12/4/2006', 2006, 12, 5]],
301
+ qp << '12/4/2006'
302
+
303
+ assert_equal [:range,
304
+ [:day, '12/04/2006', 2006, 12, 4],
305
+ [:day, '12/04/2006', 2006, 12, 5]],
306
+ qp << '12/04/2006'
307
+
308
+ assert_equal [:range,
309
+ [:day, '12/31/2006', 2006, 12, 31],
310
+ [:day, '12/31/2006', 2007, 1, 1]],
311
+ qp << '12/31/2006'
312
+
313
+ qp.this_year = 2006
314
+ assert_equal [:range,
315
+ [:day, '12/31', 2006, 12, 31],
316
+ [:day, '12/31', 2007, 1, 1]],
317
+ qp << '12/31'
318
+ end
319
+
320
+ def test_hour
321
+ qp = test_create
322
+ qp.type = :datetime
323
+
324
+ assert_equal [:range,
325
+ [:hour, '2/4/2006 12am', 2006, 2, 4, 0],
326
+ [:hour, '2/4/2006 12am', 2006, 2, 4, 1]],
327
+ qp << '2/4/2006 12am'
328
+
329
+ assert_equal [:range,
330
+ [:hour, '2/4/2006 5', 2006, 2, 4, 5],
331
+ [:hour, '2/4/2006 5', 2006, 2, 4, 6]],
332
+ qp << '2/4/2006 5'
333
+ assert_equal [:range,
334
+ [:hour, '2/4/2006-5 AM', 2006, 2, 4, 5],
335
+ [:hour, '2/4/2006-5 AM',2006, 2, 4, 6]],
336
+ qp << '2/4/2006-5 AM'
337
+
338
+ assert_equal [:range,
339
+ [:hour, '2/4/2006 12P', 2006, 2, 4, 12],
340
+ [:hour, '2/4/2006 12P', 2006, 2, 4, 13]],
341
+ qp << '2/4/2006 12P'
342
+
343
+ assert_equal [:range,
344
+ [:hour, '2/4/2006-2pm', 2006, 2, 4, 14],
345
+ [:hour, '2/4/2006-2pm', 2006, 2, 4, 15]],
346
+ qp << '2/4/2006-2pm'
347
+
348
+ assert_equal [:range,
349
+ [:hour, '2/4/2006-14', 2006, 2, 4, 14],
350
+ [:hour, '2/4/2006-14', 2006, 2, 4, 15]], qp << '2/4/2006-14'
351
+
352
+ end
353
+
354
+ def test_minute
355
+ qp = test_create
356
+ qp.type = :datetime
357
+
358
+ assert_equal [:range,
359
+ [:minute, '2/4/2006 12:30am', 2006, 2, 4, 0, 30],
360
+ [:minute, '2/4/2006 12:30am', 2006, 2, 4, 0, 31 ]],
361
+ qp << '2/4/2006 12:30am'
362
+
363
+ assert_equal [:range,
364
+ [:minute, '2/4/2006 9:00p', 2006, 2, 4, 21, 00],
365
+ [:minute, '2/4/2006 9:00p', 2006, 2, 4, 21, 01 ]],
366
+ qp << '2/4/2006 9:00p'
367
+
368
+ assert_equal [:range,
369
+ [:minute, '2/4/2006 1430', 2006, 2, 4, 14, 30],
370
+ [:minute, '2/4/2006 1430', 2006, 2, 4, 14, 31 ]],
371
+ qp << '2/4/2006 1430'
372
+
373
+
374
+ end
375
+
376
+ def test_second
377
+ qp = test_create
378
+ qp.type = :datetime
379
+
380
+ assert_equal [:range,
381
+ [:second, '2/4/2006 12:30:00am', 2006, 2, 4, 0, 30, 00 ],
382
+ [:second, '2/4/2006 12:30:00am', 2006, 2, 4, 0, 30, 01 ]],
383
+ qp << '2/4/2006 12:30:00am'
384
+
385
+ assert_equal [:range,
386
+ [:second, '2/4/2006 9:00:05p', 2006, 2, 4, 21, 00, 05 ],
387
+ [:second, '2/4/2006 9:00:05p', 2006, 2, 4, 21, 00, 06 ]],
388
+ qp << '2/4/2006 9:00:05p'
389
+
390
+ assert_equal [:range,
391
+ [:second, '2/4/2006 9:00:59p', 2006, 2, 4, 21, 00, 59 ],
392
+ [:second, '2/4/2006 9:00:59p', 2006, 2, 4, 21, 01, 00 ]],
393
+ qp << '2/4/2006 9:00:59p'
394
+
395
+ assert_equal [:range,
396
+ [:second, '2/4/2006 143033', 2006, 2, 4, 14, 30, 33 ],
397
+ [:second, '2/4/2006 143033', 2006, 2, 4, 14, 30, 34 ]],
398
+ qp << '2/4/2006 143033'
399
+
400
+
401
+ end
402
+
403
+ def test_time_now
404
+ qp = test_create
405
+ qp.type = :datetime
406
+
407
+ qp.now = Time.utc(2006, 2, 4, 0, 30, 15)
408
+ assert_equal [:range,
409
+ [:second, 'now', 2006, 2, 4, 0, 30, 15 ],
410
+ [:second, 'now', 2006, 2, 4, 0, 30, 16 ]],
411
+ qp << 'now'
412
+ end
413
+
414
+ def test_time_today
415
+ qp = test_create
416
+ qp.type = :datetime
417
+
418
+ qp.now = Time.utc(2006, 2, 4, 0, 30, 15)
419
+ assert_equal [:range,
420
+ [:day, 'today', 2006, 2, 4 ],
421
+ [:day, 'today', 2006, 2, 5 ]],
422
+ qp << 'today'
423
+
424
+
425
+ assert_equal [:range,
426
+ [:day, 'tomorrow', 2006, 2, 5 ],
427
+ [:day, 'tomorrow', 2006, 2, 6 ]],
428
+ qp << 'tomorrow'
429
+
430
+ assert_equal [:range,
431
+ [:day, 'yesterday', 2006, 2, 3 ],
432
+ [:day, 'yesterday', 2006, 2, 4 ]],
433
+ qp << 'yesterday'
434
+ end
435
+
436
+
437
+ def test_time_this_year
438
+ qp = test_create
439
+ qp.type = :datetime
440
+
441
+ qp.now = Time.utc(2006, 2, 4, 0, 30, 15)
442
+ assert_equal [:range,
443
+ [:year, 'this year', 2006 ],
444
+ [:year, 'this year', 2007 ]],
445
+ qp << 'this year'
446
+ end
447
+
448
+
449
+ def test_time_today_relative
450
+ qp = test_create
451
+ qp.type = :datetime
452
+
453
+ qp.now = Time.utc(2006, 2, 4, 0, 30, 15)
454
+ assert_equal [:range,
455
+ [:day, 'today+1', 2006, 2, 5 ],
456
+ [:day, 'today+1', 2006, 2, 6 ]],
457
+ qp << 'today+1'
458
+
459
+ qp.now = Time.utc(2006, 2, 4, 0, 30, 15)
460
+ assert_equal [:range,
461
+ [:day, 'today-2', 2006, 2, 2 ],
462
+ [:day, 'today-2', 2006, 2, 3 ]],
463
+ qp << 'today-2'
464
+ end
465
+
466
+
467
+ def test_between_day_and_year
468
+ qp = test_create
469
+ qp.type = :datetime
470
+
471
+ assert_equal [:between, [:day, '2/4/2006', 2006, 2, 4], [:year, '2007', 2007]], qp << 'BETWEEN 2/4/2006 AND 2007'
472
+
473
+ assert_equal [:between, [:day, '2/4/2006', 2006, 2, 4], [:year, '2007', 2007]], qp << '2/4/2006...2007'
474
+ end
475
+
476
+
477
+ def test_bad_between
478
+ qp = test_create
479
+
480
+ assert_raises(UserQuery::Parser::SyntaxError) {qp << 'BETWEEN 1 AND FOO'}
481
+ assert_equal [:between, [:number, '1', 1], [:number, '5', 5]], qp << 'BETWEEN 1 AND 5'
482
+
483
+ assert_equal [:between, [:word, 'BAR', 'BAR'], [:string, 'BAZ', 'BAZ']], qp << 'BETWEEN BAR AND "BAZ"'
484
+
485
+ qp.type = :datetime
486
+ assert_raises(UserQuery::Parser::SyntaxError) {qp << 'BETWEEN 12/31/2006 AND FOO'}
487
+ end
488
+
489
+ def test_eq
490
+ qp = test_create
491
+ assert_equal [:eq, [:number, '45', 45]], qp << '=45'
492
+ assert_equal [:eq, [:number, '123', 123]], qp << '= 123'
493
+
494
+ qp.type = :datetime
495
+ assert_equal [:range,
496
+ [:minute, '2/4/2006 1430', 2006, 2, 4, 14, 30],
497
+ [:minute, '2/4/2006 1430', 2006, 2, 4, 14, 31 ]],
498
+ qp << '= 2/4/2006 1430'
499
+ assert_equal [:range,
500
+ [:hour, '2/4/2006 5', 2006, 2, 4, 5],
501
+ [:hour, '2/4/2006 5', 2006, 2, 4, 6]],
502
+ qp << ' = 2/4/2006 5'
503
+ assert_equal [:range,
504
+ [:month, '12/2006', 2006, 12],
505
+ [:month, '12/2006', 2007, 1]],
506
+ qp << 'EQUAL TO 12/2006'
507
+
508
+ end
509
+
510
+ def test_ne
511
+ qp = test_create
512
+ assert_equal [:ne, [:number, '76', 76]], qp << '!=76'
513
+ assert_equal [:ne, [:number, '34', 34]], qp << '<> 34'
514
+ assert_equal [:ne, [:number, '123', 123]], qp << '<>123'
515
+
516
+ qp.type = :datetime
517
+ assert_equal [:or,
518
+ [:lt,
519
+ [:minute, '2/4/2006 1430', 2006, 2, 4, 14, 30]],
520
+ [:ge,
521
+ [:minute, '2/4/2006 1430', 2006, 2, 4, 14, 31 ]]],
522
+ qp << '<> 2/4/2006 1430'
523
+ end
524
+
525
+ def test_complex_1
526
+ qp = test_create
527
+ # qp.verbose = true
528
+ assert_equal [:and,
529
+ [:lt, [:number, '5', 5]],
530
+ [:gt, [:number, '2', 2]]
531
+ ],
532
+ qp << '<5 AND >2'
533
+ end
534
+
535
+
536
+ end
537
+
538
+ end # module
539
+