class NoSE::Plans::UpdatePlan

A plan for executing an update

Attributes

cost_model[R]
index[R]
query_plans[R]
statement[R]
update_fields[R]
update_steps[R]

Public Class Methods

new(statement, index, trees, update_steps, cost_model) click to toggle source
# File lib/nose/plans/update_planner.rb, line 29
def initialize(statement, index, trees, update_steps, cost_model)
  @statement = statement
  @index = index
  @trees = trees
  @query_plans = nil # these will be set later when we pick indexes
  update_steps.each { |step| step.calculate_cost cost_model }
  @update_steps = update_steps
  @cost_model = cost_model

  # Update with fields specified in the settings and conditions
  # (rewrite from foreign keys to IDs if needed)
  @update_fields = if statement.is_a?(Connection) ||
                      statement.is_a?(Delete)
                     []
                   else
                     statement.settings.map(&:field)
                   end
  @update_fields += statement.conditions.each_value.map(&:field)
  @update_fields.map! do |field|
    field.is_a?(Fields::ForeignKeyField) ? field.entity.id_field : field
  end
end

Public Instance Methods

<=>(other) click to toggle source

Two plans are compared by their execution cost @return [Boolean]

# File lib/nose/plans/update_planner.rb, line 143
def <=>(other)
  cost <=> other.cost
end
cost() click to toggle source

The cost is the sum of all the query costs plus the update costs @return [Integer]

# File lib/nose/plans/update_planner.rb, line 155
def cost
  @query_plans.sum_by(&:cost) + update_cost
end
eql?(other) click to toggle source

Compare all the fields for the plan for equality @return [Boolean]

# File lib/nose/plans/update_planner.rb, line 119
def eql?(other)
  return false unless other.is_a? UpdatePlan
  fail 'plans must be resolved before checking equality' \
    if @query_plans.nil? || other.query_plans.nil?

  @statement == other.statement &&
    @index == other.index &&
    @query_plans == other.query_plans &&
    @update_steps == other.update_steps &&
    @cost_model == other.cost_model
end
group() click to toggle source

The group of the associated statement @return [String]

# File lib/nose/plans/update_planner.rb, line 62
def group
  @statement.group
end
name() click to toggle source

Name the plan by the statement @return [String]

# File lib/nose/plans/update_planner.rb, line 68
def name
  "#{@statement.text} for #{@index.key}"
end
params() click to toggle source

Parameters to this update plan @return [Hash]

# File lib/nose/plans/update_planner.rb, line 80
def params
  conditions = if @statement.respond_to?(:conditions)
                 @statement.conditions
               else
                 {}
               end
  settings = if @statement.respond_to?(:settings)
               @statement.settings
             else
               []
             end

  params = conditions.merge Hash[settings.map do |setting|
    [setting.field.id, Condition.new(setting.field, :'=', setting.value)]
  end]

  convert_param_keys params
end
select_query_plans(indexes = nil, &block) click to toggle source

Select query plans to actually use here @return [void]

# File lib/nose/plans/update_planner.rb, line 101
def select_query_plans(indexes = nil, &block)
  if block_given?
    @query_plans = @trees.map(&block)
  else
    @query_plans = @trees.map do |tree|
      plan = tree.select_using_indexes(indexes).min_by(&:cost)
      fail if plan.nil?
      plan
    end
  end

  update_support_fields

  @trees = nil
end
steps() click to toggle source

The steps for this plan are the update steps @return [Array<UpdatePlanStep>]

# File lib/nose/plans/update_planner.rb, line 74
def steps
  @update_steps
end
to_color() click to toggle source

:nocov:

# File lib/nose/plans/update_planner.rb, line 132
def to_color
  "\n   statement: " + @statement.to_color +
    "\n       index: " + @index.to_color +
    "\n query_plans: " + @query_plans.to_color +
    "\nupdate_steps: " + @update_steps.to_color +
    "\n  cost_model: " + @cost_model.to_color
end
update_cost() click to toggle source

The cost of performing the update on this index @return [Integer]

# File lib/nose/plans/update_planner.rb, line 149
def update_cost
  @update_steps.sum_by(&:cost)
end
weight() click to toggle source

The weight of this query for a given workload @return [Integer]

# File lib/nose/plans/update_planner.rb, line 54
def weight
  return 1 if @workload.nil?

  @workload.statement_weights[@statement]
end

Private Instance Methods

convert_param_keys(params) click to toggle source

Ensure we only use primary keys for conditions @return [Hash]

# File lib/nose/plans/update_planner.rb, line 172
def convert_param_keys(params)
  Hash[params.each_value.map do |condition|
    field = condition.field
    if field.is_a?(Fields::ForeignKeyField)
      field = field.entity.id_field
      condition = Condition.new field, condition.operator,
                                condition.value
    end

    [field.id, condition]
  end]
end
update_support_fields() click to toggle source

Add fields from support queries to those which should be updated @return [void]

# File lib/nose/plans/update_planner.rb, line 163
def update_support_fields
  # Add fields fetched from support queries
  @update_fields += @query_plans.flat_map do |query_plan|
    query_plan.query.select.to_a
  end.compact
end