sparkql 1.2.2 → 1.2.7

Sign up to get free protection for your applications and to get access to all the features.
data/lib/sparkql/parser.y CHANGED
@@ -98,6 +98,8 @@ rule
98
98
  | field_arithmetic_expression MUL field_arithmetic_expression { result = tokenize_arithmetic(val[0], val[1], val[2]) }
99
99
  | field_arithmetic_expression DIV field_arithmetic_expression { result = tokenize_arithmetic(val[0], val[1], val[2]) }
100
100
  | field_arithmetic_expression MOD field_arithmetic_expression { result = tokenize_arithmetic(val[0], val[1], val[2]) }
101
+ | LPAREN field_arithmetic_expression RPAREN { result = tokenize_arithmetic_group(val[1]) }
102
+ | UMINUS field_arithmetic_expression { result = tokenize_arithmetic_negation(val[1]) }
101
103
  | literals
102
104
  | field_function_expression
103
105
  ;
@@ -117,6 +119,8 @@ rule
117
119
  : arithmetic_condition
118
120
  | literal_list { result = tokenize_list(val[0]) }
119
121
  | literal
122
+ | LPAREN condition RPAREN { result = group_fold(val[1]) }
123
+ | UMINUS condition { result = tokenize_literal_negation(val[1]) }
120
124
  ;
121
125
 
122
126
  arithmetic_condition
@@ -194,8 +198,6 @@ rule
194
198
  : INTEGER
195
199
  | DECIMAL
196
200
  | CHARACTER
197
- | LPAREN literals RPAREN { result = val[1] }
198
- | UMINUS literals { result = tokenize_literal_negation(val[1]) }
199
201
  ;
200
202
 
201
203
  ##### Literal
@@ -85,7 +85,7 @@ module Sparkql::ParserCompatibility
85
85
 
86
86
  # Delegator for methods to process the error list.
87
87
  def process_errors
88
- Sparkql::ErrorsProcessor.new(@errors)
88
+ Sparkql::ErrorsProcessor.new(errors)
89
89
  end
90
90
 
91
91
  # delegate :errors?, :fatal_errors?, :dropped_errors?, :recovered_errors?, :to => :process_errors
@@ -161,7 +161,7 @@ module Sparkql::ParserCompatibility
161
161
  def datetime_escape(string)
162
162
  DateTime.parse(string)
163
163
  end
164
-
164
+
165
165
  def time_escape(string)
166
166
  DateTime.parse(string)
167
167
  end
@@ -214,7 +214,8 @@ module Sparkql::ParserCompatibility
214
214
 
215
215
  # Checks the type of an expression with what is expected.
216
216
  def check_type!(expression, expected, supports_nulls = true)
217
- if expected == expression[:type] || check_function_type?(expression, expected) ||
217
+ if (expected == expression[:type] && !expression.key?(:field_manipulations)) ||
218
+ (expression.key?(:field_manipulations) && check_function_type?(expression, expected)) ||
218
219
  (supports_nulls && expression[:type] == :null)
219
220
  return true
220
221
  # If the field will be passed into a function,
@@ -230,7 +231,7 @@ module Sparkql::ParserCompatibility
230
231
  expression[:type] = :datetime
231
232
  expression[:cast] = :date
232
233
  return true
233
- elsif expected == :date && expression[:type] == :datetime
234
+ elsif expected == :date && expression[:type] == :datetime
234
235
  expression[:type] = :date
235
236
  expression[:cast] = :datetime
236
237
  if multiple_values?(expression[:value])
@@ -253,26 +254,44 @@ module Sparkql::ParserCompatibility
253
254
  :message => "expected #{expected} but found #{expression[:type]}",
254
255
  :status => :fatal )
255
256
  end
256
-
257
+
257
258
  # If a function is being applied to a field, we check that the return type of
258
259
  # the function matches what is expected, and that the function supports the
259
260
  # field type as the first argument.
260
261
  def check_function_type?(expression, expected)
261
- return false unless expression.key?(:field_manipulations) && expression[:field_manipulations][:return_type] == expression[:type]
262
- # Lookup the function arguments
263
- function = Sparkql::FunctionResolver::SUPPORTED_FUNCTIONS[deepest_function(expression[:field_manipulations])[:function_name].to_sym]
264
- return false if function.nil?
265
-
266
- Array(function[:args].first).include?(expected)
262
+ validate_manipulation_types(expression[:field_manipulations], expected)
267
263
  end
268
264
 
265
+ def validate_manipulation_types(field_manipulations, expected)
266
+ if field_manipulations[:type] == :function
267
+ function = Sparkql::FunctionResolver::SUPPORTED_FUNCTIONS[field_manipulations[:function_name].to_sym]
268
+ return false if function.nil?
269
+ field_manipulations[:args].each_with_index do |arg, index|
270
+ if arg[:type] == :field
271
+ return false unless function[:args][index].include?(:field)
272
+ end
273
+ end
274
+ elsif field_manipulations[:type] == :arithmetic
275
+ lhs = field_manipulations[:lhs]
276
+ return false unless validate_side(lhs, expected)
269
277
 
270
- def deepest_function(function)
271
- if function[:args].first[:type] == :function
272
- deepest_function(function[:args].first)
273
- else
274
- function
278
+ rhs = field_manipulations[:rhs]
279
+ return false unless rhs.nil? || validate_side(rhs, expected)
280
+ end
281
+ true
282
+ end
283
+
284
+ def validate_side(side, expected)
285
+ if side[:type] == :arithmetic
286
+ return validate_manipulation_types(side, expected)
287
+ elsif side[:type] == :field
288
+ return false unless [:decimal, :integer].include?(expected)
289
+ elsif side[:type] == :function
290
+ return false unless [:decimal, :integer].include?(side[:return_type])
291
+ elsif ![:decimal, :integer].include?(side[:type])
292
+ return false
275
293
  end
294
+ true
276
295
  end
277
296
 
278
297
  # Builds the correct operator based on the type and the value.
@@ -305,7 +324,7 @@ module Sparkql::ParserCompatibility
305
324
  def operator_supports_multiples?(operator)
306
325
  OPERATORS_SUPPORTING_MULTIPLES.include?(operator)
307
326
  end
308
-
327
+
309
328
  def coerce_datetime datetime
310
329
  if datestr = datetime.match(/^(\d{4}-\d{2}-\d{2})/)
311
330
  datestr[0]
@@ -1,10 +1,14 @@
1
1
  # This is the guts of the parser internals and is mixed into the parser for organization.
2
+ require 'bigdecimal'
3
+
2
4
  module Sparkql::ParserTools
3
5
 
4
6
  # Coercible types from highest precision to lowest
5
7
  DATE_TYPES = [:datetime, :date]
6
8
  NUMBER_TYPES = [:decimal, :integer]
7
9
  ARITHMETIC_TYPES = [:decimal, :integer, :field, :arithmetic]
10
+ GROUP = 'Group'.freeze
11
+ NEGATION = 'Negation'.freeze
8
12
 
9
13
  def parse(str)
10
14
  @lexer = Sparkql::Lexer.new(str)
@@ -24,24 +28,16 @@ module Sparkql::ParserTools
24
28
  end
25
29
 
26
30
  def arithmetic_field(nested_representation)
27
- lhs = nested_representation[:lhs]
28
- rhs = nested_representation[:rhs]
29
-
30
- if lhs[:type] == :field
31
- lhs[:value]
32
- elsif rhs[:type] == :field
33
- rhs[:value]
34
- elsif lhs.key?(:field)
35
- lhs[:field]
36
- elsif rhs.key?(:field)
37
- rhs[:field]
38
- elsif lhs[:type] == :arithmetic
39
- arithmetic_field(lhs)
40
- elsif rhs[:type] == :arithmetic
41
- arithmetic_field(rhs)
42
- else
43
- nil
44
- end
31
+ return if nested_representation.nil?
32
+
33
+ return nested_representation[:value] if nested_representation[:type] == :field
34
+ return nested_representation[:field] if nested_representation.key?(:field)
35
+
36
+ field = arithmetic_field(nested_representation[:lhs])
37
+ return field unless field.nil?
38
+
39
+ field = arithmetic_field(nested_representation[:rhs])
40
+ return field unless field.nil?
45
41
  end
46
42
 
47
43
  def no_field_error(field, operator)
