sparkql 1.1.13 → 1.1.14

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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YTJhM2I5YjU5YTg1NTVhNDgyOTJjYzE5YjI4YjlkZjkzZmI3NjFmYw==
4
+ MTMwMTA4MTcwZWRiNzFiMzJkOTFmYzgwNmVlYjRhNzQwZTZlOWQ5OA==
5
5
  data.tar.gz: !binary |-
6
- MjAyMjAwN2VhYTNmN2Q1NjhkNGZmN2FhNGY5OTgwMjdhNDY3ZWFjMQ==
6
+ OWQ3NWE4ZmQxOTQ3ZTcxMTk1MmE5MDM4OWU5NWNhNWY5NDUwZDUyYg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- OWY5MmVmNDhmMGM0OTgzNmE2NjE4OWM5NmQ4M2QxOTJiMGFiOGQ4MDlkMmJj
10
- NDBhNTVkZDgyMGJmYmU1Y2YwOTdiOTNmN2ZkYTcxOWM1MWNkNjJmZmJiMmI3
11
- ODhmOGIzNWFiYTEwYTQzMThiNGNkNThlNDc0OGQzYTNmMjA4NWU=
9
+ MzY2NGFkZWYxNWM2ZGQyZWMyNjRmZTkzMzU2OTYwZDBmNzk2YjhmMzc4ZjFj
10
+ NjdiYTM5MTBjNmY3ZTQxNmVkOWU4YzFjYzY5MjY2NDQzZDI3MzVmZmUxYWQ0
11
+ NGZmYzE5MGM3ODlkZmQ1M2M4NGY4M2I2MGE0MzQyYzVkNzcwOTU=
12
12
  data.tar.gz: !binary |-
13
- MzI5MWY5NDRkN2ViNGFhMzUzOTQwMWZmZTQ3ZmUwZjE3ZGY5NDJjM2UxMjYy
14
- ZTdiMjY0NDA1OWJiNDVlM2YyM2I0NzdiOWVlN2E3M2M2YjFmNDc4NjQ4ZmJh
15
- ZWNlYTE0ODE4ZmQ0ZGQyZjUxNTk5YTM2YWIxYTg2Y2YzMGY4Nzg=
13
+ NDVmYjg0NjJkYTI1OGJkNjI1MDYxMzc4OGNkNzkyZmFkNjM1ZmU1NmE1OGJl
14
+ ODcyOTRiYzcyYjcxNWJhMTk2NWM2ODc2YjQyZTg5YjgwMjBkNzk2NzczODAx
15
+ OTc4ZmVmZDBiY2I5ZDc0YWE3YmQyMDAwNTFlZTJkZTg4Yjg2Mjc=
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ v1.1.14, 2018-07-12
2
+ -------------------
3
+ * [IMPROVEMENT] Allow Negation for integer and decimal literals
4
+ * [IMPROVEMENT] New Functions: round(), substring(), trim()
5
+ * [BUGFIX] `MIN_DATE_TIME` was increased to 1970
6
+
1
7
  v1.1.13, 2018-06-27
2
8
  -------------------
3
9
  * [IMPROVEMENT] New Functions: length(), mindatetime(), maxdatetime()
data/GRAMMAR.md CHANGED
@@ -178,6 +178,8 @@ Literals that support multiple values in a list for a condition
178
178
  : INTEGER
179
179
  | DECIMAL
180
180
  | CHARACTER
181
+ | LPAREN literals RPAREN
182
+ | UMINUS literals
181
183
  ;
