summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2023-09-04 17:20:35 +0200
committerGitHub <noreply@github.com>2023-09-04 17:20:35 +0200
commitece1ff77d6b2bde578d3bdaad45589589d96902d (patch)
treeece8cc977362b710b14a40b46888aad165cd7cf0
parentac3f310f4b9a2bca50f0b70fe44e525650d5b836 (diff)
Add `in:library` syntax to search (#26760)
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
-rw-r--r--app/lib/search_query_transformer.rb88
-rw-r--r--app/services/statuses_search_service.rb37
-rw-r--r--spec/lib/search_query_transformer_spec.rb33
3 files changed, 98 insertions, 60 deletions
diff --git a/app/lib/search_query_transformer.rb b/app/lib/search_query_transformer.rb
index af3964fd3c9..2dc10830d48 100644
--- a/app/lib/search_query_transformer.rb
+++ b/app/lib/search_query_transformer.rb
@@ -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
diff --git a/app/services/statuses_search_service.rb b/app/services/statuses_search_service.rb
index 2317a2a1acb..e4b38a9dabe 100644
--- a/app/services/statuses_search_service.rb
+++ b/app/services/statuses_search_service.rb
@@ -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
diff --git a/spec/lib/search_query_transformer_spec.rb b/spec/lib/search_query_transformer_spec.rb
index 17f06d2833d..4b949b1b825 100644
--- a/spec/lib/search_query_transformer_spec.rb
+++ b/spec/lib/search_query_transformer_spec.rb
@@ -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