sparkql 1.2.8 → 1.3.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +111 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +4 -0
- data/Rakefile +2 -3
- data/VERSION +1 -1
- data/lib/sparkql/errors.rb +68 -71
- data/lib/sparkql/evaluator.rb +13 -9
- data/lib/sparkql/expression_resolver.rb +2 -3
- data/lib/sparkql/expression_state.rb +7 -9
- data/lib/sparkql/function_resolver.rb +15 -10
- data/lib/sparkql/geo/record_circle.rb +1 -1
- data/lib/sparkql/lexer.rb +54 -56
- data/lib/sparkql/parser.rb +35 -35
- data/lib/sparkql/parser_compatibility.rb +97 -76
- data/lib/sparkql/parser_tools.rb +159 -139
- data/lib/sparkql/token.rb +25 -25
- data/lib/sparkql/version.rb +1 -1
- data/sparkql.gemspec +1 -1
- data/test/unit/errors_test.rb +4 -5
- data/test/unit/evaluator_test.rb +15 -16
- data/test/unit/expression_state_test.rb +14 -15
- data/test/unit/function_resolver_test.rb +125 -161
- data/test/unit/geo/record_circle_test.rb +2 -2
- data/test/unit/lexer_test.rb +15 -16
- data/test/unit/parser_compatability_test.rb +177 -151
- data/test/unit/parser_test.rb +90 -90
- metadata +8 -6
data/test/unit/evaluator_test.rb
CHANGED
@@ -46,7 +46,7 @@ class EvaluatorTest < Test::Unit::TestCase
|
|
46
46
|
assert !sample(filter), "Filter: #{filter}"
|
47
47
|
end
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
# One failing Not expression in a set should always fail. Here we ensure every
|
51
51
|
# permutation of one failing
|
52
52
|
def test_nots_stay_bad
|
@@ -56,7 +56,7 @@ class EvaluatorTest < Test::Unit::TestCase
|
|
56
56
|
expressions << "Test Eq #{i == j}"
|
57
57
|
end
|
58
58
|
# Add the unary not to the front!
|
59
|
-
filter = "Not
|
59
|
+
filter = "Not #{expressions.join(' Not ')}"
|
60
60
|
assert !sample(filter), "Filter: #{filter}"
|
61
61
|
end
|
62
62
|
end
|
@@ -97,24 +97,23 @@ class EvaluatorTest < Test::Unit::TestCase
|
|
97
97
|
assert !sample("Test Eq true Not (Not Test Eq false)")
|
98
98
|
assert sample("Not (Not Test Eq true)")
|
99
99
|
assert sample("Not (Not(Not Test Eq true))")
|
100
|
-
assert !sample("Test Eq false And Test Eq true Not Test Eq false")
|
100
|
+
assert !sample("Test Eq false And Test Eq true Not Test Eq false")
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
def test_examples
|
104
104
|
# This one is based on a real life example that had problems.
|
105
105
|
#
|
106
|
-
# CurrentPrice Bt 130000.00,180000.00 And PropertySubType Eq 'Single Family Residence' And
|
107
|
-
# SchoolDistrict Eq 'Byron Center','Grandville','Jenison' And MlsStatus Eq 'Active' And
|
108
|
-
# BathsTotal Bt 1.50,9999.00 And BedsTotal Bt 3,99 And PropertyType Eq 'A'
|
109
|
-
# Not "Garage"."Garage2" Eq 'No' And "Pool"."OutdoorAbove" Eq true
|
106
|
+
# CurrentPrice Bt 130000.00,180000.00 And PropertySubType Eq 'Single Family Residence' And
|
107
|
+
# SchoolDistrict Eq 'Byron Center','Grandville','Jenison' And MlsStatus Eq 'Active' And
|
108
|
+
# BathsTotal Bt 1.50,9999.00 And BedsTotal Bt 3,99 And PropertyType Eq 'A'
|
109
|
+
# Not "Garage"."Garage2" Eq 'No' And "Pool"."OutdoorAbove" Eq true
|
110
110
|
# And "Pool"."OutdoorInground" Eq true Not "Substructure"."Michigan Basement" Eq true
|
111
111
|
|
112
|
-
assert !sample("Test Eq false And Test Eq true And "
|
113
|
-
"Test Eq false And Test Eq true And "
|
114
|
-
"Test Eq true And Test Eq true And Test Eq true "
|
115
|
-
"Not Test Eq false And Test Eq false "
|
116
|
-
"And Test Eq false Not Test Eq false"
|
117
|
-
)
|
112
|
+
assert !sample("Test Eq false And Test Eq true And " \
|
113
|
+
"Test Eq false And Test Eq true And " \
|
114
|
+
"Test Eq true And Test Eq true And Test Eq true " \
|
115
|
+
"Not Test Eq false And Test Eq false " \
|
116
|
+
"And Test Eq false Not Test Eq false")
|
118
117
|
end
|
119
118
|
|
120
119
|
def test_optimizations
|
@@ -133,10 +132,10 @@ class EvaluatorTest < Test::Unit::TestCase
|
|
133
132
|
assert !sample("MlsStatus Eq false And PropertyType Eq true And (City Eq true Or City Eq false)")
|
134
133
|
end
|
135
134
|
|
136
|
-
def sample
|
135
|
+
def sample(filter)
|
137
136
|
@parser = Parser.new
|
138
137
|
@expressions = @parser.parse(filter)
|
139
|
-
@evaluator = Evaluator.new(BooleanOrBustExpressionResolver.new
|
138
|
+
@evaluator = Evaluator.new(BooleanOrBustExpressionResolver.new)
|
140
139
|
@evaluator.evaluate(@expressions)
|
141
140
|
end
|
142
141
|
end
|
@@ -7,17 +7,17 @@ class ExpressionStateTest < Test::Unit::TestCase
|
|
7
7
|
@subject = ExpressionState.new
|
8
8
|
@parser = Parser.new
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def test_needs_join
|
12
12
|
filter = '"General Property Description"."Taxes" Lt 500.0'
|
13
13
|
process(filter)
|
14
14
|
assert @subject.needs_join?
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def test_or
|
18
18
|
filter = '"General Property Description"."Taxes" Lt 500.0 Or "General Property Description"."Taxes" Gt 400.0'
|
19
19
|
process(filter)
|
20
|
-
assert !@subject.needs_join?, "#{@subject.inspect} Expressions:#{
|
20
|
+
assert !@subject.needs_join?, "#{@subject.inspect} Expressions:#{@expressions.inspect}"
|
21
21
|
end
|
22
22
|
|
23
23
|
def test_not
|
@@ -33,31 +33,31 @@ class ExpressionStateTest < Test::Unit::TestCase
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def test_and_or
|
36
|
-
filter = '"General Property Description"."Taxes" Lt 500.0 And "General Property Description"."Taxes2" '
|
37
|
-
|
36
|
+
filter = '"General Property Description"."Taxes" Lt 500.0 And "General Property Description"."Taxes2" ' \
|
37
|
+
'Eq 1.0 Or "General Property Description"."Taxes" Gt 400.0'
|
38
38
|
process(filter)
|
39
39
|
assert !@subject.needs_join?
|
40
40
|
end
|
41
41
|
|
42
42
|
def test_or_and
|
43
|
-
filter = '"General Property Description"."Taxes" Lt 500.0 Or "General Property Description"."Taxes" '
|
44
|
-
|
43
|
+
filter = '"General Property Description"."Taxes" Lt 500.0 Or "General Property Description"."Taxes" ' \
|
44
|
+
'Gt 400.0 And "General Property Description"."Taxes2" Eq 1.0'
|
45
45
|
process(filter)
|
46
46
|
assert @subject.needs_join?
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
def test_or_with_standard_field
|
50
50
|
filter = 'Test Eq 0.0 Or "General Property Description"."Taxes" Lt 500.0'
|
51
51
|
process(filter)
|
52
52
|
assert @subject.needs_join?
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
# Nesting
|
56
56
|
def test_nested_or
|
57
57
|
parse '"General Property Description"."Taxes" Lt 5.0 Or ("General Property Description"."Taxes" Gt 4.0)'
|
58
58
|
@expressions.each do |ex|
|
59
59
|
@subject.push(ex)
|
60
|
-
assert @subject.needs_join?, "#{@subject.inspect} Expression:#{
|
60
|
+
assert @subject.needs_join?, "#{@subject.inspect} Expression:#{ex.inspect}"
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
@@ -70,20 +70,20 @@ class ExpressionStateTest < Test::Unit::TestCase
|
|
70
70
|
@subject.push(@expressions[2])
|
71
71
|
assert !@subject.needs_join?
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
# Nesting
|
75
75
|
def test_nested_and
|
76
76
|
parse '"Tax"."Taxes" Lt 5.0 Or ("Tax"."Taxes" Gt 4.0 And "Tax"."Taxes" Gt 2.0)'
|
77
77
|
@expressions.each do |ex|
|
78
78
|
@subject.push(ex)
|
79
|
-
assert @subject.needs_join?, "#{@subject.inspect} Expression:#{
|
79
|
+
assert @subject.needs_join?, "#{@subject.inspect} Expression:#{ex.inspect}"
|
80
80
|
end
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
def parse(filter)
|
84
84
|
@expressions = @parser.parse(filter)
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
def process(filter)
|
88
88
|
@expressions = @parser.parse(filter)
|
89
89
|
@expressions.each do |ex|
|
@@ -91,5 +91,4 @@ class ExpressionStateTest < Test::Unit::TestCase
|
|
91
91
|
end
|
92
92
|
@expressions
|
93
93
|
end
|
94
|
-
|
95
94
|
end
|
@@ -6,7 +6,40 @@ require 'sparkql/geo'
|
|
6
6
|
class FunctionResolverTest < Test::Unit::TestCase
|
7
7
|
include Sparkql
|
8
8
|
|
9
|
-
|
9
|
+
YEAR = 2021
|
10
|
+
MONTH = 12
|
11
|
+
DAY = 31
|
12
|
+
HOURS = 0
|
13
|
+
MINUTES = 1
|
14
|
+
SECONDS = 2
|
15
|
+
MILLI = 123_456
|
16
|
+
SECONDSF = 2.123456
|
17
|
+
|
18
|
+
EXAMPLE_DATE = Time.new(YEAR, MONTH, DAY, HOURS, MINUTES, SECONDSF)
|
19
|
+
TIME_TESTS = {
|
20
|
+
year: YEAR,
|
21
|
+
month: MONTH,
|
22
|
+
mday: DAY,
|
23
|
+
hour: HOURS,
|
24
|
+
min: MINUTES,
|
25
|
+
sec: SECONDS
|
26
|
+
}.freeze
|
27
|
+
|
28
|
+
def assert_times(call_value, expected_call_type = :datetime, overrides = {})
|
29
|
+
assert_equal call_value[:type], expected_call_type
|
30
|
+
test_time = Time.parse(call_value[:value])
|
31
|
+
tests = TIME_TESTS.merge(overrides)
|
32
|
+
tests.each do |key, value|
|
33
|
+
assert_equal value, test_time.send(key), "#{key}: #{test_time}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
test '#lookup' do
|
38
|
+
good = FunctionResolver.lookup('all')
|
39
|
+
bad = FunctionResolver.lookup('not_function')
|
40
|
+
assert !good.nil?
|
41
|
+
assert_nil bad
|
42
|
+
end
|
10
43
|
|
11
44
|
test 'all with field' do
|
12
45
|
f = FunctionResolver.new('all', [
|
@@ -297,186 +330,119 @@ class FunctionResolverTest < Test::Unit::TestCase
|
|
297
330
|
end
|
298
331
|
|
299
332
|
test 'seconds()' do
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
f.expects(:current_time).returns(test_time)
|
333
|
+
f = FunctionResolver.new('seconds',
|
334
|
+
[{ type: :integer, value: 7 }],
|
335
|
+
current_timestamp: EXAMPLE_DATE)
|
304
336
|
f.validate
|
305
|
-
assert !f.errors
|
306
|
-
|
337
|
+
assert !f.errors?
|
338
|
+
assert_times f.call, :datetime, sec: SECONDS + 7
|
307
339
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
assert_equal test_time.month, d.month
|
312
|
-
assert_equal test_time.mday, d.mday
|
313
|
-
assert_equal test_time.hour, d.hour
|
314
|
-
assert_equal test_time.min, d.min
|
315
|
-
assert_equal test_time.sec + 7, d.sec
|
316
|
-
|
317
|
-
f = FunctionResolver.new('seconds', [{ type: :integer, value: -21 }])
|
318
|
-
f.expects(:current_time).returns(test_time)
|
340
|
+
f = FunctionResolver.new('seconds',
|
341
|
+
[{ type: :integer, value: -3 }],
|
342
|
+
current_timestamp: EXAMPLE_DATE)
|
319
343
|
f.validate
|
320
|
-
assert !f.errors
|
321
|
-
|
344
|
+
assert !f.errors?
|
345
|
+
assert_times f.call, :datetime, sec: 59, min: MINUTES - 1
|
322
346
|
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
assert_equal test_time.month, d.month
|
327
|
-
assert_equal test_time.mday, d.mday
|
328
|
-
assert_equal test_time.hour, d.hour
|
329
|
-
assert_equal test_time.min - 1, d.min
|
330
|
-
assert_equal 29, d.min
|
331
|
-
assert_equal 59, d.sec
|
332
|
-
|
333
|
-
f = FunctionResolver.new('seconds', [{ type: :integer,
|
334
|
-
value: -Sparkql::FunctionResolver::SECONDS_IN_DAY }])
|
335
|
-
f.expects(:current_time).returns(test_time)
|
347
|
+
f = FunctionResolver.new('seconds',
|
348
|
+
[{ type: :integer, value: Sparkql::FunctionResolver::SECONDS_IN_DAY }],
|
349
|
+
current_timestamp: EXAMPLE_DATE)
|
336
350
|
f.validate
|
337
|
-
assert !f.errors
|
338
|
-
value = f.call
|
351
|
+
assert !f.errors?
|
339
352
|
|
340
|
-
|
341
|
-
d = DateTime.parse(value[:value])
|
342
|
-
assert_equal test_time.year, d.year
|
343
|
-
assert_equal test_time.month - 1, d.month
|
344
|
-
assert_equal 31, d.mday
|
345
|
-
assert_equal test_time.hour, d.hour
|
346
|
-
assert_equal test_time.min, d.min
|
347
|
-
assert_equal test_time.min, d.min
|
348
|
-
assert_equal test_time.sec, d.sec
|
353
|
+
assert_times f.call, :datetime, year: 2022, mday: 1, month: 1
|
349
354
|
end
|
350
355
|
|
351
356
|
test 'minutes()' do
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
f.expects(:current_time).returns(test_time)
|
357
|
+
f = FunctionResolver.new('minutes',
|
358
|
+
[{ type: :integer, value: 7 }],
|
359
|
+
current_timestamp: EXAMPLE_DATE)
|
356
360
|
f.validate
|
357
|
-
assert !f.errors
|
358
|
-
|
361
|
+
assert !f.errors?
|
362
|
+
assert_times f.call, :datetime, min: MINUTES + 7
|
359
363
|
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
assert_equal test_time.month, d.month
|
364
|
-
assert_equal test_time.mday, d.mday
|
365
|
-
assert_equal test_time.hour, d.hour
|
366
|
-
assert_equal test_time.min + 7, d.min
|
367
|
-
assert_equal test_time.sec, d.sec
|
368
|
-
|
369
|
-
f = FunctionResolver.new('minutes', [{ type: :integer, value: -37 }])
|
370
|
-
f.expects(:current_time).returns(test_time)
|
364
|
+
f = FunctionResolver.new('minutes',
|
365
|
+
[{ type: :integer, value: -2 }],
|
366
|
+
current_timestamp: EXAMPLE_DATE)
|
371
367
|
f.validate
|
372
|
-
assert !f.errors
|
373
|
-
|
374
|
-
|
375
|
-
assert_equal :datetime, value[:type]
|
376
|
-
d = DateTime.parse(value[:value])
|
377
|
-
assert_equal test_time.year, d.year
|
378
|
-
assert_equal test_time.month, d.month
|
379
|
-
assert_equal test_time.mday, d.mday
|
380
|
-
assert_equal test_time.hour - 1, d.hour
|
381
|
-
assert_equal 53, d.min
|
368
|
+
assert !f.errors?
|
369
|
+
assert_times f.call, :datetime, min: 59, hour: 23, mday: DAY - 1
|
382
370
|
|
383
|
-
f = FunctionResolver.new('minutes',
|
384
|
-
|
385
|
-
|
371
|
+
f = FunctionResolver.new('minutes',
|
372
|
+
[{ type: :integer, value: -1440 }],
|
373
|
+
current_timestamp: EXAMPLE_DATE)
|
386
374
|
f.validate
|
387
|
-
assert !f.errors
|
388
|
-
|
389
|
-
|
390
|
-
assert_equal :datetime, value[:type]
|
391
|
-
d = DateTime.parse(value[:value])
|
392
|
-
assert_equal test_time.year, d.year
|
393
|
-
assert_equal test_time.month - 1, d.month
|
394
|
-
assert_equal 31, d.mday
|
395
|
-
assert_equal test_time.hour, d.hour
|
396
|
-
assert_equal test_time.min, d.min
|
375
|
+
assert !f.errors?
|
376
|
+
assert_times f.call, :datetime, mday: DAY - 1
|
397
377
|
end
|
398
378
|
|
399
379
|
test 'hours(), same day' do
|
400
|
-
|
401
|
-
tests = [1, -1, 5, -5, 12]
|
402
|
-
|
380
|
+
tests = [1, 5, 12, 23, 0]
|
403
381
|
tests.each do |offset|
|
404
|
-
f = FunctionResolver.new('hours',
|
405
|
-
|
406
|
-
|
382
|
+
f = FunctionResolver.new('hours',
|
383
|
+
[{ type: :integer, value: offset }],
|
384
|
+
current_timestamp: EXAMPLE_DATE)
|
407
385
|
f.validate
|
408
|
-
assert !f.errors
|
409
|
-
|
386
|
+
assert !f.errors?
|
387
|
+
assert_times f.call, :datetime, hour: HOURS + offset
|
388
|
+
end
|
389
|
+
end
|
410
390
|
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
391
|
+
test 'hours(), previous day' do
|
392
|
+
tests = [-1, -5, -12]
|
393
|
+
tests.each do |offset|
|
394
|
+
f = FunctionResolver.new('hours',
|
395
|
+
[{ type: :integer, value: offset }],
|
396
|
+
current_timestamp: EXAMPLE_DATE)
|
397
|
+
f.validate
|
398
|
+
assert !f.errors?
|
399
|
+
assert_times f.call, :datetime, hour: 24 + offset, mday: DAY - 1
|
419
400
|
end
|
420
401
|
end
|
421
402
|
|
422
403
|
test 'hours(), wrap day' do
|
423
|
-
test_time = Time.new(2019, 4, 1, 8, 30, 20, 0)
|
424
|
-
|
425
404
|
# Jump forward a few days, and a few hours.
|
426
|
-
f = FunctionResolver.new('hours',
|
427
|
-
|
405
|
+
f = FunctionResolver.new('hours',
|
406
|
+
[{ type: :integer, value: 52 }],
|
407
|
+
current_timestamp: EXAMPLE_DATE)
|
428
408
|
f.validate
|
429
|
-
assert !f.errors
|
430
|
-
|
431
|
-
|
432
|
-
assert_equal :datetime, value[:type]
|
433
|
-
d = DateTime.parse(value[:value])
|
434
|
-
assert_equal test_time.year, d.year
|
435
|
-
assert_equal test_time.month, d.month
|
436
|
-
assert_equal test_time.mday + 2, d.mday
|
437
|
-
assert_equal test_time.hour + 4, d.hour
|
438
|
-
assert_equal test_time.min, d.min
|
409
|
+
assert !f.errors?
|
410
|
+
assert_times f.call, :datetime, hour: HOURS + 4, mday: 2, month: 1, year: 2022
|
439
411
|
|
440
412
|
# Drop back to the previous day, which'll also hit the previous month
|
441
|
-
f = FunctionResolver.new('hours',
|
442
|
-
|
413
|
+
f = FunctionResolver.new('hours',
|
414
|
+
[{ type: :integer, value: -24 }],
|
415
|
+
current_timestamp: EXAMPLE_DATE)
|
443
416
|
f.validate
|
444
|
-
assert !f.errors
|
445
|
-
|
446
|
-
|
447
|
-
assert_equal :datetime, value[:type]
|
448
|
-
d = DateTime.parse(value[:value])
|
449
|
-
assert_equal test_time.year, d.year
|
450
|
-
assert_equal test_time.month - 1, d.month
|
451
|
-
assert_equal 31, d.mday
|
452
|
-
assert_equal test_time.hour, d.hour
|
453
|
-
assert_equal test_time.min, d.min
|
417
|
+
assert !f.errors?
|
418
|
+
assert_times f.call, :datetime, mday: DAY - 1
|
454
419
|
|
455
420
|
# Drop back one full year's worth of hours.
|
456
|
-
f = FunctionResolver.new('hours',
|
457
|
-
|
421
|
+
f = FunctionResolver.new('hours',
|
422
|
+
[{ type: :integer, value: -8760 }],
|
423
|
+
current_timestamp: EXAMPLE_DATE)
|
458
424
|
f.validate
|
459
|
-
assert !f.errors
|
460
|
-
|
461
|
-
|
462
|
-
assert_equal :datetime, value[:type]
|
463
|
-
d = DateTime.parse(value[:value])
|
464
|
-
assert_equal test_time.year - 1, d.year
|
465
|
-
assert_equal test_time.month, d.month
|
466
|
-
assert_equal test_time.mday, d.mday
|
467
|
-
assert_equal test_time.hour, d.hour
|
468
|
-
assert_equal test_time.min, d.min
|
425
|
+
assert !f.errors?
|
426
|
+
assert_times f.call, :datetime, year: 2020
|
469
427
|
end
|
470
428
|
|
471
429
|
test 'days()' do
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
430
|
+
[
|
431
|
+
[-1, '2021-12-30', EXAMPLE_DATE],
|
432
|
+
[0, '2021-12-31', EXAMPLE_DATE],
|
433
|
+
[1, '2022-01-01', EXAMPLE_DATE],
|
434
|
+
[7, '2022-01-07', EXAMPLE_DATE],
|
435
|
+
[0, '2022-01-01', Time.parse('2022-01-01T00:00:00-0500')]
|
436
|
+
].each do |val, result, current_timestamp|
|
437
|
+
f = FunctionResolver.new('days',
|
438
|
+
[{ type: :integer, value: val }],
|
439
|
+
current_timestamp: current_timestamp)
|
440
|
+
f.validate
|
441
|
+
assert !f.errors?
|
442
|
+
value = f.call
|
443
|
+
assert_equal :date, value[:type]
|
444
|
+
assert_equal result, value[:value], val
|
445
|
+
end
|
480
446
|
end
|
481
447
|
|
482
448
|
test 'weekdays()' do
|
@@ -549,27 +515,25 @@ class FunctionResolverTest < Test::Unit::TestCase
|
|
549
515
|
end
|
550
516
|
|
551
517
|
test 'months()' do
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
f = FunctionResolver.new('months', [{ type: :integer, value: 3 }])
|
518
|
+
f = FunctionResolver.new('months',
|
519
|
+
[{ type: :integer, value: 3 }],
|
520
|
+
current_timestamp: EXAMPLE_DATE)
|
556
521
|
f.validate
|
557
|
-
assert !f.errors
|
522
|
+
assert !f.errors?
|
558
523
|
value = f.call
|
559
524
|
assert_equal :date, value[:type]
|
560
|
-
|
561
|
-
assert_equal '2014-04-06', value[:value]
|
525
|
+
assert_equal '2022-03-31', value[:value]
|
562
526
|
end
|
563
527
|
|
564
528
|
test 'years()' do
|
565
|
-
|
566
|
-
|
567
|
-
|
529
|
+
f = FunctionResolver.new('years',
|
530
|
+
[{ type: :integer, value: -4 }],
|
531
|
+
current_timestamp: EXAMPLE_DATE)
|
568
532
|
f.validate
|
569
|
-
assert !f.errors
|
533
|
+
assert !f.errors?
|
570
534
|
value = f.call
|
571
535
|
assert_equal :date, value[:type]
|
572
|
-
assert_equal '
|
536
|
+
assert_equal '2017-12-31', value[:value]
|
573
537
|
end
|
574
538
|
|
575
539
|
test 'year(), month(), and day()' do
|
@@ -821,7 +785,7 @@ class FunctionResolverTest < Test::Unit::TestCase
|
|
821
785
|
|
822
786
|
assert_equal :function, value[:type]
|
823
787
|
assert_equal 'cast', value[:value]
|
824
|
-
assert_equal(%w[Bedrooms character], value[:args].map{ |v| v[:value] })
|
788
|
+
assert_equal(%w[Bedrooms character], value[:args].map { |v| v[:value] })
|
825
789
|
end
|
826
790
|
|
827
791
|
test 'invalid cast returns null' do
|
@@ -847,7 +811,7 @@ class FunctionResolverTest < Test::Unit::TestCase
|
|
847
811
|
assert !f.errors?, "Errors #{f.errors.inspect}"
|
848
812
|
value = f.call
|
849
813
|
assert_equal :time, value[:type]
|
850
|
-
assert_equal '
|
814
|
+
assert_equal '00:01:02.123456000', value[:value]
|
851
815
|
end
|
852
816
|
|
853
817
|
test 'date(datetime)' do
|
@@ -856,7 +820,7 @@ class FunctionResolverTest < Test::Unit::TestCase
|
|
856
820
|
assert !f.errors?, "Errors #{f.errors.inspect}"
|
857
821
|
value = f.call
|
858
822
|
assert_equal :date, value[:type]
|
859
|
-
assert_equal '
|
823
|
+
assert_equal '2021-12-31', value[:value]
|
860
824
|
end
|
861
825
|
|
862
826
|
###
|
@@ -8,8 +8,8 @@ class Sparkql::Geo::RecordRadiusTest < Test::Unit::TestCase
|
|
8
8
|
"201000000000000000000000000",
|
9
9
|
"test",
|
10
10
|
"12.45,-96.5"].each do |bad_record_id|
|
11
|
-
|
12
|
-
|
11
|
+
assert !Sparkql::Geo::RecordRadius.valid_record_id?(bad_record_id),
|
12
|
+
"'#{bad_record_id}' should not be a valid record_id"
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
data/test/unit/lexer_test.rb
CHANGED
@@ -4,20 +4,20 @@ class LexerTest < Test::Unit::TestCase
|
|
4
4
|
include Sparkql
|
5
5
|
|
6
6
|
test "record the current token and current oken position" do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
@lexer = Lexer.new "City Eq 'Fargo'"
|
8
|
+
@lexer.shift
|
9
|
+
assert_equal "City", @lexer.current_token_value
|
10
|
+
assert_equal 0, @lexer.token_index
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
@lexer.shift
|
13
|
+
assert_equal " ", @lexer.current_token_value
|
14
|
+
assert_equal 4, @lexer.token_index
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
@lexer.shift
|
17
|
+
assert_equal "Eq", @lexer.current_token_value
|
18
|
+
assert_equal 5, @lexer.token_index
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
def test_check_reserved_words_standard_fields
|
22
22
|
["OrOrOr Eq true", "Equador Eq true", "Oregon Ge 10"].each do |standard_field|
|
23
23
|
@lexer = Lexer.new(standard_field)
|
@@ -27,7 +27,7 @@ class LexerTest < Test::Unit::TestCase
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def test_standard_field_formats
|
30
|
-
[
|
30
|
+
%w[City PostalCodePlus4 Inb4ParserError].each do |standard_field|
|
31
31
|
@lexer = Lexer.new("#{standard_field} Eq true")
|
32
32
|
token = @lexer.shift
|
33
33
|
assert_equal :STANDARD_FIELD, token.first, standard_field
|
@@ -39,7 +39,7 @@ class LexerTest < Test::Unit::TestCase
|
|
39
39
|
@lexer = Lexer.new("4PostalCodePlus4 Eq true")
|
40
40
|
token = @lexer.shift
|
41
41
|
assert_equal :INTEGER, token.first
|
42
|
-
assert_equal token[1][:value], "4"
|
42
|
+
assert_equal token[1][:value], "4"
|
43
43
|
end
|
44
44
|
|
45
45
|
def test_check_reserved_words_conjunctions
|
@@ -62,7 +62,7 @@ class LexerTest < Test::Unit::TestCase
|
|
62
62
|
assert_equal :OPERATOR, token.first, op
|
63
63
|
end
|
64
64
|
|
65
|
-
['Bt 1234','Bt 1234,12345'].each do |op|
|
65
|
+
['Bt 1234', 'Bt 1234,12345'].each do |op|
|
66
66
|
@lexer = Lexer.new(op)
|
67
67
|
token = @lexer.shift
|
68
68
|
assert_equal :RANGE_OPERATOR, token.first, op
|
@@ -78,7 +78,7 @@ class LexerTest < Test::Unit::TestCase
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def test_dates_matches
|
81
|
-
[
|
81
|
+
%w[2013-07-26 1999-01-01].each do |op|
|
82
82
|
@lexer = Lexer.new(op)
|
83
83
|
token = @lexer.shift
|
84
84
|
assert_equal :DATE, token.first, op
|
@@ -108,5 +108,4 @@ class LexerTest < Test::Unit::TestCase
|
|
108
108
|
assert_equal :DECIMAL, token.first, op
|
109
109
|
end
|
110
110
|
end
|
111
|
-
|
112
111
|
end
|