From 798e2b636925540b7ef020680f406dbd93868c5b Mon Sep 17 00:00:00 2001
From: LeonidMorozov <lmmoby98@yandex.ru>
Date: Thu, 15 Sep 2016 02:10:22 +0300
Subject: [PATCH 1/2] no inner join on simple queries

---
 lib/pg_search/scope_options.rb | 71 ++++++++++++++++++++++++++++++----
 1 file changed, 63 insertions(+), 8 deletions(-)

diff --git a/lib/pg_search/scope_options.rb b/lib/pg_search/scope_options.rb
index 5ce948c7..6e6ccf2f 100644
--- a/lib/pg_search/scope_options.rb
+++ b/lib/pg_search/scope_options.rb
@@ -14,14 +14,11 @@ def initialize(config)
 
     def apply(scope)
       scope = include_table_aliasing_for_rank(scope)
-      rank_table_alias = scope.pg_search_rank_table_alias(:include_counter)
-
-      scope
-        .joins(rank_join(rank_table_alias))
-        .order("#{rank_table_alias}.rank DESC, #{order_within_rank}")
-        .extend(DisableEagerLoading)
-        .extend(WithPgSearchRank)
-        .extend(WithPgSearchHighlight[feature_for(:tsearch)])
+      if config.associations.any?
+        apply_with_inner_join(scope)
+      else
+        apply_without_inner_join(scope)
+      end
     end
 
     # workaround for https://github.com/Casecommons/pg_search/issues/14
@@ -65,6 +62,32 @@ def with_pg_search_rank
       end
     end
 
+    module WithPgSearchRankNoInnerJoin
+      def self.[](rank_field)
+        Module.new do
+          include WithPgSearchRankNoInnerJoin
+          define_method(:rank_field) { rank_field }
+        end
+      end
+
+      def rank_field
+        raise TypeError.new("You need to instantiate this module with []")
+      end
+
+      def with_pg_search_rank
+        scope = self
+        scope = scope.select("#{table_name}.*") unless scope.select_values.any?
+        scope.select(rank_field)
+      end
+    end
+
+    module WithNoInnerJoin
+      def with_no_inner_join
+        scope = self
+        scope.select("#{table_name}.*") unless scope.select_values.any?
+      end
+    end
+
     module PgSearchRankTableAliasing
       def pg_search_rank_table_alias(include_counter = false)
         components = [arel_table.name]
@@ -94,6 +117,26 @@ def pg_search_scope_application_count_plus_plus
 
     delegate :connection, :quoted_table_name, :to => :model
 
+    def apply_with_inner_join(scope)
+      rank_table_alias = scope.pg_search_rank_table_alias(:include_counter)
+
+      scope
+        .joins(rank_join(rank_table_alias))
+        .order("#{rank_table_alias}.rank DESC, #{order_within_rank}")
+        .extend(DisableEagerLoading)
+        .extend(WithPgSearchRank)
+        .extend(WithPgSearchHighlight[feature_for(:tsearch)])
+    end
+
+    def apply_without_inner_join(scope)
+      scope
+        .where(conditions)
+        .order("#{rank_order}, #{order_within_rank}")
+        .extend(DisableEagerLoading)
+        .extend(WithPgSearchRankNoInnerJoin[rank_field])
+        .extend(WithPgSearchHighlight[feature_for(:tsearch)])
+    end
+
     def subquery
       model
         .unscoped
@@ -125,6 +168,10 @@ def order_within_rank
       config.order_within_rank || "#{primary_key} ASC"
     end
 
+    def has_associations?
+      config.associations.any?
+    end
+
     def primary_key
       "#{quoted_table_name}.#{connection.quote_column_name(model.primary_key)}"
     end
@@ -170,6 +217,14 @@ def rank_join(rank_table_alias)
       "INNER JOIN (#{subquery.to_sql}) AS #{rank_table_alias} ON #{primary_key} = #{rank_table_alias}.pg_search_id"
     end
 
