diff options
Diffstat (limited to 'lib/gitlab/search')
-rw-r--r-- | lib/gitlab/search/parsed_query.rb | 45 | ||||
-rw-r--r-- | lib/gitlab/search/query.rb | 8 |
2 files changed, 45 insertions, 8 deletions
diff --git a/lib/gitlab/search/parsed_query.rb b/lib/gitlab/search/parsed_query.rb index 1f6e0519b4c..5d5d407c172 100644 --- a/lib/gitlab/search/parsed_query.rb +++ b/lib/gitlab/search/parsed_query.rb @@ -3,6 +3,8 @@ module Gitlab module Search class ParsedQuery + include Gitlab::Utils::StrongMemoize + attr_reader :term, :filters def initialize(term, filters) @@ -11,13 +13,44 @@ module Gitlab end def filter_results(results) - filters = @filters.reject { |filter| filter[:matcher].nil? } - return unless filters + with_matcher = ->(filter) { filter[:matcher].present? } + + excluding = excluding_filters.select(&with_matcher) + including = including_filters.select(&with_matcher) + + return unless excluding.any? || including.any? + + results.select! do |result| + including.all? { |filter| filter[:matcher].call(filter, result) } + end + + results.reject! do |result| + excluding.any? { |filter| filter[:matcher].call(filter, result) } + end + + results + end + + private + + def including_filters + processed_filters(:including) + end + + def excluding_filters + processed_filters(:excluding) + end + + def processed_filters(type) + excluding, including = strong_memoize(:processed_filters) do + filters.partition { |filter| filter[:negated] } + end - results.select do |result| - filters.all? do |filter| - filter[:matcher].call(filter, result) - end + case type + when :including then including + when :excluding then excluding + else + raise ArgumentError.new(type) end end end diff --git a/lib/gitlab/search/query.rb b/lib/gitlab/search/query.rb index ba0e16607a6..27ea0b7367f 100644 --- a/lib/gitlab/search/query.rb +++ b/lib/gitlab/search/query.rb @@ -20,7 +20,10 @@ module Gitlab private def filter(name, **attributes) - filter = { parser: @filter_options[:default_parser], name: name }.merge(attributes) + filter = { + parser: @filter_options[:default_parser], + name: name + }.merge(attributes) @filters << filter end @@ -33,12 +36,13 @@ module Gitlab fragments = [] filters = @filters.each_with_object([]) do |filter, parsed_filters| - match = @raw_query.split.find { |part| part =~ /\A#{filter[:name]}:/ } + match = @raw_query.split.find { |part| part =~ /\A-?#{filter[:name]}:/ } next unless match input = match.split(':')[1..-1].join next if input.empty? + filter[:negated] = match.start_with?("-") filter[:value] = parse_filter(filter, input) filter[:regex_value] = Regexp.escape(filter[:value]).gsub('\*', '.*?') fragments << match |