Add in:library syntax to search (#26760)
		
	Co-authored-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
		
					parent
					
						
							
								ac3f310f4b
							
						
					
				
			
			
				commit
				
					
						ece1ff77d6
					
				
			
		
					 3 changed files with 98 additions and 60 deletions
				
			
		|  | @ -9,23 +9,90 @@ class SearchQueryTransformer < Parslet::Transform | |||
|     before | ||||
|     after | ||||
|     during | ||||
|     in | ||||
|   ).freeze | ||||
| 
 | ||||
|   class Query | ||||
|     attr_reader :must_not_clauses, :must_clauses, :filter_clauses | ||||
|     def initialize(clauses, options = {}) | ||||
|       raise ArgumentError if options[:current_account].nil? | ||||
| 
 | ||||
|     def initialize(clauses) | ||||
|       grouped = clauses.compact.chunk(&:operator).to_h | ||||
|       @must_not_clauses = grouped.fetch(:must_not, []) | ||||
|       @must_clauses = grouped.fetch(:must, []) | ||||
|       @filter_clauses = grouped.fetch(:filter, []) | ||||
|       @clauses = clauses | ||||
|       @options = options | ||||
| 
 | ||||
|       flags_from_clauses! | ||||
|     end | ||||
| 
 | ||||
|     def apply(search) | ||||
|     def request | ||||
|       search = Chewy::Search::Request.new(*indexes).filter(default_filter) | ||||
| 
 | ||||
|       must_clauses.each { |clause| search = search.query.must(clause.to_query) } | ||||
|       must_not_clauses.each { |clause| search = search.query.must_not(clause.to_query) } | ||||
|       filter_clauses.each { |clause| search = search.filter(**clause.to_query) } | ||||
|       search.query.minimum_should_match(1) | ||||
| 
 | ||||
|       search | ||||
|     end | ||||
| 
 | ||||
|     private | ||||
| 
 | ||||
|     def clauses_by_operator | ||||
|       @clauses_by_operator ||= @clauses.compact.chunk(&:operator).to_h | ||||
|     end | ||||
| 
 | ||||
|     def flags_from_clauses! | ||||
|       @flags = clauses_by_operator.fetch(:flag, []).to_h { |clause| [clause.prefix, clause.term] } | ||||
|     end | ||||
| 
 | ||||
|     def must_clauses | ||||
|       clauses_by_operator.fetch(:must, []) | ||||
|     end | ||||
| 
 | ||||
|     def must_not_clauses | ||||
|       clauses_by_operator.fetch(:must_not, []) | ||||
|     end | ||||
| 
 | ||||
|     def filter_clauses | ||||
|       clauses_by_operator.fetch(:filter, []) | ||||
|     end | ||||
| 
 | ||||
|     def indexes | ||||
|       case @flags['in'] | ||||
|       when 'library' | ||||
|         [StatusesIndex] | ||||
|       else | ||||
|         [PublicStatusesIndex, StatusesIndex] | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     def default_filter | ||||
|       { | ||||
|         bool: { | ||||
|           should: [ | ||||
|             { | ||||
|               term: { | ||||
|                 _index: PublicStatusesIndex.index_name, | ||||
|               }, | ||||
|             }, | ||||
|             { | ||||
|               bool: { | ||||
|                 must: [ | ||||
|                   { | ||||
|                     term: { | ||||
|                       _index: StatusesIndex.index_name, | ||||
|                     }, | ||||
|                   }, | ||||
|                   { | ||||
|                     term: { | ||||
|                       searchable_by: @options[:current_account].id, | ||||
|                     }, | ||||
|                   }, | ||||
|                 ], | ||||
|               }, | ||||
|             }, | ||||
|           ], | ||||
| 
 | ||||
|           minimum_should_match: 1, | ||||
|         }, | ||||
|       } | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -108,6 +175,9 @@ class SearchQueryTransformer < Parslet::Transform | |||
|         @filter = :created_at | ||||
|         @type = :range | ||||
|         @term = { gte: term, lte: term, time_zone: @options[:current_account]&.user_time_zone.presence || 'UTC' } | ||||
|       when 'in' | ||||
|         @operator = :flag | ||||
|         @term = term | ||||
|       else | ||||
|         raise "Unknown prefix: #{prefix}" | ||||
|       end | ||||
|  | @ -176,6 +246,6 @@ class SearchQueryTransformer < Parslet::Transform | |||
|   end | ||||
| 
 | ||||
|   rule(query: sequence(:clauses)) do | ||||
|     Query.new(clauses) | ||||
|     Query.new(clauses, current_account: current_account) | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -14,20 +14,8 @@ class StatusesSearchService < BaseService | |||
|   private | ||||
| 
 | ||||
|   def status_search_results | ||||
|     definition = parsed_query.apply( | ||||
|       Chewy::Search::Request.new(StatusesIndex, PublicStatusesIndex).filter( | ||||
|         bool: { | ||||
|           should: [ | ||||
|             publicly_searchable, | ||||
|             non_publicly_searchable, | ||||
|           ], | ||||
| 
 | ||||
|           minimum_should_match: 1, | ||||
|         } | ||||
|       ) | ||||
|     ) | ||||
| 
 | ||||