182
184
  ```
183
185
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.13
1
+ 1.1.14
@@ -14,7 +14,7 @@ class Sparkql::FunctionResolver
14
14
  STRFTIME_DATE_FORMAT = '%Y-%m-%d'
15
15
  STRFTIME_TIME_FORMAT = '%H:%M:%S.%N'
16
16
  VALID_REGEX_FLAGS = ["", "i"]
17
- MIN_DATE_TIME = Time.new(1, 1, 1, 0, 0, 0, "+00:00").iso8601
17
+ MIN_DATE_TIME = Time.new(1970, 1, 1, 0, 0, 0, "+00:00").iso8601
18
18
  MAX_DATE_TIME = Time.new(9999, 12, 31, 23, 59, 59, "+00:00").iso8601
19
19
  SUPPORTED_FUNCTIONS = {
20
20
  :polygon => {
@@ -37,6 +37,19 @@ class Sparkql::FunctionResolver
37
37
  }],
38
38
  :return_type => :character
39
39
  },
40
+ :substring => {
41
+ :args => [[:field, :character], :integer],
42
+ :opt_args => [{
43
+ :type => :integer
44
+ }],
45
+ :resolve_for_type => true,
46
+ :return_type => :character
47
+ },
48
+ :trim => {
49
+ :args => [[:field, :character]],
50
+ :resolve_for_type => true,
51
+ :return_type => :character
52
+ },
40
53
  :tolower => {
41
54
  :args => [[:field, :character]],
42
55
  :resolve_for_type => true,
@@ -56,6 +69,11 @@ class Sparkql::FunctionResolver
56
69
  :args => [[:field, :character], :character],
57
70
  :return_type => :integer
58
71
  },
72
+ :round => {
73
+ :args => [[:field, :decimal]],
74
+ :resolve_for_type => true,
75
+ :return_type => :integer
76
+ },
59
77
  :startswith => {
60
78
  :args => [:character],
61
79
  :return_type => :startswith
@@ -264,6 +282,57 @@ class Sparkql::FunctionResolver
264
282
  }
265
283
  end
266
284
 
285
+ def trim_field(arg)
286
+ {
287
+ :type => :function,
288
+ :value => "trim",
289
+ :args => [arg]
290
+ }
291
+ end
292
+
293
+ def trim_character(arg)
294
+ {
295
+ :type => :character,
296
+ :value => arg.strip
297
+ }
298
+ end
299
+
300
+ def substring_field(field, first_index, number_chars)
301
+ return if substring_index_error?(number_chars)
302
+ {
303
+ :type => :function,
304
+ :value => "substring",
305
+ :args => [field, first_index, number_chars]
306
+ }
307
+ end
308
+
309
+ def substring_character(character, first_index, number_chars)
310
+ return if substring_index_error?(number_chars)
311
+
312
+ second_index = if number_chars.nil?
313
+ -1
314
+ else
315
+ number_chars + first_index - 1
316
+ end
317
+
318
+ new_string = character[first_index..second_index].to_s
319
+
320
+ {
321
+ :type => :character,
322
+ :value => new_string
323
+ }
324
+ end
325
+
326
+ def substring_index_error?(second_index)
327
+ if second_index.to_i < 0
328
+ @errors << Sparkql::ParserError.new(:token => second_index,
329
+ :message => "Function call 'substring' may not have a negative integer for its second parameter",
330
+ :status => :fatal)
331
+ true
332
+ end
333
+ false
334
+ end
335
+
267
336
  def tolower_character(string)
268
337
  {
269
338
  :type => :character,
@@ -271,7 +340,8 @@ class Sparkql::FunctionResolver
271
340
  }
272
341
  end
273
342
 
274
- def tolower_field(arg) {
343
+ def tolower_field(arg)
344
+ {
275
345
  :type => :function,
276
346
  :value => "tolower",
277
347
  :args => [arg]
@@ -398,6 +468,21 @@ class Sparkql::FunctionResolver
398
468
  }
399
469
  end
400
470
 
471
+ def round_decimal(arg)
472
+ {
473
+ :type => :integer,
474
+ :value => arg.round.to_s
475
+ }
476
+ end
477
+
478
+ def round_field(arg)
479
+ {
480
+ :type => :function,
481
+ :value => "round",
482
+ :args => [arg]
483
+ }
484
+ end
485
+
401
486
  def indexof(arg1, arg2)
402
487
  {
403
488
  :type => :function,
data/lib/sparkql/lexer.rb CHANGED
@@ -47,6 +47,8 @@ class Sparkql::Lexer < StringScanner
47
47
  literal :DECIMAL, @current_token_value
48
48
  when @current_token_value = scan(INTEGER)
49
49
  literal :INTEGER, @current_token_value
50
+ when @current_token_value = scan(/\-/)
51
+ [:UMINUS, @current_token_value]
50
52
  when @current_token_value = scan(CHARACTER)
51
53
  literal :CHARACTER, @current_token_value
52
54
  when @current_token_value = scan(BOOLEAN)
@@ -1,6 +1,6 @@
1
1
  #
2
2
  # DO NOT MODIFY!!!!
3
- # This file is automatically generated by Racc 1.4.8
3
+ # This file is automatically generated by Racc 1.4.14
4
4
  # from Racc grammer file "".
5
5
  #
6
6
 
@@ -16,68 +16,72 @@ module Sparkql
16
16
  ##### State transition tables begin ###
17
17
 
18
18
  racc_action_table = [
19
- 48, 10, 11, 14, 54, 31, 32, 33, 34, 35,
20
- 36, 37, 38, 10, 11, 14, 55, 31, 32, 33,
21
- 34, 35, 36, 37, 38, 14, -28, 31, 32, 33,
22
- 34, 35, 36, 37, 38, 14, 23, 41, 42, 22,
23
- 43, 44, 45, 14, 15, 41, 42, nil, 43, 44,
24
- 45, 8, nil, 9, nil, 10, 11, 14, 8, nil,
25
- 9, nil, 10, 11, 14, 9, nil, 10, 11, 14,
26
- 9, nil, 10, 11, 14, 9, 56, 10, 11, 14,
27
- 57, 14, nil, 31, 32, 33, 17, 16, nil, 47,
28
- 18, 19, 17, 16 ]
19
+ 35, 14, 15, 43, 44, 34, 45, 46, 47, 14,
20
+ 22, 31, 32, 33, 36, 37, 38, 39, 40, 35,
21
+ 17, 16, 23, 49, 34, 50, 10, 11, 14, -28,
22
+ 31, 32, 33, 36, 37, 38, 39, 40, 35, 56,
23
+ 60, 17, 16, 34, 61, 10, 11, 14, 59, 31,
24
+ 32, 33, 36, 37, 38, 39, 40, 35, 18, 19,
25
+ 35, 64, 34, nil, nil, 34, nil, nil, 31, 32,
26
+ 33, 31, 32, 33, 35, 14, nil, 43, 44, 34,
27
+ 45, 46, 47, 14, nil, 31, 32, 33, 8, nil,
28
+ 9, nil, 10, 11, 14, 8, nil, 9, nil, 10,
29
+ 11, 14, 9, nil, 10, 11, 14, 9, nil, 10,
30
+ 11, 14, 9, nil, 10, 11, 14 ]
29
31
 
30
32
  racc_action_check = [
31
- 22, 22, 22, 22, 29, 22, 22, 22, 22, 22,
32
- 22, 22, 22, 57, 57, 57, 40, 57, 57, 57,
33
- 57, 57, 57, 57, 57, 18, 28, 18, 18, 18,
34
- 18, 18, 18, 18, 18, 19, 15, 19, 19, 13,
35
- 19, 19, 19, 55, 1, 55, 55, nil, 55, 55,
36
- 55, 9, nil, 9, nil, 9, 9, 9, 0, nil,
37
- 0, nil, 0, 0, 0, 8, nil, 8, 8, 8,
38
- 16, nil, 16, 16, 16, 17, 49, 17, 17, 17,
39
- 49, 54, nil, 54, 54, 54, 21, 21, nil, 21,
40
- 6, 6, 2, 2 ]
33
+ 18, 19, 1, 19, 19, 18, 19, 19, 19, 18,
34
+ 13, 18, 18, 18, 18, 18, 18, 18, 18, 22,
35
+ 21, 21, 15, 21, 22, 22, 22, 22, 22, 28,
36
+ 22, 22, 22, 22, 22, 22, 22, 22, 61, 29,
37
+ 51, 2, 2, 61, 51, 61, 61, 61, 42, 61,
38
+ 61, 61, 61, 61, 61, 61, 61, 34, 6, 6,
39
+ 35, 57, 34, nil, nil, 35, nil, nil, 34, 34,
40
+ 34, 35, 35, 35, 56, 59, nil, 59, 59, 56,
41
+ 59, 59, 59, 56, nil, 56, 56, 56, 0, nil,
42
+ 0, nil, 0, 0, 0, 9, nil, 9, nil, 9,
43
+ 9, 9, 8, nil, 8, 8, 8, 16, nil, 16,
44
+ 16, 16, 17, nil, 17, 17, 17 ]
41
45
 
42
46
  racc_action_pointer = [
43
- 53, 44, 87, nil, nil, nil, 87, nil, 58, 46,
44
- nil, nil, nil, 32, nil, 36, 63, 68, 14, 24,
45
- nil, 81, -8, nil, nil, nil, nil, nil, 14, -8,
46
- nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
47
- 4, nil, nil, nil, nil, nil, nil, nil, nil, 68,
48
- nil, nil, nil, nil, 70, 32, nil, 4, nil, nil,
49
- nil, nil ]
47
+ 83, 2, 36, nil, nil, nil, 55, nil, 95, 90,
48
+ nil, nil, nil, 3, nil, 22, 100, 105, -2, -10,
49
+ nil, 15, 17, nil, nil, nil, nil, nil, 17, 27,
50
+ nil, nil, nil, nil, 55, 58, nil, nil, nil, nil,
51
+ nil, nil, 36, nil, nil, nil, nil, nil, nil, nil,
52
+ nil, 32, nil, nil, nil, nil, 72, 53, nil, 64,
53
+ nil, 36, nil, nil, nil, nil, nil ]
50
54
 
51
55
  racc_action_default = [
52
- -2, -46, -1, -3, -4, -5, -46, -8, -46, -46,
53
- -13, -14, -15, -46, -21, -46, -46, -46, -46, -46,
54
- -9, -46, -46, 62, -10, -11, -6, -16, -17, -18,
55
- -27, -32, -33, -34, -35, -36, -37, -38, -39, -7,
56
- -46, -40, -41, -42, -43, -44, -45, -12, -19, -46,
57
- -22, -24, -25, -26, -46, -46, -20, -46, -29, -30,
58
- -31, -23 ]
56
+ -2, -48, -1, -3, -4, -5, -48, -8, -48, -48,
57
+ -13, -14, -15, -48, -21, -48, -48, -48, -48, -48,
58
+ -9, -48, -48, 67, -10, -11, -6, -16, -17, -18,
59
+ -27, -32, -33, -34, -48, -48, -37, -38, -39, -40,
60
+ -41, -7, -48, -42, -43, -44, -45, -46, -47, -12,
61
+ -19, -48, -22, -24, -25, -26, -48, -48, -36, -48,
62
+ -20, -48, -29, -30, -35, -31, -23 ]
59
63
 
60
64
  racc_goto_table = [
61
- 28, 46, 30, 40, 2, 53, 50, 20, 29, 27,
62
- 49, 39, 26, 21, 1, 24, 25, nil, nil, nil,
63
- nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
64
- nil, nil, nil, nil, nil, nil, 59, 46, 58, 60,
65
- 53, 61 ]
65
+ 28, 48, 42, 2, 55, 52, 20, 30, 1, 26,
66
+ 41, 27, 21, 29, 24, 25, 51, nil, nil, nil,
67
+ nil, nil, nil, 57, 58, nil, nil, nil, nil, nil,
68
+ nil, nil, nil, nil, nil, nil, nil, nil, 63, nil,
69
+ nil, 48, 65, 55, 66, 62 ]
66
70
 
67
71
  racc_goto_check = [
68
- 10, 10, 16, 17, 2, 6, 15, 3, 12, 11,
69
- 14, 8, 7, 2, 1, 3, 3, nil, nil, nil,
70
- nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
71
- nil, nil, nil, nil, nil, nil, 10, 10, 16, 17,
72
- 6, 15 ]
72
+ 10, 10, 17, 2, 6, 15, 3, 16, 1, 7,
73
+ 8, 11, 2, 12, 3, 3, 14, nil, nil, nil,
74
+ nil, nil, nil, 16, 16, nil, nil, nil, nil, nil,
75
+ nil, nil, nil, nil, nil, nil, nil, nil, 10, nil,
76
+ nil, 10, 17, 6, 15, 16 ]
73
77
 
74
78
  racc_goto_pointer = [
75
- nil, 14, 4, -1, nil, nil, -17, -6, -8, nil,
76
- -18, -9, -10, nil, -12, -16, -16, -16 ]
79
+ nil, 8, 3, -2, nil, nil, -18, -9, -9, nil,
80
+ -18, -7, -5, nil, -6, -17, -11, -17 ]
77
81
 
78
82
  racc_goto_default = [
79
83
  nil, nil, nil, 3, 4, 5, 6, nil, nil, 7,
80
- 12, 51, nil, 13, nil, nil, 52, nil ]
84
+ 12, 53, nil, 13, nil, nil, 54, nil ]
81
85
 
82
86
  racc_reduce_table = [
83
87
  0, 0, :racc_error,
@@ -115,6 +119,8 @@ racc_reduce_table = [
115
119
  1, 37, :_reduce_none,
116
120
  1, 37, :_reduce_none,
117
121
  1, 37, :_reduce_none,
122
+ 3, 37, :_reduce_35,
123
+ 2, 37, :_reduce_36,
118
124
  1, 32, :_reduce_none,
119
125
  1, 32, :_reduce_none,
120
126
  1, 32, :_reduce_none,
@@ -127,9 +133,9 @@ racc_reduce_table = [
127
133
  1, 38, :_reduce_none,
128
134
  1, 38, :_reduce_none ]
129
135
 
130
- racc_reduce_n = 46
136
+ racc_reduce_n = 48
131
137
 
132
- racc_shift_n = 62
138
+ racc_shift_n = 67
133
139
 
134
140
  racc_token_table = {
135
141
  false => 0,
@@ -334,9 +340,15 @@ end
334
340
 
335
341
  # reduce 34 omitted
336
342
 
337
- # reduce 35 omitted
343
+ def _reduce_35(val, _values, result)
344
+ result = val[1]
345
+ result
346
+ end
338
347
 
339
- # reduce 36 omitted
348
+ def _reduce_36(val, _values, result)
349
+ result = tokenize_literal_negation(val[1])
350
+ result
351
+ end
340
352
 
341
353
  # reduce 37 omitted
342
354
 
@@ -356,6 +368,10 @@ end
356
368
 
357
369
  # reduce 45 omitted
358
370
 
371
+ # reduce 46 omitted
372
+
373
+ # reduce 47 omitted
374
+
359
375
  def _reduce_none(val, _values, result)
360
376
  val[0]
361
377
  end
data/lib/sparkql/parser.y CHANGED
@@ -159,6 +159,8 @@ rule
159
159
  : INTEGER
160
160
  | DECIMAL
161
161
  | CHARACTER
162
+ | LPAREN literals RPAREN { result = val[1] }
163
+ | UMINUS literals { result = tokenize_literal_negation(val[1]) }
162
164
  ;
163
165
 
164
166
  ##### Literal
@@ -60,7 +60,7 @@ module Sparkql::ParserCompatibility
60
60
  :type => :function,
61
61
  # This type is not parseable, so no regex
62
62
  :operators => Sparkql::Token::OPERATORS + [Sparkql::Token::RANGE_OPERATOR]
63
- }
63
+ },
64
64
  ]
65
65
 
66
66
  OPERATORS_SUPPORTING_MULTIPLES = ["Eq","Ne"]
@@ -91,6 +91,25 @@ module Sparkql::ParserTools
91
91
  list
92
92
  end
93
93
 
94
+ def tokenize_literal_negation(number_token)
95
+ old_val = case number_token[:type]
96
+ when :integer
97
+ number_token[:value].to_i
98
+ when :decimal
99
+ number_token[:value].to_f
100
+ else
101
+ tokenizer_error(:token => @lexer.current_token_value,
102
+ :expression => number_token,
103
+ :message => "Negation is only allowed for integer and floats",
104
+ :status => :fatal,
105
+ :syntax => true)
106
+ return number_token
107
+ end
108
+ number_token[:value] = (-1 * old_val).to_s
109
+
110
+ number_token
111
+ end
112
+
94
113
  def tokenize_multiple(lit1, lit2)
95
114
  final_type = lit1[:type]
96
115
  if lit1[:type] != lit2[:type]
@@ -14,14 +14,151 @@ class FunctionResolverTest < Test::Unit::TestCase
14
14
  assert_equal(["35.12 -68.33", 1.0], value[:function_parameters])
15
15
  end
16
16
 
17
- test "tolower(SomeField)" do
18
- f = FunctionResolver.new('tolower', [{:type => :field, :value => "City"}])
17
+ test "round(float)" do
18
+ f = FunctionResolver.new('round', [{:type => :decimal, :value => 0.5}])
19
19
  f.validate
20
20
  assert !f.errors?, "Errors #{f.errors.inspect}"
21
21
  value = f.call
22
+ assert_equal :integer, value[:type]
23
+ assert_equal '1', value[:value]
24
+ end
25
+
26
+ test "round(Field)" do
27
+ f = FunctionResolver.new('round', [{:type => :field, :value => 'ListPrice'}])
28
+ f.validate
29
+ assert !f.errors?, "Errors #{f.errors.inspect}"
30
+ value = f.call
31
+
22
32
  assert_equal :function, value[:type]
23
- assert_equal 'tolower', value[:value]
24
- assert_equal "City", value[:args].first
33
+ assert_equal 'round', value[:value]
34
+ assert_equal "ListPrice", value[:args].first
35
+ end
36
+
37
+ test "substring character one index" do
38
+ f = FunctionResolver.new('substring', [
39
+ {:type => :character, :value => 'ListPrice'},
40
+ {:type => :integer, :value => 1}
41
+ ])
42
+
43
+ f.validate
44
+ assert !f.errors?, "Errors #{f.errors.inspect}"
45
+ value = f.call
46
+
47
+ assert_equal :character, value[:type]
48
+ assert_equal 'istPrice', value[:value]
49
+ end
50
+
51
+ test "substring character two indexes" do
52
+ f = FunctionResolver.new('substring', [
53
+ {:type => :character, :value => 'alfb'},
54
+ {:type => :integer, :value => 1},
55
+ {:type => :integer, :value => 2}
56
+ ])
57
+
58
+ f.validate
59
+ assert !f.errors?, "Errors #{f.errors.inspect}"
60
+ value = f.call
61
+
62
+ assert_equal :character, value[:type]
63
+ assert_equal "lf", value[:value]
64
+ end
65
+
66
+ test "substring character large first index" do
67
+ f = FunctionResolver.new('substring', [
68
+ {:type => :character, :value => 'ListPrice'},
69
+ {:type => :integer, :value => 10}
70
+ ])
71
+
72
+ f.validate
73
+ assert !f.errors?, "Errors #{f.errors.inspect}"
74
+ value = f.call
75
+
76
+ assert_equal :character, value[:type]
77
+ assert_equal '', value[:value]
78
+ end
79
+
80
+ test "substring field one index" do
81
+ f = FunctionResolver.new('substring', [
82
+ {:type => :field, :value => 'ListPrice'},
83
+ {:type => :integer, :value => 1}
84
+ ])
85
+
86
+ f.validate
87
+ assert !f.errors?, "Errors #{f.errors.inspect}"
88
+ value = f.call
89
+
90
+ assert_equal :function, value[:type]
91
+ assert_equal 'substring', value[:value]
92
+ assert_equal "ListPrice", value[:args].first
93
+ assert_nil value[:args].last
94
+ end
95
+
96
+ test "substring field two indexes" do
97
+ f = FunctionResolver.new('substring', [
98
+ {:type => :field, :value => 'ListPrice'},
99
+ {:type => :integer, :value => 1},
100
+ {:type => :integer, :value => 2}
101
+ ])
102
+
103
+ f.validate
104
+ assert !f.errors?, "Errors #{f.errors.inspect}"
105
+ value = f.call
106
+
107
+ assert_equal :function, value[:type]
108
+ assert_equal 'substring', value[:value]
109
+ assert_equal "ListPrice", value[:args].first
110
+ assert_equal 2, value[:args].last
111
+ end
112
+
113
+ test "substring with negative M is a parse error" do
114
+ f = FunctionResolver.new('substring', [
115
+ {:type => :field, :value => 'ListPrice'},
116
+ {:type => :integer, :value => 1},
117
+ {:type => :integer, :value => -5}
118
+ ])
119
+
120
+ f.validate
121
+ f.call
122
+ assert f.errors?
123
+ end
124
+
125
+ test "character substring with negative M is a parse error" do
126
+ f = FunctionResolver.new('substring', [
127
+ {:type => :character, :value => 'ListPrice'},
128
+ {:type => :integer, :value => 1},
129
+ {:type => :integer, :value => -5}
130
+ ])
131
+
132
+ f.validate
133
+ f.call
134
+ assert f.errors?
135
+ end
136
+
137
+ test 'trim with field' do
138
+ f = FunctionResolver.new('trim', [
139
+ {:type => :field, :value => 'Name'}
140
+ ])
141
+
142
+ f.validate
143
+ assert !f.errors?, "Errors #{f.errors.inspect}"
144
+ value = f.call
145
+
146
+ assert_equal :function, value[:type]
147
+ assert_equal 'trim', value[:value]
148
+ assert_equal "Name", value[:args].first
149
+ end
150
+
151
+ test 'trim with character' do
152
+ f = FunctionResolver.new('trim', [
153
+ {:type => :character, :value => ' val '}
154
+ ])
155
+
156
+ f.validate
157
+ assert !f.errors?, "Errors #{f.errors.inspect}"
158
+ value = f.call
159
+
160
+ assert_equal :character, value[:type]
161
+ assert_equal 'val', value[:value]
25
162
  end
26
163
 
27
164
  test "tolower('string')" do
@@ -89,7 +226,7 @@ class FunctionResolverTest < Test::Unit::TestCase
89
226
  value = f.call
90
227
  assert_equal :datetime, value[:type]
91
228
 
92
- assert_equal '0001-01-01T00:00:00+00:00', value[:value]
229
+ assert_equal '1970-01-01T00:00:00+00:00', value[:value]
93
230
  end
94
231
 
95
232
  test "maxdatetime()" do
@@ -56,13 +56,6 @@ class ParserTest < Test::Unit::TestCase
56
56
  assert_equal '10,11,12', expression[:condition]
57
57
  end
58
58
 
59
- def parse(q,v)
60
- expressions = @parser.parse(q)
61
- assert !@parser.errors?, "Unexpected error parsing #{q} #{@parser.errors.inspect}"
62
- assert_equal v, expressions.first[:value], "Expression #{expressions.inspect}"
63
- assert !expressions.first[:custom_field], "Unexepected custom field #{expressions.inspect}"
64
- end
65
-
66
59
  def test_invalid_syntax
67
60
  @parser = Parser.new
68
61
  expression = @parser.parse('Test Eq DERP')
@@ -103,20 +96,6 @@ class ParserTest < Test::Unit::TestCase
103
96
  )
104
97
  end
105
98
 
106
- # verify each expression in the query is at the right nesting level and group
107
- def assert_nesting(sparkql, levels=[], block_groups=nil)
108
- block_groups = levels.clone if block_groups.nil?
109
- parser = Parser.new
110
- expressions = parser.parse(sparkql)
111
- assert !parser.errors?, "Unexpected error parsing #{sparkql}: #{parser.errors.inspect}"
112
- count = 0
113
- expressions.each do |ex|
114
- assert_equal levels[count], ex[:level], "Nesting level wrong for #{ex.inspect}"
115
- assert_equal(block_groups[count], ex[:block_group], "Nesting block group wrong for #{ex.inspect}")
116
- count +=1
117
- end
118
- end
119
-
120
99
  def test_bad_queries
121
100
  filter = "City IsLikeA 'Town'"
122
101
  @parser = Parser.new
@@ -629,11 +608,119 @@ class ParserTest < Test::Unit::TestCase
629
608
  assert_nil @parser.coercible_types(:integer, :date)
630
609
  end
631
610
 
611
+ def test_literal_group
612
+ filter = "ListPrice Gt (5)"
613
+ @parser = Parser.new
614
+ @parser.parse(filter)
615
+ assert !@parser.errors?, "Filter '#{filter}' failed: #{@parser.errors.first.inspect}"
616
+ end
617
+
618
+ def test_integer_negation
619
+ filter = "ListPrice Gt -(5)"
620
+ @parser = Parser.new
621
+ expression = @parser.parse(filter).first
622
+ assert !@parser.errors?, "Filter '#{filter}' failed: #{@parser.errors.first.inspect}"
623
+
624
+ assert_equal :integer, expression[:type]
625
+ assert_equal '-5', expression[:value]
626
+ end
627
+
628
+ def test_decimal_negation
629
+ filter = "ListPrice Gt -(5.1)"
630
+ @parser = Parser.new
631
+ expressions = @parser.parse(filter)
632
+ assert !@parser.errors?, "Filter '#{filter}' failed: #{@parser.errors.first.inspect}"
633
+
634
+ expression = expressions.first
635
+ assert_equal :decimal, expression[:type]
636
+ assert_equal '-5.1', expression[:value]
637
+ end
638
+
639
+ def test_nested_negation
640
+ filter = "ListPrice Gt -(-5)"
641
+ @parser = Parser.new
642
+ expression = @parser.parse(filter).first
643
+ assert !@parser.errors?, "Filter '#{filter}' failed: #{@parser.errors.first.inspect}"
644
+
645
+ assert_equal :integer, expression[:type]
646
+ assert_equal '5', expression[:value]
647
+
648
+ filter = "ListPrice Gt --5"
649
+ @parser = Parser.new
650
+ expression = @parser.parse(filter).first
651
+ assert !@parser.errors?, "Filter '#{filter}' failed: #{@parser.errors.first.inspect}"
652
+
653
+ assert_equal :integer, expression[:type]
654
+ assert_equal '5', expression[:value]
655
+ end
656
+
657
+ def test_string_negation_does_not_parse
658
+ parser_errors("Field Eq -'Stringval'")
659
+ end
660
+
661
+ def test_substring
662
+ filter = "Name Eq substring('Andy', 1)"
663
+ @parser = Parser.new
664
+ expression = @parser.parse(filter).first
665
+ assert !@parser.errors?, "Filter '#{filter}' failed: #{@parser.errors.first.inspect}"
666
+ assert_equal 'ndy', expression[:value]
667
+ end
668
+
669
+ def test_round_with_literal
670
+ filter = "ListPrice Eq round(0.5)"
671
+ @parser = Parser.new
672
+ expression = @parser.parse(filter).first
673
+ assert !@parser.errors?, "Filter '#{filter}' failed: #{@parser.errors.first.inspect}"
674
+
675
+ assert_equal :integer, expression[:type]
676
+ assert_equal "1", expression[:value]
677
+
678
+ filter = "ListPrice Eq round(-0.5)"
679
+ @parser = Parser.new
680
+ expression = @parser.parse(filter).first
681
+ assert !@parser.errors?, "Filter '#{filter}' failed: #{@parser.errors.first.inspect}"
682
+
683
+ assert_equal :integer, expression[:type]
684
+ assert_equal "-1", expression[:value]
685
+ end
686
+
687
+ def test_round_with_field
688
+ filter = "ListPrice Eq round(FieldName)"
689
+ @parser = Parser.new
690
+ expression = @parser.parse(filter).first
691
+ assert !@parser.errors?, "Filter '#{filter}' failed: #{@parser.errors.first.inspect}"
692
+
693
+ assert_equal 'round', expression[:function_name]
694
+ assert_equal 'round(FieldName)', expression[:condition]
695
+ assert_equal(["FieldName"], expression[:function_parameters])
696
+ end
697
+
698
+ private
632
699
 
633
700
  def parser_errors(filter)
634
701
  @parser = Parser.new
635
702
  expression = @parser.parse(filter)
636
703
  assert @parser.errors?, "Should find errors for '#{filter}': #{expression}"
637
704
  end
638
-
705
+
706
+ def parse(q,v)
707
+ expressions = @parser.parse(q)
708
+ assert !@parser.errors?, "Unexpected error parsing #{q} #{@parser.errors.inspect}"
709
+ assert_equal v, expressions.first[:value], "Expression #{expressions.inspect}"
710
+ assert !expressions.first[:custom_field], "Unexepected custom field #{expressions.inspect}"
711
+ end
712
+
713
+ # verify each expression in the query is at the right nesting level and group
714
+ def assert_nesting(sparkql, levels=[], block_groups=nil)
715
+ block_groups = levels.clone if block_groups.nil?
716
+ parser = Parser.new
717
+ expressions = parser.parse(sparkql)
718
+ assert !parser.errors?, "Unexpected error parsing #{sparkql}: #{parser.errors.inspect}"
719
+ count = 0
720
+ expressions.each do |ex|
721
+ assert_equal levels[count], ex[:level], "Nesting level wrong for #{ex.inspect}"
722
+ assert_equal(block_groups[count], ex[:block_group], "Nesting block group wrong for #{ex.inspect}")
723
+ count +=1
724
+ end
725
+ end
639
726
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sparkql
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.13
4
+ version: 1.1.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wade McEwen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-27 00:00:00.000000000 Z
11
+ date: 2018-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: georuby