DEV: Support `posters-(min|max):<count>` on `/filter` route (#21095)
This commit adds support for the `posters-min:<count>` and `posters-max:<count>` filters for the topics filtering query language. `posters-min:1` will filter for topics with at least a one poster while `posters-max:3` will filter for topics with a maximum of 3 posters. If the filter has an invalid value, i.e string that cannot be converted into an integer, the filter will be ignored. If either of each filter is specify multiple times, only the last occurence of each filter will be taken into consideration.
This commit is contained in:
parent
e190c00bc4
commit
782b26d0eb
|
@ -41,9 +41,21 @@ class TopicsFilter
|
|||
when "in"
|
||||
filter_in(values: values)
|
||||
when "posts-min"
|
||||
filter_by_number_of_posts(min: values.last)
|
||||
min = values.last
|
||||
break if !integer_string?(min)
|
||||
filter_by_number_of_posts(min: min)
|
||||
when "posts-max"
|
||||
filter_by_number_of_posts(max: values.last)
|
||||
max = values.last
|
||||
break if !integer_string?(max)
|
||||
filter_by_number_of_posts(max: max)
|
||||
when "posters-min"
|
||||
min = values.last
|
||||
break if !integer_string?(min)
|
||||
filter_by_number_of_posters(min: min)
|
||||
when "posters-max"
|
||||
max = values.last
|
||||
break if !integer_string?(max)
|
||||
filter_by_number_of_posters(max: max)
|
||||
when "status"
|
||||
values.each { |status| @scope = filter_status(status: status) }
|
||||
when "tags"
|
||||
|
@ -81,13 +93,21 @@ class TopicsFilter
|
|||
|
||||
private
|
||||
|
||||
def filter_by_number_of_posts(min: nil, max: nil)
|
||||
def filter_by_topic_range(column_name:, min: nil, max: nil)
|
||||
{ min => ">=", max => "<=" }.each do |value, operator|
|
||||
next if !value || value !~ /^\d+$/
|
||||
@scope = @scope.where("topics.posts_count #{operator} ?", value)
|
||||
next if !value
|
||||
@scope = @scope.where("topics.#{column_name} #{operator} ?", value)
|
||||
end
|
||||
end
|
||||
|
||||
def filter_by_number_of_posts(min: nil, max: nil)
|
||||
filter_by_topic_range(column_name: "posts_count", min:, max:)
|
||||
end
|
||||
|
||||
def filter_by_number_of_posters(min: nil, max: nil)
|
||||
filter_by_topic_range(column_name: "participant_count", min:, max:)
|
||||
end
|
||||
|
||||
def filter_categories(values:)
|
||||
exclude_subcategories_category_slugs = []
|
||||
include_subcategories_category_slugs = []
|
||||
|
@ -332,4 +352,8 @@ class TopicsFilter
|
|||
def include_topics_with_any_tags(tag_ids)
|
||||
@scope = @scope.joins(:topic_tags).where("topic_tags.tag_id IN (?)", tag_ids).distinct(:id)
|
||||
end
|
||||
|
||||
def integer_string?(string)
|
||||
string =~ /\A\d+\z/
|
||||
end
|
||||
end
|
||||
|
|
|
@ -929,5 +929,100 @@ RSpec.describe TopicsFilter do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "when filtering by number of posters in a topic" do
|
||||
fab!(:topic_with_1_participant) { Fabricate(:topic, participant_count: 1) }
|
||||
fab!(:topic_with_2_participants) { Fabricate(:topic, participant_count: 2) }
|
||||
fab!(:topic_with_3_participants) { Fabricate(:topic, participant_count: 3) }
|
||||
|
||||
describe "when query string is `posters-min:1`" do
|
||||
it "should only return topics with at least 1 participant" do
|
||||
expect(
|
||||
TopicsFilter
|
||||
.new(guardian: Guardian.new)
|
||||
.filter_from_query_string("posters-min:1")
|
||||
.pluck(:id),
|
||||
).to contain_exactly(
|
||||
topic_with_1_participant.id,
|
||||
topic_with_2_participants.id,
|
||||
topic_with_3_participants.id,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when query string is `posters-min:3`" do
|
||||
it "should only return topics with at least 3 participants" do
|
||||
expect(
|
||||
TopicsFilter
|
||||
.new(guardian: Guardian.new)
|
||||
.filter_from_query_string("posters-min:3")
|
||||
.pluck(:id),
|
||||
).to contain_exactly(topic_with_3_participants.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when query string is `posters-max:1`" do
|
||||
it "should only return topics with at most 1 participant" do
|
||||
expect(
|
||||
TopicsFilter
|
||||
.new(guardian: Guardian.new)
|
||||
.filter_from_query_string("posters-max:1")
|
||||
.pluck(:id),
|
||||
).to contain_exactly(topic_with_1_participant.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when query string is `posters-max:3`" do
|
||||
it "should only return topics with at most 3 participants" do
|
||||
expect(
|
||||
TopicsFilter
|
||||
.new(guardian: Guardian.new)
|
||||
.filter_from_query_string("posters-max:3")
|
||||
.pluck(:id),
|
||||
).to contain_exactly(
|
||||
topic_with_1_participant.id,
|
||||
topic_with_2_participants.id,
|
||||
topic_with_3_participants.id,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when query string is `posters-min:1 posters-max:2`" do
|
||||
it "should only return topics with at least 1 participant and at most 2 participants" do
|
||||
expect(
|
||||
TopicsFilter
|
||||
.new(guardian: Guardian.new)
|
||||
.filter_from_query_string("posters-min:1 posters-max:2")
|
||||
.pluck(:id),
|
||||
).to contain_exactly(topic_with_1_participant.id, topic_with_2_participants.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when query string is `posters-min:3 posters-min:2 posters-max:1 posters-max:3`" do
|
||||
it "should only return topics with at least 2 participants and at most 3 participants as it ignores earlier filters which are duplicated" do
|
||||
expect(
|
||||
TopicsFilter
|
||||
.new(guardian: Guardian.new)
|
||||
.filter_from_query_string("posters-min:3 posters-min:2 posters-max:1 posters-max:3")
|
||||
.pluck(:id),
|
||||
).to contain_exactly(topic_with_2_participants.id, topic_with_3_participants.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when query string is `posters-min:invalid posters-max:invalid`" do
|
||||
it "should ignore the filters with invalid values" do
|
||||
expect(
|
||||
TopicsFilter
|
||||
.new(guardian: Guardian.new)
|
||||
.filter_from_query_string("posters-min:invalid posters-max:invalid")
|
||||
.pluck(:id),
|
||||
).to contain_exactly(
|
||||
topic_with_1_participant.id,
|
||||
topic_with_2_participants.id,
|
||||
topic_with_3_participants.id,
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue