Issues (393)

lib/nose/plans.rb (4 issues)

1
# frozen_string_literal: true
2
3 1
module NoSE
4
  # Statement planning and abstract models of execution steps
5 1
  module Plans
6
    # A single step in a statement plan
7 1
    class PlanStep
8 1
      include Supertype
9
10 1
      attr_accessor :state, :parent
11 1
      attr_reader :children, :cost, :fields
12
13 1
      def initialize
14 510
        @children = Set.new
15 510
        @parent = nil
16 510
        @fields = Set.new
17
      end
18
19
      # :nocov:
20 1
      def to_color
21
        # Split on capital letters and remove the last two parts (PlanStep)
22 5
        self.class.name.split('::').last.split(/(?=[A-Z])/)[0..-3] \
23
          .map(&:downcase).join(' ').capitalize
0 ignored issues
show
Align .map with .class on line 22.
Loading history...
24
      end
25
      # :nocov:
26
27
      # Set the children of the current plan step
28
      # @return [void]
29 1
      def children=(children)
30 111
        @children = children.to_set
31
32
        # Track the parent step of each step
33 111
        children.each do |child|
34 306
          child.instance_variable_set(:@parent, self)
35 306
          fields = child.instance_variable_get(:@fields) + self.fields
36 306
          child.instance_variable_set(:@fields, fields)
37
        end
38
      end
39
40
      # Mark the fields in this index as fetched
41
      # @return [void]
42 1
      def add_fields_from_index(index)
43 288
        @fields += index.all_fields
44
      end
45
46
      # Get the list of steps which led us here
47
      # If a cost model is not provided, statement plans using
48
      # this step cannot be evaluated on the basis of cost
49
      #
50
      # (this is to support PlanStep#parent_index which does not need cost)
51
      # @return [QueryPlan]
52 1
      def parent_steps(cost_model = nil)
53 3853
        steps = nil
54
55 3853
        if @parent.nil?
56 2054
          steps = QueryPlan.new state.query, cost_model
57
        else
58 1799
          steps = @parent.parent_steps cost_model
59 1799
          steps << self
60
        end
61
62 3853
        steps
63
      end
64
65
      # Find the closest index to this step
66
      # @return [PlanStep]
67 1
      def parent_index
68 1579
        step = parent_steps.to_a.reverse_each.find do |parent_step|
69 1046
          parent_step.is_a? IndexLookupPlanStep
70
        end
71 1579
        step.index unless step.nil?
0 ignored issues
show
Use safe navigation (&.) instead of checking if an object exists before calling the method.
Loading history...
72
      end
73
74
      # Calculate the cost of executing this step in the plan
75
      # @return [Integer]
76 1
      def calculate_cost(cost_model)
77 363
        @cost = cost_model.method((subtype_name + '_cost').to_sym).call self
0 ignored issues
show
Prefer string interpolation to string concatenation.
Loading history...
78
      end
79
80
      # Add the Subtype module to all step classes
81
      # @return [void]
82 1
      def self.inherited(child_class)
0 ignored issues
show
Call super to invoke callback defined in the parent class.
Loading history...
83 9
        child_class.send(:include, Subtype)
84
      end
85
    end
86
87
    # A dummy step used to inspect failed statement plans
88 1
    class PrunedPlanStep < PlanStep
89 1
      def state
90
        OpenStruct.new answered?: true
91
      end
92
    end
93
94
    # The root of a tree of statement plans used as a placeholder
95 1
    class RootPlanStep < PlanStep
96 1
      def initialize(state)
97 70
        super()
98 70
        @state = state
99 70
        @cost = 0
100
      end
101
    end
102
103
    # This superclass defines what is necessary for manually defined
104
    # and automatically generated plans to provide for execution
105 1
    class AbstractPlan
106 1
      attr_reader :group, :name, :weight
107
108
      # @abstract Subclasses should produce the steps for executing this query
109 1
      def steps
110
        fail NotImplementedError
111
      end
112
113
      # @abstract Subclasses should produce the fields selected by this plan
114 1
      def select_fields
115
        []
116
      end
117
118
      # @abstract Subclasses should produce the parameters
119
      # necessary for this plan
120 1
      def params
121
        fail NotImplementedError
122
      end
123
    end
124
  end
125
end
126
127 1
require_relative 'plans/filter'
128 1
require_relative 'plans/index_lookup'
129 1
require_relative 'plans/limit'
130 1
require_relative 'plans/sort'
131 1
require_relative 'plans/update'
132
133 1
require_relative 'plans/query_planner'
134 1
require_relative 'plans/update_planner'
135
require_relative 'plans/execution_plan'
136