FEATURE: add advanced order to search (#10385)

Similar to `advanced_filter` I introduced `advanced_order`.

I needed a new option because default orders are evaluated after advanced_filter so I couldn't use it.

Also, that part is a little bit more generic
```
elsif word =~ /order:\w+/
  @order = word.gsub('order:', '').to_sym
nil
```

After those changes, I can use them in plugins in this way:
```
Search.advanced_order(:votes) do |posts|
  posts.reorder("COALESCE((SELECT dvvc.counter FROM discourse_voting_vote_counters dvvc WHERE dvvc.topic_id = subquery.topic_id), 0) DESC")
end
```
This commit is contained in:
Krzysztof Kotlarek 2020-08-07 12:47:00 +10:00 committed by GitHub
parent ab2b6f8dea
commit 12a00d6dc5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 9 deletions

View File

@ -190,6 +190,22 @@ class Plugin::Instance
DiscoursePluginRegistry.register_editable_group_custom_field(field, self)
end
# Allows to define custom search order. Example usage:
# Search.advanced_order(:chars) do |posts|
# posts.reorder("(SELECT LENGTH(raw) FROM posts WHERE posts.topic_id = subquery.topic_id) DESC")
# end
def register_search_advanced_order(trigger, &block)
Search.advanced_order(trigger, &block)
end
# Allows to define custom search filters. Example usage:
# Search.advanced_filter(/^min_chars:(\d+)$/) do |posts, match|
# posts.where("(SELECT LENGTH(p2.raw) FROM posts p2 WHERE p2.id = posts.id) >= ?", match.to_i)
# end
def register_search_advanced_filter(trigger, &block)
Search.advanced_filter(trigger, &block)
end
# Request a new size for topic thumbnails
# Will respect plugin enabled setting is enabled
# Size should be an array with two elements [max_width, max_height]

View File

@ -277,6 +277,14 @@ class Search
@results
end
def self.advanced_order(trigger, &block)
(@advanced_orders ||= {})[trigger] = block
end
def self.advanced_orders
@advanced_orders
end
def self.advanced_filter(trigger, &block)
(@advanced_filters ||= {})[trigger] = block
end
@ -659,11 +667,11 @@ class Search
end
end
if word == 'order:latest' || word == 'l'
if word == 'l'
@order = :latest
nil
elsif word == 'order:latest_topic'
@order = :latest_topic
elsif word =~ /order:\w+/
@order = word.gsub('order:', '').to_sym
nil
elsif word == 'in:title' || word == 't'
@in_title = true
@ -677,12 +685,6 @@ class Search
end
end
nil
elsif word == 'order:views'
@order = :views
nil
elsif word == 'order:likes'
@order = :likes
nil
elsif word == 'in:all'
@search_all_topics = true
nil
@ -1011,6 +1013,11 @@ class Search
posts = aggregate_relation.from(posts)
end
if @order
advanced_order = Search.advanced_orders&.fetch(@order, nil)
posts = advanced_order.call(posts) if advanced_order
end
posts = posts.offset(offset)
posts.limit(limit)
end

View File

@ -1690,4 +1690,24 @@ describe Search do
end
end
context 'plugin extensions' do
let!(:post0) { Fabricate(:post, raw: 'this is the first post about advanced filter with length more than 50 chars') }
let!(:post1) { Fabricate(:post, raw: 'this is the second post about advanced filter') }
it 'allows to define custom filter' do
expect(Search.new("advanced").execute.posts).to eq([post1, post0])
Search.advanced_filter(/^min_chars:(\d+)$/) do |posts, match|
posts.where("(SELECT LENGTH(p2.raw) FROM posts p2 WHERE p2.id = posts.id) >= ?", match.to_i)
end
expect(Search.new("advanced min_chars:50").execute.posts).to eq([post0])
end
it 'allows to define custom order' do
expect(Search.new("advanced").execute.posts).to eq([post1, post0])
Search.advanced_order(:chars) do |posts|
posts.reorder("(SELECT LENGTH(raw) FROM posts WHERE posts.topic_id = subquery.topic_id) DESC")
end
expect(Search.new("advanced order:chars").execute.posts).to eq([post0, post1])
end
end
end