+    def rank_field
+      "#{rank} AS pg_search_rank"
+    end
+
+    def rank_order
+      "#{rank} DESC"
+    end
+
     def include_table_aliasing_for_rank(scope)
       if scope.included_modules.include?(PgSearchRankTableAliasing)
         scope

From 466c5091a2591c42fa8575b9ad40fa0e941cd5b6 Mon Sep 17 00:00:00 2001
From: Leonid Morozov <lmmobi98@gmail.com>
Date: Fri, 7 Oct 2016 20:10:03 +0300
Subject: [PATCH 2/2] No extra inner join for rank (#2)

* Fix the spec `where rank > 0.7` by different logic
---
 lib/pg_search/scope_options.rb     | 29 ++++++++++++++---------------
 spec/integration/pg_search_spec.rb |  2 +-
 2 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/lib/pg_search/scope_options.rb b/lib/pg_search/scope_options.rb
index 6e6ccf2f..ad8fe3c8 100644
--- a/lib/pg_search/scope_options.rb
+++ b/lib/pg_search/scope_options.rb
@@ -60,17 +60,26 @@ def with_pg_search_rank
         scope = scope.select("#{table_name}.*") unless scope.select_values.any?
         scope.select("#{pg_search_rank_table_alias}.rank AS pg_search_rank")
       end
+
+      def where_pg_search_rank(value)
+        scope = self
+        scope.where("#{PgSearch::Configuration.alias(table_name)}.rank#{value}")
+      end
     end
 
     module WithPgSearchRankNoInnerJoin
-      def self.[](rank_field)
+      def self.[](rank_value)
         Module.new do
           include WithPgSearchRankNoInnerJoin
-          define_method(:rank_field) { rank_field }
+          define_method(:rank_value) { rank_value }
         end
       end
 
       def rank_field
+        "#{rank_value} AS pg_search_rank"
+      end
+
+      def rank_value
         raise TypeError.new("You need to instantiate this module with []")
       end
 
@@ -79,12 +88,10 @@ def with_pg_search_rank
         scope = scope.select("#{table_name}.*") unless scope.select_values.any?
         scope.select(rank_field)
       end
-    end
 
-    module WithNoInnerJoin
-      def with_no_inner_join
+      def where_pg_search_rank(value)
         scope = self
-        scope.select("#{table_name}.*") unless scope.select_values.any?
+        scope.where("#{rank_value}#{value}")
       end
     end
 
@@ -133,7 +140,7 @@ def apply_without_inner_join(scope)
         .where(conditions)
         .order("#{rank_order}, #{order_within_rank}")
         .extend(DisableEagerLoading)
-        .extend(WithPgSearchRankNoInnerJoin[rank_field])
+        .extend(WithPgSearchRankNoInnerJoin[rank])
         .extend(WithPgSearchHighlight[feature_for(:tsearch)])
     end
 
@@ -168,10 +175,6 @@ def order_within_rank
       config.order_within_rank || "#{primary_key} ASC"
     end
 
-    def has_associations?
-      config.associations.any?
-    end
-
     def primary_key
       "#{quoted_table_name}.#{connection.quote_column_name(model.primary_key)}"
     end
@@ -217,10 +220,6 @@ def rank_join(rank_table_alias)
       "INNER JOIN (#{subquery.to_sql}) AS #{rank_table_alias} ON #{primary_key} = #{rank_table_alias}.pg_search_id"
     end
 
-    def rank_field
-      "#{rank} AS pg_search_rank"
-    end
-
     def rank_order
       "#{rank} DESC"
     end
diff --git a/spec/integration/pg_search_spec.rb b/spec/integration/pg_search_spec.rb
index 872babb8..ccec83e3 100644
--- a/spec/integration/pg_search_spec.rb
+++ b/spec/integration/pg_search_spec.rb
@@ -344,7 +344,7 @@
         twice = ModelWithPgSearch.create!(:content => 'foo foo')
 
         records = ModelWithPgSearch.search_content('foo')
-                  .where("#{PgSearch::Configuration.alias(ModelWithPgSearch.table_name)}.rank > 0.07")
+                      .where_pg_search_rank(' > 0.07')
 
         expect(records).to eq [twice]
       end