@@ -129,6 +125,26 @@ module Sparkql::ParserTools
129
125
  expressions
130
126
  end
131
127
 
128
+ def tokenize_arithmetic_group(lhs)
129
+ @lexer.leveldown
130
+ @lexer.block_group_identifier -= 1
131
+ lhs = {type: :field, value: lhs} if lhs.is_a?(String)
132
+ {
133
+ type: :arithmetic,
134
+ op: GROUP,
135
+ lhs: lhs
136
+ }
137
+ end
138
+
139
+ def tokenize_arithmetic_negation(lhs)
140
+ lhs = {type: :field, value: lhs} if lhs.is_a?(String)
141
+ {
142
+ type: :arithmetic,
143
+ op: NEGATION,
144
+ lhs: lhs
145
+ }
146
+ end
147
+
132
148
  def tokenize_list(list)
133
149
  return if list.nil?
134
150
  validate_multiple_values list[:value]
@@ -245,22 +261,31 @@ module Sparkql::ParserTools
245
261
  true
246
262
  end
247
263
 
264
+ def group_fold(exp)
265
+ @lexer.leveldown
266
+ @lexer.block_group_identifier -= 1
267
+ exp
268
+ end
269
+
248
270
  def add_fold(n1, n2)
249
271
  return if arithmetic_error?(n1) || arithmetic_error?(n2)
250
272
 
251
- { type: arithmetic_type(n1, n2), value: (escape_value(n1) + escape_value(n2)).to_s }
273
+ value = escape_arithmetic_value(n1) + escape_arithmetic_value(n2)
274
+ { type: arithmetic_type(n1, n2), value: unescape_arithmetic(value) }
252
275
  end
253
276
 
254
277
  def sub_fold(n1, n2)
255
278
  return if arithmetic_error?(n1) || arithmetic_error?(n2)
256
279
 
257
- { type: arithmetic_type(n1, n2), value: (escape_value(n1) - escape_value(n2)).to_s }
280
+ value = escape_arithmetic_value(n1) - escape_arithmetic_value(n2)
281
+ { type: arithmetic_type(n1, n2), value: unescape_arithmetic(value) }
258
282
  end
259
283
 
260
284
  def mul_fold(n1, n2)
261
285
  return if arithmetic_error?(n1) || arithmetic_error?(n2)
262
286
 
263
- { type: arithmetic_type(n1, n2), value: (escape_value(n1) * escape_value(n2)).to_s }
287
+ value = escape_arithmetic_value(n1) * escape_arithmetic_value(n2)
288
+ { type: arithmetic_type(n1, n2), value: unescape_arithmetic(value) }
264
289
  end
265
290
 
266
291
  def div_fold(n1, n2)
@@ -268,7 +293,8 @@ module Sparkql::ParserTools
268
293
  arithmetic_error?(n2) ||
269
294
  zero_error?(n2)
270
295
 
271
- { type: arithmetic_type(n1, n2), value: (escape_value(n1) / escape_value(n2)).to_s }
296
+ value = escape_arithmetic_value(n1) / escape_arithmetic_value(n2)
297
+ { type: arithmetic_type(n1, n2), value: unescape_arithmetic(value) }
272
298
  end
273
299
 
274
300
  def mod_fold(n1, n2)
@@ -276,7 +302,8 @@ module Sparkql::ParserTools
276
302
  arithmetic_error?(n2) ||
277
303
  zero_error?(n2)
278
304
 
279
- { type: arithmetic_type(n1, n2), value: (escape_value(n1) % escape_value(n2)).to_s }
305
+ value = escape_arithmetic_value(n1) % escape_arithmetic_value(n2)
306
+ { type: arithmetic_type(n1, n2), value: unescape_arithmetic(value) }
280
307
  end
281
308
 
282
309
  def arithmetic_type(num1, num2)
@@ -287,6 +314,23 @@ module Sparkql::ParserTools
287
314
  end
288
315
  end
289
316
 
317
+ def escape_arithmetic_value(expression)
318
+ case expression[:type]
319
+ when :decimal
320
+ BigDecimal.new(expression[:value])
321
+ else
322
+ escape_value(expression)
323
+ end
324
+ end
325
+
326
+ def unescape_arithmetic(value)
327
+ if value.is_a?(BigDecimal)
328
+ value.round(20).to_s('F')
329
+ else
330
+ value.to_s
331
+ end
332
+ end
333
+
290
334
  def zero_error?(number)
291
335
  return unless escape_value(number) == 0
292
336
 
data/sparkql.gemspec CHANGED
@@ -1,30 +1,32 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "sparkql/version"
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.push File.expand_path('lib', __dir__)
4
+ require 'sparkql/version'
4
5
 
5
6
  Gem::Specification.new do |s|
6
- s.name = "sparkql"
7
+ s.name = 'sparkql'
7
8
  s.version = Sparkql::VERSION
8
- s.authors = ["Wade McEwen"]
9
- s.email = ["wade@fbsdata.com"]
10
- s.homepage = ""
11
- s.summary = %q{API Parser engine for filter searching}
12
- s.description = %q{Specification and base implementation of the Spark API parsing system.}
9
+ s.authors = ['Wade McEwen']
10
+ s.email = ['wade@fbsdata.com']
11
+ s.homepage = ''
12
+ s.summary = 'API Parser engine for filter searching'
13
+ s.description = 'Specification and base implementation of the Spark API parsing system.'
14
+
15
+ s.rubyforge_project = 'sparkql'
13
16
 
14
- s.rubyforge_project = "sparkql"
15
-
16
17
  s.license = 'Apache 2.0'
17
-
18
+
18
19
  s.files = `git ls-files`.split("\n")
19
20
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
- s.require_paths = ["lib"]
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
22
+ s.require_paths = ['lib']
23
+
24
+ s.required_ruby_version = '>= 2.3'
22
25
 
23
26
  s.add_dependency 'georuby', '~> 2.0'
27
+ s.add_development_dependency 'ci_reporter', '~> 1.6'
28
+ s.add_development_dependency 'mocha', '~> 0.12.0'
24
29
  s.add_development_dependency 'racc', '~> 1.4.8'
25
30
  s.add_development_dependency 'rake', '~> 0.9.2'
26
31
  s.add_development_dependency 'test-unit', '~> 2.1.0'
27
- s.add_development_dependency 'ci_reporter', '~> 1.6'
28
- s.add_development_dependency 'mocha', '~> 0.12.0'
29
-
30
32
  end
@@ -1,21 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'sparkql/geo'
3
5
 
4
6
  class FunctionResolverTest < Test::Unit::TestCase
5
7
  include Sparkql
6
-
7
- EXAMPLE_DATE = DateTime.parse("2013-07-26T10:22:15.422804")
8
8
 
9
- test "function parameters and name preserved" do
10
- f = FunctionResolver.new('radius', [{:type => :character,
11
- :value => "35.12 -68.33"},{:type => :decimal, :value => 1.0}])
9
+ EXAMPLE_DATE = DateTime.parse('2013-07-26T10:22:15.422804')
10
+
11
+ test 'function parameters and name preserved' do
12
+ f = FunctionResolver.new('radius', [{ type: :character,
13
+ value: '35.12 -68.33' }, { type: :decimal, value: 1.0 }])
12
14
  value = f.call
13
15
  assert_equal 'radius', value[:function_name]
14
- assert_equal(["35.12 -68.33", 1.0], value[:function_parameters])
16
+ assert_equal(['35.12 -68.33', 1.0], value[:function_parameters])
15
17
  end
16
18
 
17
- test "round(float)" do
18
- f = FunctionResolver.new('round', [{:type => :decimal, :value => 0.5}])
19
+ test 'round(float)' do
20
+ f = FunctionResolver.new('round', [{ type: :decimal, value: 0.5 }])
19
21
  f.validate
20
22
  assert !f.errors?, "Errors #{f.errors.inspect}"
21
23
  value = f.call
@@ -23,22 +25,22 @@ class FunctionResolverTest < Test::Unit::TestCase
23
25
  assert_equal '1', value[:value]
24
26
  end
25
27
 
26
- test "round(Field)" do
27
- f = FunctionResolver.new('round', [{:type => :field, :value => 'ListPrice'}])
28
+ test 'round(Field)' do
29
+ f = FunctionResolver.new('round', [{ type: :field, value: 'ListPrice' }])
28
30
  f.validate
29
31
  assert !f.errors?, "Errors #{f.errors.inspect}"
30
32
  value = f.call
31
33
 
32
34
  assert_equal :function, value[:type]
33
35
  assert_equal 'round', value[:value]
34
- assert_equal "ListPrice", value[:args].first[:value]
36
+ assert_equal 'ListPrice', value[:args].first[:value]
35
37
  end
36
38
 
37
- test "substring character one index" do
39
+ test 'substring character one index' do
38
40
  f = FunctionResolver.new('substring', [
39
- {:type => :character, :value => 'ListPrice'},
40
- {:type => :integer, :value => 1}
41
- ])
41
+ { type: :character, value: 'ListPrice' },
42
+ { type: :integer, value: 1 }
43
+ ])
42
44
 
43
45
  f.validate
44
46
  assert !f.errors?, "Errors #{f.errors.inspect}"
@@ -48,26 +50,26 @@ class FunctionResolverTest < Test::Unit::TestCase
48
50
  assert_equal 'istPrice', value[:value]
49
51
  end
50
52
 
51
- test "substring character two indexes" do
53
+ test 'substring character two indexes' do
52
54
  f = FunctionResolver.new('substring', [
53
- {:type => :character, :value => 'alfb'},
54
- {:type => :integer, :value => 1},
55
- {:type => :integer, :value => 2}
56
- ])
55
+ { type: :character, value: 'alfb' },
56
+ { type: :integer, value: 1 },
57
+ { type: :integer, value: 2 }
58
+ ])
57
59
 
58
60
  f.validate
59
61
  assert !f.errors?, "Errors #{f.errors.inspect}"
60
62
  value = f.call
61
63
 
62
64
  assert_equal :character, value[:type]
63
- assert_equal "lf", value[:value]
65
+ assert_equal 'lf', value[:value]
64
66
  end
65
67
 
66
- test "substring character large first index" do
68
+ test 'substring character large first index' do
67
69
  f = FunctionResolver.new('substring', [
68
- {:type => :character, :value => 'ListPrice'},
69
- {:type => :integer, :value => 10}
70
- ])
70
+ { type: :character, value: 'ListPrice' },
71
+ { type: :integer, value: 10 }
72
+ ])
71
73
 
72
74
  f.validate
73
75
  assert !f.errors?, "Errors #{f.errors.inspect}"
@@ -77,11 +79,11 @@ class FunctionResolverTest < Test::Unit::TestCase
77
79
  assert_equal '', value[:value]
78
80
  end
79
81
 
80
- test "substring field one index" do
82
+ test 'substring field one index' do
81
83
  f = FunctionResolver.new('substring', [
82
- {:type => :field, :value => 'ListPrice'},
83
- {:type => :integer, :value => 1}
84
- ])
84
+ { type: :field, value: 'ListPrice' },
85
+ { type: :integer, value: 1 }
86
+ ])
85
87
 
86
88
  f.validate
87
89
  assert !f.errors?, "Errors #{f.errors.inspect}"
@@ -89,16 +91,16 @@ class FunctionResolverTest < Test::Unit::TestCase
89
91
 
90
92
  assert_equal :function, value[:type]
91
93
  assert_equal 'substring', value[:value]
92
- assert_equal "ListPrice", value[:args].first[:value]
94
+ assert_equal 'ListPrice', value[:args].first[:value]
93
95
  assert_equal 2, value[:args].size
94
96
  end
95
97
 
96
- test "substring field two indexes" do
98
+ test 'substring field two indexes' do
97
99
  f = FunctionResolver.new('substring', [
98
- {:type => :field, :value => 'ListPrice'},
99
- {:type => :integer, :value => 1},
100
- {:type => :integer, :value => 2}
101
- ])
100
+ { type: :field, value: 'ListPrice' },
101
+ { type: :integer, value: 1 },
102
+ { type: :integer, value: 2 }
103
+ ])
102
104
 
103
105
  f.validate
104
106
  assert !f.errors?, "Errors #{f.errors.inspect}"
@@ -106,28 +108,28 @@ class FunctionResolverTest < Test::Unit::TestCase
106
108
 
107
109
  assert_equal :function, value[:type]
108
110
  assert_equal 'substring', value[:value]
109
- assert_equal "ListPrice", value[:args].first[:value]
111
+ assert_equal 'ListPrice', value[:args].first[:value]
110
112
  assert_equal 2, value[:args].last[:value]
111
113
  end
112
114
 
113
- test "substring with negative M is a parse error" do
115
+ test 'substring with negative M is a parse error' do
114
116
  f = FunctionResolver.new('substring', [
115
- {:type => :field, :value => 'ListPrice'},
116
- {:type => :integer, :value => 1},
117
- {:type => :integer, :value => -5}
118
- ])
117
+ { type: :field, value: 'ListPrice' },
118
+ { type: :integer, value: 1 },
119
+ { type: :integer, value: -5 }
120
+ ])
119
121
 
120
122
  f.validate
121
123
  f.call
122
124
  assert f.errors?
123
125
  end
124
126
 
125
- test "character substring with negative M is a parse error" do
127
+ test 'character substring with negative M is a parse error' do
126
128
  f = FunctionResolver.new('substring', [
127
- {:type => :character, :value => 'ListPrice'},
128
- {:type => :integer, :value => 1},
129
- {:type => :integer, :value => -5}
130
- ])
129
+ { type: :character, value: 'ListPrice' },
130
+ { type: :integer, value: 1 },
131
+ { type: :integer, value: -5 }
132
+ ])
131
133
 
132
134
  f.validate
133
135
  f.call
@@ -136,8 +138,8 @@ class FunctionResolverTest < Test::Unit::TestCase
136
138
 
137
139
  test 'trim with field' do
138
140
  f = FunctionResolver.new('trim', [
139
- {:type => :field, :value => 'Name'}
140
- ])
141
+ { type: :field, value: 'Name' }
142
+ ])
141
143
 
142
144
  f.validate
143
145
  assert !f.errors?, "Errors #{f.errors.inspect}"
@@ -145,13 +147,13 @@ class FunctionResolverTest < Test::Unit::TestCase
145
147
 
146
148
  assert_equal :function, value[:type]
147
149
  assert_equal 'trim', value[:value]
148
- assert_equal "Name", value[:args].first[:value]
150
+ assert_equal 'Name', value[:args].first[:value]
149
151
  end
150
152
 
151
153
  test 'trim with character' do
152
154
  f = FunctionResolver.new('trim', [
153
- {:type => :character, :value => ' val '}
154
- ])
155
+ { type: :character, value: ' val ' }
156
+ ])
155
157
 
156
158
  f.validate
157
159
  assert !f.errors?, "Errors #{f.errors.inspect}"
@@ -162,7 +164,7 @@ class FunctionResolverTest < Test::Unit::TestCase
162
164
  end
163
165
 
164
166
  test "tolower('string')" do
165
- f = FunctionResolver.new('tolower', [{:type => :character, :value => "STRING"}])
167
+ f = FunctionResolver.new('tolower', [{ type: :character, value: 'STRING' }])
166
168
  f.validate
167
169
  assert !f.errors?, "Errors #{f.errors.inspect}"
168
170
  value = f.call
@@ -170,18 +172,18 @@ class FunctionResolverTest < Test::Unit::TestCase
170
172
  assert_equal "'string'", value[:value]
171
173
  end
172
174
 
173
- test "toupper(SomeField)" do
174
- f = FunctionResolver.new('toupper', [{:type => :field, :value => "City"}])
175
+ test 'toupper(SomeField)' do
176
+ f = FunctionResolver.new('toupper', [{ type: :field, value: 'City' }])
175
177
  f.validate
176
178
  assert !f.errors?, "Errors #{f.errors.inspect}"
177
179
  value = f.call
178
180
  assert_equal :function, value[:type]
179
181
  assert_equal 'toupper', value[:value]
180
- assert_equal "City", value[:args].first[:value]
182
+ assert_equal 'City', value[:args].first[:value]
181
183
  end
182
184
 
183
185
  test "toupper('string')" do
184
- f = FunctionResolver.new('toupper', [{:type => :character, :value => "string"}])
186
+ f = FunctionResolver.new('toupper', [{ type: :character, value: 'string' }])
185
187
  f.validate
186
188
  assert !f.errors?, "Errors #{f.errors.inspect}"
187
189
  value = f.call
