class NoSE::Query

A representation of a query in the workload

Attributes

limit[R]
order[R]
select[R]

Public Class Methods

new(params, text, group: nil, label: nil) click to toggle source
Calls superclass method NoSE::Statement::new
# File lib/nose/statements/query.rb, line 10
def initialize(params, text, group: nil, label: nil)
  super params, text, group: group, label: label

  populate_conditions params
  @select = params[:select]
  @order = params[:order] || []

  fail InvalidStatementException, 'can\'t order by IDs' \
    if @order.any? { |f| f.is_a? Fields::IDField }

  if join_order.first != @key_path.entities.first
    @key_path = @key_path.reverse
  end

  fail InvalidStatementException, 'must have an equality predicate' \
    if @conditions.empty? || @conditions.values.all?(&:is_range)

  @limit = params[:limit]
end
parse(tree, params, text, group: nil, label: nil) click to toggle source

Build a new query from a provided parse tree @return [Query]

# File lib/nose/statements/query.rb, line 32
def self.parse(tree, params, text, group: nil, label: nil)
  conditions_from_tree tree, params
  fields_from_tree tree, params
  order_from_tree tree, params
  params[:limit] = tree[:limit].to_i if tree[:limit]

  new params, text, group: group, label: label
end

Private Class Methods

fields_from_tree(tree, params) click to toggle source

Extract fields to be selected from a parse tree @return [Set<Field>]

# File lib/nose/statements/query.rb, line 92
def self.fields_from_tree(tree, params)
  params[:select] = tree[:select].flat_map do |field|
    if field.last == '*'
      # Find the entity along the path
      entity = params[:key_path].entities[tree[:path].index(field.first)]
      entity.fields.values
    else
      field = add_field_with_prefix tree[:path], field, params

      fail InvalidStatementException, 'Foreign keys cannot be selected' \
        if field.is_a? Fields::ForeignKeyField

      field
    end
  end.to_set
end
order_from_tree(tree, params) click to toggle source

Extract ordering fields from a parse tree @return [Array<Field>]

# File lib/nose/statements/query.rb, line 112
def self.order_from_tree(tree, params)
  return params[:order] = [] if tree[:order].nil?

  params[:order] = tree[:order][:fields].each_slice(2).map do |field|
    field = field.first if field.first.is_a?(Array)
    add_field_with_prefix tree[:path], field, params
  end
end

Public Instance Methods

==(other) click to toggle source
# File lib/nose/statements/query.rb, line 58
def ==(other)
  other.is_a?(Query) &&
    @graph == other.graph &&
    @select == other.select &&
    @conditions == other.conditions &&
    @order == other.order &&
    @limit == other.limit &&
    @comment == other.comment
end
Also aliased as: eql?
all_fields() click to toggle source

All fields referenced anywhere in the query @return [Set<Fields::Field>]

# File lib/nose/statements/query.rb, line 86
def all_fields
  (@select + @conditions.each_value.map(&:field) + @order).to_set
end
eql?(other)
Alias for: ==
hash() click to toggle source
# File lib/nose/statements/query.rb, line 69
def hash
  @hash ||= [@graph, @select, @conditions, @order, @limit, @comment].hash
end
join_order() click to toggle source

The order entities should be joined according to the query graph @return [Array<Entity>]

# File lib/nose/statements/query.rb, line 75
def join_order
  @graph.join_order(@eq_fields)
end
read_only?() click to toggle source

Specifies that queries don't modify data

# File lib/nose/statements/query.rb, line 80
def read_only?
  true
end
unparse() click to toggle source

Produce the SQL text corresponding to this query @return [String]

# File lib/nose/statements/query.rb, line 43
def unparse
  field_namer = -> (f) { field_path f }

  query = 'SELECT ' + @select.map(&field_namer).join(', ')
  query << " FROM #{from_path @graph.longest_path}"
  query << where_clause(field_namer)

  query << ' ORDER BY ' << @order.map(&field_namer).join(', ') \
    unless @order.empty?
  query << " LIMIT #{@limit}" unless @limit.nil?
  query << " -- #{@comment}" unless @comment.nil?

  query
end

Private Instance Methods

field_path(field) click to toggle source
# File lib/nose/statements/query.rb, line 124
def field_path(field)
  path = @graph.path_between @graph.longest_path.entities.first,
                             field.parent
  path = path.drop_while { |k| @graph.longest_path.include? k } << path[-1]
  path = KeyPath.new(path) unless path.is_a?(KeyPath)

  from_path path, @graph.longest_path, field
end