diff --git a/lib/search.rb b/lib/search.rb index 0a07dcf9f79..2dd6b100392 100644 --- a/lib/search.rb +++ b/lib/search.rb @@ -385,6 +385,10 @@ class Search posts = posts.where("posts.raw || ' ' || u.username || ' ' || u.name ilike ?", "%#{@term}%") else posts = posts.where("post_search_data.search_data @@ #{ts_query}") + exact_terms = @term.scan(/"([^"]+)"/).flatten + exact_terms.each do |exact| + posts = posts.where("posts.raw ilike ?", "%#{exact}%") + end end end @@ -457,20 +461,22 @@ class Search end def self.ts_query(term, locale = nil, joiner = "&") + + + data = Post.exec_sql("SELECT to_tsvector(:locale, :term)", + locale: locale || long_locale, + term: term + ).values[0][0] + locale = Post.sanitize(locale) if locale - all_terms = term.gsub(/[\p{P}\p{S}]+/, ' ').squish.split + all_terms = data.scan(/'([^']+)'\:\d+/).flatten query = Post.sanitize(all_terms.map {|t| "#{PG::Connection.escape_string(t)}:*"}.join(" #{joiner} ")) "TO_TSQUERY(#{locale || query_locale}, #{query})" end def ts_query(locale=nil) - if !locale - @ts_query ||= begin - Search.ts_query(@term, locale) - end - else - Search.ts_query(@term, locale) - end + @ts_query_cache ||= {} + @ts_query_cache[(locale || query_locale) + " " + @term] ||= Search.ts_query(@term, locale) end def aggregate_search(opts = {}) diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb index 1ded92fbc77..f2b15a86d40 100644 --- a/spec/components/search_spec.rb +++ b/spec/components/search_spec.rb @@ -389,6 +389,14 @@ describe Search do end + it 'can search numbers correctly, and match exact phrases' do + topic = Fabricate(:topic, created_at: 3.months.ago) + Fabricate(:post, raw: '3.0 eta is in 2 days horrah', topic: topic) + + expect(Search.execute('3.0 eta').posts.length).to eq(1) + expect(Search.execute('"3.0, eta is"').posts.length).to eq(0) + end + it 'can find by status' do post = Fabricate(:post, raw: 'hi this is a test 123 123') topic = post.topic