sparkql 1.2.5 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/.rubocop.yml +111 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +16 -0
- data/Gemfile +1 -2
- 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 +777 -676
- 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 +98 -77
- 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 +20 -18
- 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 +445 -203
- 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 +133 -99
- metadata +36 -35
data/test/unit/parser_test.rb
CHANGED
@@ -5,10 +5,10 @@ class ParserTest < Test::Unit::TestCase
|
|
5
5
|
|
6
6
|
def test_simple
|
7
7
|
@parser = Parser.new
|
8
|
-
parse 'Test Eq 10',10.to_s
|
9
|
-
parse 'Test Eq 10.0',10.0.to_s
|
10
|
-
parse 'Test Eq true',true.to_s
|
11
|
-
parse "Test Eq 'false'","'false'"
|
8
|
+
parse 'Test Eq 10', 10.to_s
|
9
|
+
parse 'Test Eq 10.0', 10.0.to_s
|
10
|
+
parse 'Test Eq true', true.to_s
|
11
|
+
parse "Test Eq 'false'", "'false'"
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_conjunction
|
@@ -26,7 +26,7 @@ class ParserTest < Test::Unit::TestCase
|
|
26
26
|
assert_equal 11.to_s, expression.last[:value]
|
27
27
|
assert_equal 'Not', expression.last[:conjunction]
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
def test_tough_conjunction
|
31
31
|
@parser = Parser.new
|
32
32
|
expression = @parser.parse('Test Eq 10 Or Test Ne 11 And Test Ne 9')
|
@@ -52,50 +52,50 @@ class ParserTest < Test::Unit::TestCase
|
|
52
52
|
def test_multiples
|
53
53
|
@parser = Parser.new
|
54
54
|
expression = @parser.parse('(Test Eq 10,11,12)').first
|
55
|
-
assert_equal [10.to_s,11.to_s,12.to_s], expression[:value]
|
55
|
+
assert_equal [10.to_s, 11.to_s, 12.to_s], expression[:value]
|
56
56
|
assert_equal '10,11,12', expression[:condition]
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
def test_invalid_syntax
|
60
60
|
@parser = Parser.new
|
61
61
|
expression = @parser.parse('Test Eq DERP')
|
62
62
|
assert @parser.errors?, "Should be nil: #{expression}"
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
def test_nesting
|
66
66
|
assert_nesting(
|
67
67
|
"City Eq 'Fargo' Or (BathsFull Eq 1 Or BathsFull Eq 2) Or City Eq 'Moorhead' Or City Eq 'Dilworth'",
|
68
|
-
[0,1,1,0,0]
|
68
|
+
[0, 1, 1, 0, 0]
|
69
69
|
)
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
def test_nesting_and_functions
|
73
73
|
# Nesting with a function thrown in. Yes, this was a problem.
|
74
74
|
assert_nesting(
|
75
75
|
"City Eq 'Fargo' Or (BathsFull Eq 1 And Location Eq rectangle('35.12 -68.33, 35.13 -68.32')) Or Location Eq radius('35.12 -68.33',10.0) Or City Eq 'Dilworth'",
|
76
|
-
[0,1,1,0,0]
|
76
|
+
[0, 1, 1, 0, 0]
|
77
77
|
)
|
78
78
|
end
|
79
79
|
|
80
80
|
def test_multilevel_nesting
|
81
81
|
assert_nesting(
|
82
82
|
"(City Eq 'Fargo' And (BathsFull Eq 1 Or BathsFull Eq 2)) Or City Eq 'Moorhead' Or City Eq 'Dilworth'",
|
83
|
-
[1,2,2,0,0]
|
83
|
+
[1, 2, 2, 0, 0]
|
84
84
|
)
|
85
|
-
|
85
|
+
|
86
86
|
# API-629
|
87
87
|
assert_nesting(
|
88
88
|
"((MlsStatus Eq 'A') Or (MlsStatus Eq 'D' And CloseDate Ge 2011-05-17)) And ListPrice Ge 150000.0 And PropertyType Eq 'A'",
|
89
|
-
[2,2,2,0,0],
|
90
|
-
[2,3,3,0,0]
|
89
|
+
[2, 2, 2, 0, 0],
|
90
|
+
[2, 3, 3, 0, 0]
|
91
91
|
)
|
92
92
|
assert_nesting(
|
93
93
|
"ListPrice Ge 150000.0 And PropertyType Eq 'A' And ((MlsStatus Eq 'A') Or (MlsStatus Eq 'D' And CloseDate Ge 2011-05-17))",
|
94
|
-
[0,0,2,2,2],
|
95
|
-
[0,0,2,3,3]
|
94
|
+
[0, 0, 2, 2, 2],
|
95
|
+
[0, 0, 2, 3, 3]
|
96
96
|
)
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
def test_bad_queries
|
100
100
|
filter = "City IsLikeA 'Town'"
|
101
101
|
@parser = Parser.new
|
@@ -105,8 +105,8 @@ class ParserTest < Test::Unit::TestCase
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def test_function_months
|
108
|
-
|
109
|
-
|
108
|
+
t = Time.new(2014, 1, 5, 0, 0, 0, 0)
|
109
|
+
Time.expects(:now).returns(t)
|
110
110
|
@parser = Parser.new
|
111
111
|
expressions = @parser.parse "ExpirationDate Gt months(-3)"
|
112
112
|
assert !@parser.errors?, "errors :( #{@parser.errors.inspect}"
|
@@ -115,8 +115,8 @@ class ParserTest < Test::Unit::TestCase
|
|
115
115
|
end
|
116
116
|
|
117
117
|
def test_function_years
|
118
|
-
|
119
|
-
|
118
|
+
t = Time.new(2014, 1, 5, 0, 0, 0, 0)
|
119
|
+
Time.expects(:now).returns(t)
|
120
120
|
@parser = Parser.new
|
121
121
|
expressions = @parser.parse "SoldDate Lt years(2)"
|
122
122
|
assert !@parser.errors?, "errors :( #{@parser.errors.inspect}"
|
@@ -125,19 +125,23 @@ class ParserTest < Test::Unit::TestCase
|
|
125
125
|
end
|
126
126
|
|
127
127
|
def test_function_days
|
128
|
-
|
129
|
-
|
130
|
-
filter = "OriginalEntryTimestamp Ge days(-7)"
|
128
|
+
t = Time.new(2021, 2, 22, 0, 0, 0, 0)
|
129
|
+
Time.expects(:now).returns(t)
|
131
130
|
@parser = Parser.new
|
132
|
-
expressions = @parser.parse(
|
133
|
-
assert !@parser.errors
|
134
|
-
assert_equal
|
135
|
-
|
136
|
-
|
131
|
+
expressions = @parser.parse "ExpirationDate Gt days(10)"
|
132
|
+
assert !@parser.errors?
|
133
|
+
assert_equal "2021-03-04", expressions.first[:value]
|
134
|
+
assert_equal 'days(10)', expressions.first[:condition]
|
135
|
+
end
|
137
136
|
|
138
|
-
|
139
|
-
|
140
|
-
|
137
|
+
def test_function_weekdays
|
138
|
+
t = Time.new(2021, 2, 22, 0, 0, 0, 0)
|
139
|
+
Time.expects(:now).returns(t)
|
140
|
+
@parser = Parser.new
|
141
|
+
expressions = @parser.parse "ExpirationDate Gt weekdays(10)"
|
142
|
+
assert !@parser.errors?
|
143
|
+
assert_equal "2021-03-08", expressions.first[:value]
|
144
|
+
assert_equal 'weekdays(10)', expressions.first[:condition]
|
141
145
|
end
|
142
146
|
|
143
147
|
def test_function_now
|
@@ -148,8 +152,8 @@ class ParserTest < Test::Unit::TestCase
|
|
148
152
|
assert !@parser.errors?, "errors #{@parser.errors.inspect}"
|
149
153
|
assert_equal 'now()', expressions.first[:condition]
|
150
154
|
test_time = Time.parse(expressions.first[:value])
|
151
|
-
assert
|
152
|
-
assert -
|
155
|
+
assert test_time - start < 5, "Time range off by more than five seconds #{test_time - start}"
|
156
|
+
assert(test_time - start > -5, "Time range off by more than five seconds #{test_time - start}")
|
153
157
|
end
|
154
158
|
|
155
159
|
def test_function_range
|
@@ -174,7 +178,8 @@ class ParserTest < Test::Unit::TestCase
|
|
174
178
|
assert_equal 'indexof', expression[:field_manipulations][:function_name]
|
175
179
|
assert_equal :function, expression[:field_manipulations][:type]
|
176
180
|
assert_equal :integer, expression[:field_manipulations][:return_type]
|
177
|
-
assert_equal
|
181
|
+
assert_equal(%w[City 4131800000000],
|
182
|
+
expression[:field_manipulations][:args].map { |v| v[:value] })
|
178
183
|
end
|
179
184
|
|
180
185
|
test 'add' do
|
@@ -307,7 +312,7 @@ class ParserTest < Test::Unit::TestCase
|
|
307
312
|
assert_equal 'days(-7)', expressions.first[:condition]
|
308
313
|
assert_equal([-7], expressions.first[:function_parameters])
|
309
314
|
end
|
310
|
-
|
315
|
+
|
311
316
|
test "function rangeable " do
|
312
317
|
filter = "OriginalEntryTimestamp Bt days(-7),days(-1)"
|
313
318
|
@parser = Parser.new
|
@@ -388,10 +393,40 @@ class ParserTest < Test::Unit::TestCase
|
|
388
393
|
test "invalid regex" do
|
389
394
|
filter = "ParcelNumber Eq regex('[1234', '')"
|
390
395
|
@parser = Parser.new
|
391
|
-
|
396
|
+
@parser.parse(filter)
|
392
397
|
assert @parser.errors?, "Parser error expected due to invalid regex"
|
393
398
|
end
|
394
399
|
|
400
|
+
test "dayofyear function parses" do
|
401
|
+
filter = "dayofyear(DatetimeField) Eq 2012"
|
402
|
+
@parser = Parser.new
|
403
|
+
expressions = @parser.parse(filter)
|
404
|
+
assert !@parser.errors?, @parser.errors.inspect
|
405
|
+
function = expressions.first[:field_manipulations]
|
406
|
+
assert_equal 'dayofyear', function[:function_name]
|
407
|
+
assert_equal 'DatetimeField', function[:function_parameters].first
|
408
|
+
end
|
409
|
+
|
410
|
+
test "dayofweek function parses" do
|
411
|
+
filter = "dayofweek(DatetimeField) Eq 7"
|
412
|
+
@parser = Parser.new
|
413
|
+
expressions = @parser.parse(filter)
|
414
|
+
assert !@parser.errors?, @parser.errors.inspect
|
415
|
+
function = expressions.first[:field_manipulations]
|
416
|
+
assert_equal 'dayofweek', function[:function_name]
|
417
|
+
assert_equal 'DatetimeField', function[:function_parameters].first
|
418
|
+
end
|
419
|
+
|
420
|
+
test "weekdays function resolves" do
|
421
|
+
filter = "DatetimeField Eq weekdays(10)"
|
422
|
+
@parser = Parser.new
|
423
|
+
expressions = @parser.parse(filter)
|
424
|
+
assert !@parser.errors?, @parser.errors.inspect
|
425
|
+
function = expressions.first
|
426
|
+
assert_equal 'weekdays', function[:function_name]
|
427
|
+
assert_equal 10, function[:function_parameters].first
|
428
|
+
end
|
429
|
+
|
395
430
|
test "allow timezone offsets" do
|
396
431
|
values = [
|
397
432
|
"2013-07-26",
|
@@ -418,7 +453,7 @@ class ParserTest < Test::Unit::TestCase
|
|
418
453
|
assert_equal expressions.first[:value], value, "#{value} failed"
|
419
454
|
end
|
420
455
|
end
|
421
|
-
|
456
|
+
|
422
457
|
test "Location Eq polygon()" do
|
423
458
|
filter = "Location Eq polygon('35.12 -68.33, 35.13 -68.33, 35.13 -68.32, 35.12 -68.32')"
|
424
459
|
@parser = Parser.new
|
@@ -426,7 +461,7 @@ class ParserTest < Test::Unit::TestCase
|
|
426
461
|
assert !@parser.errors?, "errors #{@parser.errors.inspect}"
|
427
462
|
assert_equal "polygon('35.12 -68.33, 35.13 -68.33, 35.13 -68.32, 35.12 -68.32')", expressions.first[:condition]
|
428
463
|
assert_equal :shape, expressions.first[:type]
|
429
|
-
assert_equal [[-68.33, 35.12], [-68.33, 35.13], [-68.32,35.13], [-68.32,35.12],[-68.33, 35.12]], expressions.first[:value].to_coordinates.first, "#{expressions.first[:value].inspect} "
|
464
|
+
assert_equal [[-68.33, 35.12], [-68.33, 35.13], [-68.32, 35.13], [-68.32, 35.12], [-68.33, 35.12]], expressions.first[:value].to_coordinates.first, "#{expressions.first[:value].inspect} "
|
430
465
|
end
|
431
466
|
|
432
467
|
test "Location Eq linestring()" do
|
@@ -437,7 +472,6 @@ class ParserTest < Test::Unit::TestCase
|
|
437
472
|
assert_equal "linestring('35.12 -68.33, 35.13 -68.33')", expressions.first[:condition]
|
438
473
|
assert_equal :shape, expressions.first[:type]
|
439
474
|
assert_equal [[-68.33, 35.12], [-68.33, 35.13]], expressions.first[:value].to_coordinates, "#{expressions.first[:value].inspect} "
|
440
|
-
|
441
475
|
end
|
442
476
|
|
443
477
|
test "Location Eq rectangle()" do
|
@@ -446,7 +480,7 @@ class ParserTest < Test::Unit::TestCase
|
|
446
480
|
expressions = @parser.parse(filter)
|
447
481
|
assert !@parser.errors?, "errors #{@parser.errors.inspect}"
|
448
482
|
assert_equal :shape, expressions.first[:type]
|
449
|
-
assert_equal [[-68.33,35.12], [-68.32,35.12], [-68.32,35.13], [-68.33,35.13], [-68.33,35.12]], expressions.first[:value].to_coordinates.first, "#{expressions.first[:value].inspect} "
|
483
|
+
assert_equal [[-68.33, 35.12], [-68.32, 35.12], [-68.32, 35.13], [-68.33, 35.13], [-68.33, 35.12]], expressions.first[:value].to_coordinates.first, "#{expressions.first[:value].inspect} "
|
450
484
|
end
|
451
485
|
|
452
486
|
test "Location Eq radius()" do
|
@@ -473,26 +507,26 @@ class ParserTest < Test::Unit::TestCase
|
|
473
507
|
test "Location eq radius() error on invalid syntax" do
|
474
508
|
filter = "Location Eq radius('35.12,-68.33',1.0)"
|
475
509
|
@parser = Parser.new
|
476
|
-
|
510
|
+
@parser.parse(filter)
|
477
511
|
assert @parser.errors?, "Parser error expected due to comma between radius points"
|
478
512
|
end
|
479
|
-
|
513
|
+
|
480
514
|
test "Location ALL TOGETHER NOW" do
|
481
515
|
filter = "Location Eq linestring('35.12 -68.33, 35.13 -68.33') And Location Eq radius('35.12 -68.33',1.0) And Location Eq rectangle('35.12 -68.33, 35.13 -68.32') And Location Eq polygon('35.12 -68.33, 35.13 -68.33, 35.13 -68.32, 35.12 -68.32')"
|
482
516
|
@parser = Parser.new
|
483
517
|
expressions = @parser.parse(filter)
|
484
518
|
assert !@parser.errors?, "errors #{@parser.errors.inspect}"
|
485
|
-
assert_equal
|
519
|
+
assert_equal(%i[shape shape shape shape], expressions.map { |e| e[:type] })
|
486
520
|
end
|
487
|
-
|
521
|
+
|
488
522
|
def test_for_reserved_words_first_literals_second
|
489
523
|
["OrOrOr Eq true", "Equador Eq true", "Oregon Ge 10"].each do |filter|
|
490
524
|
@parser = Parser.new
|
491
|
-
|
525
|
+
@parser.parse(filter)
|
492
526
|
assert !@parser.errors?, "Filter '#{filter}' errors: #{@parser.errors.inspect}"
|
493
527
|
end
|
494
528
|
end
|
495
|
-
|
529
|
+
|
496
530
|
def test_custom_fields
|
497
531
|
filter = '"General Property Description"."Taxes" Lt 500.0'
|
498
532
|
@parser = Parser.new
|
@@ -502,48 +536,46 @@ class ParserTest < Test::Unit::TestCase
|
|
502
536
|
assert expressions.first[:custom_field], "Custom field expression #{expressions.inspect}"
|
503
537
|
assert_equal '500.0', expressions.first[:value], "Custom field expression #{expressions.inspect}"
|
504
538
|
end
|
505
|
-
|
539
|
+
|
506
540
|
def test_valid_custom_field_filters
|
507
541
|
['"General Property Description"."Taxes$" Lt 500.0',
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
].each do |filter|
|
542
|
+
'"General Property Desc\'"."Taxes" Lt 500.0',
|
543
|
+
'"General Property Description"."Taxes" Lt 500.0',
|
544
|
+
'"General \'Property\' Description"."Taxes" Lt 500.0',
|
545
|
+
'"General Property Description"."Taxes #" Lt 500.0',
|
546
|
+
'"General$Description"."Taxes" Lt 500.0',
|
547
|
+
'"Garage Type"."1" Eq true',
|
548
|
+
'" a "." b " Lt 500.0'].each do |filter|
|
516
549
|
@parser = Parser.new
|
517
|
-
|
550
|
+
@parser.parse(filter)
|
518
551
|
assert !@parser.errors?, "errors '#{filter}'\n#{@parser.errors.inspect}"
|
519
552
|
end
|
520
553
|
end
|
521
|
-
|
554
|
+
|
522
555
|
def test_invalid_custom_field_filters
|
523
556
|
['"$General Property Description"."Taxes" Lt 500.0',
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
].each do |filter|
|
557
|
+
'"General Property Description"."$Taxes" Lt 500.0',
|
558
|
+
'"General Property Description"."Tax.es" Lt 500.0',
|
559
|
+
'"General Property Description".".Taxes" Lt 500.0',
|
560
|
+
'"General Property Description".".Taxes"."SUB" Lt 500.0',
|
561
|
+
'"General.Description"."Taxes" Lt 500.0',
|
562
|
+
'""."" Lt 500.0'].each do |filter|
|
531
563
|
@parser = Parser.new
|
532
|
-
|
564
|
+
@parser.parse(filter)
|
533
565
|
assert @parser.errors?, "No errors? '#{filter}'\n#{@parser.inspect}"
|
534
566
|
end
|
535
567
|
end
|
536
568
|
|
537
569
|
def test_case_insensitve_ops_and_conjunctions
|
538
570
|
@parser = Parser.new
|
539
|
-
parse 'Test EQ 10',10.to_s
|
540
|
-
parse 'Test eq 10.0',10.0.to_s
|
541
|
-
parse 'Test eQ true',true.to_s
|
571
|
+
parse 'Test EQ 10', 10.to_s
|
572
|
+
parse 'Test eq 10.0', 10.0.to_s
|
573
|
+
parse 'Test eQ true', true.to_s
|
542
574
|
parse 'Test EQ 10 AND Test NE 11', 10.to_s
|
543
575
|
parse 'Test eq 10 or Test ne 11', 10.to_s
|
544
576
|
parse 'Test eq 10 NOT Test ne 11', 10.to_s
|
545
577
|
end
|
546
|
-
|
578
|
+
|
547
579
|
def test_null
|
548
580
|
@parser = Parser.new
|
549
581
|
parse 'Test Eq NULL', "NULL"
|
@@ -557,7 +589,7 @@ class ParserTest < Test::Unit::TestCase
|
|
557
589
|
end
|
558
590
|
end
|
559
591
|
end
|
560
|
-
|
592
|
+
|
561
593
|
def test_not_expression
|
562
594
|
@parser = Parser.new
|
563
595
|
expressions = @parser.parse('Test Lt 10 Not Test Eq 2')
|
@@ -578,7 +610,7 @@ class ParserTest < Test::Unit::TestCase
|
|
578
610
|
assert_equal "And", expression[:conjunction]
|
579
611
|
assert_equal expression[:level], expression[:unary_level]
|
580
612
|
end
|
581
|
-
|
613
|
+
|
582
614
|
def test_not_expression_group
|
583
615
|
@parser = Parser.new
|
584
616
|
expressions = @parser.parse('Not (Test Eq 10 Or Test Eq 11)')
|
@@ -603,7 +635,7 @@ class ParserTest < Test::Unit::TestCase
|
|
603
635
|
|
604
636
|
def test_not_not_expression
|
605
637
|
@parser = Parser.new
|
606
|
-
filter = "Not (Not ListPrice Eq 1) Not (Not BathsTotal Eq 2) And "
|
638
|
+
filter = "Not (Not ListPrice Eq 1) Not (Not BathsTotal Eq 2) And " \
|
607
639
|
"(Not TotalRooms Eq 3) Or (HasPool Eq true)"
|
608
640
|
|
609
641
|
expressions = @parser.parse(filter)
|
@@ -672,7 +704,6 @@ class ParserTest < Test::Unit::TestCase
|
|
672
704
|
assert_equal 1, e2[:level]
|
673
705
|
assert_equal "Not", e2[:conjunction]
|
674
706
|
assert_equal 1, e2[:conjunction_level]
|
675
|
-
|
676
707
|
end
|
677
708
|
|
678
709
|
def test_expression_conditions_attribute
|
@@ -704,7 +735,7 @@ class ParserTest < Test::Unit::TestCase
|
|
704
735
|
]
|
705
736
|
conditions.each do |condition|
|
706
737
|
@parser = Parser.new
|
707
|
-
|
738
|
+
@parser.parse("Test Eq #{condition}")
|
708
739
|
assert @parser.errors?, @parser.inspect
|
709
740
|
end
|
710
741
|
end
|
@@ -714,12 +745,12 @@ class ParserTest < Test::Unit::TestCase
|
|
714
745
|
"DateTimeField Bt 2013-07-26T10:22:15,2013-07-26T10:22:16",
|
715
746
|
"DateTimeField Bt 2013-07-26T10:22:15.422804-0300,2013-07-26T10:22:15.422805-0300",
|
716
747
|
"DateTimeField Bt 2013-07-26T10:22:15+0400,2013-07-26T10:22:16+0400"].each do |filter|
|
717
|
-
|
718
|
-
|
719
|
-
|
748
|
+
@parser = Parser.new
|
749
|
+
@parser.parse filter
|
750
|
+
assert !@parser.errors?, "Filter '#{filter}' failed: #{@parser.errors.first.inspect}"
|
720
751
|
end
|
721
752
|
end
|
722
|
-
|
753
|
+
|
723
754
|
def test_coercible_types
|
724
755
|
@parser = Parser.new
|
725
756
|
assert_equal :datetime, @parser.coercible_types(:date, :datetime)
|
@@ -780,7 +811,6 @@ class ParserTest < Test::Unit::TestCase
|
|
780
811
|
parser_errors("Field Eq -'Stringval'")
|
781
812
|
end
|
782
813
|
|
783
|
-
|
784
814
|
test "field negation" do
|
785
815
|
@parser = Parser.new
|
786
816
|
expressions = @parser.parse('-Test Eq 10')
|
@@ -827,7 +857,8 @@ class ParserTest < Test::Unit::TestCase
|
|
827
857
|
|
828
858
|
assert_equal 'round', expression[:field_manipulations][:function_name]
|
829
859
|
assert_equal :function, expression[:field_manipulations][:type]
|
830
|
-
assert_equal
|
860
|
+
assert_equal(['ListPrice'],
|
861
|
+
expression[:field_manipulations][:args].map { |v| v[:value] })
|
831
862
|
end
|
832
863
|
|
833
864
|
def test_ceiling_with_literal
|
@@ -887,7 +918,8 @@ class ParserTest < Test::Unit::TestCase
|
|
887
918
|
|
888
919
|
assert_equal 'floor', expression[:field_manipulations][:function_name]
|
889
920
|
assert_equal :function, expression[:field_manipulations][:type]
|
890
|
-
assert_equal
|
921
|
+
assert_equal(['ListPrice'],
|
922
|
+
expression[:field_manipulations][:args].map { |v| v[:value] })
|
891
923
|
end
|
892
924
|
|
893
925
|
def test_concat_with_field
|
@@ -898,12 +930,13 @@ class ParserTest < Test::Unit::TestCase
|
|
898
930
|
|
899
931
|
assert_equal :character, expression[:type]
|
900
932
|
assert_equal 'concat', expression[:field_function]
|
901
|
-
assert_equal([
|
933
|
+
assert_equal(%w[City b], expression[:args])
|
902
934
|
assert_equal("City", expression[:field])
|
903
935
|
|
904
936
|
assert_equal 'concat', expression[:field_manipulations][:function_name]
|
905
937
|
assert_equal :function, expression[:field_manipulations][:type]
|
906
|
-
assert_equal
|
938
|
+
assert_equal(%w[City b],
|
939
|
+
expression[:field_manipulations][:args].map { |v| v[:value] })
|
907
940
|
end
|
908
941
|
|
909
942
|
def test_concat_with_literal
|
@@ -915,7 +948,7 @@ class ParserTest < Test::Unit::TestCase
|
|
915
948
|
assert_equal 'concat', expression[:function_name]
|
916
949
|
assert_equal :character, expression[:type]
|
917
950
|
assert_equal "'ab'", expression[:value]
|
918
|
-
assert_equal [
|
951
|
+
assert_equal %w[a b], expression[:function_parameters]
|
919
952
|
end
|
920
953
|
|
921
954
|
def test_cast_with_field
|
@@ -930,7 +963,8 @@ class ParserTest < Test::Unit::TestCase
|
|
930
963
|
|
931
964
|
assert_equal 'cast', expression[:field_manipulations][:function_name]
|
932
965
|
assert_equal :function, expression[:field_manipulations][:type]
|
933
|
-
assert_equal
|
966
|
+
assert_equal(%w[ListPrice character],
|
967
|
+
expression[:field_manipulations][:args].map { |v| v[:value] })
|
934
968
|
end
|
935
969
|
|
936
970
|
def test_cast_with_invalid_type
|
@@ -1131,7 +1165,7 @@ class ParserTest < Test::Unit::TestCase
|
|
1131
1165
|
function2 = function1[:args].first
|
1132
1166
|
assert_equal :function, function2[:type]
|
1133
1167
|
assert_equal 'toupper', function2[:function_name]
|
1134
|
-
assert_equal({:
|
1168
|
+
assert_equal({ type: :field, value: "City" }, function2[:args].first)
|
1135
1169
|
end
|
1136
1170
|
|
1137
1171
|
test 'nested functions with multiple params' do
|
@@ -1142,12 +1176,12 @@ class ParserTest < Test::Unit::TestCase
|
|
1142
1176
|
function1 = expression[:field_manipulations]
|
1143
1177
|
assert_equal :function, function1[:type]
|
1144
1178
|
assert_equal 'concat', function1[:function_name]
|
1145
|
-
assert_equal({type: :character, value: 'b'}, function1[:args].last)
|
1179
|
+
assert_equal({ type: :character, value: 'b' }, function1[:args].last)
|
1146
1180
|
|
1147
1181
|
function2 = function1[:args].first
|
1148
1182
|
assert_equal :function, function2[:type]
|
1149
1183
|
assert_equal 'tolower', function2[:function_name]
|
1150
|
-
assert_equal({:
|
1184
|
+
assert_equal({ type: :field, value: "City" }, function2[:args].first)
|
1151
1185
|
end
|
1152
1186
|
|
1153
1187
|
test 'parse error with no field' do
|
@@ -1200,30 +1234,30 @@ class ParserTest < Test::Unit::TestCase
|
|
1200
1234
|
|
1201
1235
|
private
|
1202
1236
|
|
1203
|
-
def parser_errors(filter)
|
1237
|
+
def parser_errors(filter)
|
1204
1238
|
@parser = Parser.new
|
1205
1239
|
expression = @parser.parse(filter)
|
1206
1240
|
assert @parser.errors?, "Should find errors for '#{filter}': #{expression}"
|
1207
1241
|
end
|
1208
1242
|
|
1209
|
-
def parse(
|
1210
|
-
expressions = @parser.parse(
|
1211
|
-
assert !@parser.errors?, "Unexpected error parsing #{
|
1212
|
-
assert_equal
|
1243
|
+
def parse(query, value)
|
1244
|
+
expressions = @parser.parse(query)
|
1245
|
+
assert !@parser.errors?, "Unexpected error parsing #{query} #{@parser.errors.inspect}"
|
1246
|
+
assert_equal value, expressions.first[:value], "Expression #{expressions.inspect}"
|
1213
1247
|
assert !expressions.first[:custom_field], "Unexepected custom field #{expressions.inspect}"
|
1214
1248
|
end
|
1215
1249
|
|
1216
1250
|
# verify each expression in the query is at the right nesting level and group
|
1217
|
-
def assert_nesting(sparkql, levels=[], block_groups=nil)
|
1251
|
+
def assert_nesting(sparkql, levels = [], block_groups = nil)
|
1218
1252
|
block_groups = levels.clone if block_groups.nil?
|
1219
1253
|
parser = Parser.new
|
1220
1254
|
expressions = parser.parse(sparkql)
|
1221
1255
|
assert !parser.errors?, "Unexpected error parsing #{sparkql}: #{parser.errors.inspect}"
|
1222
1256
|
count = 0
|
1223
1257
|
expressions.each do |ex|
|
1224
|
-
assert_equal levels[count],
|
1225
|
-
assert_equal(block_groups[count],
|
1226
|
-
count +=1
|
1258
|
+
assert_equal levels[count], ex[:level], "Nesting level wrong for #{ex.inspect}"
|
1259
|
+
assert_equal(block_groups[count], ex[:block_group], "Nesting block group wrong for #{ex.inspect}")
|
1260
|
+
count += 1
|
1227
1261
|
end
|
1228
1262
|
end
|
1229
1263
|
end
|