@@ -189,18 +191,18 @@ class FunctionResolverTest < Test::Unit::TestCase
189
191
  assert_equal "'STRING'", value[:value]
190
192
  end
191
193
 
192
- test "length(SomeField)" do
193
- f = FunctionResolver.new('length', [{:type => :field, :value => "City"}])
194
+ test 'length(SomeField)' do
195
+ f = FunctionResolver.new('length', [{ type: :field, value: 'City' }])
194
196
  f.validate
195
197
  assert !f.errors?, "Errors #{f.errors.inspect}"
196
198
  value = f.call
197
199
  assert_equal :function, value[:type]
198
200
  assert_equal 'length', value[:value]
199
- assert_equal "City", value[:args].first[:value]
201
+ assert_equal 'City', value[:args].first[:value]
200
202
  end
201
203
 
202
204
  test "length('string')" do
203
- f = FunctionResolver.new('length', [{:type => :character, :value => "string"}])
205
+ f = FunctionResolver.new('length', [{ type: :character, value: 'string' }])
204
206
  f.validate
205
207
  assert !f.errors?, "Errors #{f.errors.inspect}"
206
208
  value = f.call
@@ -208,7 +210,7 @@ class FunctionResolverTest < Test::Unit::TestCase
208
210
  assert_equal '6', value[:value]
209
211
  end
210
212
 
211
- test "now()" do
213
+ test 'now()' do
212
214
  start = Time.now
213
215
  f = FunctionResolver.new('now', [])
214
216
  f.validate
@@ -216,10 +218,11 @@ class FunctionResolverTest < Test::Unit::TestCase
216
218
  value = f.call
217
219
  assert_equal :datetime, value[:type]
218
220
  test_time = Time.parse(value[:value])
219
- assert (-5 < test_time - start && 5 > test_time - start), "Time range off by more than five seconds #{test_time - start} '#{test_time} - #{start}'"
221
+ assert (test_time - start > -5 && test_time - start < 5),
222
+ "Time range off by more than five seconds #{test_time - start} '#{test_time} - #{start}'"
220
223
  end
221
224
 
222
- test "mindatetime()" do
225
+ test 'mindatetime()' do
223
226
  f = FunctionResolver.new('mindatetime', [])
224
227
  f.validate
225
228
  assert !f.errors?, "Errors #{f.errors.inspect}"
@@ -229,7 +232,7 @@ class FunctionResolverTest < Test::Unit::TestCase
229
232
  assert_equal '1970-01-01T00:00:00+00:00', value[:value]
230
233
  end
231
234
 
232
- test "maxdatetime()" do
235
+ test 'maxdatetime()' do
233
236
  f = FunctionResolver.new('maxdatetime', [])
234
237
  f.validate
235
238
  assert !f.errors?, "Errors #{f.errors.inspect}"
@@ -239,8 +242,8 @@ class FunctionResolverTest < Test::Unit::TestCase
239
242
  assert_equal '9999-12-31T23:59:59+00:00', value[:value]
240
243
  end
241
244
 
242
- test "floor(float)" do
243
- f = FunctionResolver.new('floor', [{:type => :decimal, :value => 0.5}])
245
+ test 'floor(float)' do
246
+ f = FunctionResolver.new('floor', [{ type: :decimal, value: 0.5 }])
244
247
  f.validate
245
248
  assert !f.errors?, "Errors #{f.errors.inspect}"
246
249
  value = f.call
@@ -248,19 +251,19 @@ class FunctionResolverTest < Test::Unit::TestCase
248
251
  assert_equal '0', value[:value]
249
252
  end
250
253
 
251
- test "floor(Field)" do
252
- f = FunctionResolver.new('floor', [{:type => :field, :value => 'ListPrice'}])
254
+ test 'floor(Field)' do
255
+ f = FunctionResolver.new('floor', [{ type: :field, value: 'ListPrice' }])
253
256
  f.validate
254
257
  assert !f.errors?, "Errors #{f.errors.inspect}"
255
258
  value = f.call
256
259
 
257
260
  assert_equal :function, value[:type]
258
261
  assert_equal 'floor', value[:value]
259
- assert_equal "ListPrice", value[:args].first[:value]
262
+ assert_equal 'ListPrice', value[:args].first[:value]
260
263
  end
261
264
 
262
- test "ceiling(float)" do
263
- f = FunctionResolver.new('ceiling', [{:type => :decimal, :value => 0.5}])
265
+ test 'ceiling(float)' do
266
+ f = FunctionResolver.new('ceiling', [{ type: :decimal, value: 0.5 }])
264
267
  f.validate
265
268
  assert !f.errors?, "Errors #{f.errors.inspect}"
266
269
  value = f.call
@@ -268,93 +271,344 @@ class FunctionResolverTest < Test::Unit::TestCase
268
271
  assert_equal '1', value[:value]
269
272
  end
270
273
 
271
- test "ceiling(Field)" do
272
- f = FunctionResolver.new('ceiling', [{:type => :field, :value => 'ListPrice'}])
274
+ test 'ceiling(Field)' do
275
+ f = FunctionResolver.new('ceiling', [{ type: :field, value: 'ListPrice' }])
273
276
  f.validate
274
277
  assert !f.errors?, "Errors #{f.errors.inspect}"
275
278
  value = f.call
276
279
 
277
280
  assert_equal :function, value[:type]
278
281
  assert_equal 'ceiling', value[:value]
279
- assert_equal "ListPrice", value[:args].first[:value]
282
+ assert_equal 'ListPrice', value[:args].first[:value]
283
+ end
284
+
285
+ test 'seconds()' do
286
+ test_time = Time.new(2019, 4, 1, 8, 30, 20, 0)
287
+
288
+ f = FunctionResolver.new('seconds', [{ type: :integer, value: 7 }])
289
+ f.expects(:current_time).returns(test_time)
290
+ f.validate
291
+ assert !f.errors?, "Errors #{f.errors.inspect}"
292
+ value = f.call
293
+
294
+ assert_equal :datetime, value[:type]
295
+ d = DateTime.parse(value[:value])
296
+ assert_equal test_time.year, d.year
297
+ assert_equal test_time.month, d.month
298
+ assert_equal test_time.mday, d.mday
299
+ assert_equal test_time.hour, d.hour
300
+ assert_equal test_time.min, d.min
301
+ assert_equal test_time.sec + 7, d.sec
302
+
303
+ f = FunctionResolver.new('seconds', [{ type: :integer, value: -21 }])
304
+ f.expects(:current_time).returns(test_time)
305
+ f.validate
306
+ assert !f.errors?, "Errors #{f.errors.inspect}"
307
+ value = f.call
308
+
309
+ assert_equal :datetime, value[:type]
310
+ d = DateTime.parse(value[:value])
311
+ assert_equal test_time.year, d.year
312
+ assert_equal test_time.month, d.month
313
+ assert_equal test_time.mday, d.mday
314
+ assert_equal test_time.hour, d.hour
315
+ assert_equal test_time.min - 1, d.min
316
+ assert_equal 29, d.min
317
+ assert_equal 59, d.sec
318
+
319
+ f = FunctionResolver.new('seconds', [{ type: :integer,
320
+ value: -Sparkql::FunctionResolver::SECONDS_IN_DAY }])
321
+ f.expects(:current_time).returns(test_time)
322
+ f.validate
323
+ assert !f.errors?, "Errors #{f.errors.inspect}"
324
+ value = f.call
325
+
326
+ assert_equal :datetime, value[:type]
327
+ d = DateTime.parse(value[:value])
328
+ assert_equal test_time.year, d.year
329
+ assert_equal test_time.month - 1, d.month
330
+ assert_equal 31, d.mday
331
+ assert_equal test_time.hour, d.hour
332
+ assert_equal test_time.min, d.min
333
+ assert_equal test_time.min, d.min
334
+ assert_equal test_time.sec, d.sec
280
335
  end
281
336
 
