# File lib/puppet/indirector/facts/puppetdb.rb, line 93
  def search(request)
    profile("facts#search", [:puppetdb, :facts, :search, request.key]) do
      return [] unless request.options
      operator_map = {
        'eq' => '=',
        'gt' => '>',
        'lt' => '<',
        'ge' => '>=',
        'le' => '<=',
      }
      filters = request.options.sort.map do |key,value|
        type, name, operator = key.to_s.split('.')
        operator ||= 'eq'
        raise Puppet::Error, "Fact search against keys of type '#{type}' is unsupported" unless type == 'facts'
        if operator == 'ne'
          ['not', ['=', ['fact', name], value]]
        else
          [operator_map[operator], ['fact', name], value]
        end
      end

      query = ["and"] + filters
      query_param = CGI.escape(query.to_json)

      begin
        url = Puppet::Util::Puppetdb.url_path("/v3/nodes?query=#{query_param}")
        response = profile("Fact query request: #{URI.unescape(url)}",
                           [:puppetdb, :facts, :search, :query_request, request.key]) do
          http_get(request, url, headers)
        end
        log_x_deprecation_header(response)

        if response.is_a? Net::HTTPSuccess
          profile("Parse fact query response (size: #{response.body.size})",
                  [:puppetdb, :facts, :search, :parse_query_response, request.key,]) do
            JSON.parse(response.body).collect {|s| s["name"]}
          end
        else
          # Newline characters cause an HTTP error, so strip them
          raise "[#{response.code} #{response.message}] #{response.body.gsub(/[\r\n]/, '')}"
        end
      rescue => e
        raise Puppet::Error, "Could not perform inventory search from PuppetDB at #{self.class.server}:#{self.class.port}: #{e}"
      end
    end
  end