class Metasploit::Model::Search::Query

Once {Metasploit::Model::Search::Operator search operators} are {Metasploit::Model::Search defined}, a formatted query, composed of space separated formatted operation, `<operator.name>:<formatted_value>`, can be parsed to produce a validatable query.

query = Metasploit::Model::Search::Query.new(
  formatted: 'parts.number:1 parts.number:2 parts.uuid:EX,QR'
)

Operations using the same operator are unioned together, while operations with different operator are intersected together, so the above formatted query can be thought of as `(parts.number:1 || parts.number:2) && parts.uuid:EX,QR`.

# Results

Once a {Metasploit::Model::Search::Query} is defined, it needs to be converted to a data store specific visitor.

Visitors for `ActiveRecord` are defined in {rubydoc.info/gems/metasploit_data_models/MetasploitDataModels/Search/Visitor MetasploitDataModels::Search::Visitor}.

If you want to define your own visitors, you can subclass {Metasploit::Model::Visitation::Visitor}.

Attributes

formatted[RW]

@!attribute [rw] formatted

Query string containing space separated <operator>:<value> pairs.

@return [String]
formatted_operations[W]

@!attribute [rw] ::formatted_operations

@note If using `Shellwords.shellsplit` to pre-parse the query, set {#formatted_operations} instead of rejoining
  the shell words with `.join(" ")` and setting {#formatted} as `Shellwords.shellsplit` strips embedded quotes,
  so quoted spaces will not be handled correctly if joining and setting {#formatted}.

{#formatted} broken up into individual operation (<operator>:<value>) Strings.
klass[RW]

@!attribute [rw] klass

The klass that is being searched.

@return [Class, #search_operator_by_name]
operations[W]

@!attribute [rw] operations

The parsed operations in this query.

@return [Array<Metasploit::Model::Search::Operation::Base>] An Array of operations.

Public Class Methods

formatted_operations(formatted) click to toggle source

Parses {#formatted} into a list of formatted operation composed of <formatted_operator>:<formatted_value> Strings. <formatted_value> may be quoted

@param formatted [String] a String composed of space-separated <formatted_operator>:<formatted_value>

operations.  <formatted_value> may be quoted using the shell quoting rules.

@return [Array<String>] Array of formatted operation. @see Shellwords.shellsplit

# File app/models/metasploit/model/search/query.rb, line 76
def self.formatted_operations(formatted)
  Shellwords.shellsplit(formatted.to_s)
end

Public Instance Methods

formatted_operations() click to toggle source

{#formatted} broken up into individual operation (<operator>:<value>) Strings.

@return [Array<String>]

# File app/models/metasploit/model/search/query.rb, line 83
def formatted_operations
  @formatted_operations ||= self.class.formatted_operations(formatted)
end
operations() click to toggle source

Parses {#formatted} to create search operations that can validate if the {Metasploit::Model::Search::Operation::Base#value value} is correct the operation's {Metasploit::Model::Search::Operation::Base#operator operator's} type.

@return [Array<Metasploit::Model::Search::Operation::Base>] an Array of operation parsed from {#formatted}.

# File app/models/metasploit/model/search/query.rb, line 92
def operations
  unless instance_variable_defined? :@operations
    @operations = formatted_operations.flat_map { |formatted_operation|
      Metasploit::Model::Search::Operation.parse(
          :formatted_operation => formatted_operation,
          :query => self
      )
    }
  end

  @operations
end
operations_by_operator() click to toggle source

@note Query is validated before grouping the operations as {Metasploit::Model::Search::Operation::Null operation using unknown operators} with the same name should not be grouped together when processing this query into an actual search of record and/or models.

Groups {#operations} together by {Metasploit::Model::Search::Operation::Base#operator}.

@return [Hash{Metasploit::Model::Search::Operator::Base => Metasploit::Model::Search::Operation::Base}] Maps

operator to all its operations.

@raise [Metasploit::Model::Invalid] if query is invalid due to invalid operations.

# File app/models/metasploit/model/search/query.rb, line 114
def operations_by_operator
  unless instance_variable_defined? :@operations_by_operator
    valid!

    @operations_by_operator = operations.group_by(&:operator)
  end

  @operations_by_operator ||= operations.group_by(&:operator)
end
parse_operator(formatted_operator) click to toggle source

Converts formatted operator extracted from formatted operation to its {Metasploit::Model::Search::Operator::Base} instance.

@param formatted_operator [#to_sym] formatted operator as parsed from formatted operation. @return [Metasploit::Model::Search::Operation::Base] a type-specific search operation if there is an

{Metasploit::Model::Search::Operator::Base#name} on {#klass} that matches `formatted_operator`.

@return [Metasploit::Model::Search::Operator::Null] if there is not an operator with

{Metasploit::Model::Search::Operator::Base#name} on {#klass} that matches `formatted_operator`.
# File app/models/metasploit/model/search/query.rb, line 132
def parse_operator(formatted_operator)
  operator_name = formatted_operator.to_sym
  operator = klass.search_operator_by_name[operator_name]

  unless operator
    operator = Metasploit::Model::Search::Operator::Null.new(:name => operator_name)
  end

  operator
end
tree() click to toggle source

Groups {#operations} together by {Metasploit::Model::Search::Operation::Base#operator} into {Metasploit::Model::Search::Group::Union unions} that are {Metasploit::Model::Search::Group::Intersection intersected}.

@return [Metasploit::Model::Search::Group::Intersection<Metasploit::Model::Search::Group::Union<Metasploit::Model::Search::Operation::Base>>]

# File app/models/metasploit/model/search/query.rb, line 148
def tree
  unless instance_variable_defined? :@tree
    unions = operations_by_operator.collect do |_operator, operations|
      Metasploit::Model::Search::Group::Union.new(:children => operations)
    end

    @tree = Metasploit::Model::Search::Group::Intersection.new(:children => unions)
  end

  @tree
end
without_operator(operator) click to toggle source

Returns a new query with all {#operations} on the given `operator` removed.

@param operator [Metasploit::Model::Search::Operator::Base] an operator that should be removed from this query. @return [Metasploit::Model:Search::Query] a new query if `operator` is a key in {#operations_by_operator}; otherwise

this query.
# File app/models/metasploit/model/search/query.rb, line 165
def without_operator(operator)
  operations = operations_by_operator[operator]

  if operations
    filtered_operations = self.operations - operations

    self.class.new(
        klass: klass,
        operations: filtered_operations
    )
  else
    self
  end
end

Private Instance Methods

operations_valid() click to toggle source

Validates that all {#operations} are valid.

@return [void]

# File app/models/metasploit/model/search/query.rb, line 185
def operations_valid
  unless operations.all?(&:valid?)
    errors.add(:operations, :invalid)
  end
end