Add is:, has:, domain:, lang: search filters
This commit is contained in:
		
							parent
							
								
									26d465175a
								
							
						
					
					
						commit
						bf34294fcb
					
				
					 5 changed files with 52 additions and 5 deletions
				
			
		|  | @ -67,6 +67,10 @@ class StatusesIndex < Chewy::Index | ||||||
|     field :account_id, type: 'long' |     field :account_id, type: 'long' | ||||||
|     field :created_at, type: 'date' |     field :created_at, type: 'date' | ||||||
|     field :visibility, type: 'keyword' |     field :visibility, type: 'keyword' | ||||||
|  |     field :domain, type: 'keyword', value: ->(status) { status.account.domain or Rails.configuration.x.local_domain } | ||||||
|  |     field :lang, type: 'keyword', value: ->(status) { status.language } | ||||||
|  |     field :is, type: 'keyword', value: ->(status) { status.searchable_is } | ||||||
|  |     field :has, type: 'keyword', value: ->(status) { status.searchable_has } | ||||||
| 
 | 
 | ||||||
|     field :text, type: 'text', value: ->(status) { status.searchable_text } do |     field :text, type: 'text', value: ->(status) { status.searchable_text } do | ||||||
|       field :stemmed, type: 'text', analyzer: 'content' |       field :stemmed, type: 'text', analyzer: 'content' | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ class SearchQueryParser < Parslet::Parser | ||||||
|   rule(:prefix)    { (term >> colon).as(:prefix) } |   rule(:prefix)    { (term >> colon).as(:prefix) } | ||||||
|   rule(:shortcode) { (colon >> term >> colon.maybe).as(:shortcode) } |   rule(:shortcode) { (colon >> term >> colon.maybe).as(:shortcode) } | ||||||
|   rule(:phrase)    { (quote >> (term >> space.maybe).repeat >> quote).as(:phrase) } |   rule(:phrase)    { (quote >> (term >> space.maybe).repeat >> quote).as(:phrase) } | ||||||
|   rule(:clause)    { (prefix.maybe >> operator.maybe >> (phrase | term | shortcode)).as(:clause) } |   rule(:clause)    { (operator.maybe >> prefix.maybe >> (phrase | term | shortcode)).as(:clause) } | ||||||
|   rule(:query)     { (clause >> space.maybe).repeat.as(:query) } |   rule(:query)     { (clause >> space.maybe).repeat.as(:query) } | ||||||
|   root(:query) |   root(:query) | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -35,6 +35,8 @@ class SearchQueryTransformer < Parslet::Transform | ||||||
|         { multi_match: { type: 'most_fields', query: clause.term, fields: ['text', 'text.stemmed'] } } |         { multi_match: { type: 'most_fields', query: clause.term, fields: ['text', 'text.stemmed'] } } | ||||||
|       when PhraseClause |       when PhraseClause | ||||||
|         { match_phrase: { text: { query: clause.phrase } } } |         { match_phrase: { text: { query: clause.phrase } } } | ||||||
|  |       when PrefixClause | ||||||
|  |         { term: { clause.filter => clause.term } } | ||||||
|       else |       else | ||||||
|         raise "Unexpected clause type: #{clause}" |         raise "Unexpected clause type: #{clause}" | ||||||
|       end |       end | ||||||
|  | @ -99,10 +101,21 @@ class SearchQueryTransformer < Parslet::Transform | ||||||
|   class PrefixClause |   class PrefixClause | ||||||
|     attr_reader :filter, :operator, :term, :order |     attr_reader :filter, :operator, :term, :order | ||||||
| 
 | 
 | ||||||
|     def initialize(prefix, term) |     def initialize(prefix, operator, term) | ||||||
|       case prefix |       case operator | ||||||
|       when 'from' |       when '+', nil | ||||||
|         @operator = :filter |         @operator = :filter | ||||||
|  |       when '-' | ||||||
|  |         @operator = :must_not | ||||||
|  |       else | ||||||
|  |         raise "Unknown operator: #{str}" | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       case prefix | ||||||
|  |       when 'domain', 'is', 'has', 'lang' | ||||||
|  |         @filter = prefix.to_s | ||||||
|  |         @term = term | ||||||
|  |       when 'from' | ||||||
|         @filter = :account_id |         @filter = :account_id | ||||||
| 
 | 
 | ||||||
|         username, domain = term.gsub(/\A@/, '').split('@') |         username, domain = term.gsub(/\A@/, '').split('@') | ||||||
|  | @ -111,6 +124,8 @@ class SearchQueryTransformer < Parslet::Transform | ||||||
| 
 | 
 | ||||||
|         @term = account.id |         @term = account.id | ||||||
|       when 'sort' |       when 'sort' | ||||||
|  |         raise Mastodon::SyntaxError unless operator.nil? | ||||||
|  | 
 | ||||||
|         @operator = :order |         @operator = :order | ||||||
|         @term = :created_at |         @term = :created_at | ||||||
| 
 | 
 | ||||||
|  | @ -133,7 +148,7 @@ class SearchQueryTransformer < Parslet::Transform | ||||||
|     operator = clause[:operator]&.to_s |     operator = clause[:operator]&.to_s | ||||||
| 
 | 
 | ||||||
|     if clause[:prefix] |     if clause[:prefix] | ||||||
|       PrefixClause.new(prefix, clause[:term].to_s) |       PrefixClause.new(prefix, operator, clause[:term].to_s) | ||||||
|     elsif clause[:term] |     elsif clause[:term] | ||||||
|       TermClause.new(prefix, operator, clause[:term].to_s) |       TermClause.new(prefix, operator, clause[:term].to_s) | ||||||
|     elsif clause[:shortcode] |     elsif clause[:shortcode] | ||||||
|  |  | ||||||
|  | @ -173,6 +173,26 @@ class Status < ApplicationRecord | ||||||
|     ].compact.join("\n\n") |     ].compact.join("\n\n") | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   def searchable_is | ||||||
|  |     keywords = [] | ||||||
|  |     keywords << :bot if account.bot? | ||||||
|  |     keywords << :local if local? | ||||||
|  |     keywords << :local_only if local_only | ||||||
|  |     keywords << :reply if reply? | ||||||
|  |     keywords | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def searchable_has | ||||||
|  |     keywords = [] | ||||||
|  |     keywords << :cw if spoiler_text? | ||||||
|  |     keywords << :link if FetchLinkCardService.new.link?(self) | ||||||
|  |     keywords << :media if media_attachments.present? | ||||||
|  |     keywords << :mention if mentions.present? | ||||||
|  |     keywords << :poll if preloadable_poll.present? | ||||||
|  |     keywords << :tag if tags.present? | ||||||
|  |     keywords | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   def to_log_human_identifier |   def to_log_human_identifier | ||||||
|     account.acct |     account.acct | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -34,6 +34,14 @@ class FetchLinkCardService < BaseService | ||||||
|     nil |     nil | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   ## | ||||||
|  |   # Borrow most of this machinery to detect whether the status has at least one link. | ||||||
|  |   def link?(status) | ||||||
|  |     @status       = status | ||||||
|  |     @original_url = parse_urls | ||||||
|  |     !@original_url.nil? | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   private |   private | ||||||
| 
 | 
 | ||||||
|   def process_url |   def process_url | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue