1module Groonga
2  module ExpressionTree
3    class BinaryOperation
4      attr_reader :operator
5      attr_reader :left
6      attr_reader :right
7      def initialize(operator, left, right)
8        @operator = operator
9        @left = left
10        @right = right
11      end
12
13      def build(expression)
14        @left.build(expression)
15        @right.build(expression)
16        expression.append_operator(@operator, 2)
17      end
18
19      RANGE_OPERATORS = [
20        Operator::LESS,
21        Operator::GREATER,
22        Operator::LESS_EQUAL,
23        Operator::GREATER_EQUAL,
24      ]
25      def estimate_size(table)
26        case @operator
27        when *RANGE_OPERATORS
28          estimate_size_range(table)
29        else
30          table.size
31        end
32      end
33
34      private
35      def estimate_size_range(table)
36        return table.size unless @left.is_a?(Variable)
37        return table.size unless @right.is_a?(Constant)
38
39        column = @left.column
40        value = @right.value
41        index_info = column.find_index(@operator)
42        return table.size if index_info.nil?
43
44        index_column = index_info.index
45        lexicon = index_column.lexicon
46        options = {}
47        case @operator
48        when Operator::LESS
49          options[:max] = value
50          options[:flags] = TableCursorFlags::LT
51        when Operator::LESS_EQUAL
52          options[:max] = value
53          options[:flags] = TableCursorFlags::LE
54        when Operator::GREATER
55          options[:min] = value
56          options[:flags] = TableCursorFlags::GT
57        when Operator::GREATER_EQUAL
58          options[:min] = value
59          options[:flags] = TableCursorFlags::GE
60        end
61        TableCursor.open(lexicon, options) do |cursor|
62          index_column.estimate_size(:lexicon_cursor => cursor)
63        end
64      end
65    end
66  end
67end
68