DEV: Support posts-min:<count> and posts-max:<count> on /filter (#21090)

This commit adds support for the `posts-min:<count>` and
`posts-max:<count>` filters for the topics filtering query language.
`posts-min:1` will filter for topics with at least a one post while
`posts-max:3` will filter foor topics with a maximum of 3 posts.

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:
Alan Guo Xiang Tan 2023-04-14 06:05:55 +08:00 committed by GitHub
parent 9b3408223b
commit bc4a9c50f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 94 additions and 0 deletions

View File

@ -40,6 +40,10 @@ class TopicsFilter
filter_created_by_user(usernames: values.flat_map { |value| value.split(",") })
when "in"
filter_in(values: values)
when "posts-min"
filter_by_number_of_posts(min: values.last)
when "posts-max"
filter_by_number_of_posts(max: values.last)
when "status"
values.each { |status| @scope = filter_status(status: status) }
when "tags"
@ -77,6 +81,13 @@ class TopicsFilter
private
def filter_by_number_of_posts(min: nil, max: nil)
{ min => ">=", max => "<=" }.each do |value, operator|
next if !value || value !~ /^\d+$/
@scope = @scope.where("topics.posts_count #{operator} ?", value)
end
end
def filter_categories(values:)
exclude_subcategories_category_slugs = []
include_subcategories_category_slugs = []

View File

@ -846,5 +846,88 @@ RSpec.describe TopicsFilter do
end
end
end
describe "when filtering by number of posts in a topic" do
fab!(:topic_with_1_post) { Fabricate(:topic, posts_count: 1) }
fab!(:topic_with_2_posts) { Fabricate(:topic, posts_count: 2) }
fab!(:topic_with_3_posts) { Fabricate(:topic, posts_count: 3) }
describe "when query string is `posts-min:1`" do
it "should only return topics with at least 1 post" do
expect(
TopicsFilter
.new(guardian: Guardian.new)
.filter_from_query_string("posts-min:1")
.pluck(:id),
).to contain_exactly(topic_with_1_post.id, topic_with_2_posts.id, topic_with_3_posts.id)
end
end
describe "when query string is `posts-min:3`" do
it "should only return topics with at least 3 posts" do
expect(
TopicsFilter
.new(guardian: Guardian.new)
.filter_from_query_string("posts-min:3")
.pluck(:id),
).to contain_exactly(topic_with_3_posts.id)
end
end
describe "when query string is `posts-max:1`" do
it "should only return topics with at most 1 post" do
expect(
TopicsFilter
.new(guardian: Guardian.new)
.filter_from_query_string("posts-max:1")
.pluck(:id),
).to contain_exactly(topic_with_1_post.id)
end
end
describe "when query string is `posts-max:3`" do
it "should only return topics with at most 3 posts" do
expect(
TopicsFilter
.new(guardian: Guardian.new)
.filter_from_query_string("posts-max:3")
.pluck(:id),
).to contain_exactly(topic_with_1_post.id, topic_with_2_posts.id, topic_with_3_posts.id)
end
end
describe "when query string is `posts-min:1 posts-max:2`" do
it "should only return topics with at least a post and at most 2 posts" do
expect(
TopicsFilter
.new(guardian: Guardian.new)
.filter_from_query_string("posts-min:1 posts-max:2")
.pluck(:id),
).to contain_exactly(topic_with_1_post.id, topic_with_2_posts.id)
end
end
describe "when query string is `posts-min:3 posts-min:2 posts-max:1 posts-max:3`" do
it "should only return topics with at least 2 posts and at most 3 posts as it ignores earlier filters which are duplicated" do
expect(
TopicsFilter
.new(guardian: Guardian.new)
.filter_from_query_string("posts-min:3 posts-min:2 posts-max:1 posts-max:3")
.pluck(:id),
).to contain_exactly(topic_with_2_posts.id, topic_with_3_posts.id)
end
end
describe "when query string is `posts-min:invalid posts-max:invalid`" do
it "should ignore the filters with invalid values" do
expect(
TopicsFilter
.new(guardian: Guardian.new)
.filter_from_query_string("posts-min:invalid posts-max:invalid")
.pluck(:id),
).to contain_exactly(topic_with_1_post.id, topic_with_2_posts.id, topic_with_3_posts.id)
end
end
end
end
end