282
- test "days()" do
283
- d = Date.new(2012,10,20)
284
- Date.expects(:today).returns(d)
285
- dt = DateTime.new(d.year, d.month,d.day, 0,0,0, DateTime.now.offset)
286
- start = Time.parse(dt.to_s)
287
- f = FunctionResolver.new('days', [{:type=>:integer, :value =>7}])
337
+ test 'minutes()' do
338
+ test_time = Time.new(2019, 4, 1, 8, 30, 20, 0)
339
+
340
+ f = FunctionResolver.new('minutes', [{ type: :integer, value: 7 }])
341
+ f.expects(:current_time).returns(test_time)
342
+ f.validate
343
+ assert !f.errors?, "Errors #{f.errors.inspect}"
344
+ value = f.call
345
+
346
+ assert_equal :datetime, value[:type]
347
+ d = DateTime.parse(value[:value])
348
+ assert_equal test_time.year, d.year
349
+ assert_equal test_time.month, d.month
350
+ assert_equal test_time.mday, d.mday
351
+ assert_equal test_time.hour, d.hour
352
+ assert_equal test_time.min + 7, d.min
353
+ assert_equal test_time.sec, d.sec
354
+
355
+ f = FunctionResolver.new('minutes', [{ type: :integer, value: -37 }])
356
+ f.expects(:current_time).returns(test_time)
357
+ f.validate
358
+ assert !f.errors?, "Errors #{f.errors.inspect}"
359
+ value = f.call
360
+
361
+ assert_equal :datetime, value[:type]
362
+ d = DateTime.parse(value[:value])
363
+ assert_equal test_time.year, d.year
364
+ assert_equal test_time.month, d.month
365
+ assert_equal test_time.mday, d.mday
366
+ assert_equal test_time.hour - 1, d.hour
367
+ assert_equal 53, d.min
368
+
369
+ f = FunctionResolver.new('minutes', [{ type: :integer,
370
+ value: -1440 }])
371
+ f.expects(:current_time).returns(test_time)
372
+ f.validate
373
+ assert !f.errors?, "Errors #{f.errors.inspect}"
374
+ value = f.call
375
+
376
+ assert_equal :datetime, value[:type]
377
+ d = DateTime.parse(value[:value])
378
+ assert_equal test_time.year, d.year
379
+ assert_equal test_time.month - 1, d.month
380
+ assert_equal 31, d.mday
381
+ assert_equal test_time.hour, d.hour
382
+ assert_equal test_time.min, d.min
383
+ end
384
+
385
+ test 'hours(), same day' do
386
+ test_time = Time.new(2019, 4, 1, 8, 30, 20, 0)
387
+ tests = [1, -1, 5, -5, 12]
388
+
389
+ tests.each do |offset|
390
+ f = FunctionResolver.new('hours', [{ type: :integer,
391
+ value: offset }])
392
+ f.expects(:current_time).returns(test_time)
393
+ f.validate
394
+ assert !f.errors?, "Errors #{f.errors.inspect}"
395
+ value = f.call
396
+
397
+ assert_equal :datetime, value[:type]
398
+ d = DateTime.parse(value[:value])
399
+ assert_equal test_time.year, d.year
400
+ assert_equal test_time.month, d.month
401
+ assert_equal test_time.mday, d.mday
402
+ assert_equal test_time.hour + offset, d.hour
403
+ assert_equal test_time.min, d.min
404
+ assert_equal test_time.sec, d.sec
405
+ end
406
+ end
407
+
408
+ test 'hours(), wrap day' do
409
+ test_time = Time.new(2019, 4, 1, 8, 30, 20, 0)
410
+
411
+ # Jump forward a few days, and a few hours.
412
+ f = FunctionResolver.new('hours', [{ type: :integer, value: 52 }])
413
+ f.expects(:current_time).returns(test_time)
414
+ f.validate
415
+ assert !f.errors?, "Errors #{f.errors.inspect}"
416
+ value = f.call
417
+
418
+ assert_equal :datetime, value[:type]
419
+ d = DateTime.parse(value[:value])
420
+ assert_equal test_time.year, d.year
421
+ assert_equal test_time.month, d.month
422
+ assert_equal test_time.mday + 2, d.mday
423
+ assert_equal test_time.hour + 4, d.hour
424
+ assert_equal test_time.min, d.min
425
+
426
+ # Drop back to the previous day, which'll also hit the previous month
427
+ f = FunctionResolver.new('hours', [{ type: :integer, value: -24 }])
428
+ f.expects(:current_time).returns(test_time)
429
+ f.validate
430
+ assert !f.errors?, "Errors #{f.errors.inspect}"
431
+ value = f.call
432
+
433
+ assert_equal :datetime, value[:type]
434
+ d = DateTime.parse(value[:value])
435
+ assert_equal test_time.year, d.year
436
+ assert_equal test_time.month - 1, d.month
437
+ assert_equal 31, d.mday
438
+ assert_equal test_time.hour, d.hour
439
+ assert_equal test_time.min, d.min
440
+
441
+ # Drop back one full year's worth of hours.
442
+ f = FunctionResolver.new('hours', [{ type: :integer, value: -8760 }])
443
+ f.expects(:current_time).returns(test_time)
444
+ f.validate
445
+ assert !f.errors?, "Errors #{f.errors.inspect}"
446
+ value = f.call
447
+
448
+ assert_equal :datetime, value[:type]
449
+ d = DateTime.parse(value[:value])
450
+ assert_equal test_time.year - 1, d.year
451
+ assert_equal test_time.month, d.month
452
+ assert_equal test_time.mday, d.mday
453
+ assert_equal test_time.hour, d.hour
454
+ assert_equal test_time.min, d.min
455
+ end
456
+
457
+ test 'days()' do
458
+ test_date = Date.new(2012, 10, 20) # Sat, 20 Oct 2012 00:00:00 GMT
459
+ f = FunctionResolver.new('days', [{ type: :integer, value: 7 }])
460
+ f.expects(:current_date).returns(test_date)
288
461
  f.validate
289
462
  assert !f.errors?, "Errors #{f.errors.inspect}"
290
463
  value = f.call
291
464
  assert_equal :date, value[:type]
292
- test_time = Time.parse(value[:value])
293
- assert (615000 > test_time - start && 600000 < test_time - start), "Time range off by more than five seconds #{test_time - start} '#{test_time} - #{start}'"
465
+ assert_equal '2012-10-27', value[:value]
466
+ end
467
+
468
+ test 'weekdays()' do
469
+ friday = Date.new(2012, 10, 19)
470
+ saturday = Date.new(2012, 10, 20)
471
+ sunday = Date.new(2012, 10, 21)
472
+ monday = Date.new(2012, 10, 22)
473
+ {
474
+ friday => [
475
+ [-5, '2012-10-12'],
476
+ [-4, '2012-10-15'],
477
+ [-1, '2012-10-18'],
478
+ [0, '2012-10-19'],
479
+ [1, '2012-10-22'],
480
+ [2, '2012-10-23'],
481
+ [5, '2012-10-26'],
482
+ [6, '2012-10-29'],
483
+ [7, '2012-10-30'],
484
+ [31, '2012-12-03']
485
+ ],
486
+ saturday => [
487
+ [-6, '2012-10-12'],
488
+ [-5, '2012-10-15'],
489
+ [-1, '2012-10-19'],
490
+ [0, '2012-10-22'],
491
+ [1, '2012-10-22'],
492
+ [2, '2012-10-23'],
493
+ [3, '2012-10-24'],
494
+ [4, '2012-10-25'],
495
+ [5, '2012-10-26'],
496
+ [6, '2012-10-29'],
497
+ [7, '2012-10-30'],
498
+ [31, '2012-12-03']
499
+ ],
500
+ sunday => [
501
+ [-6, '2012-10-12'],
502
+ [-5, '2012-10-15'],
503
+ [-1, '2012-10-19'],
504
+ [0, '2012-10-22'],
505
+ [1, '2012-10-22'],
506
+ [2, '2012-10-23'],
507
+ [5, '2012-10-26'],
508
+ [6, '2012-10-29'],
509
+ [7, '2012-10-30'],
510
+ [31, '2012-12-03']
511
+ ],
512
+ monday => [
513
+ [-6, '2012-10-12'],
514
+ [-5, '2012-10-15'],
515
+ [-1, '2012-10-19'],
516
+ [0, '2012-10-22'],
517
+ [1, '2012-10-23'],
518
+ [2, '2012-10-24'],
519
+ [5, '2012-10-29'],
520
+ [6, '2012-10-30'],
521
+ [7, '2012-10-31'],
522
+ [31, '2012-12-04']
523
+ ]
524
+ }.each do |test_date, weekday_tests|
525
+ weekday_tests.each do |days, expected_value|
526
+ f = FunctionResolver.new('weekdays', [{ type: :integer, value: days }])
527
+ f.expects(:current_date).returns(test_date)
528
+ f.validate
529
+ assert !f.errors?, "#{test_date}: #{days} = #{expected_value}"
530
+ value = f.call
531
+ assert_equal :date, value[:type]
532
+ assert_equal expected_value, value[:value], "#{test_date}: #{days} = #{expected_value}"
533
+ end
534
+ end
294
535
  end
