FIX: Search for whole URLs wasn't working.

FIX: Search for whole URLs wasn’t working.

diff --git a/lib/search.rb b/lib/search.rb
index d17b35a..36ade32 100644
--- a/lib/search.rb
+++ b/lib/search.rb
@@ -1005,27 +1005,12 @@ class Search
     self.class.default_ts_config
   end
 
-  def self.ts_query(term: , ts_config:  nil, joiner: "&", weight_filter: nil)
-
-    data = DB.query_single(
-      "SELECT TO_TSVECTOR(:config, :term)",
-      config: 'simple',
-      term: term
-    ).first
-
+  def self.ts_query(term: , ts_config:  nil, joiner: nil, weight_filter: nil)
     ts_config = ActiveRecord::Base.connection.quote(ts_config) if ts_config
-    all_terms = data.scan(/'([^']+)'\:\d+/).flatten
-    all_terms.map! do |t|
-      t.split(/[\)\(&']/).find(&:present?)
-    end.compact!
-
-    query = ActiveRecord::Base.connection.quote(
-      all_terms
-        .map { |t| "'#{PG::Connection.escape_string(t)}':*#{weight_filter}" }
-        .join(" #{joiner} ")
-    )
-
-    "TO_TSQUERY(#{ts_config || default_ts_config}, #{query})"
+    term = term.gsub("'", "''")
+    tsquery = "TO_TSQUERY(#{ts_config || default_ts_config}, '''#{PG::Connection.escape_string(term)}'':*#{weight_filter}')"
+    tsquery = "REPLACE(#{tsquery}::text, '&', '#{PG::Connection.escape_string(joiner)}')::tsquery" if joiner
+    tsquery
   end
 
   def ts_query(ts_config = nil, weight_filter: nil)
diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb
index 09769c3..06e5638 100644
--- a/spec/components/search_spec.rb
+++ b/spec/components/search_spec.rb
@@ -1103,6 +1103,16 @@ describe Search do
       expect(Search.execute('badge:"test"').posts.length).to eq(0)
     end
 
+    it 'can match exact phrases' do
+      post = Fabricate(:post, raw: %{this is a test post with 'a URL https://some.site.com/search?q=test.test.test some random text I have to add})
+      post2 = Fabricate(:post, raw: 'test URL post with')
+
+      expect(Search.execute("test post with 'a URL).posts").posts).to eq([post2, post])
+      expect(Search.execute(%{"test post with 'a URL"}).posts).to eq([post])
+      expect(Search.execute(%{"https://some.site.com/search?q=test.test.test"}).posts).to eq([post])
+      expect(Search.execute(%{" with 'a URL https://some.site.com/search?q=test.test.test"}).posts).to eq([post])
+    end
+
     it 'can search numbers correctly, and match exact phrases' do
       post = Fabricate(:post, raw: '3.0 eta is in 2 days horrah')
       post2 = Fabricate(:post, raw: '3.0 is eta in 2 days horrah')
@@ -1250,10 +1260,15 @@ describe Search do
       expect(Search.execute('bill').posts.map(&:id)).to eq([post.id])
     end
 
-    it 'can tokanize website names correctly' do
+    it 'can search URLS correctly' do
       post = Fabricate(:post, raw: 'i like http://wb.camra.org.uk/latest#test so yay')
       expect(Search.execute('http://wb.camra.org.uk/latest#test').posts.map(&:id)).to eq([post.id])
       expect(Search.execute('camra').posts.map(&:id)).to eq([post.id])
+
+      complex_url = "https://test.some.site.com/path?some.range_input=74235a"
+      post2 = Fabricate(:post, raw: "this is a complex url #{complex_url} so complex")
+
+      expect(Search.execute(complex_url).posts.map(&:id)).to eq([post2.id])
     end
 
     it 'supports category slug and tags' do

GitHub sha: 5c31216a