Skip to content
Open
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
1 change: 1 addition & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ Elegant/GoodMethodName:
- search_commits
- search_issues
- sort_by
- sorted_values
- timeout_unaware
- total_commits
- total_commits_pushed
Expand Down
24 changes: 21 additions & 3 deletions lib/fbe/iterate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,9 @@ def sort_by(prop)
raise(Fbe::Error, 'Cannot set sort field to nil') if prop.nil?
raise(Fbe::Error, 'Sort field must be a String') unless prop.is_a?(String)
raise(Fbe::Error, 'Sort field cannot be empty') if prop.empty?
unless prop.match?(/\A[_a-z][a-zA-Z0-9_]*\z/)
raise(Fbe::Error, "Wrong sort field format '#{prop}', use [_a-z][a-zA-Z0-9_]*")
end
@sorting = prop
end

Expand Down Expand Up @@ -316,9 +319,7 @@ def over # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metric
end
nxt =
if @sorting
values[repo] ||= @fb.query(@query).each(
@fb, before: before[repo], repository: repo
).filter_map { _1[@sorting]&.first }.uniq.sort!.each
values[repo] ||= sorted_values(repo, before[repo])
begin
values[repo].next
rescue StopIteration
Expand Down Expand Up @@ -379,4 +380,21 @@ def over # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metric
end
end
end

private

# Fetches and sorts the values of the +sort_by+ field for one repository.
#
# @param [Integer] repo The repository ID
# @param [Object] since The +$before+ value to run the query with
# @return [Enumerator] The sorted values, ready for +.next+
# @raise [Fbe::Error] If matched facts exist but none of them carry the sort field
def sorted_values(repo, since)
raw = @fb.query(@query).each(@fb, before: since, repository: repo).to_a
sorted = raw.filter_map { _1[@sorting]&.first }.uniq
if sorted.empty? && !raw.empty?
raise(Fbe::Error, "None of the #{raw.size} matched facts in ##{repo} carry the '#{@sorting}' property")
end
sorted.sort!.each
end
end
36 changes: 36 additions & 0 deletions test/fbe/test_iterate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,42 @@ def test_sort_by_configuration # rubocop:disable Metrics/AbcSize
assert_equal(25, fb.query('(eq what "iterate")').each.to_a.first.marker)
end

def test_sort_by_rejects_a_bad_format
ex =
assert_raises(Fbe::Error) do
Fbe.iterate(
fb: Fbe.fb(fb: Factbase.new, global: {}, options: Judges::Options.new, loog: Loog::NULL),
loog: Loog::NULL, options: Judges::Options.new, global: {}, epoch: Time.now, kickoff: Time.now
) do
sort_by('9number')
end
end
assert_match(/Wrong sort field format/, ex.message)
end

def test_sort_by_reports_a_misspelled_field_instead_of_looking_exhausted
opts = Judges::Options.new(['repositories=foo/bar', 'testing=true'])
global = {}
fb = Fbe.fb(fb: Factbase.new, global:, options: opts, loog: Loog::NULL)
fb.insert.then do |f|
f.where = 'github'
f.what = 'judge'
f.repository = 3_861_188_962
f.number = 1
end
ex =
assert_raises(Fbe::Error) do
Fbe.iterate(fb:, loog: Loog::NULL, options: opts, global:, epoch: Time.now, kickoff: Time.now) do
as('marker')
sort_by('numero')
by("(and (eq repository $repository) (eq where 'github') (eq what 'judge'))")
repeats(1)
over { |_repository, n| n }
end
end
assert_match(/carry the 'numero' property/, ex.message)
end

def test_custom_since
opts = Judges::Options.new(['repositories=foo/bar', 'testing=true'])
fb = Fbe.fb(fb: Factbase.new, global: {}, options: opts, loog: Loog::NULL)
Expand Down
Loading