295
536
 
296
- test "months()" do
537
+ test 'months()' do
297
538
  dt = DateTime.new(2014, 1, 6, 0, 0, 0, 0)
298
539
  DateTime.expects(:now).once.returns(dt)
299
540
 
300
- f = FunctionResolver.new('months', [{:type=>:integer, :value =>3}])
541
+ f = FunctionResolver.new('months', [{ type: :integer, value: 3 }])
301
542
  f.validate
302
543
  assert !f.errors?, "Errors resolving months(): #{f.errors.inspect}"
303
544
  value = f.call
304
545
  assert_equal :date, value[:type]
305
546
 
306
- assert_equal "2014-04-06", value[:value]
547
+ assert_equal '2014-04-06', value[:value]
307
548
  end
308
-
309
- test "years()" do
549
+
550
+ test 'years()' do
310
551
  dt = DateTime.new(2014, 1, 6, 0, 0, 0, 0)
311
552
  DateTime.expects(:now).once.returns(dt)
312
- f = FunctionResolver.new('years', [{:type=>:integer, :value =>-4}])
553
+ f = FunctionResolver.new('years', [{ type: :integer, value: -4 }])
313
554
  f.validate
314
555
  assert !f.errors?, "Errors resolving years(): #{f.errors.inspect}"
315
556
  value = f.call
316
557
  assert_equal :date, value[:type]
317
- assert_equal '2010-01-06', value[:value], "negative values should go back in time"
558
+ assert_equal '2010-01-06', value[:value], 'negative values should go back in time'
318
559
  end
319
560
 
320
- test "year(), month(), and day()" do
321
- ['year', 'month', 'day'].each do |function|
322
- f = FunctionResolver.new(function, [{:type => :field, :value => "OriginalEntryTimestamp"}])
561
+ test 'year(), month(), and day()' do
562
+ %w[year month day].each do |function|
563
+ f = FunctionResolver.new(function, [{ type: :field, value: 'OriginalEntryTimestamp' }])
323
564
  f.validate
324
565
  assert !f.errors?, "Errors #{f.errors.inspect}"
325
566
  value = f.call
326
567
  assert_equal :function, value[:type]
327
568
  assert_equal function, value[:value]
328
- assert_equal "OriginalEntryTimestamp", value[:args].first[:value]
569
+ assert_equal 'OriginalEntryTimestamp', value[:args].first[:value]
329
570
  end
330
571
  end
331
572
 
332
- test "hour(), minute(), and second()" do
333
- ['year', 'month', 'day'].each do |function|
334
- f = FunctionResolver.new(function, [{:type => :field, :value => "OriginalEntryTimestamp"}])
573
+ test 'hour(), minute(), and second()' do
574
+ %w[year month day].each do |function|
575
+ f = FunctionResolver.new(function, [{ type: :field, value: 'OriginalEntryTimestamp' }])
335
576
  f.validate
336
577
  assert !f.errors?, "Errors #{f.errors.inspect}"
337
578
  value = f.call
338
579
  assert_equal :function, value[:type]
339
580
  assert_equal function, value[:value]
340
- assert_equal "OriginalEntryTimestamp", value[:args].first[:value]
581
+ assert_equal 'OriginalEntryTimestamp', value[:args].first[:value]
341
582
  end
342
583
  end
343
584
 
344
- test "fractionalseconds()" do
345
- f = FunctionResolver.new('fractionalseconds', [{:type => :field, :value => "OriginalEntryTimestamp"}])
585
+ test 'day of week and day of year parse' do
586
+ %w[dayofyear dayofweek].each do |function|
587
+ f = FunctionResolver.new(function, [{ type: :field, value: 'OriginalEntryTimestamp' }])
588
+ f.validate
589
+ assert !f.errors?, "Errors #{f.errors.inspect}"
590
+ value = f.call
591
+ assert_equal :function, value[:type]
592
+ assert_equal function, value[:value]
593
+ assert_equal 'OriginalEntryTimestamp', value[:args].first[:value]
594
+ end
595
+ end
596
+
597
+ test 'fractionalseconds()' do
598
+ f = FunctionResolver.new('fractionalseconds', [{ type: :field, value: 'OriginalEntryTimestamp' }])
346
599
  f.validate
347
600
  assert !f.errors?, "Errors #{f.errors.inspect}"
348
601
  value = f.call
349
602
  assert_equal :function, value[:type]
350
603
  assert_equal 'fractionalseconds', value[:value]
351
- assert_equal "OriginalEntryTimestamp", value[:args].first[:value]
604
+ assert_equal 'OriginalEntryTimestamp', value[:args].first[:value]
352
605
  end
353
606
 
354
607
  # Polygon searches
355
-
356
- test "radius()" do
357
- f = FunctionResolver.new('radius', [{:type => :character, :value => "35.12 -68.33"},{:type => :decimal, :value => 1.0}])
608
+
609
+ test 'radius()' do
610
+ f = FunctionResolver.new('radius',
611
+ [{ type: :character, value: '35.12 -68.33' }, { type: :decimal, value: 1.0 }])
358
612
  f.validate
359
613
  assert !f.errors?, "Errors #{f.errors.inspect}"
360
614
  value = f.call
@@ -364,38 +618,41 @@ class FunctionResolverTest < Test::Unit::TestCase
364
618
  assert_equal 1.0, value[:value].radius, "#{value[:value].inspect} "
365
619
  end
366
620
 
367
- test "radius() can be overloaded with a ListingKey" do
368
- f = FunctionResolver.new('radius', [{:type => :character, :value => "20100000000000000000000000"},
369
- {:type => :decimal, :value => 1.0}])
621
+ test 'radius() can be overloaded with a ListingKey' do
622
+ f = FunctionResolver.new('radius', [{ type: :character, value: '20100000000000000000000000' },
623
+ { type: :decimal, value: 1.0 }])
370
624
  f.validate
371
625
  assert !f.errors?, "Errors #{f.errors.inspect}"
372
626
  value = f.call
373
627
  assert_equal :shape, value[:type]
374
628
  assert_equal Sparkql::Geo::RecordRadius, value[:value].class
375
- assert_equal "20100000000000000000000000", value[:value].record_id, "#{value[:value].inspect} "
629
+ assert_equal '20100000000000000000000000', value[:value].record_id, "#{value[:value].inspect} "
376
630
  assert_equal 1.0, value[:value].radius, "#{value[:value].inspect} "
377
631
  end
378
632
 
379
- test "radius() fails if not given coords or a flex ID" do
380
- f = FunctionResolver.new('radius', [{:type => :character, :value => "35.12,-68.33"},
381
- {:type => :decimal, :value => 1.0}])
633
+ test 'radius() fails if not given coords or a flex ID' do
634
+ f = FunctionResolver.new('radius', [{ type: :character, value: '35.12,-68.33' },
635
+ { type: :decimal, value: 1.0 }])
382
636
  f.validate
383
637
  f.call
384
638
  assert f.errors?
385
639
  end
386
640
 
387
- test "polygon()" do
388
- f = FunctionResolver.new('polygon', [{:type => :character, :value => "35.12 -68.33,35.12 -68.32, 35.13 -68.32,35.13 -68.33"}])
641
+ test 'polygon()' do
642
+ f = FunctionResolver.new('polygon',
643
+ [{ type: :character,
644
+ value: '35.12 -68.33,35.12 -68.32, 35.13 -68.32,35.13 -68.33' }])
389
645
  f.validate
390
646
  assert !f.errors?, "Errors #{f.errors.inspect}"
391
647
  value = f.call
392
648
  assert_equal :shape, value[:type]
393
649
  assert_equal GeoRuby::SimpleFeatures::Polygon, value[:value].class
394
- assert_equal [[-68.33, 35.12], [-68.32, 35.12], [-68.32, 35.13], [-68.33, 35.13], [-68.33, 35.12]], value[:value].to_coordinates.first, "#{value[:value].inspect} "
650
+ assert_equal [[-68.33, 35.12], [-68.32, 35.12], [-68.32, 35.13], [-68.33, 35.13], [-68.33, 35.12]],
651
+ value[:value].to_coordinates.first, "#{value[:value].inspect} "
395
652
  end
