Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
v1.3.4, 20265-01-20
* [BUGFIX] Validate limit for days and weekdays

v1.3.3, 2025-08-12
-------------------
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.3.3
1.3.4
29 changes: 24 additions & 5 deletions lib/sparkql/function_resolver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class FunctionResolver
VALID_REGEX_FLAGS = ['', 'i'].freeze
MIN_DATE_TIME = Time.new(1970, 1, 1, 0, 0, 0, '+00:00').iso8601
MAX_DATE_TIME = Time.new(9999, 12, 31, 23, 59, 59, '+00:00').iso8601
MAX_DAYS = (365 * 1000).freeze # 1000 years ought to cover most cases
VALID_CAST_TYPES = %i[field character decimal integer].freeze

SUPPORTED_FUNCTIONS = {
Expand All @@ -43,16 +44,16 @@ class FunctionResolver
regex: {
args: [:character],
opt_args: [{
type: :character,
default: ''
}],
type: :character,
default: ''
}],
return_type: :character
},
substring: {
args: [%i[field character], :integer],
opt_args: [{
type: :integer
}],
type: :integer
}],
resolve_for_type: true,
return_type: :character
},
Expand Down Expand Up @@ -526,6 +527,15 @@ def hours(num)

# Offset the current timestamp by a number of days
def days(number_of_days)
if number_of_days.abs > MAX_DAYS
@errors << Sparkql::ParserError.new(token: number_of_days,
message: "Function call 'days' max offset #{MAX_DAYS} days",
status: :fatal,
syntax: false,
constraint: true)
return
end

# date calculated as the offset from midnight tommorrow. Zero will provide values for all times
# today.
d = current_date + number_of_days
Expand All @@ -536,6 +546,15 @@ def days(number_of_days)
end

def weekdays(number_of_days)
if number_of_days.abs > MAX_DAYS
@errors << Sparkql::ParserError.new(token: number_of_days,
message: "Function call 'weekdays' max offset #{MAX_DAYS} days",
status: :fatal,
syntax: false,
constraint: true)
return
end

today = current_date
weekend_start = today.saturday? || today.sunday?
direction = number_of_days.positive? ? 1 : -1
Expand Down
36 changes: 36 additions & 0 deletions test/unit/function_resolver_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,24 @@ def assert_times(call_value, expected_call_type = :datetime, overrides = {})
end
end

test 'days - exceed max' do
f = FunctionResolver.new('days',
[{ type: :integer, value: 365_001 }],
current_timestamp: EXAMPLE_DATE)
f.validate
assert !f.errors?
assert_nil f.call
assert f.errors?, "function 'days' limit 365000"

f = FunctionResolver.new('days',
[{ type: :integer, value: -365_001 }],
current_timestamp: EXAMPLE_DATE)
f.validate
assert !f.errors?
assert_nil f.call
assert f.errors?, "function 'days' limit 365000"
end

test 'weekdays()' do
friday = Date.new(2012, 10, 19)
saturday = Date.new(2012, 10, 20)
Expand Down Expand Up @@ -514,6 +532,24 @@ def assert_times(call_value, expected_call_type = :datetime, overrides = {})
end
end

test 'weekdays - exceed max' do
f = FunctionResolver.new('weekdays',
[{ type: :integer, value: 365_001 }],
current_timestamp: EXAMPLE_DATE)
f.validate
assert !f.errors?
assert_nil f.call
assert f.errors?, "function 'weekdays' limit 365000"

f = FunctionResolver.new('weekdays',
[{ type: :integer, value: -365_001 }],
current_timestamp: EXAMPLE_DATE)
f.validate
assert !f.errors?
assert_nil f.call
assert f.errors?, "function 'weekdays' limit 365000"
end

test 'months()' do
f = FunctionResolver.new('months',
[{ type: :integer, value: 3 }],
Expand Down