From c2765cbe30ea92d78a74135f73bc93267f301f20 Mon Sep 17 00:00:00 2001 From: Dat Le Date: Sun, 14 May 2023 13:30:20 +0700 Subject: [PATCH] Add ranking order to set higher priorities over rank --- lib/pg_search/configuration.rb | 6 ++++- lib/pg_search/scope_options.rb | 16 +++++++++--- spec/integration/pg_search_spec.rb | 40 ++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/lib/pg_search/configuration.rb b/lib/pg_search/configuration.rb index 5dd88f4d..07b42bbd 100644 --- a/lib/pg_search/configuration.rb +++ b/lib/pg_search/configuration.rb @@ -75,6 +75,10 @@ def order_within_rank options[:order_within_rank] end + def ranking_order + options[:ranking_order] + end + private attr_reader :options @@ -84,7 +88,7 @@ def default_options end VALID_KEYS = %w[ - against ranked_by ignoring using query associated_against order_within_rank + against ranked_by ignoring using query associated_against order_within_rank ranking_order ].map(&:to_sym) VALID_VALUES = { diff --git a/lib/pg_search/scope_options.rb b/lib/pg_search/scope_options.rb index b03d13d0..9c84d91a 100644 --- a/lib/pg_search/scope_options.rb +++ b/lib/pg_search/scope_options.rb @@ -18,7 +18,7 @@ def apply(scope) scope .joins(rank_join(rank_table_alias)) - .order(Arel.sql("#{rank_table_alias}.rank DESC, #{order_within_rank}")) + .order(order_clause(rank_table_alias)) .extend(WithPgSearchRank) .extend(WithPgSearchHighlight[feature_for(:tsearch)]) end @@ -96,8 +96,18 @@ def conditions .inject { |accumulator, expression| Arel::Nodes::Or.new(accumulator, expression) } end - def order_within_rank - config.order_within_rank || "#{primary_key} ASC" + def order_clause(rank_table_alias) + pre_order = if (cfg = config.ranking_order).is_a?(Hash) + cfg.map { |field, od| "#{field} #{od}" }.join(", ") + else + cfg + end + + rank_order = "#{rank_table_alias}.rank DESC" + + post_order = config.order_within_rank || "#{primary_key} ASC" + + Arel.sql([pre_order, rank_order, post_order].compact.join(", ")) end def primary_key diff --git a/spec/integration/pg_search_spec.rb b/spec/integration/pg_search_spec.rb index 056b267c..04231574 100644 --- a/spec/integration/pg_search_spec.rb +++ b/spec/integration/pg_search_spec.rb @@ -756,6 +756,46 @@ end end + describe "ranking with custom order" do + before do + {"Strip Down" => 1, "Down" => 2, "Down and Out" => 3, "Won't Let You Down" => 2}.each do |name, importance| + ModelWithPgSearch.create! content: name, importance: importance + end + end + + context "with ranking_order importance DESC" do + before do + ModelWithPgSearch.pg_search_scope :search_content_with_ranking_order, + against: :content, + using: :tsearch, + ranking_order: "importance DESC" + end + + it "returns results sorted by importance before rank" do + results = ModelWithPgSearch.search_content_with_ranking_order("down") + + expect(results.map(&:content)).to eq(["Down and Out", "Down", "Won't Let You Down", "Strip Down"]) + expect(results.map(&:importance)).to eq([3, 2, 2, 1]) + end + end + + context "with ranking_order importance DESC, id DESC" do + before do + ModelWithPgSearch.pg_search_scope :search_content_with_ranking_order, + against: :content, + using: :tsearch, + ranking_order: {importance: :desc, id: :desc} + end + + it "returns results sorted by importance before rank" do + results = ModelWithPgSearch.search_content_with_ranking_order("down") + + expect(results.map(&:content)).to eq(["Down and Out", "Won't Let You Down", "Down", "Strip Down"]) + expect(results.map(&:importance)).to eq([3, 2, 2, 1]) + end + end + end + context "when against columns ranked with arrays" do before do ModelWithPgSearch.pg_search_scope :search_weighted_by_array_of_arrays,