396
-
397
- test "linestring()" do
398
- f = FunctionResolver.new('linestring', [{:type => :character, :value => "35.12 -68.33,35.12 -68.32"}])
653
+
654
+ test 'linestring()' do
655
+ f = FunctionResolver.new('linestring', [{ type: :character, value: '35.12 -68.33,35.12 -68.32' }])
399
656
  f.validate
400
657
  assert !f.errors?, "Errors #{f.errors.inspect}"
401
658
  value = f.call
@@ -404,70 +661,72 @@ class FunctionResolverTest < Test::Unit::TestCase
404
661
  assert_equal [[-68.33, 35.12], [-68.32, 35.12]], value[:value].to_coordinates, "#{value[:value].inspect} "
405
662
  end
406
663
 
407
- test "rectangle()" do
408
- f = FunctionResolver.new('rectangle', [{:type => :character, :value => "35.12 -68.33, 35.13 -68.32"}])
664
+ test 'rectangle()' do
665
+ f = FunctionResolver.new('rectangle', [{ type: :character, value: '35.12 -68.33, 35.13 -68.32' }])
409
666
  f.validate
410
667
  assert !f.errors?, "Errors #{f.errors.inspect}"
411
668
  value = f.call
412
669
  assert_equal :shape, value[:type]
413
670
  assert_equal GeoRuby::SimpleFeatures::Polygon, value[:value].class
414
- assert_equal [[-68.33,35.12], [-68.32,35.12], [-68.32,35.13], [-68.33,35.13], [-68.33,35.12]], value[:value].to_coordinates.first, "#{value[:value].inspect} "
671
+ assert_equal [[-68.33, 35.12], [-68.32, 35.12], [-68.32, 35.13], [-68.33, 35.13], [-68.33, 35.12]],
672
+ value[:value].to_coordinates.first, "#{value[:value].inspect} "
415
673
  end
416
674
 
417
- test "range()" do
418
- f = FunctionResolver.new('range', [{:type => :character, :value => "M01"},
419
- {:type => :character, :value => "M05"}])
675
+ test 'range()' do
676
+ f = FunctionResolver.new('range', [{ type: :character, value: 'M01' },
677
+ { type: :character, value: 'M05' }])
420
678
  f.validate
421
679
  assert !f.errors?, "Errors #{f.errors.inspect}"
422
680
  value = f.call
423
681
  assert_equal :character, value[:type]
424
- assert_equal ["M01", "M05"], value[:value]
682
+ assert_equal %w[M01 M05], value[:value]
425
683
  end
426
-
427
- test "invalid params" do
428
- f = FunctionResolver.new('now', [{:type => :character, :value=>'bad value'}])
684
+
685
+ test 'invalid params' do
686
+ f = FunctionResolver.new('now', [{ type: :character, value: 'bad value' }])
429
687
  f.validate
430
688
  assert f.errors?, "'now' function does not support parameters"
431
-
689
+
432
690
  f = FunctionResolver.new('days', [])
433
691
  f.validate
434
692
  assert f.errors?, "'days' function requires one parameter"
435
-
436
- f = FunctionResolver.new('days', [{:type => :character, :value=>'bad value'}])
693
+
694
+ f = FunctionResolver.new('days', [{ type: :character, value: 'bad value' }])
437
695
  f.validate
438
696
  assert f.errors?, "'days' function needs integer parameter"
439
697
  end
440
698
 
441
- test "assert nil returned when function called with errors" do
442
- f = FunctionResolver.new('radius', [{:type => :character,
443
- :value => "35.12 -68.33, 35.13 -68.34"},{:type => :decimal,
444
- :value => 1.0}])
699
+ test 'assert nil returned when function called with errors' do
700
+ f = FunctionResolver.new('radius', [{ type: :character,
701
+ value: '35.12 -68.33, 35.13 -68.34' }, { type: :decimal,
702
+ value: 1.0 }])
445
703
  assert_nil f.call
446
704
  end
447
-
448
- test "return_type" do
449
- f = FunctionResolver.new('radius', [{:type => :character,
450
- :value => "35.12 -68.33, 35.13 -68.34"},{:type => :decimal,
451
- :value => 1.0}])
705
+
706
+ test 'return_type' do
707
+ f = FunctionResolver.new('radius', [{ type: :character,
708
+ value: '35.12 -68.33, 35.13 -68.34' }, { type: :decimal,
709
+ value: 1.0 }])
452
710
  assert_equal :shape, f.return_type
453
711
  end
454
712
 
455
713
  test 'return_type for cast()' do
456
- f = FunctionResolver.new('cast', [{:type => :character,
457
- :value => "1"},{:type => :character,
458
- :value => 'decimal'}])
714
+ f = FunctionResolver.new('cast', [{ type: :character,
715
+ value: '1' }, { type: :character,
716
+ value: 'decimal' }])
459
717
 
460
718
  assert_equal :decimal, f.return_type
461
719
 
462
- f = FunctionResolver.new('cast', [{:type => :character,
463
- :value => "1"},{:type => :character,
464
- :value => 'integer'}])
720
+ f = FunctionResolver.new('cast', [{ type: :character,
721
+ value: '1' }, { type: :character,
722
+ value: 'integer' }])
465
723
 
466
724
  assert_equal :integer, f.return_type
467
725
  end
468
726
 
469
- test "cast() decimal to integer" do
470
- f = FunctionResolver.new('cast', [{:type => :decimal, :value => '1.2'}, {type: :character, :value => 'integer'}])
727
+ test 'cast() decimal to integer' do
728
+ f = FunctionResolver.new('cast',
729
+ [{ type: :decimal, value: '1.2' }, { type: :character, value: 'integer' }])
471
730
  f.validate
472
731
  assert !f.errors?, "Errors #{f.errors.inspect}"
473
732
  value = f.call
@@ -476,8 +735,8 @@ class FunctionResolverTest < Test::Unit::TestCase
476
735
  assert_equal '1', value[:value]
477
736
  end
478
737
 
479
- test "cast() integer to decimal" do
480
- f = FunctionResolver.new('cast', [{:type => :decimal, :value => '1'}, {type: :character, :value => 'decimal'}])
738
+ test 'cast() integer to decimal' do
739
+ f = FunctionResolver.new('cast', [{ type: :decimal, value: '1' }, { type: :character, value: 'decimal' }])
481
740
  f.validate
482
741
  assert !f.errors?, "Errors #{f.errors.inspect}"
483
742
  value = f.call
@@ -486,8 +745,8 @@ class FunctionResolverTest < Test::Unit::TestCase
486
745
  assert_equal '1.0', value[:value]
487
746
  end
488
747
 
489
- test "cast() nil to integer" do
490
- f = FunctionResolver.new('cast', [{:type => :null, :value => 'NULL'}, {type: :character, :value => 'integer'}])
748
+ test 'cast() nil to integer' do
749
+ f = FunctionResolver.new('cast', [{ type: :null, value: 'NULL' }, { type: :character, value: 'integer' }])
491
750
  f.validate
492
751
  assert !f.errors?, "Errors #{f.errors.inspect}"
493
752
  value = f.call
@@ -496,8 +755,8 @@ class FunctionResolverTest < Test::Unit::TestCase
496
755
  assert_equal '0', value[:value]
497
756
  end
498
757
 
499
- test "cast() nil to decimal" do
500
- f = FunctionResolver.new('cast', [{:type => :null, :value => 'NULL'}, {type: :character, :value => 'decimal'}])
758
+ test 'cast() nil to decimal' do
759
+ f = FunctionResolver.new('cast', [{ type: :null, value: 'NULL' }, { type: :character, value: 'decimal' }])
501
760
  f.validate
502
761
  assert !f.errors?, "Errors #{f.errors.inspect}"
503
762
  value = f.call
@@ -506,8 +765,9 @@ class FunctionResolverTest < Test::Unit::TestCase
506
765
  assert_equal '0.0', value[:value]
507
766
  end
508
767
 
509
- test "cast() nil to character" do
510
- f = FunctionResolver.new('cast', [{:type => :null, :value => 'NULL'}, {type: :character, :value => 'character'}])
768
+ test 'cast() nil to character' do
769
+ f = FunctionResolver.new('cast',
770
+ [{ type: :null, value: 'NULL' }, { type: :character, value: 'character' }])
511
771
  f.validate
512
772
  assert !f.errors?, "Errors #{f.errors.inspect}"
513
773
  value = f.call
@@ -516,39 +776,43 @@ class FunctionResolverTest < Test::Unit::TestCase
516
776
  assert_equal "''", value[:value]
517
777
  end
518
778
 
519
- test "cast() character to decimal" do
520
- f = FunctionResolver.new('cast', [{:type => :character, :value => "1.1"}, {type: :character, :value => 'decimal'}])
779
+ test 'cast() character to decimal' do
780
+ f = FunctionResolver.new('cast',
781
+ [{ type: :character, value: '1.1' }, { type: :character, value: 'decimal' }])
521
782
  f.validate
522
783
  assert !f.errors?, "Errors #{f.errors.inspect}"
523
784
  value = f.call
524
785
 
525
786
  assert_equal :decimal, value[:type]
526
- assert_equal "1.1", value[:value]
787
+ assert_equal '1.1', value[:value]
527
788
  end
528
789
 
529
- test "cast() character to integer" do
530
- f = FunctionResolver.new('cast', [{:type => :character, :value => "1"}, {type: :character, :value => 'integer'}])
790
+ test 'cast() character to integer' do
791
+ f = FunctionResolver.new('cast',
792
+ [{ type: :character, value: '1' }, { type: :character, value: 'integer' }])
531
793
  f.validate
532
794
  assert !f.errors?, "Errors #{f.errors.inspect}"
533
795
  value = f.call
534
796
 
535
797
  assert_equal :integer, value[:type]
536
- assert_equal "1", value[:value]
798
+ assert_equal '1', value[:value]
537
799
  end
538
800
 
539
- test "cast() Field" do
540
- f = FunctionResolver.new('cast', [{:type => :field, :value => 'Bedrooms'}, {type: :character, :value => 'character'}])
801
+ test 'cast() Field' do
802
+ f = FunctionResolver.new('cast',
803
+ [{ type: :field, value: 'Bedrooms' }, { type: :character, value: 'character' }])
541
804
  f.validate
542
805
  assert !f.errors?, "Errors #{f.errors.inspect}"
543
806
  value = f.call
544
807
 
545
808
  assert_equal :function, value[:type]
546
809
  assert_equal 'cast', value[:value]
547
- assert_equal ['Bedrooms', 'character'], value[:args].map { |v| v[:value]}
810
+ assert_equal(%w[Bedrooms character], value[:args].map{ |v| v[:value] })
548
811
  end
549
812
 
550
- test "invalid cast returns null" do
551
- f = FunctionResolver.new('cast', [{:type => :character, :value => '1.1.1'}, {type: :character, :value => 'integer'}])
813
+ test 'invalid cast returns null' do
814
+ f = FunctionResolver.new('cast',
815
+ [{ type: :character, value: '1.1.1' }, { type: :character, value: 'integer' }])
552
816
  f.validate
553
817
  assert !f.errors?, "Errors #{f.errors.inspect}"
554
818
  value = f.call
@@ -557,14 +821,14 @@ class FunctionResolverTest < Test::Unit::TestCase
557
821
  assert_equal 'NULL', value[:value]
558
822
  end
559
823
 
560
- test "invalid function" do
824
+ test 'invalid function' do
561
825
  f = FunctionResolver.new('then', [])
562
826
  f.validate
563
827
  assert f.errors?, "'then' is not a function"
564
828
  end
565
829
 
566
- test "time(datetime)" do
567
- f = FunctionResolver.new('time', [{:type => :datetime, :value => EXAMPLE_DATE}])
830
+ test 'time(datetime)' do
831
+ f = FunctionResolver.new('time', [{ type: :datetime, value: EXAMPLE_DATE }])
568
832
  f.validate
569
833
  assert !f.errors?, "Errors #{f.errors.inspect}"
570
834
  value = f.call
@@ -572,8 +836,8 @@ class FunctionResolverTest < Test::Unit::TestCase
572
836
  assert_equal '10:22:15.422804000', value[:value]
573
837
  end
574
838
 
575
- test "date(datetime)" do
576
- f = FunctionResolver.new('date', [{:type => :datetime, :value => EXAMPLE_DATE}])
839
+ test 'date(datetime)' do
840
+ f = FunctionResolver.new('date', [{ type: :datetime, value: EXAMPLE_DATE }])
577
841
  f.validate
578
842
  assert !f.errors?, "Errors #{f.errors.inspect}"
579
843
  value = f.call
@@ -581,39 +845,39 @@ class FunctionResolverTest < Test::Unit::TestCase
581
845
  assert_equal '2013-07-26', value[:value]
582
846
  end
583
847
 
584
- ###
585
- # Delayed functions. These functions don't get run immediately and require
586
- # resolution by the backing system
587
- ###
588
-
589
- test "time(field)" do
590
- f = FunctionResolver.new('time', [{:type => :field, :value => "OriginalEntryTimestamp"}])
848
+ ###
849
+ # Delayed functions. These functions don't get run immediately and require
850
+ # resolution by the backing system
851
+ ###
852
+
853
+ test 'time(field)' do
854
+ f = FunctionResolver.new('time', [{ type: :field, value: 'OriginalEntryTimestamp' }])
591
855
  f.validate
592
856
  assert !f.errors?, "Errors #{f.errors.inspect}"
593
857
  value = f.call
594
858
  assert_equal :function, value[:type]
595
859
  assert_equal 'time', value[:value]
596
- assert_equal "OriginalEntryTimestamp", value[:args].first[:value]
860
+ assert_equal 'OriginalEntryTimestamp', value[:args].first[:value]
597
861
  end
598
-
599
- test "date(field)" do
600
- f = FunctionResolver.new('date', [{:type => :field, :value => "OriginalEntryTimestamp"}])
862
+
863
+ test 'date(field)' do
864
+ f = FunctionResolver.new('date', [{ type: :field, value: 'OriginalEntryTimestamp' }])
601
865
  f.validate
602
866
  assert !f.errors?, "Errors #{f.errors.inspect}"
603
867
  value = f.call
604
868
  assert_equal :function, value[:type]
605
869
  assert_equal 'date', value[:value]
606
- assert_equal "OriginalEntryTimestamp", value[:args].first[:value]
870
+ assert_equal 'OriginalEntryTimestamp', value[:args].first[:value]
607
871
  end
608
872
 
609
- test "startswith(), endswith() and contains()" do
610
- [{'startswith' => "^far"},
611
- {'endswith' => "far$"},
612
- {'contains' => "far"}].each do |test_case|
873
+ test 'startswith(), endswith() and contains()' do
874
+ [{ 'startswith' => '^far' },
875
+ { 'endswith' => 'far$' },
876
+ { 'contains' => 'far' }].each do |test_case|
613
877
  function = test_case.keys.first
614
878
  expected_value = test_case[function]
615
879
 
616
- f = FunctionResolver.new(function, [{:type => :character, :value => "far"}])
880
+ f = FunctionResolver.new(function, [{ type: :character, value: 'far' }])
617
881
  f.validate
618
882
  assert !f.errors?, "Errors #{f.errors.inspect}"
619
883
  value = f.call
@@ -626,8 +890,8 @@ class FunctionResolverTest < Test::Unit::TestCase
626
890
 
627
891
  test 'wkt()' do
628
892
  f = FunctionResolver.new('wkt',
629
- [{:type => :character,
630
- :value => "SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534,-127.89734578345 45.234534534,-127.89734578345 45.234534534))"}])
893
+ [{ type: :character,
894
+ value: 'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534,-127.89734578345 45.234534534,-127.89734578345 45.234534534))' }])
631
895
  f.validate
632
896
  assert !f.errors?, "Errors #{f.errors.inspect}"
633
897
  value = f.call
@@ -636,8 +900,8 @@ class FunctionResolverTest < Test::Unit::TestCase
636
900
 
637
901
  test 'wkt() invalid params' do
638
902
  f = FunctionResolver.new('wkt',
639
- [{:type => :character,
640
- :value => "POLYGON((45.234534534))"}])
903
+ [{ type: :character,
904
+ value: 'POLYGON((45.234534534))' }])
641
905
  f.validate
642
906
  f.call
643
907
  assert f.errors?