Don't forget to lycansubscribe

added word/phrase exclusions

Changed files
+39 -9
app
+11
app/models/searchable.rb
··· 24 24 } 25 25 26 26 scope :matching_terms, ->(terms) { 27 + return self if terms.empty? 28 + 27 29 where( 28 30 (["(posts.text ~* ?)"] * (terms.length)).join(" AND "), 31 + *(terms.map { |x| "\\y" + x.gsub(/\s+/, "\\s+") + "\\y" }) 32 + ) 33 + } 34 + 35 + scope :excluding_terms, ->(terms) { 36 + return self if terms.empty? 37 + 38 + where( 39 + (["(posts.text !~* ?)"] * (terms.length)).join(" AND "), 29 40 *(terms.map { |x| "\\y" + x.gsub(/\s+/, "\\s+") + "\\y" }) 30 41 ) 31 42 }
+20 -6
app/query_parser.rb
··· 1 1 class QueryParser 2 - attr_reader :terms 2 + attr_reader :terms, :exclusions 3 3 4 4 def initialize(query) 5 5 @terms = [] 6 - query = query.strip 6 + @exclusions = [] 7 + 8 + query = query.clone 7 9 8 - while match = query.match(/".+?"/) 10 + while match = query.match(/\-?".+?"/) 9 11 range = match.begin(0)...match.end(0) 10 - phrase = query[range][1..-2].gsub(/[\W_]+/, ' ').strip 12 + phrase = query[range] 11 13 query[range] = ' ' 12 - @terms << phrase 14 + 15 + negative = phrase.start_with?('-') 16 + phrase = phrase.gsub(/^\-/, '').gsub(/^"|"$/, '').gsub(/[^\w\-]+/, ' ').strip 17 + 18 + if negative 19 + @exclusions << phrase 20 + else 21 + @terms << phrase 22 + end 13 23 end 14 24 15 - @terms += query.gsub(/[\W_]+/, ' ').strip.split(/ +/) 25 + terms = query.gsub(/[^\w\-]+/, ' ').strip.split(/ +/) 26 + negative, positive = terms.partition { |x| x.start_with?('-') } 27 + 28 + @terms += positive 29 + @exclusions += negative.map { |x| x[1..-1] }.reject(&:empty?) 16 30 end 17 31 end
+8 -3
app/server.rb
··· 55 55 return json_error('MissingParameter', 'Missing "collection" parameter') 56 56 end 57 57 58 - terms = QueryParser.new(params[:query]).terms 58 + query = QueryParser.new(params[:query]) 59 59 60 60 collection = case params[:collection] 61 61 when 'likes' then user.likes ··· 63 63 when 'quotes' then user.quotes 64 64 when 'reposts' then user.reposts 65 65 else return json_error('InvalidParameter', 'Invalid search collection') 66 + end 67 + 68 + if query.terms.empty? 69 + return json_response(terms: [], posts: [], cursor: nil) 66 70 end 67 71 68 72 items = collection 69 73 .joins(:post) 70 74 .includes(:post => :user) 71 - .matching_terms(terms) 75 + .matching_terms(query.terms) 76 + .excluding_terms(query.exclusions) 72 77 .reverse_chronologically 73 78 .after_cursor(params[:cursor]) 74 79 .limit(PAGE_LIMIT) ··· 80 85 items.map(&:post).map(&:at_uri) 81 86 end 82 87 83 - json_response(terms: terms, posts: post_uris, cursor: items.last&.cursor) 88 + json_response(terms: query.terms, posts: post_uris, cursor: items.last&.cursor) 84 89 end 85 90 86 91 get '/.well-known/did.json' do