sparkql 1.2.2 → 1.2.7
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 +5 -13
- data/CHANGELOG.md +21 -0
- data/GRAMMAR.md +5 -4
- data/Gemfile +1 -2
- data/VERSION +1 -1
- data/lib/sparkql/function_resolver.rb +768 -676
- data/lib/sparkql/parser.rb +198 -178
- data/lib/sparkql/parser.y +4 -2
- data/lib/sparkql/parser_compatibility.rb +36 -17
- data/lib/sparkql/parser_tools.rb +67 -23
- data/sparkql.gemspec +19 -17
- data/test/unit/function_resolver_test.rb +455 -191
- data/test/unit/parser_compatability_test.rb +15 -0
- data/test/unit/parser_test.rb +148 -13
- metadata +34 -35
- data/.ruby-version +0 -1
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(
|
|
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]
|
|
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
|
-
|
|
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
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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]
|
data/lib/sparkql/parser_tools.rb
CHANGED
|
@@ -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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
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 =
|
|
7
|
+
s.name = 'sparkql'
|
|
7
8
|
s.version = Sparkql::VERSION
|
|
8
|
-
s.authors = [
|
|
9
|
-
s.email = [
|
|
10
|
-
s.homepage =
|
|
11
|
-
s.summary =
|
|
12
|
-
s.description =
|
|
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 = [
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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([
|
|
16
|
+
assert_equal(['35.12 -68.33', 1.0], value[:function_parameters])
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
test
|
|
18
|
-
f = FunctionResolver.new('round', [{:
|
|
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
|
|
27
|
-
f = FunctionResolver.new('round', [{:
|
|
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
|
|
36
|
+
assert_equal 'ListPrice', value[:args].first[:value]
|
|
35
37
|
end
|
|
36
38
|
|
|
37
|
-
test
|
|
39
|
+
test 'substring character one index' do
|
|
38
40
|
f = FunctionResolver.new('substring', [
|
|
39
|
-
|
|
40
|
-
|
|
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
|
|
53
|
+
test 'substring character two indexes' do
|
|
52
54
|
f = FunctionResolver.new('substring', [
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
|
65
|
+
assert_equal 'lf', value[:value]
|
|
64
66
|
end
|
|
65
67
|
|
|
66
|
-
test
|
|
68
|
+
test 'substring character large first index' do
|
|
67
69
|
f = FunctionResolver.new('substring', [
|
|
68
|
-
|
|
69
|
-
|
|
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
|
|
82
|
+
test 'substring field one index' do
|
|
81
83
|
f = FunctionResolver.new('substring', [
|
|
82
|
-
|
|
83
|
-
|
|
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
|
|
94
|
+
assert_equal 'ListPrice', value[:args].first[:value]
|
|
93
95
|
assert_equal 2, value[:args].size
|
|
94
96
|
end
|
|
95
97
|
|
|
96
|
-
test
|
|
98
|
+
test 'substring field two indexes' do
|
|
97
99
|
f = FunctionResolver.new('substring', [
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
|
111
|
+
assert_equal 'ListPrice', value[:args].first[:value]
|
|
110
112
|
assert_equal 2, value[:args].last[:value]
|
|
111
113
|
end
|
|
112
114
|
|
|
113
|
-
test
|
|
115
|
+
test 'substring with negative M is a parse error' do
|
|
114
116
|
f = FunctionResolver.new('substring', [
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
|
127
|
+
test 'character substring with negative M is a parse error' do
|
|
126
128
|
f = FunctionResolver.new('substring', [
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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', [{:
|
|
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
|
|
174
|
-
f = FunctionResolver.new('toupper', [{:
|
|
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
|
|
182
|
+
assert_equal 'City', value[:args].first[:value]
|
|
181
183
|
end
|
|
182
184
|
|
|
183
185
|
test "toupper('string')" do
|
|
184
|
-
f = FunctionResolver.new('toupper', [{:
|
|
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
|
|
193
|
-
f = FunctionResolver.new('length', [{:
|
|
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
|
|
201
|
+
assert_equal 'City', value[:args].first[:value]
|
|
200
202
|
end
|
|
201
203
|
|
|
202
204
|
test "length('string')" do
|
|
203
|
-
f = FunctionResolver.new('length', [{:
|
|
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
|
|
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 (
|
|
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
|
|
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
|
|
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
|
|
243
|
-
f = FunctionResolver.new('floor', [{:
|
|
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
|
|
252
|
-
f = FunctionResolver.new('floor', [{:
|
|
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
|
|
262
|
+
assert_equal 'ListPrice', value[:args].first[:value]
|
|
260
263
|
end
|
|
261
264
|
|
|
262
|
-
test
|
|
263
|
-
f = FunctionResolver.new('ceiling', [{:
|
|
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
|
|
272
|
-
f = FunctionResolver.new('ceiling', [{:
|
|
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
|
|
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
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
f
|
|
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
|
-
|
|
293
|
-
|
|
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
|
|
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', [{:
|
|
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
|
|
547
|
+
assert_equal '2014-04-06', value[:value]
|
|
307
548
|
end
|
|
308
|
-
|
|
309
|
-
test
|
|
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', [{:
|
|
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],
|
|
558
|
+
assert_equal '2010-01-06', value[:value], 'negative values should go back in time'
|
|
318
559
|
end
|
|
319
560
|
|
|
320
|
-
test
|
|
321
|
-
[
|
|
322
|
-
f = FunctionResolver.new(function, [{:
|
|
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
|
|
569
|
+
assert_equal 'OriginalEntryTimestamp', value[:args].first[:value]
|
|
329
570
|
end
|
|
330
571
|
end
|
|
331
572
|
|
|
332
|
-
test
|
|
333
|
-
[
|
|
334
|
-
f = FunctionResolver.new(function, [{:
|
|
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
|
|
581
|
+
assert_equal 'OriginalEntryTimestamp', value[:args].first[:value]
|
|
341
582
|
end
|
|
342
583
|
end
|
|
343
584
|
|
|
344
|
-
test
|
|
345
|
-
|
|
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
|
|
604
|
+
assert_equal 'OriginalEntryTimestamp', value[:args].first[:value]
|
|
352
605
|
end
|
|
353
606
|
|
|
354
607
|
# Polygon searches
|
|
355
|
-
|
|
356
|
-
test
|
|
357
|
-
f = FunctionResolver.new('radius',
|
|
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
|
|
368
|
-
f = FunctionResolver.new('radius', [{:
|
|
369
|
-
|
|
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
|
|
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
|
|
380
|
-
f = FunctionResolver.new('radius', [{:
|
|
381
|
-
|
|
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
|
|
388
|
-
f = FunctionResolver.new('polygon',
|
|
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]],
|
|
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
|
|
398
|
-
f = FunctionResolver.new('linestring', [{:
|
|
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
|
|
408
|
-
f = FunctionResolver.new('rectangle', [{:
|
|
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]],
|
|
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
|
|
418
|
-
f = FunctionResolver.new('range', [{:
|
|
419
|
-
|
|
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 [
|
|
682
|
+
assert_equal %w[M01 M05], value[:value]
|
|
425
683
|
end
|
|
426
|
-
|
|
427
|
-
test
|
|
428
|
-
f = FunctionResolver.new('now', [{:
|
|
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', [{:
|
|
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
|
|
442
|
-
f = FunctionResolver.new('radius', [{:
|
|
443
|
-
|
|
444
|
-
|
|
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
|
|
449
|
-
f = FunctionResolver.new('radius', [{:
|
|
450
|
-
|
|
451
|
-
|
|
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', [{:
|
|
457
|
-
|
|
458
|
-
|
|
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', [{:
|
|
463
|
-
|
|
464
|
-
|
|
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
|
|
470
|
-
f = FunctionResolver.new('cast',
|
|
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
|
|
480
|
-
f = FunctionResolver.new('cast', [{:
|
|
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
|
|
490
|
-
f = FunctionResolver.new('cast', [{:
|
|
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
|
|
500
|
-
f = FunctionResolver.new('cast', [{:
|
|
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
|
|
510
|
-
f = FunctionResolver.new('cast',
|
|
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
|
|
520
|
-
f = FunctionResolver.new('cast',
|
|
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
|
|
787
|
+
assert_equal '1.1', value[:value]
|
|
527
788
|
end
|
|
528
789
|
|
|
529
|
-
test
|
|
530
|
-
f = FunctionResolver.new('cast',
|
|
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
|
|
798
|
+
assert_equal '1', value[:value]
|
|
537
799
|
end
|
|
538
800
|
|
|
539
|
-
test
|
|
540
|
-
f = FunctionResolver.new('cast',
|
|
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
|
|
810
|
+
assert_equal(%w[Bedrooms character], value[:args].map{ |v| v[:value] })
|
|
548
811
|
end
|
|
549
812
|
|
|
550
|
-
test
|
|
551
|
-
f = FunctionResolver.new('cast',
|
|
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
|
|
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
|
|
567
|
-
f = FunctionResolver.new('time', [{:
|
|
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
|
|
576
|
-
f = FunctionResolver.new('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
|
|
590
|
-
f = FunctionResolver.new('time', [{:
|
|
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
|
|
860
|
+
assert_equal 'OriginalEntryTimestamp', value[:args].first[:value]
|
|
597
861
|
end
|
|
598
|
-
|
|
599
|
-
test
|
|
600
|
-
f = FunctionResolver.new('date', [{:
|
|
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
|
|
870
|
+
assert_equal 'OriginalEntryTimestamp', value[:args].first[:value]
|
|
607
871
|
end
|
|
608
872
|
|
|
609
|
-
test
|
|
610
|
-
[{'startswith' =>
|
|
611
|
-
{'endswith' =>
|
|
612
|
-
{'contains' =>
|
|
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, [{:
|
|
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
|
-
[{:
|
|
630
|
-
|
|
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
|
-
[{:
|
|
640
|
-
|
|
903
|
+
[{ type: :character,
|
|
904
|
+
value: 'POLYGON((45.234534534))' }])
|
|
641
905
|
f.validate
|
|
642
906
|
f.call
|
|
643
907
|
assert f.errors?
|