|     results             = definition.collapse(field: :id).order(id: { order: :desc }).limit(@limit).offset(@offset).objects.compact | ||||
|     request             = parsed_query.request | ||||
|     results             = request.collapse(field: :id).order(id: { order: :desc }).limit(@limit).offset(@offset).objects.compact | ||||
|     account_ids         = results.map(&:account_id) | ||||
|     account_domains     = results.map(&:account_domain) | ||||
|     preloaded_relations = @account.relations_map(account_ids, account_domains) | ||||
|  | @ -37,27 +25,6 @@ class StatusesSearchService < BaseService | |||
|     [] | ||||
|   end | ||||
| 
 | ||||
|   def publicly_searchable | ||||
|     { | ||||
|       term: { _index: PublicStatusesIndex.index_name }, | ||||
|     } | ||||
|   end | ||||
| 
 | ||||
|   def non_publicly_searchable | ||||
|     { | ||||
|       bool: { | ||||
|         must: [ | ||||
|           { | ||||
|             term: { _index: StatusesIndex.index_name }, | ||||
|           }, | ||||
|           { | ||||
|             term: { searchable_by: @account.id }, | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|     } | ||||
|   end | ||||
| 
 | ||||
|   def parsed_query | ||||
|     SearchQueryTransformer.new.apply(SearchQueryParser.new.parse(@query), current_account: @account) | ||||
|   end | ||||
|  |  | |||
|  | @ -3,17 +3,18 @@ | |||
| require 'rails_helper' | ||||
| 
 | ||||
| describe SearchQueryTransformer do | ||||
|   subject { described_class.new.apply(parser, current_account: nil) } | ||||
|   subject { described_class.new.apply(parser, current_account: account) } | ||||
| 
 | ||||
|   let(:account) { Fabricate(:account) } | ||||
|   let(:parser) { SearchQueryParser.new.parse(query) } | ||||
| 
 | ||||
|   context 'with "hello world"' do | ||||
|     let(:query) { 'hello world' } | ||||
| 
 | ||||
|     it 'transforms clauses' do | ||||
|       expect(subject.must_clauses.map(&:term)).to match_array %w(hello world) | ||||
|       expect(subject.must_not_clauses).to be_empty | ||||
|       expect(subject.filter_clauses).to be_empty | ||||
|       expect(subject.send(:must_clauses).map(&:term)).to match_array %w(hello world) | ||||
|       expect(subject.send(:must_not_clauses)).to be_empty | ||||
|       expect(subject.send(:filter_clauses)).to be_empty | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -21,9 +22,9 @@ describe SearchQueryTransformer do | |||
|     let(:query) { 'hello -world' } | ||||
| 
 | ||||
|     it 'transforms clauses' do | ||||
|       expect(subject.must_clauses.map(&:term)).to match_array %w(hello) | ||||
|       expect(subject.must_not_clauses.map(&:term)).to match_array %w(world) | ||||
|       expect(subject.filter_clauses).to be_empty | ||||
|       expect(subject.send(:must_clauses).map(&:term)).to match_array %w(hello) | ||||
|       expect(subject.send(:must_not_clauses).map(&:term)).to match_array %w(world) | ||||
|       expect(subject.send(:filter_clauses)).to be_empty | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -31,9 +32,9 @@ describe SearchQueryTransformer do | |||
|     let(:query) { 'hello is:reply' } | ||||
| 
 | ||||
|     it 'transforms clauses' do | ||||
|       expect(subject.must_clauses.map(&:term)).to match_array %w(hello) | ||||
|       expect(subject.must_not_clauses).to be_empty | ||||
|       expect(subject.filter_clauses.map(&:term)).to match_array %w(reply) | ||||
|       expect(subject.send(:must_clauses).map(&:term)).to match_array %w(hello) | ||||
|       expect(subject.send(:must_not_clauses)).to be_empty | ||||
|       expect(subject.send(:filter_clauses).map(&:term)).to match_array %w(reply) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -41,9 +42,9 @@ describe SearchQueryTransformer do | |||
|     let(:query) { 'foo: bar' } | ||||
| 
 | ||||
|     it 'transforms clauses' do | ||||
|       expect(subject.must_clauses.map(&:term)).to match_array %w(foo bar) | ||||
|       expect(subject.must_not_clauses).to be_empty | ||||
|       expect(subject.filter_clauses).to be_empty | ||||
|       expect(subject.send(:must_clauses).map(&:term)).to match_array %w(foo bar) | ||||
|       expect(subject.send(:must_not_clauses)).to be_empty | ||||
|       expect(subject.send(:filter_clauses)).to be_empty | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -51,9 +52,9 @@ describe SearchQueryTransformer do | |||
|     let(:query) { 'foo:bar' } | ||||
| 
 | ||||
|     it 'transforms clauses' do | ||||
|       expect(subject.must_clauses.map(&:term)).to contain_exactly('foo bar') | ||||
|       expect(subject.must_not_clauses).to be_empty | ||||
|       expect(subject.filter_clauses).to be_empty | ||||
|       expect(subject.send(:must_clauses).map(&:term)).to contain_exactly('foo bar') | ||||
|       expect(subject.send(:must_not_clauses)).to be_empty | ||||
|       expect(subject.send(:filter_clauses)).to be_empty | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue