From 5c31216aea5f872cd749ee6f59586435fa9d859c Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 8 Jul 2020 15:29:02 +0800 Subject: [PATCH] FIX: Search for whole URLs wasn't working. --- lib/search.rb | 25 +++++-------------------- spec/components/search_spec.rb | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/search.rb b/lib/search.rb index d17b35a008f..36ade32e8f0 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 09769c38ba2..06e5638759a 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