class NoSE::Plans::FilterPlanStep

A query plan performing a filter without an index

Attributes

eq[R]
range[R]

Public Class Methods

apply(parent, state) click to toggle source

Check if filtering can be done (we have all the necessary fields)

# File lib/nose/plans/filter.rb, line 44
def self.apply(parent, state)
  # Get fields and check for possible filtering
  filter_fields, eq_filter, range_filter = filter_fields parent, state
  return nil if filter_fields.empty?

  FilterPlanStep.new eq_filter, range_filter, state \
    if required_fields?(filter_fields, parent)
end
new(eq, range, state = nil) click to toggle source
Calls superclass method NoSE::Plans::PlanStep::new
# File lib/nose/plans/filter.rb, line 9
def initialize(eq, range, state = nil)
  @eq = eq
  @range = range
  super()

  return if state.nil?
  @state = state.dup
  update_state
  @state.freeze
end

Private Class Methods

filter_fields(parent, state) click to toggle source

Get the fields we can possibly filter on

# File lib/nose/plans/filter.rb, line 54
def self.filter_fields(parent, state)
  eq_filter = state.eq.select { |field| parent.fields.include? field }
  filter_fields = eq_filter.dup
  if state.range && parent.fields.include?(state.range)
    range_filter = state.range
    filter_fields << range_filter
  else
    range_filter = nil
  end

  [filter_fields, eq_filter, range_filter]
end
required_fields?(filter_fields, parent) click to toggle source

Check that we have all the fields we are filtering @return [Boolean]

# File lib/nose/plans/filter.rb, line 70
def self.required_fields?(filter_fields, parent)
  filter_fields.map do |field|
    next true if parent.fields.member? field

    # We can also filter if we have a foreign key
    # XXX for now we assume this value is the same
    next unless field.is_a? IDField
    parent.fields.any? do |pfield|
      pfield.is_a?(ForeignKeyField) && pfield.entity == field.parent
    end
  end.all?
end

Public Instance Methods

==(other) click to toggle source

Two filtering steps are equal if they filter on the same fields @return [Boolean]

# File lib/nose/plans/filter.rb, line 22
def ==(other)
  other.instance_of?(self.class) && \
    @eq == other.eq && @range == other.range
end
hash() click to toggle source
# File lib/nose/plans/filter.rb, line 27
def hash
  [@eq.map(&:id), @range.nil? ? nil : @range.id].hash
end
to_color() click to toggle source

:nocov:

# File lib/nose/plans/filter.rb, line 32
def to_color
  "#{super} #{@eq.to_color} #{@range.to_color} " +
    begin
      "#{@parent.state.cardinality} " \
        "-> #{state.cardinality}"
    rescue NoMethodError
      ''
    end
end

Private Instance Methods

update_state() click to toggle source

Apply the filters and perform a uniform estimate on the cardinality @return [void]

# File lib/nose/plans/filter.rb, line 88
def update_state
  @state.eq -= @eq
  @state.cardinality *= @eq.map { |field| 1.0 / field.cardinality } \
                           .inject(1.0, &:*)
  return unless @range

  @state.range = nil
  @state.cardinality *= 0.1
end