mirror of https://github.com/mastodon/mastodon
Add a bit more to the term rule in the parser (#19)
* Add a bit more to the term rule in the parser * Add a shortcode transformer * lint
This commit is contained in:
parent
57f592fed5
commit
81813da9e6
|
@ -1,13 +1,13 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class SearchQueryParser < Parslet::Parser
|
class SearchQueryParser < Parslet::Parser
|
||||||
rule(:term) { match('[^\s":]').repeat(1).as(:term) }
|
rule(:term) { match('[^\s":+-]').repeat(1).as(:term) }
|
||||||
rule(:quote) { str('"') }
|
rule(:quote) { str('"') }
|
||||||
rule(:colon) { str(':') }
|
rule(:colon) { str(':') }
|
||||||
rule(:space) { match('\s').repeat(1) }
|
rule(:space) { match('\s').repeat(1) }
|
||||||
rule(:operator) { (str('+') | str('-')).as(:operator) }
|
rule(:operator) { (str('+') | str('-')).as(:operator) }
|
||||||
rule(:prefix) { term >> colon }
|
rule(:prefix) { term >> colon }
|
||||||
rule(:shortcode) { (colon >> term >> colon.maybe).as(:shortcode) }
|
rule(:shortcode) { (operator.maybe >> colon >> term >> colon.maybe).as(:shortcode) }
|
||||||
rule(:phrase) { (quote >> (match('[^\s"]').repeat(1).as(:term) >> space.maybe).repeat >> quote).as(:phrase) }
|
rule(:phrase) { (quote >> (match('[^\s"]').repeat(1).as(:term) >> space.maybe).repeat >> quote).as(:phrase) }
|
||||||
rule(:clause) { (operator.maybe >> prefix.maybe.as(:prefix) >> (phrase | term | shortcode)).as(:clause) | prefix.as(:clause) | quote.as(:junk) }
|
rule(:clause) { (operator.maybe >> prefix.maybe.as(:prefix) >> (phrase | term | shortcode)).as(:clause) | prefix.as(:clause) | quote.as(:junk) }
|
||||||
rule(:query) { (clause >> space.maybe).repeat.as(:query) }
|
rule(:query) { (clause >> space.maybe).repeat.as(:query) }
|
||||||
|
|
|
@ -222,10 +222,29 @@ class SearchQueryTransformer < Parslet::Transform
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class ShortCodeClause
|
||||||
|
attr_reader :operator, :prefix, :shortcode
|
||||||
|
|
||||||
|
def initialize(operator, shortcode)
|
||||||
|
@operator = Operator.symbol(operator)
|
||||||
|
@shortcode = shortcode
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_query
|
||||||
|
{ multi_match: { type: 'most_fields', query: @shortcode, fields: ['text', 'text.stemmed'], operator: 'and' } }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
rule(clause: subtree(:clause)) do
|
rule(clause: subtree(:clause)) do
|
||||||
prefix = clause[:prefix][:term].to_s if clause[:prefix]
|
prefix = clause[:prefix][:term].to_s if clause[:prefix]
|
||||||
operator = clause[:operator]&.to_s
|
operator = clause[:operator]&.to_s
|
||||||
term = clause[:phrase] ? clause[:phrase].map { |term| term[:term].to_s }.join(' ') : clause[:term].to_s
|
term = if clause[:phrase]
|
||||||
|
clause[:phrase].map { |term| term[:term].to_s }.join(' ')
|
||||||
|
elsif clause[:shortcode]
|
||||||
|
clause[:shortcode][:term].to_s
|
||||||
|
else
|
||||||
|
clause[:term].to_s
|
||||||
|
end
|
||||||
|
|
||||||
if clause[:prefix] && SUPPORTED_PREFIXES.include?(prefix)
|
if clause[:prefix] && SUPPORTED_PREFIXES.include?(prefix)
|
||||||
PrefixClause.new(prefix, operator, term, current_account: current_account)
|
PrefixClause.new(prefix, operator, term, current_account: current_account)
|
||||||
|
@ -235,6 +254,8 @@ class SearchQueryTransformer < Parslet::Transform
|
||||||
TermClause.new(operator, term)
|
TermClause.new(operator, term)
|
||||||
elsif clause[:phrase]
|
elsif clause[:phrase]
|
||||||
PhraseClause.new(operator, term)
|
PhraseClause.new(operator, term)
|
||||||
|
elsif clause[:shortcode]
|
||||||
|
ShortCodeClause.new(operator, term)
|
||||||
else
|
else
|
||||||
raise "Unexpected clause type: #{clause}"
|
raise "Unexpected clause type: #{clause}"
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,6 +32,10 @@ describe SearchQueryParser do
|
||||||
it 'consumes ":foo:"' do
|
it 'consumes ":foo:"' do
|
||||||
expect(parser.shortcode).to parse(':foo:')
|
expect(parser.shortcode).to parse(':foo:')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'consumes "+:foo:"' do
|
||||||
|
expect(parser.shortcode).to parse('+:foo:')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with phrase' do
|
context 'with phrase' do
|
||||||
|
@ -53,6 +57,10 @@ describe SearchQueryParser do
|
||||||
expect(parser.clause).to parse('foo:bar')
|
expect(parser.clause).to parse('foo:bar')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'consumes "+:foo:"' do
|
||||||
|
expect(parser.clause).to parse('+:foo:')
|
||||||
|
end
|
||||||
|
|
||||||
it 'consumes "-foo:bar"' do
|
it 'consumes "-foo:bar"' do
|
||||||
expect(parser.clause).to parse('-foo:bar')
|
expect(parser.clause).to parse('-foo:bar')
|
||||||
end
|
end
|
||||||
|
@ -94,5 +102,13 @@ describe SearchQueryParser do
|
||||||
it 'consumes "foo:bar bar: hello"' do
|
it 'consumes "foo:bar bar: hello"' do
|
||||||
expect(parser.query).to parse('foo:bar bar: hello')
|
expect(parser.query).to parse('foo:bar bar: hello')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'consumes "foo +:bar:"' do
|
||||||
|
expect(parser.query).to parse('foo +:bar:')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'consumes "foo+:bar:"' do
|
||||||
|
expect(parser.query).to parse('foo+:bar:')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -58,6 +58,26 @@ describe SearchQueryTransformer do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with ":foo:"' do
|
||||||
|
let(:query) { ':foo:' }
|
||||||
|
|
||||||
|
it 'transforms clauses' do
|
||||||
|
expect(subject.send(:must_clauses).map(&:shortcode)).to contain_exactly('foo')
|
||||||
|
expect(subject.send(:must_not_clauses)).to be_empty
|
||||||
|
expect(subject.send(:filter_clauses)).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with "-:foo:"' do
|
||||||
|
let(:query) { '-:foo:' }
|
||||||
|
|
||||||
|
it 'transforms clauses' do
|
||||||
|
expect(subject.send(:must_clauses)).to be_empty
|
||||||
|
expect(subject.send(:must_not_clauses).map(&:shortcode)).to contain_exactly('foo')
|
||||||
|
expect(subject.send(:filter_clauses)).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with \'"hello world"\'' do
|
context 'with \'"hello world"\'' do
|
||||||
let(:query) { '"hello world"' }
|
let(:query) { '"hello world"' }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue