summaryrefslogtreecommitdiff
path: root/lib/gitlab/search/query.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/search/query.rb')
-rw-r--r--lib/gitlab/search/query.rb55
1 files changed, 55 insertions, 0 deletions
diff --git a/lib/gitlab/search/query.rb b/lib/gitlab/search/query.rb
new file mode 100644
index 00000000000..8583bce7792
--- /dev/null
+++ b/lib/gitlab/search/query.rb
@@ -0,0 +1,55 @@
+module Gitlab
+ module Search
+ class Query < SimpleDelegator
+ def initialize(query, filter_opts = {}, &block)
+ @raw_query = query.dup
+ @filters = []
+ @filter_options = { default_parser: :downcase.to_proc }.merge(filter_opts)
+
+ self.instance_eval(&block) if block_given?
+
+ @query = Gitlab::Search::ParsedQuery.new(*extract_filters)
+ # set the ParsedQuery as our default delegator thanks to SimpleDelegator
+ super(@query)
+ end
+
+ private
+
+ def filter(name, **attributes)
+ filter = { parser: @filter_options[:default_parser], name: name }.merge(attributes)
+
+ @filters << filter
+ end
+
+ def filter_options(**options)
+ @filter_options.merge!(options)
+ end
+
+ def extract_filters
+ fragments = []
+
+ filters = @filters.each_with_object([]) do |filter, parsed_filters|
+ match = @raw_query.split.find { |part| part =~ /\A#{filter[:name]}:/ }
+ next unless match
+
+ input = match.split(':')[1..-1].join
+ next if input.empty?
+
+ filter[:value] = parse_filter(filter, input)
+ filter[:regex_value] = Regexp.escape(filter[:value]).gsub('\*', '.*?')
+ fragments << match
+
+ parsed_filters << filter
+ end
+
+ query = (@raw_query.split - fragments).join(' ')
+
+ [query, filters]
+ end
+
+ def parse_filter(filter, input)
+ filter[:parser].call(input)
+ end
+ end
+ end
+end